summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static_arp.py34
-rwxr-xr-xsrc/conf_mode/protocols_static_arp.py16
2 files changed, 46 insertions, 4 deletions
diff --git a/smoketest/scripts/cli/test_protocols_static_arp.py b/smoketest/scripts/cli/test_protocols_static_arp.py
index f89cdacbb..47b04a48a 100755
--- a/smoketest/scripts/cli/test_protocols_static_arp.py
+++ b/smoketest/scripts/cli/test_protocols_static_arp.py
@@ -86,5 +86,39 @@ class TestARP(VyOSUnitTestSHIM.TestCase):
print(entry)
self.assertTrue(found)
+ def test_static_arp_deletion(self):
+ # deleting the "protocols static arp" node must remove the
+ # previously installed PERMANENT ARP entry from the kernel
+ host = '192.0.2.10'
+ mac = '00:01:02:03:04:0a'
+
+ def get_static_arp_entry():
+ # Return our static (PERMANENT) neighbour, matched by dst + dev.
+ arp_table = json.loads(cmdl(['ip', '-j', '-4', 'neigh', 'show']))
+ for entry in arp_table:
+ if (
+ entry['dst'] == host
+ and entry['dev'] == interface
+ and 'PERMANENT' in entry.get('state', [])
+ ):
+ return entry
+ return None
+
+ self.cli_set(base_path + ['interface', interface, 'address', host, 'mac', mac])
+ self.cli_commit()
+
+ # the static PERMANENT entry must be present with all configured fields
+ entry = get_static_arp_entry()
+ self.assertIsNotNone(entry)
+ self.assertEqual(entry['dst'], host)
+ self.assertEqual(entry['lladdr'], mac)
+ self.assertEqual(entry['dev'], interface)
+
+ # delete the whole node and verify the static entry is gone
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ self.assertIsNone(get_static_arp_entry())
+
if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
diff --git a/src/conf_mode/protocols_static_arp.py b/src/conf_mode/protocols_static_arp.py
index 87dc5229e..2b5570ab0 100755
--- a/src/conf_mode/protocols_static_arp.py
+++ b/src/conf_mode/protocols_static_arp.py
@@ -32,10 +32,18 @@ def get_config(config=None):
base = ['protocols', 'static', 'arp']
arp = conf.get_config_dict(base, get_first_key=True)
- if 'interface' in arp:
- for interface in arp['interface']:
- tmp = node_changed(conf, base + ['interface', interface, 'address'], recursive=True)
- if tmp: arp['interface'][interface].update({'address_old' : tmp})
+ # Collect both configured interfaces and interfaces removed in this commit
+ # (e.g. deleting the whole node), so their old ARP entries get cleaned up.
+ interfaces = set(arp.get('interface', {}))
+ interfaces.update(node_changed(conf, base + ['interface']))
+
+ for interface in interfaces:
+ tmp = node_changed(
+ conf, base + ['interface', interface, 'address'], recursive=True
+ )
+ if tmp:
+ arp.setdefault('interface', {}).setdefault(interface, {})
+ arp['interface'][interface].update({'address_old': tmp})
return arp