Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vxlan: T5668: add CLI knob to enable ARP/ND suppression (backport #2413) #2419

Merged
merged 1 commit into from
Oct 31, 2023
Merged
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
6 changes: 6 additions & 0 deletions interface-definitions/interfaces-vxlan.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@
<valueless/>
</properties>
</leafNode>
<leafNode name="neighbor-suppress">
<properties>
<help>Enable neighbor discovery (ARP and ND) suppression</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
#include <include/port-number.xml.i>
Expand Down
23 changes: 23 additions & 0 deletions python/vyos/ifconfig/vxlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class VXLANIf(Interface):
}

_command_set = {**Interface._command_set, **{
'neigh_suppress': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'shellcmd': 'bridge link set dev {ifname} neigh_suppress {value} learning off',
},
'vlan_tunnel': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'shellcmd': 'bridge link set dev {ifname} vlan_tunnel {value}',
Expand Down Expand Up @@ -113,6 +117,19 @@ def _create(self):
'port {port} dev {ifname}'
self._cmd(cmd.format(**self.config))

def set_neigh_suppress(self, state):
"""
Controls whether neigh discovery (arp and nd) proxy and suppression
is enabled on the port. By default this flag is off.
"""

# Determine current OS Kernel neigh_suppress setting - only adjust when needed
tmp = get_interface_config(self.ifname)
cur_state = 'on' if dict_search(f'linkinfo.info_slave_data.neigh_suppress', tmp) == True else 'off'
new_state = 'on' if state else 'off'
if cur_state != new_state:
self.set_interface('neigh_suppress', state)

def set_vlan_vni_mapping(self, state):
"""
Controls whether vlan to tunnel mapping is enabled on the port.
Expand Down Expand Up @@ -163,3 +180,9 @@ def update(self, config):
# Enable/Disable VLAN tunnel mapping
# This is only possible after the interface was assigned to the bridge
self.set_vlan_vni_mapping(dict_search('vlan_to_vni', config) != None)

# Enable/Disable neighbor suppression and learning, there is no need to
# explicitly "disable" it, as VXLAN interface will be recreated if anything
# under "parameters" changes.
if dict_search('parameters.neighbor_suppress', config) != None:
self.set_neigh_suppress('on')
39 changes: 39 additions & 0 deletions smoketest/scripts/cli/test_interfaces_vxlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,50 @@ def test_vxlan_vlan_vni_mapping(self):

tmp = get_interface_config(interface)
self.assertEqual(tmp['master'], bridge)
self.assertFalse(tmp['linkinfo']['info_slave_data']['neigh_suppress'])

tmp = get_vxlan_vlan_tunnels('vxlan0')
self.assertEqual(tmp, list(vlan_to_vni))

self.cli_delete(['interfaces', 'bridge', bridge])

def test_vxlan_neighbor_suppress(self):
bridge = 'br555'
interface = 'vxlan555'
source_interface = 'eth0'

self.cli_set(self._base_path + [interface, 'external'])
self.cli_set(self._base_path + [interface, 'source-interface', source_interface])

self.cli_set(self._base_path + [interface, 'parameters', 'neighbor-suppress'])

# This must fail as this VXLAN interface is not associated with any bridge
with self.assertRaises(ConfigSessionError):
self.cli_commit()
self.cli_set(['interfaces', 'bridge', bridge, 'member', 'interface', interface])

# commit configuration
self.cli_commit()

self.assertTrue(interface_exists(bridge))
self.assertTrue(interface_exists(interface))

tmp = get_interface_config(interface)
self.assertEqual(tmp['master'], bridge)
self.assertTrue(tmp['linkinfo']['info_slave_data']['neigh_suppress'])
self.assertFalse(tmp['linkinfo']['info_slave_data']['learning'])

# Remove neighbor suppress configuration and re-test
self.cli_delete(self._base_path + [interface, 'parameters', 'neighbor-suppress'])
# commit configuration
self.cli_commit()

tmp = get_interface_config(interface)
self.assertEqual(tmp['master'], bridge)
self.assertFalse(tmp['linkinfo']['info_slave_data']['neigh_suppress'])
self.assertTrue(tmp['linkinfo']['info_slave_data']['learning'])

self.cli_delete(['interfaces', 'bridge', bridge])

if __name__ == '__main__':
unittest.main(verbosity=2)
5 changes: 5 additions & 0 deletions src/conf_mode/interfaces-vxlan.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ def verify(vxlan):
raise ConfigError(f'VNI "{vni}" is already assigned to a different VLAN!')
vnis_used.append(vni)

if dict_search('parameters.neighbor_suppress', vxlan):
if 'is_bridge_member' not in vxlan:
raise ConfigError('Neighbor suppression requires that VXLAN interface '\
'is member of a bridge interface!')

verify_mtu_ipv6(vxlan)
verify_address(vxlan)
verify_bond_bridge_member(vxlan)
Expand Down
Loading