diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in
index 3fae171787a..911c14f0c46 100644
--- a/interface-definitions/interfaces-vxlan.xml.in
+++ b/interface-definitions/interfaces-vxlan.xml.in
@@ -89,6 +89,12 @@
+
+
+ Enable neighbor discovery (ARP and ND) suppression
+
+
+
#include
diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py
index 1fe5db7cdd4..ea45e007c3f 100644
--- a/python/vyos/ifconfig/vxlan.py
+++ b/python/vyos/ifconfig/vxlan.py
@@ -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}',
+ },
'vlan_tunnel': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'shellcmd': 'bridge link set dev {ifname} vlan_tunnel {value}',
@@ -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.
@@ -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, 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')
diff --git a/smoketest/scripts/cli/test_interfaces_vxlan.py b/smoketest/scripts/cli/test_interfaces_vxlan.py
index e9c9e68fd10..235649d434d 100755
--- a/smoketest/scripts/cli/test_interfaces_vxlan.py
+++ b/smoketest/scripts/cli/test_interfaces_vxlan.py
@@ -177,11 +177,48 @@ 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'])
+
+ # 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.cli_delete(['interfaces', 'bridge', bridge])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index ff8144e74a7..7bd3fa69254 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -34,6 +34,7 @@
from vyos.ifconfig import Interface
from vyos.ifconfig import VXLANIf
from vyos.template import is_ipv6
+from vyos.utils.dict import dict_search
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -164,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)