summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/include/interface-mirror.xml.i11
-rw-r--r--interface-definitions/interfaces-bonding.xml.in1
-rw-r--r--interface-definitions/interfaces-bridge.xml.in1
-rw-r--r--interface-definitions/interfaces-ethernet.xml.in1
-rw-r--r--python/vyos/ifconfig/interface.py38
-rw-r--r--smoketest/scripts/cli/base_interfaces_test.py28
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bonding.py1
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py1
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_ethernet.py1
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 (.)