[prev in list] [next in list] [prev in thread] [next in thread] 

List:       lnst-developers
Subject:    [patch lnst] recipes: Add recipeset for testing switchdev based switches
From:       Jiri Pirko <jiri () resnulli ! us>
Date:       2016-01-20 16:21:48
Message-ID: 1453306908-10105-1-git-send-email-jiri () resnulli ! us
[Download RAW message or body]

From: Jiri Pirko <jiri@mellanox.com>

This patch introduces initial recipe set for testing basic and l2
functionality of switchdev offloaded switches.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@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@mellanox.com (Jiri Pirko)
+idosch@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@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@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@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@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@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@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@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@mellanox.com (Jiri Pirko)
+idosch@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@mellanox.com (Jiri Pirko)
+idosch@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@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@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@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@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@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@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@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@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@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@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@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@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@mellanox.com (Jiri Pirko)
+idosch@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@mellanox.com (Jiri Pirko)
+idosch@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@mellanox.com (Jiri Pirko)
+idosch@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
_______________________________________________
LNST-developers mailing list
lnst-developers@lists.fedorahosted.org
https://lists.fedorahosted.org/admin/lists/lnst-developers@lists.fedorahosted.org


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic