From: Ido Schimmel <idosch(a)mellanox.com>
Check that the appropriate parameters are used for the calculation of
the multipath hash.
Signed-off-by: Ido Schimmel <idosch(a)mellanox.com>
Signed-off-by: Yuval Mintz <yuvalm(a)mellanox.com>
---
recipes/switchdev/l3-012-ipv4-multipath-hash.py | 168 +++++++++++++++++++++++
recipes/switchdev/l3-012-ipv4-multipath-hash.xml | 58 ++++++++
2 files changed, 226 insertions(+)
create mode 100644 recipes/switchdev/l3-012-ipv4-multipath-hash.py
create mode 100644 recipes/switchdev/l3-012-ipv4-multipath-hash.xml
diff --git a/recipes/switchdev/l3-012-ipv4-multipath-hash.py
b/recipes/switchdev/l3-012-ipv4-multipath-hash.py
new file mode 100644
index 0000000..c17fcbb
--- /dev/null
+++ b/recipes/switchdev/l3-012-ipv4-multipath-hash.py
@@ -0,0 +1,168 @@
+"""
+Copyright 2017 Mellanox Technologies. All rights reserved.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+idosch(a)mellanox.com (Ido Schimmel)
+"""
+
+from lnst.Controller.Task import ctl
+from TestLib import TestLib
+from time import sleep
+import logging
+
+def ping(ctl, if1, dst):
+ m1 = if1.get_host()
+ m1.sync_resources(modules=["IcmpPing"])
+
+ ping_mod = ctl.get_module("IcmpPing",
+ options={
+ "addr": dst,
+ "count": 100,
+ "interval": 0.2,
+ "iface" : if1.get_devname(),
+ "limit_rate": 90})
+ m1.run(ping_mod)
+
+def pktgen_l4(ctl, if1, dst, neigh_mac):
+ m1 = if1.get_host()
+ m1.sync_resources(modules=["PktgenTx"])
+
+ pktgen_option = ["pkt_size {}".format(if1.get_mtu()),
+ "clone_skb 0",
+ "count {}".format(10 * 10 ** 6),
+ "dst_mac {}".format(neigh_mac),
+ "dst {}".format(dst),
+ "udp_src_min 1024", "udp_src_max 4096",
+ "udp_dst_min 1024", "udp_dst_max 4096",
+ "flag UDPSRC_RND", "flag UDPDST_RND"]
+ pktgen_mod = ctl.get_module("PktgenTx",
+ options={
+ "netdev_name": if1.get_devname(),
+ "pktgen_option": pktgen_option})
+ m1.run(pktgen_mod, timeout=600)
+
+def pktgen_l3(ctl, if1, neigh_mac, src_subnet, dst_subnet):
+ m1 = if1.get_host()
+ m1.sync_resources(modules=["PktgenTx"])
+
+ pktgen_option = ["pkt_size {}".format(if1.get_mtu()),
+ "clone_skb 0",
+ "count {}".format(10 * 10 ** 6),
+ "dst_mac {}".format(neigh_mac),
+ "dst_min {}".format(dst_subnet + ".1"),
+ "dst_max {}".format(dst_subnet + ".254"),
+ "src_min {}".format(src_subnet + ".1"),
+ "src_max {}".format(src_subnet + ".254"),
+ "udp_src_min 1024", "udp_src_max 1024",
+ "udp_dst_min 1024", "udp_dst_max 1024",
+ "flag IPSRC_RND", "flag IPDST_RND"]
+ pktgen_mod = ctl.get_module("PktgenTx",
+ options={
+ "netdev_name": if1.get_devname(),
+ "pktgen_option": pktgen_option})
+ m1.run(pktgen_mod, timeout=600)
+
+def check_res(tl, m, if2_pkts, if3_pkts, should_multipath):
+ msg = "Tx-ed packets: if2 ({}) , if3 ({})"
+ logging.info(msg.format(if2_pkts, if3_pkts))
+
+ # In case multipathing took place, following ratio should be very
+ # close to 0. Otherwise, very close to 1.
+ ratio = abs(if2_pkts - if3_pkts) / float(if2_pkts + if3_pkts)
+ if should_multipath:
+ err_msg = "" if ratio < 0.1 else "Multipathing didn't occur
when should"
+ else:
+ err_msg = "" if ratio > 0.9 else "Multipathing occurred when
shouldn't"
+ tl.custom(m, "Multipath test", err_msg)
+
+def multipath_test(ctl, hosts, ifaces, aliases, l3, should_multipath):
+ m1_if1, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3 = ifaces
+ tl = TestLib(ctl, aliases)
+ m1, m2, sw = hosts
+
+ if2_pre = sw_if2.link_stats()["tx_packets"]
+ if3_pre = sw_if3.link_stats()["tx_packets"]
+
+ if l3:
+ pktgen_l3(ctl, m1_if1, sw_if1.get_hwaddr(), aliases["subnet0"],
+ aliases["subnet3"])
+ else:
+ pktgen_l4(ctl, m1_if1, m2_if2.get_ip(1), sw_if1.get_hwaddr())
+
+ if2_post = sw_if2.link_stats()["tx_packets"]
+ if3_post = sw_if3.link_stats()["tx_packets"]
+
+ check_res(tl, m1, if2_post - if2_pre, if3_post - if3_pre, should_multipath)
+
+def do_task(ctl, hosts, ifaces, aliases):
+ m1, m2, sw = hosts
+ m1_if1, m2_if1, m2_if2, sw_if1, sw_if2, sw_if3 = ifaces
+
+ subnet0 = aliases["subnet0"] + ".0/24"
+ subnet1 = aliases["subnet1"] + ".0/24"
+ subnet2 = aliases["subnet2"] + ".0/24"
+ subnet3 = aliases["subnet3"] + ".0/24"
+
+ tl = TestLib(ctl, aliases)
+
+ # +----------------------------------+
+ # | |
+ # | |
+ # | sw_if1 sw_if2 sw_if3 |
+ # +---+-----------------+-------+----+
+ # | | |
+ # | | |
+ # | | |
+ # | | |
+ # + + +
+ # m1_if1 m2_if1 m2_if2
+
+ cmd = "ip -4 route add {subnet} nexthop via {gw_ip} dev {nh_dev}"
+ m1.run(cmd.format(subnet=subnet3, gw_ip=sw_if1.get_ip(0),
+ nh_dev=m1_if1.get_devname()))
+
+ cmd = ("ip -4 route add {subnet} nexthop via {gw_ip0} dev {nh_dev0} "
+ "nexthop via {gw_ip1} dev {nh_dev1}")
+ m2.run(cmd.format(subnet=subnet0, gw_ip0=sw_if2.get_ip(0),
+ nh_dev0=m2_if1.get_devname(), gw_ip1=sw_if3.get_ip(0),
+ nh_dev1=m2_if2.get_devname()))
+
+ cmd = ("ip -4 route add {subnet} nexthop via {gw_ip0} dev {nh_dev0} "
+ "nexthop via {gw_ip1} dev {nh_dev1}")
+ sw.run(cmd.format(subnet=subnet3, gw_ip0=m2_if1.get_ip(0),
+ nh_dev0=sw_if2.get_devname(), gw_ip1=m2_if2.get_ip(0),
+ nh_dev1=sw_if3.get_devname()))
+
+ sleep(30)
+
+ # Basic sanity check to make sure test is not failing due to
+ # setup issues.
+ ping(ctl, m1_if1, m2_if2.get_ip(1))
+
+ # Use only source and destination IP for IPv4 multipath hash.
+ sw.run("sysctl -w net.ipv4.fib_multipath_hash_policy=0")
+
+ multipath_test(ctl, hosts, ifaces, aliases, False, False)
+
+ multipath_test(ctl, hosts, ifaces, aliases, True, True)
+
+ # Use a 5-tuple for the multipath hash.
+ sw.run("sysctl -w net.ipv4.fib_multipath_hash_policy=1")
+
+ multipath_test(ctl, hosts, ifaces, aliases, False, True)
+
+ multipath_test(ctl, hosts, ifaces, aliases, True, 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("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_aliases())
diff --git a/recipes/switchdev/l3-012-ipv4-multipath-hash.xml
b/recipes/switchdev/l3-012-ipv4-multipath-hash.xml
new file mode 100644
index 0000000..c03c839
--- /dev/null
+++ b/recipes/switchdev/l3-012-ipv4-multipath-hash.xml
@@ -0,0 +1,58 @@
+<lnstrecipe
xmlns:xi="http://www.w3.org/2003/XInclude">
+ <xi:include href="default_aliases.xml" />
+ <define>
+ <alias name="ipv" value="ipv4" />
+ <alias name="subnet0" value="192.168.100" />
+ <alias name="subnet1" value="192.168.101" />
+ <alias name="subnet2" value="192.168.102" />
+ <alias name="subnet3" value="192.168.103" />
+ </define>
+ <network>
+ <host id="machine1">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="A">
+ <addresses>
+ <address>{$subnet0}.2/24</address>
+ </addresses>
+ </eth>
+ </interfaces>
+ </host>
+ <host id="machine2">
+ <params/>
+ <interfaces>
+ <eth id="if1" label="B">
+ <addresses>
+ <address>{$subnet1}.2/24</address>
+ </addresses>
+ </eth>
+ <eth id="if2" label="C">
+ <addresses>
+ <address>{$subnet2}.2/24</address>
+ <address>{$subnet3}.1/24</address>
+ </addresses>
+ </eth>
+ </interfaces>
+ </host>
+ <host id="switch">
+ <interfaces>
+ <eth id="if1" label="A">
+ <addresses>
+ <address>{$subnet0}.1/24</address>
+ </addresses>
+ </eth>
+ <eth id="if2" label="B">
+ <addresses>
+ <address>{$subnet1}.1/24</address>
+ </addresses>
+ </eth>
+ <eth id="if3" label="C">
+ <addresses>
+ <address>{$subnet2}.1/24</address>
+ </addresses>
+ </eth>
+ </interfaces>
+ </host>
+ </network>
+ <task python="l3-012-ipv4-multipath-hash.py" />
+</lnstrecipe>
--
2.4.3