diff options
-rw-r--r-- | interface-definitions/include/interface-mirror.xml.i | 11 | ||||
-rw-r--r-- | interface-definitions/interfaces-bonding.xml.in | 1 | ||||
-rw-r--r-- | interface-definitions/interfaces-bridge.xml.in | 1 | ||||
-rw-r--r-- | interface-definitions/interfaces-ethernet.xml.in | 1 | ||||
-rw-r--r-- | python/vyos/ifconfig/interface.py | 38 | ||||
-rw-r--r-- | smoketest/scripts/cli/base_interfaces_test.py | 28 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bonding.py | 1 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bridge.py | 1 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_ethernet.py | 1 |
9 files changed, 82 insertions, 1 deletions
diff --git a/interface-definitions/include/interface-mirror.xml.i b/interface-definitions/include/interface-mirror.xml.i new file mode 100644 index 000000000..e3720cde7 --- /dev/null +++ b/interface-definitions/include/interface-mirror.xml.i @@ -0,0 +1,11 @@ +<!-- included start from interface-mirror.xml.i --> +<leafNode name="mirror"> + <properties> + <help>Incoming/outgoing packet mirroring destination</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <multi/> + </properties> +</leafNode> +<!-- included end --> diff --git a/interface-definitions/interfaces-bonding.xml.in b/interface-definitions/interfaces-bonding.xml.in index 66fc5f7a9..423d94f76 100644 --- a/interface-definitions/interfaces-bonding.xml.in +++ b/interface-definitions/interfaces-bonding.xml.in @@ -55,6 +55,7 @@ #include <include/interface-disable-link-detect.xml.i> #include <include/interface-disable.xml.i> #include <include/interface-vrf.xml.i> + #include <include/interface-mirror.xml.i> <leafNode name="hash-policy"> <properties> <help>Bonding transmit hash policy</help> diff --git a/interface-definitions/interfaces-bridge.xml.in b/interface-definitions/interfaces-bridge.xml.in index 778acda78..c32c0ca32 100644 --- a/interface-definitions/interfaces-bridge.xml.in +++ b/interface-definitions/interfaces-bridge.xml.in @@ -85,6 +85,7 @@ #include <include/interface-ipv4-options.xml.i> #include <include/interface-ipv6-options.xml.i> #include <include/interface-mac.xml.i> + #include <include/interface-mirror.xml.i> <leafNode name="max-age"> <properties> <help>Interval at which neighbor bridges are removed</help> diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in index 83f3d9e46..223a94bff 100644 --- a/interface-definitions/interfaces-ethernet.xml.in +++ b/interface-definitions/interfaces-ethernet.xml.in @@ -59,6 +59,7 @@ #include <include/interface-ipv6-options.xml.i> #include <include/interface-mac.xml.i> #include <include/interface-mtu-68-16000.xml.i> + #include <include/interface-mirror.xml.i> <node name="offload-options"> <properties> <help>Configurable offload options</help> diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 43cd7220a..9f067b75e 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -35,6 +35,7 @@ from vyos.configdict import dict_merge from vyos.template import render from vyos.util import mac2eui64 from vyos.util import dict_search +from vyos.util import cmd from vyos.template import is_ipv4 from vyos.template import is_ipv6 from vyos.validate import is_intf_addr_assigned @@ -929,7 +930,39 @@ class Interface(Control): if os.path.isfile(config_file): os.remove(config_file) - + + def get_tc_config(self,objectname): + # Parse configuration + get_tc_cmd = f'tc -j {objectname}' + tmp = cmd(get_tc_cmd, shell=True) + return json.loads(tmp) + + def del_tc_qdisc(self,dev,kind,handle): + tc_qdisc = self.get_tc_config('qdisc') + for rule in tc_qdisc: + old_dev = rule['dev'] + old_handle = rule['handle'] + old_kind = rule['kind'] + if old_dev == dev and old_handle == handle and old_kind == kind: + delete_tc_cmd = f'tc qdisc del dev {dev} handle {handle} {kind}' + self._cmd(delete_tc_cmd) + + + + def apply_mirror(self,config): + ifname = config['ifname'] + + # Remove existing mirroring rules + self.del_tc_qdisc(ifname,'ingress','ffff:') + + # Setting up packet mirroring + mirror = dict_search('mirror', config) + if mirror: + for interface in mirror: + mirror_cmd = f'tc qdisc add dev {ifname} handle ffff: ingress' + self._cmd(mirror_cmd) + mirror_cmd = f'tc filter add dev {ifname} parent ffff: protocol all prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress mirror dev {interface}' + self._cmd(mirror_cmd) def update(self, config): """ General helper function which works on a dictionary retrived by @@ -1136,6 +1169,9 @@ class Interface(Control): vif_config['ifname'] = vif_ifname vlan = VLANIf(vif_ifname, **tmp) vlan.update(vif_config) + + self.apply_mirror(config) + class VLANIf(Interface): diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index e02424073..0a4e85c0f 100644 --- a/smoketest/scripts/cli/base_interfaces_test.py +++ b/smoketest/scripts/cli/base_interfaces_test.py @@ -33,6 +33,7 @@ class BasicInterfaceTest: _test_vlan = False _test_qinq = False _test_ipv6 = False + _test_mirror = False _base_path = [] _options = {} @@ -66,6 +67,33 @@ class BasicInterfaceTest: self.session.commit() del self.session + + def test_mirror(self): + Success = 0 + i = 0 + if self._test_mirror: + for interface in self._interfaces: + self.session.set(self._base_path + [interface, 'mirror', 'lo']) + i+=1 + self.session.commit() + # Parse configuration + for interface in self._interfaces: + get_tc_cmd = 'tc -j qdisc' + tmp = cmd(get_tc_cmd, shell=True) + data = json.loads(tmp) + for rule in data: + dev = rule['dev'] + handle = rule['handle'] + kind = rule['kind'] + if dev == interface and handle == "ffff:" and kind == "ingress": + Success+=1 + if Success == i: + self.assertTrue(True) + else: + self.assertTrue(False) + else: + return None + def test_add_description(self): """ diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py index ac5e01e50..93ed1ced5 100755 --- a/smoketest/scripts/cli/test_interfaces_bonding.py +++ b/smoketest/scripts/cli/test_interfaces_bonding.py @@ -34,6 +34,7 @@ class BondingInterfaceTest(BasicInterfaceTest.BaseTest): self._test_vlan = True self._test_qinq = True self._test_ipv6 = True + self._test_mirror = True self._members = [] # we need to filter out VLAN interfaces identified by a dot (.) diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index 3742491e8..9bddede31 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -31,6 +31,7 @@ class BridgeInterfaceTest(BasicInterfaceTest.BaseTest): self._test_ipv6 = True self._test_vlan = True self._test_qinq = True + self._test_mirror = True self._base_path = ['interfaces', 'bridge'] self._interfaces = ['br0'] diff --git a/smoketest/scripts/cli/test_interfaces_ethernet.py b/smoketest/scripts/cli/test_interfaces_ethernet.py index 761ec7506..bdb20a5c7 100755 --- a/smoketest/scripts/cli/test_interfaces_ethernet.py +++ b/smoketest/scripts/cli/test_interfaces_ethernet.py @@ -30,6 +30,7 @@ class EthernetInterfaceTest(BasicInterfaceTest.BaseTest): self._test_vlan = True self._test_qinq = True self._test_ipv6 = True + self._test_mirror = True self._interfaces = [] # we need to filter out VLAN interfaces identified by a dot (.) |