1import logging, time, re
2from autotest_lib.client.common_lib import error
3from autotest_lib.client.virt import virt_utils, virt_test_utils, aexpect
4
5
6def run_vlan(test, params, env):
7    """
8    Test 802.1Q vlan of NIC, config it by vconfig command.
9
10    1) Create two VMs.
11    2) Setup guests in 10 different vlans by vconfig and using hard-coded
12       ip address.
13    3) Test by ping between same and different vlans of two VMs.
14    4) Test by TCP data transfer, floop ping between same vlan of two VMs.
15    5) Test maximal plumb/unplumb vlans.
16    6) Recover the vlan config.
17
18    @param test: KVM test object.
19    @param params: Dictionary with the test parameters.
20    @param env: Dictionary with test environment.
21    """
22    vm = []
23    session = []
24    ifname = []
25    vm_ip = []
26    digest_origin = []
27    vlan_ip = ['', '']
28    ip_unit = ['1', '2']
29    subnet = params.get("subnet")
30    vlan_num = int(params.get("vlan_num"))
31    maximal = int(params.get("maximal"))
32    file_size = params.get("file_size")
33
34    vm.append(env.get_vm(params["main_vm"]))
35    vm.append(env.get_vm("vm2"))
36    for vm_ in vm:
37        vm_.verify_alive()
38
39    def add_vlan(session, v_id, iface="eth0"):
40        session.cmd("vconfig add %s %s" % (iface, v_id))
41
42    def set_ip_vlan(session, v_id, ip, iface="eth0"):
43        iface = "%s.%s" % (iface, v_id)
44        session.cmd("ifconfig %s %s" % (iface, ip))
45
46    def set_arp_ignore(session, iface="eth0"):
47        ignore_cmd = "echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore"
48        session.cmd(ignore_cmd)
49
50    def rem_vlan(session, v_id, iface="eth0"):
51        rem_vlan_cmd = "if [[ -e /proc/net/vlan/%s ]];then vconfig rem %s;fi"
52        iface = "%s.%s" % (iface, v_id)
53        return session.cmd_status(rem_vlan_cmd % (iface, iface))
54
55    def nc_transfer(src, dst):
56        nc_port = virt_utils.find_free_port(1025, 5334, vm_ip[dst])
57        listen_cmd = params.get("listen_cmd")
58        send_cmd = params.get("send_cmd")
59
60        #listen in dst
61        listen_cmd = listen_cmd % (nc_port, "receive")
62        session[dst].sendline(listen_cmd)
63        time.sleep(2)
64        #send file from src to dst
65        send_cmd = send_cmd % (vlan_ip[dst], str(nc_port), "file")
66        session[src].cmd(send_cmd, timeout=60)
67        try:
68            session[dst].read_up_to_prompt(timeout=60)
69        except aexpect.ExpectError:
70            raise error.TestFail ("Fail to receive file"
71                                    " from vm%s to vm%s" % (src+1, dst+1))
72        #check MD5 message digest of receive file in dst
73        output = session[dst].cmd_output("md5sum receive").strip()
74        digest_receive = re.findall(r'(\w+)', output)[0]
75        if digest_receive == digest_origin[src]:
76            logging.info("file succeed received in vm %s", vlan_ip[dst])
77        else:
78            logging.info("digest_origin is  %s", digest_origin[src])
79            logging.info("digest_receive is %s", digest_receive)
80            raise error.TestFail("File transfered differ from origin")
81        session[dst].cmd_output("rm -f receive")
82
83    for i in range(2):
84        session.append(vm[i].wait_for_login(
85            timeout=int(params.get("login_timeout", 360))))
86        if not session[i] :
87            raise error.TestError("Could not log into guest(vm%d)" % i)
88        logging.info("Logged in")
89
90        ifname.append(virt_test_utils.get_linux_ifname(session[i],
91                      vm[i].get_mac_address()))
92        #get guest ip
93        vm_ip.append(vm[i].get_address())
94
95        #produce sized file in vm
96        dd_cmd = "dd if=/dev/urandom of=file bs=1024k count=%s"
97        session[i].cmd(dd_cmd % file_size)
98        #record MD5 message digest of file
99        output = session[i].cmd("md5sum file", timeout=60)
100        digest_origin.append(re.findall(r'(\w+)', output)[0])
101
102        #stop firewall in vm
103        session[i].cmd_output("/etc/init.d/iptables stop")
104
105        #load 8021q module for vconfig
106        session[i].cmd("modprobe 8021q")
107
108    try:
109        for i in range(2):
110            for vlan_i in range(1, vlan_num+1):
111                add_vlan(session[i], vlan_i, ifname[i])
112                set_ip_vlan(session[i], vlan_i, "%s.%s.%s" %
113                            (subnet, vlan_i, ip_unit[i]), ifname[i])
114            set_arp_ignore(session[i], ifname[i])
115
116        for vlan in range(1, vlan_num+1):
117            logging.info("Test for vlan %s", vlan)
118
119            logging.info("Ping between vlans")
120            interface = ifname[0] + '.' + str(vlan)
121            for vlan2 in range(1, vlan_num+1):
122                for i in range(2):
123                    interface = ifname[i] + '.' + str(vlan)
124                    dest = subnet +'.'+ str(vlan2)+ '.' + ip_unit[(i+1)%2]
125                    s, o = virt_test_utils.ping(dest, count=2,
126                                              interface=interface,
127                                              session=session[i], timeout=30)
128                    if ((vlan == vlan2) ^ (s == 0)):
129                        raise error.TestFail ("%s ping %s unexpected" %
130                                                    (interface, dest))
131
132            vlan_ip[0] = subnet + '.' + str(vlan) + '.' + ip_unit[0]
133            vlan_ip[1] = subnet + '.' + str(vlan) + '.' + ip_unit[1]
134
135            logging.info("Flood ping")
136            def flood_ping(src, dst):
137                # we must use a dedicated session becuase the aexpect
138                # does not have the other method to interrupt the process in
139                # the guest rather than close the session.
140                session_flood = vm[src].wait_for_login(timeout=60)
141                virt_test_utils.ping(vlan_ip[dst], flood=True,
142                                   interface=ifname[src],
143                                   session=session_flood, timeout=10)
144                session_flood.close()
145
146            flood_ping(0, 1)
147            flood_ping(1, 0)
148
149            logging.info("Transfering data through nc")
150            nc_transfer(0, 1)
151            nc_transfer(1, 0)
152
153    finally:
154        for vlan in range(1, vlan_num+1):
155            rem_vlan(session[0], vlan, ifname[0])
156            rem_vlan(session[1], vlan, ifname[1])
157            logging.info("rem vlan: %s", vlan)
158
159    # Plumb/unplumb maximal number of vlan interfaces
160    i = 1
161    s = 0
162    try:
163        logging.info("Testing the plumb of vlan interface")
164        for i in range (1, maximal+1):
165            add_vlan(session[0], i, ifname[0])
166    finally:
167        for j in range (1, i+1):
168            s = s or rem_vlan(session[0], j, ifname[0])
169        if s == 0:
170            logging.info("maximal interface plumb test done")
171        else:
172            logging.error("maximal interface plumb test failed")
173
174    session[0].close()
175    session[1].close()
176