1import logging, os, re
2from autotest_lib.client.common_lib import error
3from autotest_lib.client.bin import utils
4from autotest_lib.client.virt import virt_test_utils, aexpect
5
6
7def run_multicast(test, params, env):
8    """
9    Test multicast function of nic (rtl8139/e1000/virtio)
10
11    1) Create a VM.
12    2) Join guest into multicast groups.
13    3) Ping multicast addresses on host.
14    4) Flood ping test with different size of packets.
15    5) Final ping test and check if lose packet.
16
17    @param test: KVM test object.
18    @param params: Dictionary with the test parameters.
19    @param env: Dictionary with test environment.
20    """
21    vm = env.get_vm(params["main_vm"])
22    vm.verify_alive()
23    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))
24
25    def run_guest(cmd):
26        try:
27            session.cmd(cmd)
28        except aexpect.ShellError, e:
29            logging.warning(e)
30
31    def run_host_guest(cmd):
32        run_guest(cmd)
33        utils.system(cmd, ignore_status=True)
34
35    # flush the firewall rules
36    cmd_flush = "iptables -F"
37    cmd_selinux = ("if [ -e /selinux/enforce ]; then setenforce 0; "
38                   "else echo 'no /selinux/enforce file present'; fi")
39    run_host_guest(cmd_flush)
40    run_host_guest(cmd_selinux)
41    # make sure guest replies to broadcasts
42    cmd_broadcast = "echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts"
43    cmd_broadcast_2 = "echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all"
44    run_guest(cmd_broadcast)
45    run_guest(cmd_broadcast_2)
46
47    # base multicast address
48    mcast = params.get("mcast", "225.0.0.1")
49    # count of multicast addresses, less than 20
50    mgroup_count = int(params.get("mgroup_count", 5))
51    flood_minutes = float(params.get("flood_minutes", 10))
52    ifname = vm.get_ifname()
53    prefix = re.findall("\d+.\d+.\d+", mcast)[0]
54    suffix = int(re.findall("\d+", mcast)[-1])
55    # copy python script to guest for joining guest to multicast groups
56    mcast_path = os.path.join(test.bindir, "scripts/multicast_guest.py")
57    vm.copy_files_to(mcast_path, "/tmp")
58    output = session.cmd_output("python /tmp/multicast_guest.py %d %s %d" %
59                                (mgroup_count, prefix, suffix))
60
61    # if success to join multicast, the process will be paused, and return PID.
62    try:
63        pid = re.findall("join_mcast_pid:(\d+)", output)[0]
64    except IndexError:
65        raise error.TestFail("Can't join multicast groups,output:%s" % output)
66
67    try:
68        for i in range(mgroup_count):
69            new_suffix = suffix + i
70            mcast = "%s.%d" % (prefix, new_suffix)
71
72            logging.info("Initial ping test, mcast: %s", mcast)
73            s, o = virt_test_utils.ping(mcast, 10, interface=ifname, timeout=20)
74            if s != 0:
75                raise error.TestFail(" Ping return non-zero value %s" % o)
76
77            logging.info("Flood ping test, mcast: %s", mcast)
78            virt_test_utils.ping(mcast, None, interface=ifname, flood=True,
79                                output_func=None, timeout=flood_minutes*60)
80
81            logging.info("Final ping test, mcast: %s", mcast)
82            s, o = virt_test_utils.ping(mcast, 10, interface=ifname, timeout=20)
83            if s != 0:
84                raise error.TestFail("Ping failed, status: %s, output: %s" %
85                                     (s, o))
86
87    finally:
88        logging.debug(session.cmd_output("ipmaddr show"))
89        session.cmd_output("kill -s SIGCONT %s" % pid)
90        session.close()
91