From: Jiri Pirko <jiri(a)mellanox.com>
This patch introduces initial recipe set for testing basic and l2
functionality of switchdev offloaded switches.
Signed-off-by: Ido Schimmel <idosch(a)mellanox.com>
Signed-off-by: Jiri Pirko <jiri(a)mellanox.com>
---
recipes/switchdev/TestLib.py | 202 +++++++++++++++++++++
recipes/switchdev/basic-001-links.py | 65 +++++++
recipes/switchdev/basic-001-links.xml | 23 +++
recipes/switchdev/basic-004-slowpath.py | 33 ++++
recipes/switchdev/basic-004-slowpath.xml | 17 ++
recipes/switchdev/basic-005-slowpath-exhaustive.py | 36 ++++
.../switchdev/basic-005-slowpath-exhaustive.xml | 17 ++
recipes/switchdev/basic-006-slowpath-vlan.py | 35 ++++
recipes/switchdev/basic-006-slowpath-vlan.xml | 17 ++
.../basic-007-slowpath-vlan-exhaustive.py | 40 ++++
.../basic-007-slowpath-vlan-exhaustive.xml | 17 ++
recipes/switchdev/default_aliases.xml | 6 +
recipes/switchdev/l2-000-minimal.py | 36 ++++
recipes/switchdev/l2-000-minimal.xml | 24 +++
recipes/switchdev/l2-001-bridge.py | 38 ++++
recipes/switchdev/l2-001-bridge.xml | 22 +++
recipes/switchdev/l2-002-bridge_fdb.py | 142 +++++++++++++++
recipes/switchdev/l2-002-bridge_fdb.xml | 22 +++
recipes/switchdev/l2-003-bridge_stp.py | 93 ++++++++++
recipes/switchdev/l2-003-bridge_stp.xml | 24 +++
recipes/switchdev/l2-004-bridge_bond.py | 48 +++++
recipes/switchdev/l2-004-bridge_bond.xml | 26 +++
recipes/switchdev/l2-005-bridge_bond_failover.py | 64 +++++++
recipes/switchdev/l2-005-bridge_bond_failover.xml | 26 +++
recipes/switchdev/l2-006-bridge_team.py | 54 ++++++
recipes/switchdev/l2-006-bridge_team.xml | 26 +++
recipes/switchdev/l2-007-bridge_team_failover.py | 70 +++++++
recipes/switchdev/l2-007-bridge_team_failover.xml | 26 +++
recipes/switchdev/l2-008-bridge_vlan1q_sanity.py | 86 +++++++++
recipes/switchdev/l2-008-bridge_vlan1q_sanity.xml | 22 +++
recipes/switchdev/l2-009-bridge_vlan1q.py | 70 +++++++
recipes/switchdev/l2-009-bridge_vlan1q.xml | 22 +++
recipes/switchdev/l2-010-bridge_vlan1d_sanity.py | 60 ++++++
recipes/switchdev/l2-010-bridge_vlan1d_sanity.xml | 22 +++
recipes/switchdev/l2-011-bridge_vlan1d.py | 66 +++++++
recipes/switchdev/l2-011-bridge_vlan1d.xml | 22 +++
.../switchdev/l2-012-bridge_bond_vlan1d_sanity.py | 68 +++++++
.../switchdev/l2-012-bridge_bond_vlan1d_sanity.xml | 26 +++
recipes/switchdev/l2-013-bridge_bond_vlan1d.py | 74 ++++++++
recipes/switchdev/l2-013-bridge_bond_vlan1d.xml | 26 +++
.../switchdev/l2-014-bridge_team_vlan1d_sanity.py | 68 +++++++
.../switchdev/l2-014-bridge_team_vlan1d_sanity.xml | 26 +++
recipes/switchdev/l2-015-bridge_team_vlan1d.py | 74 ++++++++
recipes/switchdev/l2-015-bridge_team_vlan1d.xml | 27 +++
recipes/switchdev/l2-017-bridge_fdb_vlan1d.py | 144 +++++++++++++++
recipes/switchdev/l2-017-bridge_fdb_vlan1d.xml | 22 +++
recipes/switchdev/l2-018-bridge_fdb_team.py | 150 +++++++++++++++
recipes/switchdev/l2-018-bridge_fdb_team.xml | 26 +++
recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.py | 157 ++++++++++++++++
.../switchdev/l2-019-bridge_fdb_team_vlan1d.xml | 26 +++
50 files changed, 2533 insertions(+)
create mode 100644 recipes/switchdev/TestLib.py
create mode 100644 recipes/switchdev/basic-001-links.py
create mode 100644 recipes/switchdev/basic-001-links.xml
create mode 100644 recipes/switchdev/basic-004-slowpath.py
create mode 100644 recipes/switchdev/basic-004-slowpath.xml
create mode 100644 recipes/switchdev/basic-005-slowpath-exhaustive.py
create mode 100644 recipes/switchdev/basic-005-slowpath-exhaustive.xml
create mode 100644 recipes/switchdev/basic-006-slowpath-vlan.py
create mode 100644 recipes/switchdev/basic-006-slowpath-vlan.xml
create mode 100644 recipes/switchdev/basic-007-slowpath-vlan-exhaustive.py
create mode 100644 recipes/switchdev/basic-007-slowpath-vlan-exhaustive.xml
create mode 100644 recipes/switchdev/default_aliases.xml
create mode 100644 recipes/switchdev/l2-000-minimal.py
create mode 100644 recipes/switchdev/l2-000-minimal.xml
create mode 100644 recipes/switchdev/l2-001-bridge.py
create mode 100644 recipes/switchdev/l2-001-bridge.xml
create mode 100644 recipes/switchdev/l2-002-bridge_fdb.py
create mode 100644 recipes/switchdev/l2-002-bridge_fdb.xml
create mode 100644 recipes/switchdev/l2-003-bridge_stp.py
create mode 100644 recipes/switchdev/l2-003-bridge_stp.xml
create mode 100644 recipes/switchdev/l2-004-bridge_bond.py
create mode 100644 recipes/switchdev/l2-004-bridge_bond.xml
create mode 100644 recipes/switchdev/l2-005-bridge_bond_failover.py
create mode 100644 recipes/switchdev/l2-005-bridge_bond_failover.xml
create mode 100644 recipes/switchdev/l2-006-bridge_team.py
create mode 100644 recipes/switchdev/l2-006-bridge_team.xml
create mode 100644 recipes/switchdev/l2-007-bridge_team_failover.py
create mode 100644 recipes/switchdev/l2-007-bridge_team_failover.xml
create mode 100644 recipes/switchdev/l2-008-bridge_vlan1q_sanity.py
create mode 100644 recipes/switchdev/l2-008-bridge_vlan1q_sanity.xml
create mode 100644 recipes/switchdev/l2-009-bridge_vlan1q.py
create mode 100644 recipes/switchdev/l2-009-bridge_vlan1q.xml
create mode 100644 recipes/switchdev/l2-010-bridge_vlan1d_sanity.py
create mode 100644 recipes/switchdev/l2-010-bridge_vlan1d_sanity.xml
create mode 100644 recipes/switchdev/l2-011-bridge_vlan1d.py
create mode 100644 recipes/switchdev/l2-011-bridge_vlan1d.xml
create mode 100644 recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.py
create mode 100644 recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.xml
create mode 100644 recipes/switchdev/l2-013-bridge_bond_vlan1d.py
create mode 100644 recipes/switchdev/l2-013-bridge_bond_vlan1d.xml
create mode 100644 recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.py
create mode 100644 recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.xml
create mode 100644 recipes/switchdev/l2-015-bridge_team_vlan1d.py
create mode 100644 recipes/switchdev/l2-015-bridge_team_vlan1d.xml
create mode 100644 recipes/switchdev/l2-017-bridge_fdb_vlan1d.py
create mode 100644 recipes/switchdev/l2-017-bridge_fdb_vlan1d.xml
create mode 100644 recipes/switchdev/l2-018-bridge_fdb_team.py
create mode 100644 recipes/switchdev/l2-018-bridge_fdb_team.xml
create mode 100644 recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.py
create mode 100644 recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.xml
diff --git a/recipes/switchdev/TestLib.py b/recipes/switchdev/TestLib.py
new file mode 100644
index 0000000..1159a30
--- /dev/null
+++ b/recipes/switchdev/TestLib.py
@@ -0,0 +1,202 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from time import sleep
+
+class TestLib:
+ def __init__(self, ctl, aliases):
+ self._ctl = ctl
+ self._ipv = aliases["ipv"]
+ self._mtu = int(aliases["mtu"])
+ if "netperf_duration" in aliases:
+ self._netperf_duration = int(aliases["netperf_duration"])
+ if "netperf_num_parallel" in aliases:
+ self._netperf_num_parallel = int(aliases["netperf_num_parallel"])
+
+ def _generate_default_desc(self, if1, if2):
+ return "from %s->%s to %s->%s" % (if1.get_host().get_id(),
if1.get_id(),
+ if2.get_host().get_id(), if2.get_id())
+
+ def linkneg(self, if1, if2, state, speed=0, timeout=5, desc=None):
+ if not desc:
+ desc = self._generate_default_desc(if1, if2)
+
+ m2 = if2.get_host()
+ m2.sync_resources(modules=["LinkNeg"])
+
+ linkneg_mod = self._ctl.get_module("LinkNeg",
+ options={
+ "iface": if2.get_devname(),
+ "state": state,
+ "speed": speed,
+ "timeout": timeout})
+
+ if speed:
+ # Make sure the link at the other end advertises all of
+ # its supported speeds.
+ if2.set_autoneg()
+ sleep(3)
+
+ # Setting the speed causes the link to first go down, so make
+ # sure LinkNeg will only get the following up event by sleeping
+ # for one second.
+ if1.set_speed(speed)
+ sleep(1)
+ elif state:
+ if1.set_link_up()
+ else:
+ if1.set_link_down()
+
+ m2.run(linkneg_mod, desc=desc)
+
+ def ping_simple(self, if1, if2, fail_expected=False, desc=None):
+ if not desc:
+ desc = self._generate_default_desc(if1, if2)
+
+ if1.set_mtu(self._mtu)
+ if2.set_mtu(self._mtu)
+
+ m1 = if1.get_host()
+ m1.sync_resources(modules=["Icmp6Ping", "IcmpPing"])
+
+ ping_mod = self._ctl.get_module("IcmpPing",
+ options={
+ "addr": if2.get_ip(0),
+ "count": 100,
+ "interval": 0.2,
+ "iface" : if1.get_devname(),
+ "limit_rate": 90})
+
+ ping_mod6 = self._ctl.get_module("Icmp6Ping",
+ options={
+ "addr": if2.get_ip(1),
+ "count": 100,
+ "interval": 0.2,
+ "iface" : if1.get_ip(1),
+ "limit_rate": 90})
+
+ if self._ipv in [ 'ipv6', 'both' ]:
+ m1.run(ping_mod6, fail_expected=fail_expected, desc=desc)
+
+ if self._ipv in [ 'ipv4', 'both' ]:
+ m1.run(ping_mod, fail_expected=fail_expected, desc=desc)
+
+ def _get_netperf_srv_mod(self, if1, is_ipv6):
+ if is_ipv6:
+ addr_index = 1
+ else:
+ addr_index = 0
+ modules_options = {
+ "role" : "server",
+ "bind" : if1.get_ip(addr_index)
+ }
+ if is_ipv6:
+ modules_options["netperf_opts"] = "-6"
+ return self._ctl.get_module("Netperf", options = modules_options)
+
+ def _get_netperf_cli_mod(self, if1, if2, testname,
+ duration, num_parallel, is_ipv6):
+ if is_ipv6:
+ ipv6_str = " -6"
+ addr_index = 1
+ else:
+ ipv6_str = ""
+ addr_index = 0
+ modules_options = {
+ "role" : "client",
+ "netperf_server" : if1.get_ip(addr_index),
+ "duration" : duration,
+ "num_parallel" : num_parallel,
+ "testname" : testname,
+ "netperf_opts" : "-L %s%s" % (if2.get_ip(addr_index),
ipv6_str),
+ }
+ return self._ctl.get_module("Netperf", options = modules_options)
+
+ def _run_netperf(self, if1, if2, testname, is_ipv6, desc):
+ if not desc:
+ desc = self._generate_default_desc(if1, if2)
+
+ m1 = if1.get_host()
+ m2 = if2.get_host()
+
+ m1.sync_resources(modules=["Netperf"])
+ m2.sync_resources(modules=["Netperf"])
+
+ duration = self._netperf_duration
+ num_parallel = self._netperf_num_parallel
+
+ server_proc = m1.run(self._get_netperf_srv_mod(if1, is_ipv6), bg=True)
+ self._ctl.wait(2)
+ netperf_cli_mod = self._get_netperf_cli_mod(if1, if2, testname,
+ duration, num_parallel,
+ is_ipv6)
+ m2.run(netperf_cli_mod, timeout=duration + 10, desc=desc)
+ server_proc.intr()
+
+ def _netperf(self, if1, if2, testname, desc):
+ if1.set_mtu(self._mtu)
+ if2.set_mtu(self._mtu)
+
+ if self._ipv in [ 'ipv4', 'both' ]:
+ self._run_netperf(if1, if2, testname, False, desc)
+
+ if self._ipv in [ 'ipv6', 'both' ]:
+ self._run_netperf(if1, if2, testname, True, desc)
+
+ def netperf_tcp(self, if1, if2, desc=None):
+ self._netperf(if1, if2, "TCP_STREAM", desc)
+
+ def netperf_udp(self, if1, if2, desc=None):
+ self._netperf(if1, if2, "UDP_STREAM", desc)
+
+ def pktgen(self, if1, if2, pkt_size, desc=None):
+ if1.set_mtu(self._mtu)
+ m1 = if1.get_host()
+ m1.sync_resources(modules=["PktgenTx"])
+
+ pktgen_option = ["count 10000", "clone_skb 0", "delay
0"]
+ pktgen_option.append("pkt_size %s" % pkt_size)
+ pktgen_option.append("dst_mac %s" % if2.get_hwaddr())
+ pktgen_option.append("dst %s" % if2.get_ip(0))
+ pktgen_mod = self._ctl.get_module("PktgenTx",
+ options={
+ "netdev_name": if1.get_devname(),
+ "pktgen_option": pktgen_option})
+
+ m1.run(pktgen_mod, desc=desc)
+
+ def custom(self, m1, desc, err_msg=None):
+ m1.sync_resources(modules=["Custom"])
+ options = {}
+ if err_msg:
+ options["fail"] = "yes"
+ options["msg"] = err_msg
+ custom_mod = self._ctl.get_module("Custom", options=options)
+ m1.run(custom_mod, desc=desc)
+
+ def check_fdb(self, iface, hwaddr, vlan_id, rec_type, find=True):
+ fdb_table = iface.get_br_fdbs()
+
+ rec = "offload" if rec_type == "software" else
"self"
+ found = False
+ for fdb in fdb_table:
+ if (fdb["hwaddr"] == str(hwaddr) and fdb["vlan_id"] ==
vlan_id and
+ fdb[rec]):
+ found = True
+
+ if found and not find:
+ err_msg = "found %s record when shouldn't" % rec_type
+ elif find and not found:
+ err_msg = "didn't find %s record when should've" %
rec_type
+ else:
+ err_msg = ""
+
+ self.custom(iface.get_host(), "fdb test", err_msg)
diff --git a/recipes/switchdev/basic-001-links.py b/recipes/switchdev/basic-001-links.py
new file mode 100644
index 0000000..998c986
--- /dev/null
+++ b/recipes/switchdev/basic-001-links.py
@@ -0,0 +1,65 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def linkneg(tl, if1, if2):
+ if1_drv = str(if1.get_driver())
+ if2_drv = str(if2.get_driver())
+
+ # The mlx5_core upstream driver is currently buggy and does not support
+ # link negotiation. Patches were sent to the NIC team.
+ if 'mlx5' in if1_drv or 'mlx5' in if2_drv:
+ return
+
+ if 'mlx4' in if1_drv or 'mlx4' in if2_drv:
+ speeds = [10000, 40000]
+ else:
+ speeds = [10000, 40000, 100000]
+
+ for speed in speeds:
+ tl.linkneg(if1, if2, True, speed=speed, timeout=10)
+ tl.ping_simple(if1, if2)
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, sw = hosts
+ m1_if1, m1_if2, m1_if3, m1_if4, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ m1_if1.reset(ip=["192.168.101.10/24", "2002::1/64"])
+ m1_if2.reset(ip=["192.168.102.10/24", "2003::1/64"])
+ m1_if3.reset(ip=["192.168.103.10/24", "2004::1/64"])
+ m1_if4.reset(ip=["192.168.104.10/24", "2005::1/64"])
+ sw_if1.reset(ip=["192.168.101.11/24", "2002::2/64"])
+ sw_if2.reset(ip=["192.168.102.11/24", "2003::2/64"])
+ sw_if3.reset(ip=["192.168.103.11/24", "2004::2/64"])
+ sw_if4.reset(ip=["192.168.104.11/24", "2005::2/64"])
+
+ sleep(10)
+
+ tl = TestLib(ctl, aliases)
+
+ for (if1, if2) in [(sw_if1, m1_if1), (sw_if2, m1_if2), (sw_if3, m1_if3),
+ (sw_if4, m1_if4)]:
+ linkneg(tl, if1, if2)
+ linkneg(tl, if2, if1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine1").get_interface("if3"),
+ ctl.get_host("machine1").get_interface("if4"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/basic-001-links.xml
b/recipes/switchdev/basic-001-links.xml
new file mode 100644
index 0000000..1663299
--- /dev/null
+++ b/recipes/switchdev/basic-001-links.xml
@@ -0,0 +1,23 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="basic-001-links.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/basic-004-slowpath.py
b/recipes/switchdev/basic-004-slowpath.py
new file mode 100644
index 0000000..2408500
--- /dev/null
+++ b/recipes/switchdev/basic-004-slowpath.py
@@ -0,0 +1,33 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, sw = hosts
+ m1_if1, sw_if1 = ifaces
+
+ m1_if1.reset(ip=["192.168.101.10/24", "2002::1/64"])
+ sw_if1.reset(ip=["192.168.101.11/24", "2002::2/64"])
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_if1, sw_if1)
+ tl.netperf_tcp(m1_if1, sw_if1)
+ tl.netperf_udp(m1_if1, sw_if1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/basic-004-slowpath.xml
b/recipes/switchdev/basic-004-slowpath.xml
new file mode 100644
index 0000000..a0f3587
--- /dev/null
+++ b/recipes/switchdev/basic-004-slowpath.xml
@@ -0,0 +1,17 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="basic-004-slowpath.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/basic-005-slowpath-exhaustive.py
b/recipes/switchdev/basic-005-slowpath-exhaustive.py
new file mode 100644
index 0000000..c8a443e
--- /dev/null
+++ b/recipes/switchdev/basic-005-slowpath-exhaustive.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, sw = hosts
+ m1_if1, sw_if1 = ifaces
+
+ m1_if1.reset(ip=["192.168.101.10/24", "2002::1/64"])
+ sw_if1.reset(ip=["192.168.101.11/24", "2002::2/64"])
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ for x in range(64, 1500):
+ tl.pktgen(sw_if1, m1_if1, x)
+ for x in range(64, 1500):
+ tl.pktgen(m1_if1, sw_if1, x)
+ # Make sure switch is not stuck by performing ping test
+ tl.ping_simple(m1_if1, sw_if1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/basic-005-slowpath-exhaustive.xml
b/recipes/switchdev/basic-005-slowpath-exhaustive.xml
new file mode 100644
index 0000000..666d911
--- /dev/null
+++ b/recipes/switchdev/basic-005-slowpath-exhaustive.xml
@@ -0,0 +1,17 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="basic-005-slowpath-exhaustive.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/basic-006-slowpath-vlan.py
b/recipes/switchdev/basic-006-slowpath-vlan.py
new file mode 100644
index 0000000..7f34777
--- /dev/null
+++ b/recipes/switchdev/basic-006-slowpath-vlan.py
@@ -0,0 +1,35 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, sw = hosts
+ m1_if1, sw_if1 = ifaces
+
+ m1_if1_10 = m1.create_vlan(m1_if1, 10, ip=["192.168.101.10/24",
+ "2002::1/64"])
+ sw_if1_10 = sw.create_vlan(sw_if1, 10, ip=["192.168.101.11/24",
+ "2002::2/64"])
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_if1_10, sw_if1_10)
+ tl.netperf_tcp(m1_if1_10, sw_if1_10)
+ tl.netperf_udp(m1_if1_10, sw_if1_10)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/basic-006-slowpath-vlan.xml
b/recipes/switchdev/basic-006-slowpath-vlan.xml
new file mode 100644
index 0000000..e6df240
--- /dev/null
+++ b/recipes/switchdev/basic-006-slowpath-vlan.xml
@@ -0,0 +1,17 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="basic-006-slowpath-vlan.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/basic-007-slowpath-vlan-exhaustive.py
b/recipes/switchdev/basic-007-slowpath-vlan-exhaustive.py
new file mode 100644
index 0000000..e2d8fc7
--- /dev/null
+++ b/recipes/switchdev/basic-007-slowpath-vlan-exhaustive.py
@@ -0,0 +1,40 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, sw = hosts
+ m1_if1, sw_if1 = ifaces
+
+ m1_if1_20 = m1.create_vlan(m1_if1, 20, ip=["192.168.101.10/24",
+ "2002::1/64"])
+ sw_if1_20 = sw.create_vlan(sw_if1, 20, ip=["192.168.101.11/24",
+ "2002::2/64"])
+
+ # We need to get a netlink message with the VLAN devices' info,
+ # so make sure we wait long enough.
+ sleep(30)
+
+ tl = TestLib(ctl, aliases)
+ for x in range(64, 1500):
+ tl.pktgen(sw_if1_20, m1_if1_20, x)
+ for x in range(64, 1500):
+ tl.pktgen(m1_if1_20, sw_if1_20, x)
+ # Make sure switch is not stuck by performing ping test
+ tl.ping_simple(m1_if1_20, sw_if1_20)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/basic-007-slowpath-vlan-exhaustive.xml
b/recipes/switchdev/basic-007-slowpath-vlan-exhaustive.xml
new file mode 100644
index 0000000..26eaf46
--- /dev/null
+++ b/recipes/switchdev/basic-007-slowpath-vlan-exhaustive.xml
@@ -0,0 +1,17 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="basic-007-slowpath-vlan-exhaustive.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/default_aliases.xml
b/recipes/switchdev/default_aliases.xml
new file mode 100644
index 0000000..783fb5e
--- /dev/null
+++ b/recipes/switchdev/default_aliases.xml
@@ -0,0 +1,6 @@
+<define>
+ <alias name="ipv" value="both" />
+ <alias name="mtu" value="1500" />
+ <alias name="netperf_duration" value="60" />
+ <alias name="netperf_num_parallel" value="30" />
+</define>
diff --git a/recipes/switchdev/l2-000-minimal.py b/recipes/switchdev/l2-000-minimal.py
new file mode 100644
index 0000000..dcc9532
--- /dev/null
+++ b/recipes/switchdev/l2-000-minimal.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1.reset(ip=["192.168.101.10/24", "2002::1/64"])
+ m2_if1.reset(ip=["192.168.101.11/24", "2002::2/64"])
+
+ sw.create_bridge(slaves=[sw_if1, sw_if2], options={"vlan_filtering": 1})
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_if1, m2_if1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-000-minimal.xml b/recipes/switchdev/l2-000-minimal.xml
new file mode 100644
index 0000000..210974e
--- /dev/null
+++ b/recipes/switchdev/l2-000-minimal.xml
@@ -0,0 +1,24 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-000-minimal.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-001-bridge.py b/recipes/switchdev/l2-001-bridge.py
new file mode 100644
index 0000000..f92dae9
--- /dev/null
+++ b/recipes/switchdev/l2-001-bridge.py
@@ -0,0 +1,38 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1.reset(ip=["192.168.101.10/24", "2002::1/64"])
+ m2_if1.reset(ip=["192.168.101.11/24", "2002::2/64"])
+
+ sw.create_bridge(slaves=[sw_if1, sw_if2], options={"vlan_filtering": 1})
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.netperf_tcp(m1_if1, m2_if1)
+ tl.netperf_udp(m1_if1, m2_if1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-001-bridge.xml b/recipes/switchdev/l2-001-bridge.xml
new file mode 100644
index 0000000..1fdc211
--- /dev/null
+++ b/recipes/switchdev/l2-001-bridge.xml
@@ -0,0 +1,22 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-001-bridge.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-002-bridge_fdb.py
b/recipes/switchdev/l2-002-bridge_fdb.py
new file mode 100644
index 0000000..8e35758
--- /dev/null
+++ b/recipes/switchdev/l2-002-bridge_fdb.py
@@ -0,0 +1,142 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1.reset(ip=test_ip(1,1))
+ m2_if1.reset(ip=test_ip(1,2))
+
+ # Ageing time is 10 seconds.
+ br_options = {"vlan_filtering": 1, "ageing_time": 1000}
+ sw_br = sw.create_bridge(slaves = [sw_if1, sw_if2], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Disable learning and make sure FDB is not populated.
+ sw_if1.set_br_learning(on=False, self=True)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Disable flooding and make sure ping fails.
+ sw_if1.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+
+ # Set a static FDB entry and make sure ping works again.
+ sw_if1.add_br_fdb(str(m1_if1.get_hwaddr()), self=True, vlan_tci=1)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ # Remove static FDB entry. Ping should fail.
+ sw_if1.del_br_fdb(str(m1_if1.get_hwaddr()), self=True, vlan_tci=1)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Enable learning_sync and make sure both FDBs are populated.
+ sw_if1.set_br_learning(on=True, self=True)
+ sw_if1.set_br_flooding(on=True, self=True)
+ sw_if1.set_br_learning_sync(on=True, self=True)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Disable learning_sync and make sure only hardware FDB is populated.
+ sw_if1.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver.
+ sw_br.slave_del(sw_if1.get_id())
+ sw_br.slave_add(sw_if1.get_id()) # Enables learning sync by default.
+ sw_if1.set_br_learning(on=False, self=True)
+ sw_if1.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+
+ # Enable learning and make sure ping works again.
+ sw_if1.set_br_learning(on=True, self=True)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Insert a static FDB entry and disable learning sync. Ping should work.
+ sw_if1.add_br_fdb(str(m1_if1.get_hwaddr()), self=True, vlan_tci=1)
+ sw_if1.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ # Make sure static entry is not aged out.
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver. Unlike the
+ # previous case, here we check if the driver correctly removes the static
+ # entry.
+ # XXX: This currently fails because firmware doesn't flush static FDBs.
+ # Uncomment it when it's introduced.
+ #sw_br.slave_del(sw_if1.get_id())
+ #sw_br.slave_add(sw_if1.get_id())
+ #sw_if1.set_br_learning(on=False, self=True)
+ #sw_if1.set_br_flooding(on=False, self=True)
+ #tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+
+ # XXX: Cleanup because firmware doesn't do it.
+ sw_if1.del_br_fdb(str(m1_if1.get_hwaddr()), self=True, vlan_tci=1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-002-bridge_fdb.xml
b/recipes/switchdev/l2-002-bridge_fdb.xml
new file mode 100644
index 0000000..eab2cf0
--- /dev/null
+++ b/recipes/switchdev/l2-002-bridge_fdb.xml
@@ -0,0 +1,22 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-002-bridge_fdb.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-003-bridge_stp.py
b/recipes/switchdev/l2-003-bridge_stp.py
new file mode 100644
index 0000000..94bd6be
--- /dev/null
+++ b/recipes/switchdev/l2-003-bridge_stp.py
@@ -0,0 +1,93 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ # We can't set STP state if kernel's STP is running.
+ br_options = {"stp_state": 0, "vlan_filtering": 1,
"ageing_time": 1000}
+ sw.create_bridge(slaves=[sw_if1, sw_if2], options=br_options)
+
+ m1_if1.reset(ip=test_ip(1, 1))
+ m2_if1.reset(ip=test_ip(1, 2))
+
+ sleep(40)
+
+ tl = TestLib(ctl, aliases)
+
+ # Set STP state to DISABLED and make sure ping fails and FDB is not
+ # populated.
+ sw_if1.set_br_state(0)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Set STP state to LISTENING and make sure ping fails and FDB is not
+ # populated.
+ sw_if1.set_br_state(1)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Set STP state to LEARNING and make sure ping fails, but FDB *is*
+ # populated.
+ sw_if1.set_br_state(2)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Set STP state to FORWARDING and make sure ping works and FDB is
+ # populated.
+ sw_if1.set_br_state(3)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_if1, m1_if1.get_hwaddr(), 1, "hardware", False)
+
+ # Make sure that even with a static FDB record we don't get traffic
+ # when state is DISABLED, LEARNING or LISTENING.
+ sw_if2.add_br_fdb(str(m2_if1.get_hwaddr()), self=True, vlan_tci=1)
+ sw_if1.set_br_state(0)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+ sw_if1.set_br_state(1)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+ sw_if1.set_br_state(2)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+
+ # Cleanup
+ sw_if2.del_br_fdb(str(m2_if1.get_hwaddr()), self=True, vlan_tci=1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-003-bridge_stp.xml
b/recipes/switchdev/l2-003-bridge_stp.xml
new file mode 100644
index 0000000..d6c8f62
--- /dev/null
+++ b/recipes/switchdev/l2-003-bridge_stp.xml
@@ -0,0 +1,24 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-003-bridge_stp.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-004-bridge_bond.py
b/recipes/switchdev/l2-004-bridge_bond.py
new file mode 100644
index 0000000..8378bbd
--- /dev/null
+++ b/recipes/switchdev/l2-004-bridge_bond.py
@@ -0,0 +1,48 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ bond_options = {"mode": "802.3ad", "miimon":
"100"}
+ m1_lag1 = m1.create_bond(slaves=[m1_if1, m1_if2], options=bond_options,
+ ip=["192.168.101.10/24", "2002::1/64"])
+ m2_lag1 = m2.create_bond(slaves=[m2_if1, m2_if2], options=bond_options,
+ ip=["192.168.101.11/24", "2002::2/64"])
+
+ sw_lag1 = sw.create_bond(slaves=[sw_if1, sw_if2], options=bond_options)
+ sw_lag2 = sw.create_bond(slaves=[sw_if3, sw_if4], options=bond_options)
+
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options={"vlan_filtering": 1})
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.netperf_tcp(m1_lag1, m2_lag1)
+ tl.netperf_udp(m1_lag1, m2_lag1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-004-bridge_bond.xml
b/recipes/switchdev/l2-004-bridge_bond.xml
new file mode 100644
index 0000000..45fb919
--- /dev/null
+++ b/recipes/switchdev/l2-004-bridge_bond.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-004-bridge_bond.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-005-bridge_bond_failover.py
b/recipes/switchdev/l2-005-bridge_bond_failover.py
new file mode 100644
index 0000000..c7b4eca
--- /dev/null
+++ b/recipes/switchdev/l2-005-bridge_bond_failover.py
@@ -0,0 +1,64 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ bond_options = {"mode": "802.3ad", "miimon":
"100"}
+ m1_lag1 = m1.create_bond(slaves=[m1_if1, m1_if2], options=bond_options,
+ ip=["192.168.101.10/24", "2002::1/64"])
+ m2_lag1 = m2.create_bond(slaves=[m2_if1, m2_if2], options=bond_options,
+ ip=["192.168.101.11/24", "2002::2/64"])
+
+ sw_lag1 = sw.create_bond(slaves=[sw_if1, sw_if2], options=bond_options)
+ sw_lag2 = sw.create_bond(slaves=[sw_if3, sw_if4], options=bond_options)
+
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options={"vlan_filtering": 1})
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if1.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if1.set_link_up()
+ sw_if2.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if2.set_link_up()
+ sw_if1.set_link_down()
+ sw_if3.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if1.set_link_up()
+ sw_if3.set_link_up()
+ sw_if2.set_link_down()
+ sw_if4.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-005-bridge_bond_failover.xml
b/recipes/switchdev/l2-005-bridge_bond_failover.xml
new file mode 100644
index 0000000..ba87205
--- /dev/null
+++ b/recipes/switchdev/l2-005-bridge_bond_failover.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-005-bridge_bond_failover.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-006-bridge_team.py
b/recipes/switchdev/l2-006-bridge_team.py
new file mode 100644
index 0000000..fd648c9
--- /dev/null
+++ b/recipes/switchdev/l2-006-bridge_team.py
@@ -0,0 +1,54 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ team_config = '{"runner" : {"name" : "lacp"}}'
+ m1_lag1 = m1.create_team(slaves=[m1_if1, m1_if2],
+ config=team_config,
+ ip=["192.168.101.10/24", "2002::1/64"])
+
+ m2_lag1 = m2.create_team(slaves=[m2_if1, m2_if2],
+ config=team_config,
+ ip=["192.168.101.11/24", "2002::2/64"])
+
+ sw_lag1 = sw.create_team(slaves=[sw_if1, sw_if2],
+ config=team_config)
+
+ sw_lag2 = sw.create_team(slaves=[sw_if3, sw_if4],
+ config=team_config)
+
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options={"vlan_filtering": 1})
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.netperf_tcp(m1_lag1, m2_lag1)
+ tl.netperf_udp(m1_lag1, m2_lag1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-006-bridge_team.xml
b/recipes/switchdev/l2-006-bridge_team.xml
new file mode 100644
index 0000000..9df081f
--- /dev/null
+++ b/recipes/switchdev/l2-006-bridge_team.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-006-bridge_team.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-007-bridge_team_failover.py
b/recipes/switchdev/l2-007-bridge_team_failover.py
new file mode 100644
index 0000000..23d1a7c
--- /dev/null
+++ b/recipes/switchdev/l2-007-bridge_team_failover.py
@@ -0,0 +1,70 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ team_config = '{"runner" : {"name" : "lacp"}}'
+ m1_lag1 = m1.create_team(slaves=[m1_if1, m1_if2],
+ config=team_config,
+ ip=["192.168.101.10/24", "2002::1/64"])
+
+ m2_lag1 = m2.create_team(slaves=[m2_if1, m2_if2],
+ config=team_config,
+ ip=["192.168.101.11/24", "2002::2/64"])
+
+ sw_lag1 = sw.create_team(slaves=[sw_if1, sw_if2],
+ config=team_config)
+
+ sw_lag2 = sw.create_team(slaves=[sw_if3, sw_if4],
+ config=team_config)
+
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options={"vlan_filtering": 1})
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if1.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if1.set_link_up()
+ sw_if2.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if2.set_link_up()
+ sw_if1.set_link_down()
+ sw_if3.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+ sw_if1.set_link_up()
+ sw_if3.set_link_up()
+ sw_if2.set_link_down()
+ sw_if4.set_link_down()
+ tl.ping_simple(m1_lag1, m2_lag1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-007-bridge_team_failover.xml
b/recipes/switchdev/l2-007-bridge_team_failover.xml
new file mode 100644
index 0000000..3a20245
--- /dev/null
+++ b/recipes/switchdev/l2-007-bridge_team_failover.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-007-bridge_team_failover.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-008-bridge_vlan1q_sanity.py
b/recipes/switchdev/l2-008-bridge_vlan1q_sanity.py
new file mode 100644
index 0000000..740de76
--- /dev/null
+++ b/recipes/switchdev/l2-008-bridge_vlan1q_sanity.py
@@ -0,0 +1,86 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def check_vlan(tl, iface, vlan_id, pvid=False, untagged = False):
+ vlans = iface.get_br_vlans()
+ err_msg = "vlan not found"
+ for vlan in vlans:
+ if vlan_id == vlan["vlan_id"]:
+ if pvid != vlan["pvid"]:
+ err_msg = "PVID is not as expected"
+ elif untagged != vlan["untagged"]:
+ err_msg = "Untagged is not as expected"
+ else:
+ err_msg = ""
+ tl.custom(iface.get_host(), "vlan creation verification", err_msg)
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1.reset(ip=test_ip(1, 1))
+
+ m1_if1_10 = m1.create_vlan(m1_if1, 10, ip=test_ip(2, 1))
+ m1_if1_20 = m1.create_vlan(m1_if1, 20, ip=test_ip(3, 1))
+ m1_if1_30 = m1.create_vlan(m1_if1, 30, ip=test_ip(4, 1))
+
+ m2_if1.reset(ip=test_ip(1, 2))
+ m2_if1_10 = m2.create_vlan(m2_if1, 10, ip=test_ip(2, 2))
+ m2_if1_20 = m2.create_vlan(m2_if1, 20, ip=test_ip(3, 2))
+ m2_if1_30 = m2.create_vlan(m2_if1, 30, ip=test_ip(4, 2))
+
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_if1, sw_if2], options=br_options)
+
+ sw_if1.add_br_vlan(10)
+ sw_if2.add_br_vlan(10)
+ sw_if1.add_br_vlan(20)
+ sw_if2.add_br_vlan(20)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+
+ check_vlan(tl, sw_if1, 10)
+ check_vlan(tl, sw_if2, 10)
+ check_vlan(tl, sw_if1, 20)
+ check_vlan(tl, sw_if2, 20)
+
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.ping_simple(m1_if1_10, m2_if1_10)
+ tl.ping_simple(m1_if1_20, m2_if1_20)
+ tl.ping_simple(m1_if1_30, m2_if1_30, fail_expected=True)
+
+ sw_if1.add_br_vlan(500, pvid=True, untagged=True)
+ check_vlan(tl, sw_if1, 500, pvid=True, untagged=True)
+ sleep(1)
+ tl.ping_simple(m1_if1, m2_if1, fail_expected=True)
+
+ sw_if2.add_br_vlan(500, pvid=True, untagged=True)
+ check_vlan(tl, sw_if2, 500, pvid=True, untagged=True)
+ sleep(1)
+ tl.ping_simple(m1_if1, m2_if1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-008-bridge_vlan1q_sanity.xml
b/recipes/switchdev/l2-008-bridge_vlan1q_sanity.xml
new file mode 100644
index 0000000..1aa7f12
--- /dev/null
+++ b/recipes/switchdev/l2-008-bridge_vlan1q_sanity.xml
@@ -0,0 +1,22 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-008-bridge_vlan1q_sanity.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-009-bridge_vlan1q.py
b/recipes/switchdev/l2-009-bridge_vlan1q.py
new file mode 100644
index 0000000..af24b8d
--- /dev/null
+++ b/recipes/switchdev/l2-009-bridge_vlan1q.py
@@ -0,0 +1,70 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1.reset(ip=test_ip(1, 1))
+
+ m1_if1_10 = m1.create_vlan(m1_if1, 10, ip=test_ip(2, 1))
+ m1_if1_20 = m1.create_vlan(m1_if1, 20, ip=test_ip(3, 1))
+
+ m2_if1.reset(ip=test_ip(1, 2))
+ m2_if1_10 = m2.create_vlan(m2_if1, 10, ip=test_ip(2, 2))
+ m2_if1_20 = m2.create_vlan(m2_if1, 20, ip=test_ip(3, 2))
+
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_if1, sw_if2], options=br_options)
+
+ sw_if1.add_br_vlan(10)
+ sw_if2.add_br_vlan(10)
+ sw_if1.add_br_vlan(20)
+ sw_if2.add_br_vlan(20)
+
+ sleep(15)
+
+ tl = TestLib(ctl, ipv, aliases)
+
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.netperf_tcp(m1_if1, m2_if1)
+ tl.netperf_udp(m1_if1, m2_if1)
+
+ tl.ping_simple(m1_if1_10, m2_if1_10)
+ tl.netperf_tcp(m1_if1_10, m2_if1_10)
+ tl.netperf_udp(m1_if1_10, m2_if1_10)
+
+ tl.ping_simple(m1_if1_20, m2_if1_20)
+ tl.netperf_tcp(m1_if1_20, m2_if1_20)
+ tl.netperf_udp(m1_if1_20, m2_if1_20)
+
+ sw_if1.add_br_vlan(500, pvid=True, untagged=True)
+ sw_if2.add_br_vlan(500, pvid=True, untagged=True)
+ sleep(1)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.netperf_tcp(m1_if1, m2_if1)
+ tl.netperf_udp(m1_if1, m2_if1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-009-bridge_vlan1q.xml
b/recipes/switchdev/l2-009-bridge_vlan1q.xml
new file mode 100644
index 0000000..43703a7
--- /dev/null
+++ b/recipes/switchdev/l2-009-bridge_vlan1q.xml
@@ -0,0 +1,22 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-009-bridge_vlan1q.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-010-bridge_vlan1d_sanity.py
b/recipes/switchdev/l2-010-bridge_vlan1d_sanity.py
new file mode 100644
index 0000000..2c0062f
--- /dev/null
+++ b/recipes/switchdev/l2-010-bridge_vlan1d_sanity.py
@@ -0,0 +1,60 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1.reset(ip=test_ip(1, 1))
+
+ m1_if1_10 = m1.create_vlan(m1_if1, 10, ip=test_ip(2, 1))
+ m1_if1_20 = m1.create_vlan(m1_if1, 20, ip=test_ip(3, 1))
+ m1_if1_30 = m1.create_vlan(m1_if1, 30, ip=test_ip(4, 1))
+
+ m2_if1.reset(ip=test_ip(1, 2))
+ m2_if1_10 = m2.create_vlan(m2_if1, 10, ip=test_ip(2, 2))
+ m2_if1_21 = m2.create_vlan(m2_if1, 21, ip=test_ip(3, 2))
+ m2_if1_30 = m2.create_vlan(m2_if1, 30, ip=test_ip(4, 2))
+
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_if1, sw_if2], options=br_options)
+
+ sw_if1_10 = sw.create_vlan(sw_if1, 10)
+ sw_if2_10 = sw.create_vlan(sw_if2, 10)
+ sw.create_bridge(slaves=[sw_if1_10, sw_if2_10], options=br_options)
+
+ sw_if1_20 = sw.create_vlan(sw_if1, 20)
+ sw_if2_21 = sw.create_vlan(sw_if2, 21)
+ sw.create_bridge(slaves=[sw_if1_20, sw_if2_21], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.ping_simple(m1_if1_10, m2_if1_10)
+ tl.ping_simple(m1_if1_20, m2_if1_21)
+ tl.ping_simple(m1_if1_30, m2_if1_30, fail_expected=True)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-010-bridge_vlan1d_sanity.xml
b/recipes/switchdev/l2-010-bridge_vlan1d_sanity.xml
new file mode 100644
index 0000000..4384c43
--- /dev/null
+++ b/recipes/switchdev/l2-010-bridge_vlan1d_sanity.xml
@@ -0,0 +1,22 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-010-bridge_vlan1d_sanity.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-011-bridge_vlan1d.py
b/recipes/switchdev/l2-011-bridge_vlan1d.py
new file mode 100644
index 0000000..ccacf79
--- /dev/null
+++ b/recipes/switchdev/l2-011-bridge_vlan1d.py
@@ -0,0 +1,66 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1.reset(ip=test_ip(1, 1))
+
+ m1_if1_10 = m1.create_vlan(m1_if1, 10, ip=test_ip(2, 1))
+ m1_if1_20 = m1.create_vlan(m1_if1, 20, ip=test_ip(3, 1))
+
+ m2_if1.reset(ip=test_ip(1, 2))
+ m2_if1_10 = m2.create_vlan(m2_if1, 10, ip=test_ip(2, 2))
+ m2_if1_21 = m2.create_vlan(m2_if1, 21, ip=test_ip(3, 2))
+
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_if1, sw_if2], options=br_options)
+
+ sw_if1_10 = sw.create_vlan(sw_if1, 10)
+ sw_if2_10 = sw.create_vlan(sw_if2, 10)
+ sw.create_bridge(slaves=[sw_if1_10, sw_if2_10], options=br_options)
+
+ sw_if1_20 = sw.create_vlan(sw_if1, 20)
+ sw_if2_21 = sw.create_vlan(sw_if2, 21)
+ sw.create_bridge(slaves=[sw_if1_20, sw_if2_21], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+
+ tl.ping_simple(m1_if1, m2_if1)
+ tl.netperf_tcp(m1_if1, m2_if1)
+ tl.netperf_udp(m1_if1, m2_if1)
+
+ tl.ping_simple(m1_if1_10, m2_if1_10)
+ tl.netperf_tcp(m1_if1_10, m2_if1_10)
+ tl.netperf_udp(m1_if1_10, m2_if1_10)
+
+ tl.ping_simple(m1_if1_20, m2_if1_21)
+ tl.netperf_tcp(m1_if1_20, m2_if1_21)
+ tl.netperf_udp(m1_if1_20, m2_if1_21)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-011-bridge_vlan1d.xml
b/recipes/switchdev/l2-011-bridge_vlan1d.xml
new file mode 100644
index 0000000..fd53578
--- /dev/null
+++ b/recipes/switchdev/l2-011-bridge_vlan1d.xml
@@ -0,0 +1,22 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-011-bridge_vlan1d.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.py
b/recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.py
new file mode 100644
index 0000000..66c3eff
--- /dev/null
+++ b/recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.py
@@ -0,0 +1,68 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ bond_options = {"mode": "802.3ad", "miimon":
"100"}
+ m1_lag1 = m1.create_bond(slaves=[m1_if1, m1_if2],
+ options=bond_options, ip=test_ip(1, 1))
+ m1_lag1_10 = m1.create_vlan(m1_lag1, 10, ip=test_ip(2, 1))
+ m1_lag1_20 = m1.create_vlan(m1_lag1, 20, ip=test_ip(3, 1))
+ m1_lag1_30 = m1.create_vlan(m1_lag1, 30, ip=test_ip(4, 1))
+
+ m2_lag1 = m2.create_bond(slaves=[m2_if1, m2_if2],
+ options=bond_options, ip=test_ip(1, 2))
+ m2_lag1_10 = m2.create_vlan(m2_lag1, 10, ip=test_ip(2, 2))
+ m2_lag1_21 = m2.create_vlan(m2_lag1, 21, ip=test_ip(3, 2))
+ m2_lag1_30 = m2.create_vlan(m2_lag1, 30, ip=test_ip(4, 2))
+
+ sw_lag1 = sw.create_bond(slaves=[sw_if1, sw_if2], options=bond_options)
+ sw_lag2 = sw.create_bond(slaves=[sw_if3, sw_if4], options=bond_options)
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options=br_options)
+
+ sw_lag1_10 = sw.create_vlan(sw_lag1, 10)
+ sw_lag2_10 = sw.create_vlan(sw_lag2, 10)
+ sw.create_bridge(slaves=[sw_lag1_10, sw_lag2_10], options=br_options)
+
+ sw_lag1_20 = sw.create_vlan(sw_lag1, 20)
+ sw_lag2_21 = sw.create_vlan(sw_lag2, 21)
+ sw.create_bridge(slaves=[sw_lag1_20, sw_lag2_21], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.ping_simple(m1_lag1_10, m2_lag1_10)
+ tl.ping_simple(m1_lag1_20, m2_lag1_21)
+ tl.ping_simple(m1_lag1_30, m2_lag1_30, fail_expected=True)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.xml
b/recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.xml
new file mode 100644
index 0000000..52c6a3f
--- /dev/null
+++ b/recipes/switchdev/l2-012-bridge_bond_vlan1d_sanity.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-012-bridge_bond_vlan1d_sanity.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-013-bridge_bond_vlan1d.py
b/recipes/switchdev/l2-013-bridge_bond_vlan1d.py
new file mode 100644
index 0000000..f2f68d2
--- /dev/null
+++ b/recipes/switchdev/l2-013-bridge_bond_vlan1d.py
@@ -0,0 +1,74 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ bond_options = {"mode": "802.3ad", "miimon":
"100"}
+ m1_lag1 = m1.create_bond(slaves=[m1_if1, m1_if2],
+ options=bond_options, ip=test_ip(1, 1))
+ m1_lag1_10 = m1.create_vlan(m1_lag1, 10, ip=test_ip(2, 1))
+ m1_lag1_20 = m1.create_vlan(m1_lag1, 20, ip=test_ip(3, 1))
+
+ m2_lag1 = m2.create_bond(slaves=[m2_if1, m2_if2],
+ options=bond_options, ip=test_ip(1, 2))
+ m2_lag1_10 = m2.create_vlan(m2_lag1, 10, ip=test_ip(2, 2))
+ m2_lag1_21 = m2.create_vlan(m2_lag1, 21, ip=test_ip(3, 2))
+
+ sw_lag1 = sw.create_bond(slaves=[sw_if1, sw_if2], options=bond_options)
+ sw_lag2 = sw.create_bond(slaves=[sw_if3, sw_if4], options=bond_options)
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options=br_options)
+
+ sw_lag1_10 = sw.create_vlan(sw_lag1, 10)
+ sw_lag2_10 = sw.create_vlan(sw_lag2, 10)
+ sw.create_bridge(slaves=[sw_lag1_10, sw_lag2_10], options=br_options)
+
+ sw_lag1_20 = sw.create_vlan(sw_lag1, 20)
+ sw_lag2_21 = sw.create_vlan(sw_lag2, 21)
+ sw.create_bridge(slaves=[sw_lag1_20, sw_lag2_21], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.netperf_tcp(m1_lag1, m2_lag1)
+ tl.netperf_udp(m1_lag1, m2_lag1)
+
+ tl.ping_simple(m1_lag1_10, m2_lag1_10)
+ tl.netperf_tcp(m1_lag1_10, m2_lag1_10)
+ tl.netperf_udp(m1_lag1_10, m2_lag1_10)
+
+ tl.ping_simple(m1_lag1_20, m2_lag1_21)
+ tl.netperf_tcp(m1_lag1_20, m2_lag1_21)
+ tl.netperf_udp(m1_lag1_20, m2_lag1_21)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-013-bridge_bond_vlan1d.xml
b/recipes/switchdev/l2-013-bridge_bond_vlan1d.xml
new file mode 100644
index 0000000..3690d63
--- /dev/null
+++ b/recipes/switchdev/l2-013-bridge_bond_vlan1d.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-013-bridge_bond_vlan1d.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.py
b/recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.py
new file mode 100644
index 0000000..58753ca
--- /dev/null
+++ b/recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.py
@@ -0,0 +1,68 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ team_config = '{"runner" : {"name" : "lacp"}}'
+ m1_lag1 = m1.create_team(slaves=[m1_if1, m1_if2],
+ config=team_config, ip=test_ip(1, 1))
+ m1_lag1_10 = m1.create_vlan(m1_lag1, 10, ip=test_ip(2, 1))
+ m1_lag1_20 = m1.create_vlan(m1_lag1, 20, ip=test_ip(3, 1))
+ m1_lag1_30 = m1.create_vlan(m1_lag1, 30, ip=test_ip(4, 1))
+
+ m2_lag1 = m2.create_team(slaves=[m2_if1, m2_if2],
+ config=team_config, ip=test_ip(1, 2))
+ m2_lag1_10 = m2.create_vlan(m2_lag1, 10, ip=test_ip(2, 2))
+ m2_lag1_21 = m2.create_vlan(m2_lag1, 21, ip=test_ip(3, 2))
+ m2_lag1_30 = m2.create_vlan(m2_lag1, 30, ip=test_ip(4, 2))
+
+ sw_lag1 = sw.create_team(slaves=[sw_if1, sw_if2], config=team_config)
+ sw_lag2 = sw.create_team(slaves=[sw_if3, sw_if4], config=team_config)
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options=br_options)
+
+ sw_lag1_10 = sw.create_vlan(sw_lag1, 10)
+ sw_lag2_10 = sw.create_vlan(sw_lag2, 10)
+ sw.create_bridge(slaves=[sw_lag1_10, sw_lag2_10], options=br_options)
+
+ sw_lag1_20 = sw.create_vlan(sw_lag1, 20)
+ sw_lag2_21 = sw.create_vlan(sw_lag2, 21)
+ sw.create_bridge(slaves=[sw_lag1_20, sw_lag2_21], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.ping_simple(m1_lag1_10, m2_lag1_10)
+ tl.ping_simple(m1_lag1_20, m2_lag1_21)
+ tl.ping_simple(m1_lag1_30, m2_lag1_30, fail_expected=True)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.xml
b/recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.xml
new file mode 100644
index 0000000..730f0f0
--- /dev/null
+++ b/recipes/switchdev/l2-014-bridge_team_vlan1d_sanity.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-014-bridge_team_vlan1d_sanity.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-015-bridge_team_vlan1d.py
b/recipes/switchdev/l2-015-bridge_team_vlan1d.py
new file mode 100644
index 0000000..3bea6e2
--- /dev/null
+++ b/recipes/switchdev/l2-015-bridge_team_vlan1d.py
@@ -0,0 +1,74 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ team_config = '{"runner" : {"name" : "lacp"}}'
+ m1_lag1 = m1.create_team(slaves=[m1_if1, m1_if2],
+ config=team_config, ip=test_ip(1, 1))
+ m1_lag1_10 = m1.create_vlan(m1_lag1, 10, ip=test_ip(2, 1))
+ m1_lag1_20 = m1.create_vlan(m1_lag1, 20, ip=test_ip(3, 1))
+
+ m2_lag1 = m2.create_team(slaves=[m2_if1, m2_if2],
+ config=team_config, ip=test_ip(1, 2))
+ m2_lag1_10 = m2.create_vlan(m2_lag1, 10, ip=test_ip(2, 2))
+ m2_lag1_21 = m2.create_vlan(m2_lag1, 21, ip=test_ip(3, 2))
+
+ sw_lag1 = sw.create_team(slaves=[sw_if1, sw_if2], config=team_config)
+ sw_lag2 = sw.create_team(slaves=[sw_if3, sw_if4], config=team_config)
+ br_options = {"vlan_filtering": 1}
+ sw.create_bridge(slaves=[sw_lag1, sw_lag2], options=br_options)
+
+ sw_lag1_10 = sw.create_vlan(sw_lag1, 10)
+ sw_lag2_10 = sw.create_vlan(sw_lag2, 10)
+ sw.create_bridge(slaves=[sw_lag1_10, sw_lag2_10], options=br_options)
+
+ sw_lag1_20 = sw.create_vlan(sw_lag1, 20)
+ sw_lag2_21 = sw.create_vlan(sw_lag2, 21)
+ sw.create_bridge(slaves=[sw_lag1_20, sw_lag2_21], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.netperf_tcp(m1_lag1, m2_lag1)
+ tl.netperf_udp(m1_lag1, m2_lag1)
+
+ tl.ping_simple(m1_lag1_10, m2_lag1_10)
+ tl.netperf_tcp(m1_lag1_10, m2_lag1_10)
+ tl.netperf_udp(m1_lag1_10, m2_lag1_10)
+
+ tl.ping_simple(m1_lag1_20, m2_lag1_21)
+ tl.netperf_tcp(m1_lag1_20, m2_lag1_21)
+ tl.netperf_udp(m1_lag1_20, m2_lag1_21)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-015-bridge_team_vlan1d.xml
b/recipes/switchdev/l2-015-bridge_team_vlan1d.xml
new file mode 100644
index 0000000..14c40e3
--- /dev/null
+++ b/recipes/switchdev/l2-015-bridge_team_vlan1d.xml
@@ -0,0 +1,27 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-015-bridge_team_vlan1d.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-017-bridge_fdb_vlan1d.py
b/recipes/switchdev/l2-017-bridge_fdb_vlan1d.py
new file mode 100644
index 0000000..3edcfc6
--- /dev/null
+++ b/recipes/switchdev/l2-017-bridge_fdb_vlan1d.py
@@ -0,0 +1,144 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, sw_if1, sw_if2 = ifaces
+
+ m1_if1_10 = m1.create_vlan(m1_if1, 10, ip=test_ip(1,1))
+ m2_if1_20 = m2.create_vlan(m2_if1, 20, ip=test_ip(1,2))
+ sw_if1_10 = sw.create_vlan(sw_if1, 10)
+ sw_if2_20 = sw.create_vlan(sw_if2, 20)
+
+ # Ageing time is 10 seconds.
+ br_options = {"vlan_filtering": 0, "ageing_time": 1000}
+ sw_br = sw.create_bridge(slaves = [sw_if1_10, sw_if2_20], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_if1_10, m2_if1_20)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software")
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Disable learning and make sure FDB is not populated.
+ sw_if1_10.set_br_learning(on=False, self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Disable flooding and make sure ping fails.
+ sw_if1_10.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20, fail_expected=True)
+
+ # Set a static FDB entry and make sure ping works again.
+ sw_if1_10.add_br_fdb(str(m1_if1_10.get_hwaddr()), self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware")
+
+ # Remove static FDB entry. Ping should fail.
+ sw_if1_10.del_br_fdb(str(m1_if1_10.get_hwaddr()), self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20, fail_expected=True)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Enable learning_sync and make sure both FDBs are populated.
+ sw_if1_10.set_br_learning(on=True, self=True)
+ sw_if1_10.set_br_flooding(on=True, self=True)
+ sw_if1_10.set_br_learning_sync(on=True, self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software")
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Disable learning_sync and make sure only hardware FDB is populated.
+ sw_if1_10.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver.
+ sw_br.slave_del(sw_if1_10.get_id())
+ sw_br.slave_add(sw_if1_10.get_id()) # Enables learning sync by default.
+ sw_if1_10.set_br_learning(on=False, self=True)
+ sw_if1_10.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20, fail_expected=True)
+
+ # Enable learning and make sure ping works again.
+ sw_if1_10.set_br_learning(on=True, self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software")
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Insert a static FDB entry and disable learning sync. Ping should work.
+ sw_if1_10.add_br_fdb(str(m1_if1_10.get_hwaddr()), self=True)
+ sw_if1_10.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_if1_10, m2_if1_20)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ # Make sure static entry is not aged out.
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_if1_10, m1_if1_10.get_hwaddr(), 0, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver. Unlike the
+ # previous case, here we check if the driver correctly removes the static
+ # entry.
+ # XXX: This currently fails because firmware doesn't flush static FDBs.
+ # Uncomment it when it's introduced.
+ #sw_br.slave_del(sw_if1_10.get_id())
+ #sw_br.slave_add(sw_if1_10.get_id())
+ #sw_if1_10.set_br_learning(on=False, self=True)
+ #sw_if1_10.set_br_flooding(on=False, self=True)
+ #tl.ping_simple(m1_if1_10, m2_if1_20, fail_expected=True)
+
+ # XXX: Cleanup because firmware doesn't do it.
+ sw_if1_10.del_br_fdb(str(m1_if1_10.get_hwaddr()), self=True)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-017-bridge_fdb_vlan1d.xml
b/recipes/switchdev/l2-017-bridge_fdb_vlan1d.xml
new file mode 100644
index 0000000..2d3df4c
--- /dev/null
+++ b/recipes/switchdev/l2-017-bridge_fdb_vlan1d.xml
@@ -0,0 +1,22 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="B" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-017-bridge_fdb_vlan1d.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-018-bridge_fdb_team.py
b/recipes/switchdev/l2-018-bridge_fdb_team.py
new file mode 100644
index 0000000..a4443f6
--- /dev/null
+++ b/recipes/switchdev/l2-018-bridge_fdb_team.py
@@ -0,0 +1,150 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ team_config = '{"runner" : {"name" : "lacp"}}'
+ m1_lag1 = m1.create_team(slaves=[m1_if1, m1_if2], config=team_config,
+ ip=["192.168.101.10/24", "2002::1/64"])
+
+ m2_lag1 = m2.create_team(slaves=[m2_if1, m2_if2], config=team_config,
+ ip=["192.168.101.11/24", "2002::2/64"])
+
+ sw_lag1 = sw.create_team(slaves=[sw_if1, sw_if2], config=team_config)
+
+ sw_lag2 = sw.create_team(slaves=[sw_if3, sw_if4], config=team_config)
+
+ # Ageing time is 10 seconds.
+ br_options = {"vlan_filtering": 1, "ageing_time": 1000}
+ sw_br = sw.create_bridge(slaves = [sw_lag1, sw_lag2], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware", False)
+
+ # Disable learning and make sure FDB is not populated.
+ sw_lag1.set_br_learning(on=False, self=True)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware", False)
+
+ # Disable flooding and make sure ping fails.
+ sw_lag1.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_lag1, m2_lag1, fail_expected=True)
+
+ # Set a static FDB entry and make sure ping works again.
+ sw_lag1.add_br_fdb(str(m1_lag1.get_hwaddr()), self=True, vlan_tci=1)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware")
+
+ # Remove static FDB entry. Ping should fail.
+ sw_lag1.del_br_fdb(str(m1_lag1.get_hwaddr()), self=True, vlan_tci=1)
+ tl.ping_simple(m1_lag1, m2_lag1, fail_expected=True)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware", False)
+
+ # Enable learning_sync and make sure both FDBs are populated.
+ sw_lag1.set_br_learning(on=True, self=True)
+ sw_lag1.set_br_flooding(on=True, self=True)
+ sw_lag1.set_br_learning_sync(on=True, self=True)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware", False)
+
+ # Disable learning_sync and make sure only hardware FDB is populated.
+ sw_lag1.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver.
+ sw_br.slave_del(sw_lag1.get_id())
+ sw_br.slave_add(sw_lag1.get_id()) # Enables learning sync by default.
+ sw_lag1.set_br_learning(on=False, self=True)
+ sw_lag1.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_lag1, m2_lag1, fail_expected=True)
+
+ # Enable learning and make sure ping works again.
+ sw_lag1.set_br_learning(on=True, self=True)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software")
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware", False)
+
+ # Insert a static FDB entry and disable learning sync. Ping should work.
+ sw_lag1.add_br_fdb(str(m1_lag1.get_hwaddr()), self=True, vlan_tci=1)
+ sw_lag1.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_lag1, m2_lag1)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware")
+
+ sleep(20)
+
+ # Make sure static entry is not aged out.
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "software", False)
+ tl.check_fdb(sw_lag1, m1_lag1.get_hwaddr(), 1, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver. Unlike the
+ # previous case, here we check if the driver correctly removes the static
+ # entry.
+ # XXX: This currently fails because firmware doesn't flush static FDBs.
+ # Uncomment it when it's introduced.
+ #sw_br.slave_del(sw_lag1.get_id())
+ #sw_br.slave_add(sw_lag1.get_id())
+ #sw_lag1.set_br_learning(on=False, self=True)
+ #sw_lag1.set_br_flooding(on=False, self=True)
+ #tl.ping_simple(m1_lag1, m2_lag1, fail_expected=True)
+
+ # XXX: Cleanup because firmware doesn't do it.
+ sw_lag1.del_br_fdb(str(m1_lag1.get_hwaddr()), self=True, vlan_tci=1)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-018-bridge_fdb_team.xml
b/recipes/switchdev/l2-018-bridge_fdb_team.xml
new file mode 100644
index 0000000..266fed9
--- /dev/null
+++ b/recipes/switchdev/l2-018-bridge_fdb_team.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-018-bridge_fdb_team.py" />
+</lnstrecipe>
diff --git a/recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.py
b/recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.py
new file mode 100644
index 0000000..3d588d0
--- /dev/null
+++ b/recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.py
@@ -0,0 +1,157 @@
+"""
+Copyright 2016 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+jiri(a)mellanox.com (Jiri Pirko)
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+
+def test_ip(major, minor):
+ return ["192.168.10%d.%d/24" % (major, minor),
+ "2002:%d::%d/64" % (major, minor)]
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m1_if2, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3, sw_if4 = ifaces
+
+ team_config = '{"runner" : {"name" : "lacp"}}'
+ m1_lag1 = m1.create_team(slaves=[m1_if1, m1_if2], config=team_config)
+
+ m2_lag1 = m2.create_team(slaves=[m2_if1, m2_if2], config=team_config)
+
+ sw_lag1 = sw.create_team(slaves=[sw_if1, sw_if2], config=team_config)
+
+ sw_lag2 = sw.create_team(slaves=[sw_if3, sw_if4], config=team_config)
+
+ m1_lag1_10 = m1.create_vlan(m1_lag1, 10, ip=test_ip(1,1))
+ m2_lag1_20 = m2.create_vlan(m2_lag1, 20, ip=test_ip(1,2))
+ sw_lag1_10 = sw.create_vlan(sw_lag1, 10)
+ sw_lag2_20 = sw.create_vlan(sw_lag2, 20)
+
+ # Ageing time is 10 seconds.
+ br_options = {"vlan_filtering": 0, "ageing_time": 1000}
+ sw_br = sw.create_bridge(slaves = [sw_lag1_10, sw_lag2_20], options=br_options)
+
+ sleep(15)
+
+ tl = TestLib(ctl, aliases)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software")
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Disable learning and make sure FDB is not populated.
+ sw_lag1_10.set_br_learning(on=False, self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Disable flooding and make sure ping fails.
+ sw_lag1_10.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20, fail_expected=True)
+
+ # Set a static FDB entry and make sure ping works again.
+ sw_lag1_10.add_br_fdb(str(m1_lag1_10.get_hwaddr()), self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware")
+
+ # Remove static FDB entry. Ping should fail.
+ sw_lag1_10.del_br_fdb(str(m1_lag1_10.get_hwaddr()), self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20, fail_expected=True)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Enable learning_sync and make sure both FDBs are populated.
+ sw_lag1_10.set_br_learning(on=True, self=True)
+ sw_lag1_10.set_br_flooding(on=True, self=True)
+ sw_lag1_10.set_br_learning_sync(on=True, self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software")
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Disable learning_sync and make sure only hardware FDB is populated.
+ sw_lag1_10.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver.
+ sw_br.slave_del(sw_lag1_10.get_id())
+ sw_br.slave_add(sw_lag1_10.get_id()) # Enables learning sync by default.
+ sw_lag1_10.set_br_learning(on=False, self=True)
+ sw_lag1_10.set_br_flooding(on=False, self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20, fail_expected=True)
+
+ # Enable learning and make sure ping works again.
+ sw_lag1_10.set_br_learning(on=True, self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software")
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware", False)
+
+ # Insert a static FDB entry and disable learning sync. Ping should work.
+ sw_lag1_10.add_br_fdb(str(m1_lag1_10.get_hwaddr()), self=True)
+ sw_lag1_10.set_br_learning_sync(on=False, self=True)
+ tl.ping_simple(m1_lag1_10, m2_lag1_20)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware")
+
+ sleep(20)
+
+ # Make sure static entry is not aged out.
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "software", False)
+ tl.check_fdb(sw_lag1_10, m1_lag1_10.get_hwaddr(), 0, "hardware")
+
+ # Remove port from bridge and add it back. Disable flooding and learning
+ # and make sure ping doesn't work. Note that port must be removed from
+ # bridge when the FDB entry exists only in the hardware table. Otherwise,
+ # bridge code will flush it himself, instead of driver. Unlike the
+ # previous case, here we check if the driver correctly removes the static
+ # entry.
+ # XXX: This currently fails because firmware doesn't flush static FDBs.
+ # Uncomment it when it's introduced.
+ #sw_br.slave_del(sw_lag1_10.get_id())
+ #sw_br.slave_add(sw_lag1_10.get_id())
+ #sw_lag1_10.set_br_learning(on=False, self=True)
+ #sw_lag1_10.set_br_flooding(on=False, self=True)
+ #tl.ping_simple(m1_lag1_10, m2_lag1_20, fail_expected=True)
+
+ # XXX: Cleanup because firmware doesn't do it.
+ sw_lag1_10.del_br_fdb(str(m1_lag1_10.get_hwaddr()), self=True)
+
+do_task(ctl, [ctl.get_host("machine1"),
+ ctl.get_host("machine2"),
+ ctl.get_host("switch")],
+ [ctl.get_host("machine1").get_interface("if1"),
+ ctl.get_host("machine1").get_interface("if2"),
+ ctl.get_host("machine2").get_interface("if1"),
+ ctl.get_host("machine2").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if1"),
+ ctl.get_host("switch").get_interface("if2"),
+ ctl.get_host("switch").get_interface("if3"),
+ ctl.get_host("switch").get_interface("if4")],
+ ctl.get_aliases())
diff --git a/recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.xml
b/recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.xml
new file mode 100644
index 0000000..b2e3ca9
--- /dev/null
+++ b/recipes/switchdev/l2-019-bridge_fdb_team_vlan1d.xml
@@ -0,0 +1,26 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <network>
+ <host id="machine1">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <interfaces>
+ <eth id="if1" label="C" />
+ <eth id="if2" label="D" />
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A" />
+ <eth id="if2" label="B" />
+ <eth id="if3" label="C" />
+ <eth id="if4" label="D" />
+ </interfaces>
+ </host>
+ </network>
+ <task python="l2-019-bridge_fdb_team_vlan1d.py" />
+</lnstrecipe>
--
2.4.3