Skip to content
This repository was archived by the owner on Aug 15, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion data/config-mode-dependencies/vyos-vpp.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"vpp_acl": ["vpp_acl"],
"vpp_nat": ["vpp_nat"],
"vpp_nat_cgnat": ["vpp_nat_cgnat"],
"vpp_kernel_interface": ["vpp_kernel-interfaces"]
"vpp_kernel_interface": ["vpp_kernel-interfaces"],
"vpp_vrrp": ["vpp_vrrp"]
},
"vpp_interfaces_bonding": {
"vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"],
Expand Down
2 changes: 2 additions & 0 deletions data/templates/vpp/startup.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ plugins {
# plugin wireguard_plugin.so { enable }
# ACL
plugin acl_plugin.so { enable }
# VRRP
plugin vrrp_plugin.so { enable }
}

linux-cp {
Expand Down
109 changes: 109 additions & 0 deletions interface-definitions/vpp.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,115 @@
</node>
</children>
</node>
<node name="vrrp" owner="${vyos_conf_scripts_dir}/vpp_vrrp.py">
<properties>
<help>VPP Virtual Router Redundancy Protocol (VRRP) settings</help>
<priority>333</priority>
</properties>
<children>
<tagNode name="group">
<properties>
<help>VPP VRRP group</help>
</properties>
<children>
<leafNode name="interface">
<properties>
<help>Interface</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
</properties>
</leafNode>
<leafNode name="advertise-interval">
<properties>
<help>Advertise interval</help>
<valueHelp>
<format>u32:1-255</format>
<description>Advertise interval in seconds</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-255"/>
</constraint>
</properties>
<defaultValue>1</defaultValue>
</leafNode>
#include <include/generic-description.xml.i>
#include <include/generic-disable-node.xml.i>
<leafNode name="peer-address">
<properties>
<help>Unicast VRRP peer address</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 unicast peer address</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 unicast peer address</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
<multi/>
</properties>
</leafNode>
<leafNode name="no-preempt">
<properties>
<valueless/>
<help>Disable master preemption</help>
</properties>
</leafNode>
<leafNode name="accept-mode">
<properties>
<valueless/>
<help>Allow backup VRRP router to accept and process packets</help>
</properties>
</leafNode>
<leafNode name="priority">
<properties>
<help>Router priority</help>
<valueHelp>
<format>u32:1-255</format>
<description>Router priority</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-255"/>
</constraint>
</properties>
<defaultValue>100</defaultValue>
</leafNode>
<leafNode name="address">
<properties>
<help>Virtual IP address</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 address</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address</description>
</valueHelp>
<constraint>
<validator name="ip-address"/>
</constraint>
<multi/>
</properties>
</leafNode>
<leafNode name="vrid">
<properties>
<help>Virtual router identifier</help>
<valueHelp>
<format>u32:1-255</format>
<description>Virtual router identifier</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-255"/>
</constraint>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</node>
<tagNode name="kernel-interfaces" owner="${vyos_conf_scripts_dir}/vpp_kernel-interfaces.py">
<properties>
<help>VPP kernel interface settings</help>
Expand Down
24 changes: 24 additions & 0 deletions op-mode-definitions/vpp_vrrp.xml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="show">
<children>
<node name="vpp">
<children>
<tagNode name="vrrp">
<properties>
<help>Show specified VPP VRRP group</help>
<completionHelp>
<path>vpp vrrp group</path>
</completionHelp>
</properties>
<standalone>
<help>Show VPP VRRP information</help>
<command>sudo ${vyos_op_scripts_dir}/vpp_vrrp.py show_vrrp</command>
</standalone>
<command>sudo ${vyos_op_scripts_dir}/vpp_vrrp.py show_vrrp --group="$5"</command>
</tagNode>
</children>
</node>
</children>
</node>
</interfaceDefinition>
3 changes: 3 additions & 0 deletions python/vyos/vpp/vrrp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .vrrp import Vrrp

__all__ = ['Vrrp']
68 changes: 68 additions & 0 deletions python/vyos/vpp/vrrp/vrrp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#
# Copyright (C) 2025 VyOS Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

from vyos.vpp import VPPControl


class Vrrp:
def __init__(self):
self.vpp = VPPControl()

def add_vrrp_vr(self, interface, vrid, priority, interval, flags, addrs):
"""Add new VRRP VR"""
self.vpp.api.vrrp_vr_add_del(
vr_id=vrid,
is_add=True,
sw_if_index=self.vpp.get_sw_if_index(interface),
priority=priority,
interval=interval * 100,
flags=flags,
n_addrs=len(addrs),
addrs=addrs,
)

def delete_vrrp_vr(self, interface, vrid, priority, interval, flags, addrs):
"""Delete existing VRRP VR"""
self.vpp.api.vrrp_vr_add_del(
vr_id=vrid,
is_add=False,
sw_if_index=self.vpp.get_sw_if_index(interface),
priority=priority,
interval=interval * 100,
flags=flags,
n_addrs=len(addrs),
addrs=addrs,
)

def start_stop_proto_vrrp_vr(self, vrid, interface, is_ipv6, is_start):
"""Start or shutdown the VRRP protocol for a VR"""
self.vpp.api.vrrp_vr_start_stop(
vr_id=vrid,
sw_if_index=self.vpp.get_sw_if_index(interface),
is_ipv6=is_ipv6,
is_start=is_start,
)

def set_vrrp_peers(self, interface, vrid, is_ipv6, addrs):
"""Set unicast peers for a VR"""
self.vpp.api.vrrp_vr_set_peers(
sw_if_index=self.vpp.get_sw_if_index(interface),
vr_id=vrid,
is_ipv6=is_ipv6,
n_addrs=len(addrs),
addrs=addrs,
)
87 changes: 87 additions & 0 deletions smoketest/scripts/cli/test_vpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,93 @@ def test_17_vpp_nat(self):
_, out = rc_cmd('sudo vppctl show nat44 summary')
self.assertIn(f'max translations per thread: {sess_limit} fib 0', out)

def test_18_vpp_vrrp(self):
base_vrrp = base_path + ['vrrp', 'group']
addresses_first = ['192.0.10.1']
vrid_first = '10'
advertise_interval = '5'
priority = '150'
peer_addresses = ['192.0.2.11', '192.0.2.12']
addresses_second = ['2001:db8:1111::1', '2001:db8:1112::1']
vrid_second = '20'
addresses_third = ['192.0.20.1']
vrid_third = '30'

# Set VRRP group FIRST (ipv4)
self.cli_set(base_vrrp + ['FIRST', 'interface', interface])
self.cli_set(base_vrrp + ['FIRST', 'vrid', vrid_first])
self.cli_set(base_vrrp + ['FIRST', 'advertise-interval', advertise_interval])
self.cli_set(base_vrrp + ['FIRST', 'priority', priority])
for address in addresses_first:
self.cli_set(base_vrrp + ['FIRST', 'address', address])
for address in peer_addresses:
self.cli_set(base_vrrp + ['FIRST', 'peer-address', address])

# Interface should have IP address
# expect raise ConfigError
with self.assertRaises(ConfigSessionError):
self.cli_commit()

self.cli_set(['interfaces', 'ethernet', interface, 'address', '192.0.2.11/24'])

self.cli_commit()

# Check information for group FIRST
_, out = rc_cmd('sudo vppctl show vrrp vr')
self.assertIn(f'[0] sw_if_index 1 VR ID {vrid_first} IPv4', out)
self.assertIn('flags: preempt yes accept no unicast yes', out)
self.assertIn(f'priority: configured {priority}', out)
self.assertIn(f'timers: adv interval {advertise_interval}00', out)
self.assertIn(f'addresses {" ".join(addresses_first)}', out)
self.assertIn(f'peer addresses {" ".join(peer_addresses)}', out)

# Set VRRP group SECOND (ipv6)
self.cli_set(base_vrrp + ['SECOND', 'interface', interface])
self.cli_set(base_vrrp + ['SECOND', 'vrid', vrid_second])
for address in addresses_second:
self.cli_set(base_vrrp + ['SECOND', 'address', address])

self.cli_commit()

# Check information for group SECOND
_, out = rc_cmd('sudo vppctl show vrrp vr')
self.assertIn(f'[1] sw_if_index 1 VR ID {vrid_second} IPv6', out)
self.assertIn('flags: preempt yes accept no unicast no', out)
self.assertIn('priority: configured 100', out) # default priority
self.assertIn('timers: adv interval 100', out) # default advertise-interval
self.assertIn(f'addresses {" ".join(addresses_second)}', out)

# VRID can only be used once on interface with the same address family
self.cli_set(base_vrrp + ['THIRD', 'interface', interface])
self.cli_set(base_vrrp + ['THIRD', 'vrid', vrid_first])
self.cli_set(base_vrrp + ['THIRD', 'no-preempt'])
for address in addresses_third:
self.cli_set(base_vrrp + ['THIRD', 'address', address])

# expect raise ConfigError
with self.assertRaises(ConfigSessionError):
self.cli_commit()

self.cli_set(base_vrrp + ['THIRD', 'vrid', vrid_third])

# Virtual address should not be used in another group
self.cli_set(base_vrrp + ['THIRD', 'address', addresses_first[0]])
# expect raise ConfigError
with self.assertRaises(ConfigSessionError):
self.cli_commit()

self.cli_delete(base_vrrp + ['THIRD', 'address', addresses_first[0]])

self.cli_commit()

# Check information for group THIRD
_, out = rc_cmd('sudo vppctl show vrrp vr')
self.assertIn(f'[2] sw_if_index 1 VR ID {vrid_third} IPv4', out)
self.assertIn('flags: preempt no accept no unicast no', out)
self.assertIn('priority: configured 100', out) # default priority
self.assertIn('timers: adv interval 100', out) # default advertise-interval
self.assertIn(f'addresses {" ".join(addresses_third)}', out)


if __name__ == '__main__':
unittest.main(verbosity=2)
4 changes: 4 additions & 0 deletions src/conf_mode/vpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ def get_config(config=None):
# Return to config dictionary
config['persist_config'] = eth_ifaces_persist

# VRRP dependency
if conf.exists(['vpp', 'vrrp', 'group']):
set_dependents('vpp_vrrp', conf)

return config


Expand Down
Loading