summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/netflow/uacctd.conf.tmpl2
-rw-r--r--interface-definitions/interfaces-bonding.xml.in17
-rw-r--r--python/vyos/configdict.py30
-rw-r--r--python/vyos/configverify.py12
-rw-r--r--python/vyos/ifconfig/bond.py75
-rw-r--r--python/vyos/ifconfig/interface.py28
-rw-r--r--python/vyos/validate.py19
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bonding.py67
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py31
-rwxr-xr-xsmoketest/scripts/cli/test_system_flow-accounting.py38
-rwxr-xr-xsrc/conf_mode/interfaces-bonding.py19
-rwxr-xr-xsrc/conf_mode/interfaces-bridge.py10
-rwxr-xr-xsrc/conf_mode/interfaces-ethernet.py2
-rwxr-xr-xsrc/conf_mode/interfaces-geneve.py2
-rwxr-xr-xsrc/conf_mode/interfaces-l2tpv3.py2
-rwxr-xr-xsrc/conf_mode/interfaces-macsec.py2
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py2
-rwxr-xr-xsrc/conf_mode/interfaces-tunnel.py2
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py3
-rwxr-xr-xsrc/conf_mode/interfaces-wireguard.py2
-rwxr-xr-xsrc/conf_mode/interfaces-wireless.py2
21 files changed, 294 insertions, 73 deletions
diff --git a/data/templates/netflow/uacctd.conf.tmpl b/data/templates/netflow/uacctd.conf.tmpl
index d53f5374d..1ee65a28e 100644
--- a/data/templates/netflow/uacctd.conf.tmpl
+++ b/data/templates/netflow/uacctd.conf.tmpl
@@ -21,7 +21,7 @@ imt_mem_pools_number: 169
{% endif %}
plugins: {% if templatecfg['netflow']['servers'] != none %}
{% for server in templatecfg['netflow']['servers'] %}
-{% if loop.last %}nfprobe[nf_{{ server['address'] | dot_colon_to_dash }}]{% else %}nfprobe[nf_{{ server['address'] | dot_colon_to_dash }} ],{% endif %}
+{% if loop.last %}nfprobe[nf_{{ server['address'] | dot_colon_to_dash }}]{% else %}nfprobe[nf_{{ server['address'] | dot_colon_to_dash }}],{% endif %}
{% endfor %}
{% set plugins_presented = true %}
{% endif %}
diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in
index 5a4f08bef..307dd7558 100644
--- a/interface-definitions/interfaces-bonding.xml.in
+++ b/interface-definitions/interfaces-bonding.xml.in
@@ -92,6 +92,23 @@
#include <include/interface/ipv4-options.xml.i>
#include <include/interface/ipv6-options.xml.i>
#include <include/interface/mac.xml.i>
+ <leafNode name="mii-mon-interval">
+ <properties>
+ <help>Specifies the MII link monitoring frequency in milliseconds</help>
+ <valueHelp>
+ <format>u32:0</format>
+ <description>Disable MII link monitoring</description>
+ </valueHelp>
+ <valueHelp>
+ <format>u32:50-1000</format>
+ <description>MII link monitoring frequency in milliseconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 0-0 --range 50-1000"/>
+ </constraint>
+ </properties>
+ <defaultValue>100</defaultValue>
+ </leafNode>
<leafNode name="min-links">
<properties>
<help>Minimum number of member interfaces required up before enabling bond</help>
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index be10cbdfc..70e5cd889 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -203,11 +203,12 @@ def is_member(conf, interface, intftype=None):
intftype is optional, if not passed it will search all known types
(currently bridge and bonding)
- Returns:
- None -> Interface is not a member
- interface name -> Interface is a member of this interface
- False -> interface type cannot have members
+ Returns: dict
+ empty -> Interface is not a member
+ key -> Interface is a member of this interface
"""
+ from vyos.ifconfig import Section
+
ret_val = {}
intftypes = ['bonding', 'bridge']
@@ -227,9 +228,24 @@ def is_member(conf, interface, intftype=None):
for intf in conf.list_nodes(base):
member = base + [intf, 'member', 'interface', interface]
if conf.exists(member):
- tmp = conf.get_config_dict(member, key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
- ret_val.update({intf : tmp})
+ member_type = Section.section(interface)
+ # Check if it's a VLAN (QinQ) interface
+ interface = interface.split('.')
+ if len(interface) == 3:
+ if conf.exists(['interfaces', member_type, interface[0], 'vif-s', interface[1], 'vif-c', interface[2]]):
+ tmp = conf.get_config_dict(['interfaces', member_type, interface[0]],
+ key_mangling=('-', '_'), get_first_key=True)
+ ret_val.update({intf : tmp})
+ elif len(interface) == 2:
+ if conf.exists(['interfaces', member_type, interface[0], 'vif', interface[1]]):
+ tmp = conf.get_config_dict(['interfaces', member_type, interface[0]],
+ key_mangling=('-', '_'), get_first_key=True)
+ ret_val.update({intf : tmp})
+ else:
+ if conf.exists(['interfaces', member_type, interface[0]]):
+ tmp = conf.get_config_dict(['interfaces', member_type, interface[0]],
+ key_mangling=('-', '_'), get_first_key=True)
+ ret_val.update({intf : tmp})
old_level = conf.set_level(old_level)
return ret_val
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index 6566e8863..44342f289 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -84,6 +84,18 @@ def verify_mtu_ipv6(config):
tmp = dict_search('ipv6.address.eui64', config)
if tmp != None: raise ConfigError(error_msg)
+def verify_bond_bridge_member(config):
+ """
+ Checks if interface has a VRF configured and is also part of a bond or
+ bridge, which is not allowed!
+ """
+ if 'vrf' in config:
+ ifname = config['ifname']
+ if 'is_bond_member' in config:
+ raise ConfigError(f'Can not add interface "{ifname}" to bond, it has a VRF assigned!')
+ if 'is_bridge_member' in config:
+ raise ConfigError(f'Can not add interface "{ifname}" to bridge, it has a VRF assigned!')
+
def verify_tunnel(config):
"""
This helper is used to verify the common part of the tunnel
diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py
index 27d0182e9..47e0598ab 100644
--- a/python/vyos/ifconfig/bond.py
+++ b/python/vyos/ifconfig/bond.py
@@ -176,6 +176,21 @@ class BondIf(Interface):
"""
self.set_interface('bond_lacp_rate', slow_fast)
+ def set_miimon_interval(self, interval):
+ """
+ Specifies the MII link monitoring frequency in milliseconds. This
+ determines how often the link state of each slave is inspected for link
+ failures. A value of zero disables MII link monitoring. A value of 100
+ is a good starting point.
+
+ The default value is 0.
+
+ Example:
+ >>> from vyos.ifconfig import BondIf
+ >>> BondIf('bond0').set_miimon_interval('100')
+ """
+ return self.set_interface('bond_miimon', interval)
+
def set_arp_interval(self, interval):
"""
Specifies the ARP link monitoring frequency in milliseconds.
@@ -199,16 +214,7 @@ class BondIf(Interface):
>>> from vyos.ifconfig import BondIf
>>> BondIf('bond0').set_arp_interval('100')
"""
- if int(interval) == 0:
- """
- Specifies the MII link monitoring frequency in milliseconds.
- This determines how often the link state of each slave is
- inspected for link failures. A value of zero disables MII
- link monitoring. A value of 100 is a good starting point.
- """
- return self.set_interface('bond_miimon', interval)
- else:
- return self.set_interface('bond_arp_interval', interval)
+ return self.set_interface('bond_arp_interval', interval)
def get_arp_ip_target(self):
"""
@@ -365,26 +371,9 @@ class BondIf(Interface):
if 'shutdown_required' in config:
self.set_admin_state('down')
- # ARP monitor targets need to be synchronized between sysfs and CLI.
- # Unfortunately an address can't be send twice to sysfs as this will
- # result in the following exception: OSError: [Errno 22] Invalid argument.
- #
- # We remove ALL addresses prior to adding new ones, this will remove
- # addresses manually added by the user too - but as we are limited to 16 adresses
- # from the kernel side this looks valid to me. We won't run into an error
- # when a user added manual adresses which would result in having more
- # then 16 adresses in total.
- arp_tgt_addr = list(map(str, self.get_arp_ip_target().split()))
- for addr in arp_tgt_addr:
- self.set_arp_ip_target('-' + addr)
-
- # Add configured ARP target addresses
- value = dict_search('arp_monitor.target', config)
- if isinstance(value, str):
- value = [value]
- if value:
- for addr in value:
- self.set_arp_ip_target('+' + addr)
+ # Specifies the MII link monitoring frequency in milliseconds
+ value = config.get('mii_mon_interval')
+ self.set_miimon_interval(value)
# Bonding transmit hash policy
value = config.get('hash_policy')
@@ -414,6 +403,32 @@ class BondIf(Interface):
if mode == '802.3ad':
self.set_lacp_rate(config.get('lacp_rate'))
+ if mode not in ['802.3ad', 'balance-tlb', 'balance-alb']:
+ tmp = dict_search('arp_monitor.interval', config)
+ value = tmp if (tmp != None) else '0'
+ self.set_arp_interval(value)
+
+ # ARP monitor targets need to be synchronized between sysfs and CLI.
+ # Unfortunately an address can't be send twice to sysfs as this will
+ # result in the following exception: OSError: [Errno 22] Invalid argument.
+ #
+ # We remove ALL addresses prior to adding new ones, this will remove
+ # addresses manually added by the user too - but as we are limited to 16 adresses
+ # from the kernel side this looks valid to me. We won't run into an error
+ # when a user added manual adresses which would result in having more
+ # then 16 adresses in total.
+ arp_tgt_addr = list(map(str, self.get_arp_ip_target().split()))
+ for addr in arp_tgt_addr:
+ self.set_arp_ip_target('-' + addr)
+
+ # Add configured ARP target addresses
+ value = dict_search('arp_monitor.target', config)
+ if isinstance(value, str):
+ value = [value]
+ if value:
+ for addr in value:
+ self.set_arp_ip_target('+' + addr)
+
# Add (enslave) interfaces to bond
value = dict_search('member.interface', config)
for interface in (value or []):
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 9eed3acb9..9b08d83de 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -1304,14 +1304,22 @@ class Interface(Control):
if dhcpv6pd:
self.set_dhcpv6(True)
- # There are some items in the configuration which can only be applied
- # if this instance is not bound to a bridge. This should be checked
- # by the caller but better save then sorry!
- if not any(k in ['is_bond_member', 'is_bridge_member'] for k in config):
- # Bind interface to given VRF or unbind it if vrf node is not set.
- # unbinding will call 'ip link set dev eth0 nomaster' which will
- # also drop the interface out of a bridge or bond - thus this is
- # checked before
+ # XXX: Bind interface to given VRF or unbind it if vrf is not set. Unbinding
+ # will call 'ip link set dev eth0 nomaster' which will also drop the
+ # interface out of any bridge or bond - thus this is checked before.
+ if 'is_bond_member' in config:
+ bond_if = next(iter(config['is_bond_member']))
+ tmp = get_interface_config(config['ifname'])
+ if 'master' in tmp and tmp['master'] != bond_if:
+ self.set_vrf('')
+
+ elif 'is_bridge_member' in config:
+ bridge_if = next(iter(config['is_bridge_member']))
+ tmp = get_interface_config(config['ifname'])
+ if 'master' in tmp and tmp['master'] != bridge_if:
+ self.set_vrf('')
+
+ else:
self.set_vrf(config.get('vrf', ''))
# Add this section after vrf T4331
@@ -1412,8 +1420,8 @@ class Interface(Control):
# re-add ourselves to any bridge we might have fallen out of
if 'is_bridge_member' in config:
- bridge_dict = config.get('is_bridge_member')
- self.add_to_bridge(bridge_dict)
+ tmp = config.get('is_bridge_member')
+ self.add_to_bridge(tmp)
# configure port mirror
self.set_mirror()
diff --git a/python/vyos/validate.py b/python/vyos/validate.py
index 23e88b5ac..9aa23d3dc 100644
--- a/python/vyos/validate.py
+++ b/python/vyos/validate.py
@@ -260,3 +260,22 @@ def has_address_configured(conf, intf):
conf.set_level(old_level)
return ret
+
+def has_vrf_configured(conf, intf):
+ """
+ Checks if interface has a VRF configured.
+
+ Returns True if interface has VRF configured, False if it doesn't.
+ """
+ from vyos.ifconfig import Section
+ ret = False
+
+ old_level = conf.get_level()
+ conf.set_level([])
+
+ tmp = ['interfaces', Section.get_config_path(intf), 'vrf']
+ if conf.exists(tmp):
+ ret = True
+
+ conf.set_level(old_level)
+ return ret
diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py
index 9bb561275..ab75cdcc9 100755
--- a/smoketest/scripts/cli/test_interfaces_bonding.py
+++ b/smoketest/scripts/cli/test_interfaces_bonding.py
@@ -49,7 +49,7 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
if not '.' in tmp:
cls._members.append(tmp)
- cls._options['bond0'] = []
+ cls._options = {'bond0' : []}
for member in cls._members:
cls._options['bond0'].append(f'member interface {member}')
cls._interfaces = list(cls._options)
@@ -136,7 +136,7 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
def test_bonding_hash_policy(self):
# Define available bonding hash policies
- hash_policies = ['layer2', 'layer2+3', 'layer2+3', 'encap2+3', 'encap3+4']
+ hash_policies = ['layer2', 'layer2+3', 'encap2+3', 'encap3+4']
for hash_policy in hash_policies:
for interface in self._interfaces:
for option in self._options.get(interface, []):
@@ -151,6 +151,29 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
defined_policy = read_file(f'/sys/class/net/{interface}/bonding/xmit_hash_policy').split()
self.assertEqual(defined_policy[0], hash_policy)
+ def test_bonding_mii_monitoring_interval(self):
+ for interface in self._interfaces:
+ for option in self._options.get(interface, []):
+ self.cli_set(self._base_path + [interface] + option.split())
+
+ self.cli_commit()
+
+ # verify default
+ for interface in self._interfaces:
+ tmp = read_file(f'/sys/class/net/{interface}/bonding/miimon').split()
+ self.assertIn('100', tmp)
+
+ mii_mon = '250'
+ for interface in self._interfaces:
+ self.cli_set(self._base_path + [interface, 'mii-mon-interval', mii_mon])
+
+ self.cli_commit()
+
+ # verify new CLI value
+ for interface in self._interfaces:
+ tmp = read_file(f'/sys/class/net/{interface}/bonding/miimon').split()
+ self.assertIn(mii_mon, tmp)
+
def test_bonding_multi_use_member(self):
# Define available bonding hash policies
for interface in ['bond10', 'bond20']:
@@ -165,6 +188,46 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_commit()
+ def test_bonding_source_interface(self):
+ # Re-use member interface that is already a source-interface
+ bond = 'bond99'
+ pppoe = 'pppoe98756'
+ member = next(iter(self._members))
+
+ self.cli_set(self._base_path + [bond, 'member', 'interface', member])
+ self.cli_set(['interfaces', 'pppoe', pppoe, 'source-interface', member])
+
+ # check validate() - can not add interface to bond, it is the source-interface of ...
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_delete(['interfaces', 'pppoe', pppoe])
+ self.cli_commit()
+
+ # verify config
+ slaves = read_file(f'/sys/class/net/{bond}/bonding/slaves').split()
+ self.assertIn(member, slaves)
+
+ def test_bonding_source_bridge_interface(self):
+ # Re-use member interface that is already a source-interface
+ bond = 'bond1097'
+ bridge = 'br6327'
+ member = next(iter(self._members))
+
+ self.cli_set(self._base_path + [bond, 'member', 'interface', member])
+ self.cli_set(['interfaces', 'bridge', bridge, 'member', 'interface', member])
+
+ # check validate() - can not add interface to bond, it is a member of bridge ...
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_delete(['interfaces', 'bridge', bridge])
+ self.cli_commit()
+
+ # verify config
+ slaves = read_file(f'/sys/class/net/{bond}/bonding/slaves').split()
+ self.assertIn(member, slaves)
+
def test_bonding_uniq_member_description(self):
ethernet_path = ['interfaces', 'ethernet']
for interface in self._interfaces:
diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py
index 09441326a..b4b91f226 100755
--- a/smoketest/scripts/cli/test_interfaces_bridge.py
+++ b/smoketest/scripts/cli/test_interfaces_bridge.py
@@ -224,7 +224,7 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_delete(self._base_path + [interface, 'member'])
- def test_bridge_vlan_members(self):
+ def test_bridge_vif_members(self):
# T2945: ensure that VIFs are not dropped from bridge
vifs = ['300', '400']
for interface in self._interfaces:
@@ -249,5 +249,34 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
self.cli_delete(['interfaces', 'ethernet', member, 'vif', vif])
self.cli_delete(['interfaces', 'bridge', interface, 'member', 'interface', f'{member}.{vif}'])
+ def test_bridge_vif_s_vif_c_members(self):
+ # T2945: ensure that VIFs are not dropped from bridge
+ vifs = ['300', '400']
+ vifc = ['301', '401']
+ for interface in self._interfaces:
+ for member in self._members:
+ for vif_s in vifs:
+ for vif_c in vifc:
+ self.cli_set(['interfaces', 'ethernet', member, 'vif-s', vif_s, 'vif-c', vif_c])
+ self.cli_set(['interfaces', 'bridge', interface, 'member', 'interface', f'{member}.{vif_s}.{vif_c}'])
+
+ self.cli_commit()
+
+ # Verify config
+ for interface in self._interfaces:
+ for member in self._members:
+ for vif_s in vifs:
+ for vif_c in vifc:
+ # member interface must be assigned to the bridge
+ self.assertTrue(os.path.exists(f'/sys/class/net/{interface}/lower_{member}.{vif_s}.{vif_c}'))
+
+ # delete all members
+ for interface in self._interfaces:
+ for member in self._members:
+ for vif_s in vifs:
+ self.cli_delete(['interfaces', 'ethernet', member, 'vif-s', vif_s])
+ for vif_c in vifc:
+ self.cli_delete(['interfaces', 'bridge', interface, 'member', 'interface', f'{member}.{vif_s}.{vif_c}'])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py
index 57866a198..92a7973fa 100755
--- a/smoketest/scripts/cli/test_system_flow-accounting.py
+++ b/smoketest/scripts/cli/test_system_flow-accounting.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2022 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -64,7 +64,8 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
# verify configuration
tmp = cmd('sudo iptables-save -t raw')
for interface in Section.interfaces('ethernet'):
- self.assertIn(f'-A VYATTA_CT_PREROUTING_HOOK -i {interface} -m comment --comment FLOW_ACCOUNTING_RULE -j NFLOG --nflog-group 2 --nflog-size 128 --nflog-threshold 100', tmp)
+ self.assertIn(f'-A VYATTA_CT_PREROUTING_HOOK -i {interface} -m comment --comment FLOW_ACCOUNTING_RULE -j '
+ f'NFLOG --nflog-group 2 --nflog-size 128 --nflog-threshold 100', tmp)
uacctd = read_file(uacctd_conf)
# circular queue size - buffer_size
@@ -130,14 +131,15 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
self.assertNotIn(f'plugins: memory', uacctd)
for server, server_config in sflow_server.items():
+ tmp_srv = server.replace('.', '-')
if 'port' in server_config:
- self.assertIn(f'sfprobe_receiver[sf_{server}]: {server}', uacctd)
+ self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {server}', uacctd)
else:
- self.assertIn(f'sfprobe_receiver[sf_{server}]: {server}:6343', uacctd)
+ self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {server}:6343', uacctd)
- self.assertIn(f'sfprobe_agentip[sf_{server}]: {agent_address}', uacctd)
- self.assertIn(f'sampling_rate[sf_{server}]: {sampling_rate}', uacctd)
- self.assertIn(f'sfprobe_source_ip[sf_{server}]: {source_address}', uacctd)
+ self.assertIn(f'sfprobe_agentip[sf_{tmp_srv}]: {agent_address}', uacctd)
+ self.assertIn(f'sampling_rate[sf_{tmp_srv}]: {sampling_rate}', uacctd)
+ self.assertIn(f'sfprobe_source_ip[sf_{tmp_srv}]: {source_address}', uacctd)
self.cli_delete(['interfaces', 'dummy', dummy_if])
@@ -203,23 +205,27 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
tmp = 'plugins: '
for server, server_config in netflow_server.items():
- tmp += f'nfprobe[nf_{server}],'
+ tmp_srv = server.replace('.', '-')
+ tmp += f'nfprobe[nf_{tmp_srv}],'
tmp += 'memory'
self.assertIn(f'{tmp}', uacctd)
for server, server_config in netflow_server.items():
- self.assertIn(f'nfprobe_engine[nf_{server}]: {engine_id}', uacctd)
- self.assertIn(f'nfprobe_maxflows[nf_{server}]: {max_flows}', uacctd)
- self.assertIn(f'sampling_rate[nf_{server}]: {sampling_rate}', uacctd)
- self.assertIn(f'nfprobe_source_ip[nf_{server}]: {source_address}', uacctd)
- self.assertIn(f'nfprobe_version[nf_{server}]: {version}', uacctd)
+ tmp_srv = server.replace('.', '-')
+ self.assertIn(f'nfprobe_engine[nf_{tmp_srv}]: {engine_id}', uacctd)
+ self.assertIn(f'nfprobe_maxflows[nf_{tmp_srv}]: {max_flows}', uacctd)
+ self.assertIn(f'sampling_rate[nf_{tmp_srv}]: {sampling_rate}', uacctd)
+ self.assertIn(f'nfprobe_source_ip[nf_{tmp_srv}]: {source_address}', uacctd)
+ self.assertIn(f'nfprobe_version[nf_{tmp_srv}]: {version}', uacctd)
if 'port' in server_config:
- self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}', uacctd)
+ self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {server}', uacctd)
else:
- self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}:2055', uacctd)
+ self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {server}:2055', uacctd)
- self.assertIn(f'nfprobe_timeouts[nf_{server}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd)
+ self.assertIn(f'nfprobe_timeouts[nf_{tmp_srv}]: expint={tmo_expiry}:general={tmo_flow}:'
+ f'icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:'
+ f'tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd)
self.cli_delete(['interfaces', 'dummy', dummy_if])
diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py
index d5be21949..06e6f059a 100755
--- a/src/conf_mode/interfaces-bonding.py
+++ b/src/conf_mode/interfaces-bonding.py
@@ -35,6 +35,7 @@ from vyos.ifconfig import BondIf
from vyos.ifconfig import Section
from vyos.util import dict_search
from vyos.validate import has_address_configured
+from vyos.validate import has_vrf_configured
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -108,20 +109,26 @@ def get_config(config=None):
for interface, interface_config in bond['member']['interface'].items():
# Check if member interface is already member of another bridge
tmp = is_member(conf, interface, 'bridge')
- if tmp: interface_config.update({'is_bridge_member' : tmp})
+ if tmp: bond['member']['interface'][interface].update({'is_bridge_member' : tmp})
# Check if member interface is already member of a bond
tmp = is_member(conf, interface, 'bonding')
- if tmp and bond['ifname'] not in tmp:
- interface_config.update({'is_bond_member' : tmp})
+ for tmp in is_member(conf, interface, 'bonding'):
+ if bond['ifname'] == tmp:
+ continue
+ bond['member']['interface'][interface].update({'is_bond_member' : tmp})
# Check if member interface is used as source-interface on another interface
tmp = is_source_interface(conf, interface)
- if tmp: interface_config.update({'is_source_interface' : tmp})
+ if tmp: bond['member']['interface'][interface].update({'is_source_interface' : tmp})
# bond members must not have an assigned address
tmp = has_address_configured(conf, interface)
- if tmp: interface_config.update({'has_address' : ''})
+ if tmp: bond['member']['interface'][interface].update({'has_address' : {}})
+
+ # bond members must not have a VRF attached
+ tmp = has_vrf_configured(conf, interface)
+ if tmp: bond['member']['interface'][interface].update({'has_vrf' : {}})
return bond
@@ -179,6 +186,8 @@ def verify(bond):
if 'has_address' in interface_config:
raise ConfigError(error_msg + 'it has an address assigned!')
+ if 'has_vrf' in interface_config:
+ raise ConfigError(error_msg + 'it has a VRF assigned!')
if 'primary' in bond:
if bond['primary'] not in bond['member']['interface']:
diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py
index f4dba9d4a..9ad39e080 100755
--- a/src/conf_mode/interfaces-bridge.py
+++ b/src/conf_mode/interfaces-bridge.py
@@ -30,6 +30,7 @@ from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_vrf
from vyos.ifconfig import BridgeIf
from vyos.validate import has_address_configured
+from vyos.validate import has_vrf_configured
from vyos.xml import defaults
from vyos.util import cmd
@@ -92,6 +93,10 @@ def get_config(config=None):
tmp = has_address_configured(conf, interface)
if tmp: bridge['member']['interface'][interface].update({'has_address' : ''})
+ # Bridge members must not have a VRF attached
+ tmp = has_vrf_configured(conf, interface)
+ if tmp: bridge['member']['interface'][interface].update({'has_vrf' : ''})
+
# VLAN-aware bridge members must not have VLAN interface configuration
tmp = has_vlan_subinterface_configured(conf,interface)
if 'enable_vlan' in bridge and tmp:
@@ -130,9 +135,12 @@ def verify(bridge):
if 'has_address' in interface_config:
raise ConfigError(error_msg + 'it has an address assigned!')
+ if 'has_vrf' in interface_config:
+ raise ConfigError(error_msg + 'it has a VRF assigned!')
+
if 'enable_vlan' in bridge:
if 'has_vlan' in interface_config:
- raise ConfigError(error_msg + 'it has an VLAN subinterface assigned!')
+ raise ConfigError(error_msg + 'it has VLAN subinterface(s) assigned!')
if 'wlan' in interface:
raise ConfigError(error_msg + 'VLAN aware cannot be set!')
diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py
index de851262b..e8236bf89 100755
--- a/src/conf_mode/interfaces-ethernet.py
+++ b/src/conf_mode/interfaces-ethernet.py
@@ -30,6 +30,7 @@ from vyos.configverify import verify_mtu
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_bond_bridge_member
from vyos.ethtool import Ethtool
from vyos.ifconfig import EthernetIf
from vyos.template import render
@@ -67,6 +68,7 @@ def verify(ethernet):
verify_dhcpv6(ethernet)
verify_address(ethernet)
verify_vrf(ethernet)
+ verify_bond_bridge_member(ethernet)
verify_eapol(ethernet)
verify_mirror(ethernet)
diff --git a/src/conf_mode/interfaces-geneve.py b/src/conf_mode/interfaces-geneve.py
index f49d5b304..a5213fbce 100755
--- a/src/conf_mode/interfaces-geneve.py
+++ b/src/conf_mode/interfaces-geneve.py
@@ -25,6 +25,7 @@ from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_address
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_bridge_delete
+from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import GeneveIf
from vyos import ConfigError
@@ -59,6 +60,7 @@ def verify(geneve):
verify_mtu_ipv6(geneve)
verify_address(geneve)
+ verify_bond_bridge_member(geneve)
if 'remote' not in geneve:
raise ConfigError('Remote side must be configured')
diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py
index 9b6ddd5aa..c1ed8ec59 100755
--- a/src/conf_mode/interfaces-l2tpv3.py
+++ b/src/conf_mode/interfaces-l2tpv3.py
@@ -25,6 +25,7 @@ from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_mtu_ipv6
+from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import L2TPv3If
from vyos.util import check_kmod
from vyos.validate import is_addr_assigned
@@ -76,6 +77,7 @@ def verify(l2tpv3):
verify_mtu_ipv6(l2tpv3)
verify_address(l2tpv3)
+ verify_bond_bridge_member(l2tpv3)
return None
def generate(l2tpv3):
diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py
index bfebed7e4..6ec34a961 100755
--- a/src/conf_mode/interfaces-macsec.py
+++ b/src/conf_mode/interfaces-macsec.py
@@ -30,6 +30,7 @@ from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_source_interface
+from vyos.configverify import verify_bond_bridge_member
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -66,6 +67,7 @@ def verify(macsec):
verify_vrf(macsec)
verify_mtu_ipv6(macsec)
verify_address(macsec)
+ verify_bond_bridge_member(macsec)
if not (('security' in macsec) and
('cipher' in macsec['security'])):
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index f7edddcbf..7d20b3fd0 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -33,6 +33,7 @@ from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_diffie_hellman_length
+from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import VTunIf
from vyos.template import render
from vyos.template import is_ipv4
@@ -425,6 +426,7 @@ def verify(openvpn):
raise ConfigError('Username for authentication is missing')
verify_vrf(openvpn)
+ verify_bond_bridge_member(openvpn)
return None
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index c4023586a..3bfc7d665 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -28,6 +28,7 @@ from vyos.configverify import verify_interface_exists
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_vrf
from vyos.configverify import verify_tunnel
+from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import Interface
from vyos.ifconfig import Section
from vyos.ifconfig import TunnelIf
@@ -137,6 +138,7 @@ def verify(tunnel):
verify_mtu_ipv6(tunnel)
verify_address(tunnel)
verify_vrf(tunnel)
+ verify_bond_bridge_member(tunnel)
if 'source_interface' in tunnel:
verify_interface_exists(tunnel['source_interface'])
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index 5ee4603af..bdf47eba0 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -26,6 +26,7 @@ from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_source_interface
+from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import Interface
from vyos.ifconfig import VXLANIf
from vyos.template import is_ipv6
@@ -113,6 +114,8 @@ def verify(vxlan):
verify_mtu_ipv6(vxlan)
verify_address(vxlan)
+ verify_bond_bridge_member(vxlan)
+
return None
def generate(vxlan):
diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py
index 024ab8f59..34e80cca3 100755
--- a/src/conf_mode/interfaces-wireguard.py
+++ b/src/conf_mode/interfaces-wireguard.py
@@ -28,6 +28,7 @@ from vyos.configverify import verify_vrf
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_mtu_ipv6
+from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import WireGuardIf
from vyos.util import check_kmod
from vyos import ConfigError
@@ -69,6 +70,7 @@ def verify(wireguard):
verify_mtu_ipv6(wireguard)
verify_address(wireguard)
verify_vrf(wireguard)
+ verify_bond_bridge_member(wireguard)
if not os.path.exists(wireguard['private_key']):
raise ConfigError('Wireguard private-key not found! Execute: ' \
diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py
index b25fcd4e0..7e967ed79 100755
--- a/src/conf_mode/interfaces-wireless.py
+++ b/src/conf_mode/interfaces-wireless.py
@@ -29,6 +29,7 @@ from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_source_interface
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import WiFiIf
from vyos.template import render
from vyos.util import call
@@ -188,6 +189,7 @@ def verify(wifi):
verify_address(wifi)
verify_vrf(wifi)
+ verify_bond_bridge_member(wifi)
# use common function to verify VLAN configuration
verify_vlan_config(wifi)