diff options
| author | Nataliia Solomko <natalirs1985@gmail.com> | 2026-09-09 12:35:03 +0300 |
|---|---|---|
| committer | Nataliia Solomko <natalirs1985@gmail.com> | 2026-09-09 13:01:45 +0300 |
| commit | 30ac19fd30f0d6f1396ea2fc2facdbe06bdfeee4 (patch) | |
| tree | 9246d24379db426a22f5fb9a66f90730a52dc9f4 | |
| parent | e152d756fdd9d43c31e3ce3a79c64370f2df9615 (diff) | |
| download | vyos-1x-30ac19fd30f0d6f1396ea2fc2facdbe06bdfeee4.tar.gz vyos-1x-30ac19fd30f0d6f1396ea2fc2facdbe06bdfeee4.zip | |
static_arp: T9268: Fix deletion of static ARP entries
| -rwxr-xr-x | smoketest/scripts/cli/test_protocols_static_arp.py | 34 | ||||
| -rwxr-xr-x | src/conf_mode/protocols_static_arp.py | 16 |
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 |
