summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2022-04-27 21:42:22 +0200
committerChristian Poessinger <christian@poessinger.com>2022-04-28 15:03:36 +0200
commitb0aeb2a9c196ea7048545e38e6f3c5759ff4a5ac (patch)
tree3bfc4a149cabf926adb9aea94ec6c0e890ba020d
parent92b834fdc0129b24de6683afe18a81a24f7bc495 (diff)
downloadvyos-1x-b0aeb2a9c196ea7048545e38e6f3c5759ff4a5ac.tar.gz
vyos-1x-b0aeb2a9c196ea7048545e38e6f3c5759ff4a5ac.zip
arp: T4397: change CLI syntax to support interface and VRF bound ARP entries
* set protocols static arp interface eth0 address 192.0.2.1 mac 01:23:45:67:89:01
-rw-r--r--interface-definitions/protocols-static-arp.xml.in44
-rw-r--r--smoketest/configs/basic-vyos32
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_static_arp.py16
-rwxr-xr-xsrc/conf_mode/arp.py28
-rwxr-xr-xsrc/migration-scripts/system/23-to-2485
5 files changed, 170 insertions, 35 deletions
diff --git a/interface-definitions/protocols-static-arp.xml.in b/interface-definitions/protocols-static-arp.xml.in
index e5e8a9ad9..8b1b3b5e1 100644
--- a/interface-definitions/protocols-static-arp.xml.in
+++ b/interface-definitions/protocols-static-arp.xml.in
@@ -4,32 +4,46 @@
<children>
<node name="static">
<children>
- <tagNode name="arp" owner="${vyos_conf_scripts_dir}/arp.py">
+ <node name="arp" owner="${vyos_conf_scripts_dir}/arp.py">
<properties>
<help>Static ARP translation</help>
- <valueHelp>
- <format>ipv4</format>
- <description>IPv4 destination address</description>
- </valueHelp>
- <constraint>
- <validator name="ipv4-address"/>
- </constraint>
</properties>
<children>
- <leafNode name="hwaddr">
+ <tagNode name="interface">
<properties>
- <help>Translation MAC address</help>
+ <help>Interface configuration</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces.py</script>
+ </completionHelp>
<valueHelp>
- <format>macaddr</format>
- <description>Hardware (MAC) address</description>
+ <format>txt</format>
+ <description>Interface name</description>
</valueHelp>
<constraint>
- <validator name="mac-address"/>
+ <validator name="interface-name"/>
</constraint>
</properties>
- </leafNode>
+ <children>
+ <tagNode name="address">
+ <properties>
+ <help>IP address for static ARP entry</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 destination address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ipv4-address"/>
+ </constraint>
+ </properties>
+ <children>
+ #include <include/generic-description.xml.i>
+ #include <include/interface/mac.xml.i>
+ </children>
+ </tagNode>
+ </children>
+ </tagNode>
</children>
- </tagNode>
+ </node>
</children>
</node>
</children>
diff --git a/smoketest/configs/basic-vyos b/smoketest/configs/basic-vyos
index 3d62d269c..e6f89954f 100644
--- a/smoketest/configs/basic-vyos
+++ b/smoketest/configs/basic-vyos
@@ -6,16 +6,26 @@ interfaces {
speed auto
}
ethernet eth1 {
- address 100.64.0.0/31
duplex auto
smp-affinity auto
speed auto
}
ethernet eth2 {
- address 100.100.0.1/24
duplex auto
smp-affinity auto
speed auto
+ vif 100 {
+ address 100.100.0.1/24
+ }
+ vif-s 200 {
+ address 100.64.200.254/24
+ vif-c 201 {
+ address 100.64.201.254/24
+ }
+ vif-c 202 {
+ address 100.64.202.254/24
+ }
+ }
}
loopback lo {
}
@@ -40,6 +50,24 @@ protocols {
arp 100.100.0.4 {
hwaddr 00:50:00:00:02:04
}
+ arp 100.64.200.1 {
+ hwaddr 00:50:00:00:00:01
+ }
+ arp 100.64.200.2 {
+ hwaddr 00:50:00:00:00:02
+ }
+ arp 100.64.201.10 {
+ hwaddr 00:50:00:00:00:10
+ }
+ arp 100.64.201.20 {
+ hwaddr 00:50:00:00:00:20
+ }
+ arp 100.64.202.30 {
+ hwaddr 00:50:00:00:00:30
+ }
+ arp 100.64.202.40 {
+ hwaddr 00:50:00:00:00:40
+ }
route 0.0.0.0/0 {
next-hop 100.64.0.1 {
}
diff --git a/smoketest/scripts/cli/test_protocols_static_arp.py b/smoketest/scripts/cli/test_protocols_static_arp.py
index 6663ade96..b61d8f854 100755
--- a/smoketest/scripts/cli/test_protocols_static_arp.py
+++ b/smoketest/scripts/cli/test_protocols_static_arp.py
@@ -52,16 +52,16 @@ class TestARP(VyOSUnitTestSHIM.TestCase):
def test_static_arp(self):
test_data = {
- '192.0.2.10' : { 'lladdr' : '00:01:02:03:04:0a' },
- '192.0.2.11' : { 'lladdr' : '00:01:02:03:04:0b' },
- '192.0.2.12' : { 'lladdr' : '00:01:02:03:04:0c' },
- '192.0.2.13' : { 'lladdr' : '00:01:02:03:04:0d' },
- '192.0.2.14' : { 'lladdr' : '00:01:02:03:04:0e' },
- '192.0.2.15' : { 'lladdr' : '00:01:02:03:04:0f' },
+ '192.0.2.10' : { 'mac' : '00:01:02:03:04:0a' },
+ '192.0.2.11' : { 'mac' : '00:01:02:03:04:0b' },
+ '192.0.2.12' : { 'mac' : '00:01:02:03:04:0c' },
+ '192.0.2.13' : { 'mac' : '00:01:02:03:04:0d' },
+ '192.0.2.14' : { 'mac' : '00:01:02:03:04:0e' },
+ '192.0.2.15' : { 'mac' : '00:01:02:03:04:0f' },
}
for host, host_config in test_data.items():
- self.cli_set(base_path + [host, 'hwaddr', host_config['lladdr']])
+ self.cli_set(base_path + ['interface', interface, 'address', host, 'mac', host_config['mac']])
self.cli_commit()
@@ -76,7 +76,7 @@ class TestARP(VyOSUnitTestSHIM.TestCase):
continue
if entry['dst'] == host:
- self.assertEqual(entry['lladdr'], host_config['lladdr'])
+ self.assertEqual(entry['lladdr'], host_config['mac'])
self.assertEqual(entry['dev'], interface)
found = True
diff --git a/src/conf_mode/arp.py b/src/conf_mode/arp.py
index 51a08bee5..1cd8f5451 100755
--- a/src/conf_mode/arp.py
+++ b/src/conf_mode/arp.py
@@ -30,9 +30,12 @@ def get_config(config=None):
conf = Config()
base = ['protocols', 'static', 'arp']
- arp = conf.get_config_dict(base)
- tmp = node_changed(conf, base)
- if tmp: arp.update({'removed' : node_changed(conf, base)})
+ 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})
return arp
@@ -46,14 +49,19 @@ def apply(arp):
if not arp:
return None
- if 'removed' in arp:
- for host in arp['removed']:
- call(f'arp --delete {host}')
+ if 'interface' in arp:
+ for interface, interface_config in arp['interface'].items():
+ # Delete old static ARP assignments first
+ if 'address_old' in interface_config:
+ for address in interface_config['address_old']:
+ call(f'ip neigh del {address} dev {interface}')
- if 'arp' in arp:
- for host, host_config in arp['arp'].items():
- mac = host_config['hwaddr']
- call(f'arp --set {host} {mac}')
+ # Add new static ARP entries to interface
+ if 'address' not in interface_config:
+ continue
+ for address, address_config in interface_config['address'].items():
+ mac = address_config['mac']
+ call(f'ip neigh add {address} lladdr {mac} dev {interface}')
if __name__ == '__main__':
try:
diff --git a/src/migration-scripts/system/23-to-24 b/src/migration-scripts/system/23-to-24
new file mode 100755
index 000000000..5ea71d51a
--- /dev/null
+++ b/src/migration-scripts/system/23-to-24
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 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
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+from ipaddress import ip_interface
+from ipaddress import ip_address
+from sys import exit, argv
+from vyos.configtree import ConfigTree
+
+if (len(argv) < 1):
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+base = ['protocols', 'static', 'arp']
+tmp_base = ['protocols', 'static', 'arp-tmp']
+config = ConfigTree(config_file)
+
+def fixup_cli(config, path, interface):
+ if config.exists(path + ['address']):
+ for address in config.return_values(path + ['address']):
+ tmp = ip_interface(address)
+ if ip_address(host) in tmp.network.hosts():
+ mac = config.return_value(tmp_base + [host, 'hwaddr'])
+ iface_path = ['protocols', 'static', 'arp', 'interface']
+ config.set(iface_path + [interface, 'address', host, 'mac'], value=mac)
+ config.set_tag(iface_path)
+ config.set_tag(iface_path + [interface, 'address'])
+ continue
+
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+# We need a temporary copy of the config tree as the original one needs to be
+# deleted first due to a change iun thge tagNode structure.
+config.copy(base, tmp_base)
+config.delete(base)
+
+for host in config.list_nodes(tmp_base):
+ for type in config.list_nodes(['interfaces']):
+ for interface in config.list_nodes(['interfaces', type]):
+ if_base = ['interfaces', type, interface]
+ fixup_cli(config, if_base, interface)
+
+ if config.exists(if_base + ['vif']):
+ for vif in config.list_nodes(if_base + ['vif']):
+ vif_base = ['interfaces', type, interface, 'vif', vif]
+ fixup_cli(config, vif_base, f'{interface}.{vif}')
+
+ if config.exists(if_base + ['vif-s']):
+ for vif_s in config.list_nodes(if_base + ['vif-s']):
+ vif_s_base = ['interfaces', type, interface, 'vif-s', vif_s]
+ fixup_cli(config, vif_s_base, f'{interface}.{vif_s}')
+
+ if config.exists(if_base + ['vif-s', vif_s, 'vif-c']):
+ for vif_c in config.list_nodes(if_base + ['vif-s', vif_s, 'vif-c']):
+ vif_c_base = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c', vif_c]
+ fixup_cli(config, vif_c_base, f'{interface}.{vif_s}.{vif_c}')
+
+config.delete(tmp_base)
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)