def run(test, params, env): """ Test Step: 1. Boot up two virtual machine 2. Set openflow rules 3. Run ping test, nc(tcp, udp) test, check whether openflow rules take effect. Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def run_tcpdump_bg(vm, addresses, dump_protocol): """ Run tcpdump in background, tcpdump will exit once catch a packet match the rules. """ bg_session = vm.wait_for_login() if tcpdump_is_alive(bg_session): bg_session.cmd("killall -9 tcpdump") tcpdump_cmd = ("setsid tcpdump -iany -n -v %s and 'src %s and dst %s'" " -c 1 >/dev/null 2>&1") bg_session.sendline(tcpdump_cmd % (dump_protocol, addresses[0], addresses[1])) if not utils_misc.wait_for(lambda: tcpdump_is_alive(bg_session), 30, 0, 1, "Waiting tcpdump start..."): test.cancel("Error, can not run tcpdump") bg_session.close() def dump_catch_data(session, dump_log, catch_reg): """ Search data from dump_log """ dump_info = session.cmd_output("cat %s" % dump_log) if re.findall(catch_reg, dump_info, re.I): return True return False def tcpdump_is_alive(session): """ Check whether tcpdump is alive """ if session.cmd_status("pidof tcpdump"): return False return True def tcpdump_catch_packet_test(session, drop_flow=False): """ Check whether tcpdump catch match rules packets, once catch a packet match rules tcpdump will exit. when drop_flow is 'True', tcpdump couldn't catch any packets. """ packet_receive = not tcpdump_is_alive(session) if packet_receive == drop_flow: err_msg = "Error, flow %s" % (drop_flow and "was" or "wasn't") err_msg += " dropped, tcpdump " err_msg += "%s " % (packet_receive and "can" or "can not") err_msg += "receive the packets" test.error(err_msg) logging.info("Correct, flow %s dropped, tcpdump %s receive the packet" % ((drop_flow and "was" or "was not"), (packet_receive and "can" or "can not"))) def arp_entry_clean(entry=None): """ Clean arp catch in guest """ if not entry: arp_clean_cmd = "arp -n | awk '/^[1-2]/{print \"arp -d \" $1}'|sh" else: arp_clean_cmd = "arp -d %s" % entry for session in sessions: session.cmd_output_safe(arp_clean_cmd) def check_arp_info(session, entry, vm, match_mac=None): arp_info = session.cmd_output("arp -n") arp_entries = [_ for _ in arp_info.splitlines() if re.match(entry, _)] match_string = match_mac or "incomplete" if not arp_entries: test.error("Can not find arp entry in %s: %s" % (vm.name, arp_info)) if not re.findall(match_string, arp_entries[0], re.I): test.fail("Can not find the mac address" " %s of %s in arp" " entry %s" % (match_mac, vm.name, arp_entries[0])) def ping_test(session, dst, drop_flow=False): """ Ping test, check icmp """ ping_status, ping_output = utils_test.ping(dest=dst, count=10, timeout=20, session=session) # when drop_flow is true, ping should failed(return not zero) # drop_flow is false, ping should success packets_lost = 100 if ping_status and not drop_flow: test.error("Ping should success when not drop_icmp") elif not ping_status: packets_lost = utils_test.get_loss_ratio(ping_output) if drop_flow and packets_lost != 100: test.error("When drop_icmp, ping shouldn't works") if not drop_flow and packets_lost == 100: test.error("When not drop_icmp, ping should works") info_msg = "Correct, icmp flow %s dropped, ping '%s', " info_msg += "packets lost rate is: '%s'" logging.info(info_msg % ((drop_flow and "was" or "was not"), (ping_status and "failed" or "success"), packets_lost)) def run_ping_bg(vm, dst): """ Run ping in background """ ping_cmd = "ping %s" % dst session = vm.wait_for_login() logging.info("Ping %s in background" % dst) session.sendline(ping_cmd) return session def check_bg_ping(session): ping_pattern = r"\d+ bytes from \d+.\d+.\d+.\d+:" ping_pattern += r" icmp_seq=\d+ ttl=\d+ time=.*? ms" ping_failed_pattern = r"From .*? icmp_seq=\d+ Destination" ping_failed_pattern += r" Host Unreachable" try: out = session.read_until_output_matches([ping_pattern, ping_failed_pattern]) if re.search(ping_failed_pattern, out[1]): return False, out[1] else: return True, out[1] except Exception as msg: return False, msg def file_transfer(sessions, addresses, timeout): prepare_cmd = "dd if=/dev/zero of=/tmp/copy_file count=1024 bs=1M" md5_cmd = "md5sum /tmp/copy_file" port = params.get("shell_port") prompt = params.get("shell_prompt") username = params.get("username") password = params.get("password") sessions[0].cmd(prepare_cmd, timeout=timeout) ori_md5 = sessions[0].cmd_output(md5_cmd) scp_cmd = (r"scp -v -o UserKnownHostsFile=/dev/null " r"-o StrictHostKeyChecking=no " r"-o PreferredAuthentications=password -r " r"-P %s /tmp/copy_file %s@\[%s\]:/tmp/copy_file" % (port, username, addresses[1])) sessions[0].sendline(scp_cmd) remote.handle_prompts(sessions[0], username, password, prompt, 600) new_md5 = sessions[1].cmd_output(md5_cmd) for session in sessions: session.cmd("rm -f /tmp/copy_file") if new_md5 != ori_md5: test.fail("Md5 value changed after file transfer, " "original is %s and the new file" " is: %s" % (ori_md5, new_md5)) def nc_connect_test(sessions, addresses, drop_flow=False, nc_port="8899", udp_model=False): """ Nc connect test, check tcp and udp """ nc_log = "/tmp/nc_log" server_cmd = "nc -l %s" client_cmd = "echo client | nc %s %s" if udp_model: server_cmd += " -u -w 3" client_cmd += " -u -w 3" server_cmd += " > %s &" client_cmd += " &" try: sessions[1].cmd_output_safe(server_cmd % (nc_port, nc_log)) sessions[0].cmd_output_safe(client_cmd % (addresses[1], nc_port)) nc_protocol = udp_model and "UDP" or "TCP" nc_connect = False if utils_misc.wait_for( lambda: dump_catch_data(sessions[1], nc_log, "client"), 10, 0, 2, text="Wait '%s' connect" % nc_protocol): nc_connect = True if nc_connect == drop_flow: err_msg = "Error, '%s' " % nc_protocol err_msg += "flow %s " % (drop_flow and "was" or "was not") err_msg += "dropped, nc connect should" err_msg += " '%s'" % (nc_connect and "failed" or "success") test.error(err_msg) logging.info("Correct, '%s' flow %s dropped, and nc connect %s" % (nc_protocol, (drop_flow and "was" or "was not"), (nc_connect and "success" or "failed"))) finally: for session in sessions: session.cmd_output_safe("killall nc || killall ncat") session.cmd("%s %s" % (clean_cmd, nc_log), ignore_all_errors=True) def acl_rules_check(acl_rules, flow_options): flow_options = re.sub("action=", "actions=", flow_options) if "arp" in flow_options: flow_options = re.sub("nw_src=", "arp_spa=", flow_options) flow_options = re.sub("nw_dst=", "arp_tpa=", flow_options) acl_options = re.split(",", flow_options) for line in acl_rules.splitlines(): rule = [_.lower() for _ in re.split("[ ,]", line) if _] item_in_rule = 0 for acl_item in acl_options: if acl_item.lower() in rule: item_in_rule += 1 if item_in_rule == len(acl_options): return True return False def remove_plus_items(open_flow_rules): plus_items = ["duration", "n_packets", "n_bytes", "idle_age", "hard_age"] for plus_item in plus_items: open_flow_rules = re.sub("%s=.*?," % plus_item, "", open_flow_rules) return open_flow_rules br_name = params.get("netdst", "ovs0") timeout = int(params.get("login_timeout", '360')) prepare_timeout = int(params.get("prepare_timeout", '360')) clean_cmd = params.get("clean_cmd", "rm -f") sessions = [] addresses = [] vms = [] bg_ping_session = None if not utils_net.ovs_br_exists(br_name): test.cancel("%s isn't an openvswith bridge" % br_name) error_context.context("Init boot the vms") for vm_name in params.objects("vms"): vms.append(env.get_vm(vm_name)) for vm in vms: vm.verify_alive() sessions.append(vm.wait_for_login(timeout=timeout)) addresses.append(vm.get_address()) # set openflow rules: f_protocol = params.get("flow", "arp") f_base_options = "%s,nw_src=%s,nw_dst=%s" % (f_protocol, addresses[0], addresses[1]) for session in sessions: session.cmd("systemctl stop firewalld || service firewalld stop", ignore_all_errors=True) try: for drop_flow in [True, False]: if drop_flow: f_command = "add-flow" f_options = f_base_options + ",action=drop" drop_icmp = eval(params.get("drop_icmp", 'True')) drop_tcp = eval(params.get("drop_tcp", 'True')) drop_udp = eval(params.get("drop_udp", 'True')) else: f_command = "mod-flows" f_options = f_base_options + ",action=normal" drop_icmp = False drop_tcp = False drop_udp = False error_context.base_context("Test prepare") error_context.context("Do %s %s on %s" % (f_command, f_options, br_name)) utils_net.openflow_manager(br_name, f_command, f_options) acl_rules = utils_net.openflow_manager( br_name, "dump-flows").stdout.decode() if not acl_rules_check(acl_rules, f_options): test.fail("Can not find the rules from" " ovs-ofctl: %s" % acl_rules) error_context.context("Run tcpdump in guest %s" % vms[1].name, logging.info) run_tcpdump_bg(vms[1], addresses, f_protocol) if drop_flow or f_protocol is not "arp": error_context.context("Clean arp cache in both guest", logging.info) arp_entry_clean(addresses[1]) error_context.base_context( "Exec '%s' flow '%s' test" % (f_protocol, drop_flow and "drop" or "normal")) if drop_flow: error_context.context("Ping test form %s to %s" % (vms[0].name, vms[1].name), logging.info) ping_test(sessions[0], addresses[1], drop_icmp) if params.get("run_file_transfer") == "yes": error_context.context("Transfer file form %s to %s" % (vms[0].name, vms[1].name), logging.info) file_transfer(sessions, addresses, prepare_timeout) else: error_context.context("Ping test form %s to %s in background" % (vms[0].name, vms[1].name), logging.info) bg_ping_session = run_ping_bg(vms[0], addresses[1]) if f_protocol == 'arp' and drop_flow: error_context.context("Check arp inside %s" % vms[0].name, logging.info) check_arp_info(sessions[0], addresses[1], vms[0]) elif f_protocol == 'arp' or params.get("check_arp") == "yes": time.sleep(2) error_context.context("Check arp inside guests.", logging.info) for index, address in enumerate(addresses): sess_index = (index + 1) % 2 mac = vms[index].virtnet.get_mac_address(0) check_arp_info(sessions[sess_index], address, vms[index], mac) error_context.context("Run nc connect test via tcp", logging.info) nc_connect_test(sessions, addresses, drop_tcp) error_context.context("Run nc connect test via udp", logging.info) nc_connect_test(sessions, addresses, drop_udp, udp_model=True) error_context.context("Check tcpdump data catch", logging.info) tcpdump_catch_packet_test(sessions[1], drop_flow) finally: openflow_rules_ori = utils_net.openflow_manager( br_name, "dump-flows").stdout.decode() openflow_rules_ori = remove_plus_items(openflow_rules_ori) utils_net.openflow_manager(br_name, "del-flows", f_protocol) openflow_rules = utils_net.openflow_manager( br_name, "dump-flows").stdout.decode() openflow_rules = remove_plus_items(openflow_rules) removed_rule = list(set(openflow_rules_ori.splitlines()) - set(openflow_rules.splitlines())) if f_protocol == "tcp": error_context.context("Run nc connect test via tcp", logging.info) nc_connect_test(sessions, addresses) elif f_protocol == "udp": error_context.context("Run nc connect test via udp", logging.info) nc_connect_test(sessions, addresses, udp_model=True) for session in sessions: session.close() failed_msg = [] if (not removed_rule or not acl_rules_check(removed_rule[0], f_options)): failed_msg.append("Failed to delete %s" % f_options) if bg_ping_session: bg_ping_ok = check_bg_ping(bg_ping_session) bg_ping_session.close() if not bg_ping_ok[0]: failed_msg.append("There is something wrong happen in " "background ping: %s" % bg_ping_ok[1]) if failed_msg: test.fail(failed_msg)
if drop_flow: f_command = "add-flow" f_options = f_base_options + ",action=drop" drop_icmp = eval(params.get("drop_icmp", 'True')) drop_tcp = eval(params.get("drop_tcp", 'True')) drop_udp = eval(params.get("drop_udp", 'True')) else: f_command = "mod-flows" f_options = f_base_options + ",action=normal" drop_icmp = False drop_tcp = False drop_udp = False error.base_context("Test prepare") error.context("Do %s %s on %s" % (f_command, f_options, br_name)) utils_net.openflow_manager(br_name, f_command, f_options) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout if not acl_rules_check(acl_rules, f_options): raise error.TestFail("Can not find the rules from" " ovs-ofctl: %s" % acl_rules) error.context("Run tcpdump in guest %s" % vms[1].name, logging.info) run_tcpdump_bg(sessions[1], addresses, f_protocol) if drop_flow or f_protocol is not "arp": error.context("Clean arp cache in both guest", logging.info) arp_entry_clean(addresses[1]) error.base_context("Exec '%s' flow '%s' test" % (f_protocol, drop_flow and "drop" or "normal")) if drop_flow:
def run(test, params, env): """ Test Step: 1. Boot up two virtual machine 2. Set openflow rules 3. Run ping test, nc(tcp, udp) test, check whether openflow rules take effect. Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def run_tcpdump_bg(session, addresses, dump_protocol): """ Run tcpdump in background, tcpdump will exit once catch a packet match the rules. """ tcpdump_cmd = "killall -9 tcpdump; " tcpdump_cmd += "tcpdump -iany -n -v %s and 'src %s and dst %s' -c 1 &" session.cmd_output_safe(tcpdump_cmd % (dump_protocol, addresses[0], addresses[1])) if not utils_misc.wait_for(lambda: tcpdump_is_alive(session), 30, 0, 1, "Waiting tcpdump start..."): raise error.TestNAError("Error, can not run tcpdump") def dump_catch_data(session, dump_log, catch_reg): """ Search data from dump_log """ dump_info = session.cmd_output("cat %s" % dump_log) if re.findall(catch_reg, dump_info, re.I): return True return False def tcpdump_is_alive(session): """ Check whether tcpdump is alive """ if session.cmd_status("pidof tcpdump"): return False return True def tcpdump_catch_packet_test(session, drop_flow=False): """ Check whether tcpdump catch match rules packets, once catch a packet match rules tcpdump will exit. when drop_flow is 'True', tcpdump couldn't catch any packets. """ packet_receive = not tcpdump_is_alive(session) if packet_receive == drop_flow: err_msg = "Error, flow %s dropped, tcpdump %s receive the packets" raise error.TestError(err_msg % ((drop_flow and "was" or "wasn't"), (packet_receive and "can" or "can not"))) logging.info( "Correct, flow %s dropped, tcpdump %s receive the packet" % ((drop_flow and "was" or "was not"), (packet_receive and "can" or "can not"))) def arp_entry_clean(session, entry=None): """ Clean arp catch in guest """ if not entry: arp_clean_cmd = "arp -n | awk '/^[1-2]/{print \"arp -d \" $1}'|sh" else: arp_clean_cmd = "arp -d %s" % entry for session in sessions: session.cmd_output_safe(arp_clean_cmd) def ping_test(session, dst, drop_flow=False): """ Ping test, check icmp """ ping_status, ping_output = utils_test.ping(dest=dst, count=10, timeout=20, session=session) # when drop_flow is true, ping should failed(return not zero) # drop_flow is false, ping should success packets_lost = 100 if ping_status and not drop_flow: raise error.TestError("Ping should success when not drop_icmp") elif not ping_status: packets_lost = utils_test.get_loss_ratio(ping_output) if drop_flow and packets_lost != 100: raise error.TestError("When drop_icmp, ping shouldn't works") if not drop_flow and packets_lost == 100: raise error.TestError("When not drop_icmp, ping should works") info_msg = "Correct, icmp flow %s dropped, ping '%s', " info_msg += "packets lost rate is: '%s'" logging.info(info_msg % ((drop_flow and "was" or "was not"), (ping_status and "failed" or "success"), packets_lost)) def nc_connect_test(sessions, addresses, drop_flow=False, nc_port="8899", udp_model=False): """ Nc connect test, check tcp and udp """ nc_log = "/tmp/nc_log" server_cmd = "nc -l %s" client_cmd = "echo client | nc %s %s" if udp_model: server_cmd += " -u -w 3" client_cmd += " -u -w 3" server_cmd += " > %s &" client_cmd += " &" try: sessions[1].cmd_output_safe(server_cmd % (nc_port, nc_log)) sessions[0].cmd_output_safe(client_cmd % (addresses[1], nc_port)) nc_protocol = udp_model and "UDP" or "TCP" nc_connect = False if utils_misc.wait_for( lambda: dump_catch_data(sessions[1], nc_log, "client"), 10, 0, 2, text="Wait '%s' connect" % nc_protocol): nc_connect = True if nc_connect == drop_flow: err_msg = "Error, '%s' flow %s dropped, nc connect should '%s'" raise error.TestError( err_msg % (nc_protocol, (drop_flow and "was" or "was not"), (nc_connect and "failed" or "success"))) logging.info("Correct, '%s' flow %s dropped, and nc connect %s" % (nc_protocol, (drop_flow and "was" or "was not"), (nc_connect and "success" or "failed"))) finally: for session in sessions: session.cmd_output_safe("killall nc || killall ncat") session.cmd("%s %s" % (clean_cmd, nc_log), ignore_all_errors=True) timeout = int(params.get("login_timeout", '360')) clean_cmd = params.get("clean_cmd", "rm -f") sessions = [] addresses = [] vms = [] error.context("Init boot the vms") for vm_name in params.get("vms", "vm1 vm2").split(): vms.append(env.get_vm(vm_name)) for vm in vms: vm.verify_alive() sessions.append(vm.wait_for_login(timeout=timeout)) addresses.append(vm.get_address()) # set openflow rules: br_name = params.get("netdst", "ovs0") f_protocol = params.get("flow", "arp") f_base_options = "%s,nw_src=%s,nw_dst=%s" % (f_protocol, addresses[0], addresses[1]) for session in sessions: session.cmd("service iptables stop; iptables -F", ignore_all_errors=True) try: for drop_flow in [True, False]: if drop_flow: f_command = "add-flow" f_options = f_base_options + ",action=drop" drop_icmp = eval(params.get("drop_icmp", 'True')) drop_tcp = eval(params.get("drop_tcp", 'True')) drop_udp = eval(params.get("drop_udp", 'True')) else: f_command = "mod-flows" f_options = f_base_options + ",action=normal" drop_icmp = False drop_tcp = False drop_udp = False error.base_context("Test prepare") error.context("Do %s %s on %s" % (f_command, f_options, br_name)) utils_net.openflow_manager(br_name, f_command, f_options) error.context("Run tcpdump in guest %s" % vms[1].name, logging.info) run_tcpdump_bg(sessions[1], addresses, f_protocol) error.context("Clean arp cache in both guest", logging.info) arp_entry_clean(sessions[0], addresses[1]) error.base_context("Exec '%s' flow '%s' test" % (f_protocol, drop_flow and "drop" or "normal")) error.context("Ping test form vm1 to vm2", logging.info) ping_test(sessions[0], addresses[1], drop_icmp) error.context("Run nc connect test via tcp", logging.info) nc_connect_test(sessions, addresses, drop_tcp) error.context("Run nc connect test via udp", logging.info) nc_connect_test(sessions, addresses, drop_udp, udp_model=True) error.context("Check tcpdump data catch", logging.info) tcpdump_catch_packet_test(sessions[1], drop_flow) finally: utils_net.openflow_manager(br_name, "del-flows", f_protocol) for session in sessions: session.close()
if drop_flow: f_command = "add-flow" f_options = f_base_options + ",action=drop" drop_icmp = eval(params.get("drop_icmp", 'True')) drop_tcp = eval(params.get("drop_tcp", 'True')) drop_udp = eval(params.get("drop_udp", 'True')) else: f_command = "mod-flows" f_options = f_base_options + ",action=normal" drop_icmp = False drop_tcp = False drop_udp = False error.base_context("Test prepare") error.context("Do %s %s on %s" % (f_command, f_options, br_name)) utils_net.openflow_manager(br_name, f_command, f_options) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout if not acl_rules_check(acl_rules, f_options): raise error.TestFail("Can not find the rules from" " ovs-ofctl: %s" % acl_rules) error.context("Run tcpdump in guest %s" % vms[1].name, logging.info) run_tcpdump_bg(sessions[1], addresses, f_protocol) if drop_flow or f_protocol is not "arp": error.context("Clean arp cache in both guest", logging.info) arp_entry_clean(addresses[1]) error.base_context("Exec '%s' flow '%s' test" %
def run(test, params, env): """ Test Step: 1. Boot up two virtual machine 2. Set openflow rules 3. Run ping test, nc(tcp, udp) test, check whether openflow rules take effect. Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def run_tcpdump_bg(session, addresses, dump_protocol): """ Run tcpdump in background, tcpdump will exit once catch a packet match the rules. """ tcpdump_cmd = "killall -9 tcpdump; " tcpdump_cmd += "tcpdump -iany -n -v %s and 'src %s and dst %s' -c 1 &" session.cmd_output_safe(tcpdump_cmd % (dump_protocol, addresses[0], addresses[1])) if not utils_misc.wait_for(lambda: tcpdump_is_alive(session), 30, 0, 1, "Waiting tcpdump start..."): test.cancel("Error, can not run tcpdump") def dump_catch_data(session, dump_log, catch_reg): """ Search data from dump_log """ dump_info = session.cmd_output("cat %s" % dump_log) if re.findall(catch_reg, dump_info, re.I): return True return False def tcpdump_is_alive(session): """ Check whether tcpdump is alive """ if session.cmd_status("pidof tcpdump"): return False return True def tcpdump_catch_packet_test(session, drop_flow=False): """ Check whether tcpdump catch match rules packets, once catch a packet match rules tcpdump will exit. when drop_flow is 'True', tcpdump couldn't catch any packets. """ packet_receive = not tcpdump_is_alive(session) if packet_receive == drop_flow: err_msg = "Error, flow %s" % (drop_flow and "was" or "wasn't") err_msg += " dropped, tcpdump " err_msg += "%s " % (packet_receive and "can" or "can not") err_msg += "receive the packets" test.error(err_msg) logging.info("Correct, flow %s dropped, tcpdump %s receive the packet" % ((drop_flow and "was" or "was not"), (packet_receive and "can" or "can not"))) def arp_entry_clean(entry=None): """ Clean arp catch in guest """ if not entry: arp_clean_cmd = "arp -n | awk '/^[1-2]/{print \"arp -d \" $1}'|sh" else: arp_clean_cmd = "arp -d %s" % entry for session in sessions: session.cmd_output_safe(arp_clean_cmd) def check_arp_info(session, entry, vm, match_mac=None): arp_info = session.cmd_output("arp -n") arp_entries = [_ for _ in arp_info.splitlines() if re.match(entry, _)] match_string = match_mac or "incomplete" if not arp_entries: test.error("Can not find arp entry in %s: %s" % (vm.name, arp_info)) if not re.findall(match_string, arp_entries[0], re.I): test.fail("Can not find the mac address" " %s of %s in arp" " entry %s" % (mac, vm.name, arp_entries[0])) def ping_test(session, dst, drop_flow=False): """ Ping test, check icmp """ ping_status, ping_output = utils_test.ping(dest=dst, count=10, timeout=20, session=session) # when drop_flow is true, ping should failed(return not zero) # drop_flow is false, ping should success packets_lost = 100 if ping_status and not drop_flow: test.error("Ping should success when not drop_icmp") elif not ping_status: packets_lost = utils_test.get_loss_ratio(ping_output) if drop_flow and packets_lost != 100: test.error("When drop_icmp, ping shouldn't works") if not drop_flow and packets_lost == 100: test.error("When not drop_icmp, ping should works") info_msg = "Correct, icmp flow %s dropped, ping '%s', " info_msg += "packets lost rate is: '%s'" logging.info(info_msg % ((drop_flow and "was" or "was not"), (ping_status and "failed" or "success"), packets_lost)) def run_ping_bg(vm, dst): """ Run ping in background """ ping_cmd = "ping %s" % dst session = vm.wait_for_login() logging.info("Ping %s in background" % dst) session.sendline(ping_cmd) return session def check_bg_ping(session): ping_pattern = r"\d+ bytes from \d+.\d+.\d+.\d+:" ping_pattern += r" icmp_seq=\d+ ttl=\d+ time=.*? ms" ping_failed_pattern = r"From .*? icmp_seq=\d+ Destination" ping_failed_pattern += r" Host Unreachable" try: out = session.read_until_output_matches([ping_pattern, ping_failed_pattern]) if re.search(ping_failed_pattern, out[1]): return False, out[1] else: return True, out[1] except Exception as msg: return False, msg def file_transfer(sessions, addresses, timeout): prepare_cmd = "dd if=/dev/zero of=/tmp/copy_file count=1024 bs=1M" md5_cmd = "md5sum /tmp/copy_file" port = params.get("shell_port") prompt = params.get("shell_prompt") username = params.get("username") password = params.get("password") sessions[0].cmd(prepare_cmd, timeout=timeout) ori_md5 = sessions[0].cmd_output(md5_cmd) scp_cmd = (r"scp -v -o UserKnownHostsFile=/dev/null " r"-o StrictHostKeyChecking=no " r"-o PreferredAuthentications=password -r " r"-P %s /tmp/copy_file %s@\[%s\]:/tmp/copy_file" % (port, username, addresses[1])) sessions[0].sendline(scp_cmd) remote.handle_prompts(sessions[0], username, password, prompt, 600) new_md5 = sessions[1].cmd_output(md5_cmd) for session in sessions: session.cmd("rm -f /tmp/copy_file") if new_md5 != ori_md5: test.fail("Md5 value changed after file transfer, " "original is %s and the new file" " is: %s" % (ori_md5, new_md5)) def nc_connect_test(sessions, addresses, drop_flow=False, nc_port="8899", udp_model=False): """ Nc connect test, check tcp and udp """ nc_log = "/tmp/nc_log" server_cmd = "nc -l %s" client_cmd = "echo client | nc %s %s" if udp_model: server_cmd += " -u -w 3" client_cmd += " -u -w 3" server_cmd += " > %s &" client_cmd += " &" try: sessions[1].cmd_output_safe(server_cmd % (nc_port, nc_log)) sessions[0].cmd_output_safe(client_cmd % (addresses[1], nc_port)) nc_protocol = udp_model and "UDP" or "TCP" nc_connect = False if utils_misc.wait_for( lambda: dump_catch_data(sessions[1], nc_log, "client"), 10, 0, 2, text="Wait '%s' connect" % nc_protocol): nc_connect = True if nc_connect == drop_flow: err_msg = "Error, '%s' " % nc_protocol err_msg += "flow %s " % (drop_flow and "was" or "was not") err_msg += "dropped, nc connect should" err_msg += " '%s'" % (nc_connect and "failed" or "success") test.error(err_msg) logging.info("Correct, '%s' flow %s dropped, and nc connect %s" % (nc_protocol, (drop_flow and "was" or "was not"), (nc_connect and "success" or "failed"))) finally: for session in sessions: session.cmd_output_safe("killall nc || killall ncat") session.cmd("%s %s" % (clean_cmd, nc_log), ignore_all_errors=True) def acl_rules_check(acl_rules, flow_options): flow_options = re.sub("action=", "actions=", flow_options) if "arp" in flow_options: flow_options = re.sub("nw_src=", "arp_spa=", flow_options) flow_options = re.sub("nw_dst=", "arp_tpa=", flow_options) acl_options = re.split(",", flow_options) for line in acl_rules.splitlines(): rule = [_.lower() for _ in re.split("[ ,]", line) if _] item_in_rule = 0 for acl_item in acl_options: if acl_item.lower() in rule: item_in_rule += 1 if item_in_rule == len(acl_options): return True return False def remove_plus_items(open_flow_rules): plus_items = ["duration", "n_packets", "n_bytes", "idle_age", "hard_age"] for plus_item in plus_items: open_flow_rules = re.sub("%s=.*?," % plus_item, "", open_flow_rules) return open_flow_rules timeout = int(params.get("login_timeout", '360')) prepare_timeout = int(params.get("prepare_timeout", '360')) clean_cmd = params.get("clean_cmd", "rm -f") sessions = [] addresses = [] vms = [] bg_ping_session = None error_context.context("Init boot the vms") for vm_name in params.get("vms", "vm1 vm2").split(): vms.append(env.get_vm(vm_name)) for vm in vms: vm.verify_alive() sessions.append(vm.wait_for_login(timeout=timeout)) addresses.append(vm.get_address()) # set openflow rules: br_name = params.get("netdst", "ovs0") f_protocol = params.get("flow", "arp") f_base_options = "%s,nw_src=%s,nw_dst=%s" % (f_protocol, addresses[0], addresses[1]) for session in sessions: session.cmd("service iptables stop; iptables -F", ignore_all_errors=True) try: for drop_flow in [True, False]: if drop_flow: f_command = "add-flow" f_options = f_base_options + ",action=drop" drop_icmp = eval(params.get("drop_icmp", 'True')) drop_tcp = eval(params.get("drop_tcp", 'True')) drop_udp = eval(params.get("drop_udp", 'True')) else: f_command = "mod-flows" f_options = f_base_options + ",action=normal" drop_icmp = False drop_tcp = False drop_udp = False error_context.base_context("Test prepare") error_context.context("Do %s %s on %s" % (f_command, f_options, br_name)) utils_net.openflow_manager(br_name, f_command, f_options) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout if not acl_rules_check(acl_rules, f_options): test.fail("Can not find the rules from" " ovs-ofctl: %s" % acl_rules) error_context.context("Run tcpdump in guest %s" % vms[1].name, logging.info) run_tcpdump_bg(sessions[1], addresses, f_protocol) if drop_flow or f_protocol is not "arp": error_context.context("Clean arp cache in both guest", logging.info) arp_entry_clean(addresses[1]) error_context.base_context( "Exec '%s' flow '%s' test" % (f_protocol, drop_flow and "drop" or "normal")) if drop_flow: error_context.context("Ping test form vm1 to vm2", logging.info) ping_test(sessions[0], addresses[1], drop_icmp) if params.get("run_file_transfer") == "yes": error_context.context("Transfer file form vm1 to vm2", logging.info) file_transfer(sessions, addresses, prepare_timeout) else: error_context.context("Ping test form vm1 to vm2 in " "background", logging.info) bg_ping_session = run_ping_bg(vms[0], addresses[1]) if f_protocol == 'arp' and drop_flow: error_context.context("Check arp inside %s" % vms[0].name, logging.info) check_arp_info(sessions[0], addresses[1], vms[0]) elif f_protocol == 'arp' or params.get("check_arp") == "yes": time.sleep(2) error_context.context("Check arp inside guests.", logging.info) for index, address in enumerate(addresses): sess_index = (index + 1) % 2 mac = vms[index].virtnet.get_mac_address(0) check_arp_info(sessions[sess_index], address, vms[index], mac) error_context.context("Run nc connect test via tcp", logging.info) nc_connect_test(sessions, addresses, drop_tcp) error_context.context("Run nc connect test via udp", logging.info) nc_connect_test(sessions, addresses, drop_udp, udp_model=True) error_context.context("Check tcpdump data catch", logging.info) tcpdump_catch_packet_test(sessions[1], drop_flow) finally: openflow_rules_ori = utils_net.openflow_manager(br_name, "dump-flows").stdout openflow_rules_ori = remove_plus_items(openflow_rules_ori) utils_net.openflow_manager(br_name, "del-flows", f_protocol) openflow_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout openflow_rules = remove_plus_items(openflow_rules) removed_rule = list(set(openflow_rules_ori.splitlines()) - set(openflow_rules.splitlines())) if f_protocol == "tcp": error_context.context("Run nc connect test via tcp", logging.info) nc_connect_test(sessions, addresses) elif f_protocol == "udp": error_context.context("Run nc connect test via udp", logging.info) nc_connect_test(sessions, addresses, udp_model=True) for session in sessions: session.close() failed_msg = [] if (not removed_rule or not acl_rules_check(removed_rule[0], f_options)): failed_msg.append("Failed to delete %s" % f_options) if bg_ping_session: bg_ping_ok = check_bg_ping(bg_ping_session) bg_ping_session.close() if not bg_ping_ok[0]: failed_msg.append("There is something wrong happen in " "background ping: %s" % bg_ping_ok[1]) if failed_msg: test.fail(failed_msg)
access_sys[target] = {} access_sys[target]['access_cmd'] = access_param['access_cmd'] access_sys[target]['ref_cmd'] = access_param.get('ref_cmd', "") access_sys[target]['clean_cmd'] = access_param.get('clean_guest', "") if check_from_output: access_sys[target]['check_from_output'] = check_from_output for tgt in access_targets: tgt_param = access_param.object_params(tgt) acl_disabled = tgt_param.get("acl_disabled") == "yes" access_sys[target]['disabled_%s' % tgt] = acl_disabled error.context("Try to access target before setup the rules", logging.info) access_service(access_sys, access_targets, False, host_ip, ref=True) error.context("Disable the access in ovs", logging.info) br_infos = utils_net.openflow_manager(br_name, "show").stdout if_port = re.findall("(\d+)\(%s\)" % if_name, br_infos) if not if_port: raise error.TestNAError("Can not find %s in bridge %s" % (if_name, br_name)) if_port = if_port[0] acl_cmd = get_acl_cmd(acl_protocol, if_port, "drop", acl_extra_options) utils_net.openflow_manager(br_name, "add-flow", acl_cmd) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout if not acl_rules_check(acl_rules, acl_cmd): raise error.TestFail("Can not find the rules from" " ovs-ofctl: %s" % acl_rules) error.context("Try to acess target to exam the disable rules", logging.info)
def run_openflow_test(test, params, env): """ Test Step: 1. Boot up two virtual machine 2. Set openflow rules 3. Run ping test, nc(tcp, udp) test, check whether openflow rules take effect. Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def run_tcpdump_bg(session, addresses, dump_protocol): """ Run tcpdump in background, tcpdump will exit once catch a packet match the rules. """ tcpdump_cmd = "killall -9 tcpdump; " tcpdump_cmd += "tcpdump -iany -n -v %s and 'src %s and dst %s' -c 1 &" session.cmd_output_safe(tcpdump_cmd % (dump_protocol, addresses[0], addresses[1])) if not utils_misc.wait_for(lambda: tcpdump_is_alive(session), 30, 0, 1, "Waiting tcpdump start..."): raise error.TestNAError("Error, can not run tcpdump") def dump_catch_data(session, dump_log, catch_reg): """ Search data from dump_log """ dump_info = session.cmd_output("cat %s" % dump_log) if re.findall(catch_reg, dump_info, re.I): return True return False def tcpdump_is_alive(session): """ Check whether tcpdump is alive """ if session.cmd_status("pidof tcpdump"): return False return True def tcpdump_catch_packet_test(session, drop_flow=False): """ Check whether tcpdump catch match rules packets, once catch a packet match rules tcpdump will exit. when drop_flow is 'True', tcpdump couldn't catch any packets. """ packet_receive = not tcpdump_is_alive(session) if packet_receive == drop_flow: err_msg = "Error, flow %s dropped, tcpdump %s receive the packets" raise error.TestError(err_msg % ((drop_flow and "was" or "wasn't"), (packet_receive and "can" or "can not"))) logging.info("Correct, flow %s dropped, tcpdump %s receive the packet" % ((drop_flow and "was" or "was not"), (packet_receive and "can" or "can not"))) def arp_entry_clean(session, entry=None): """ Clean arp catch in guest """ if not entry: arp_clean_cmd = "arp -n | awk '/^[1-2]/{print \"arp -d \" $1}'|sh" else: arp_clean_cmd = "arp -d %s" % entry for session in sessions: session.cmd_output_safe(arp_clean_cmd) def ping_test(session, dst, drop_flow=False): """ Ping test, check icmp """ ping_status, ping_output = utils_test.ping(dest=dst, count=10, timeout=20, session=session) # when drop_flow is true, ping should failed(return not zero) # drop_flow is false, ping should success packets_lost = 100 if ping_status and not drop_flow: raise error.TestError("Ping should success when not drop_icmp") elif not ping_status: packets_lost = utils_test.get_loss_ratio(ping_output) if drop_flow and packets_lost != 100: raise error.TestError("When drop_icmp, ping shouldn't works") if not drop_flow and packets_lost == 100: raise error.TestError("When not drop_icmp, ping should works") info_msg = "Correct, icmp flow %s dropped, ping '%s', " info_msg += "packets lost rate is: '%s'" logging.info(info_msg % ((drop_flow and "was" or "was not"), (ping_status and "failed" or "success"), packets_lost)) def nc_connect_test(sessions, addresses, drop_flow=False, nc_port="8899", udp_model=False): """ Nc connect test, check tcp and udp """ nc_log = "/tmp/nc_log" server_cmd = "nc -l %s" client_cmd = "echo client | nc %s %s" if udp_model == True: server_cmd += " -u -w 3" client_cmd += " -u -w 3" server_cmd += " > %s &" client_cmd += " &" try: sessions[1].cmd_output_safe(server_cmd % (nc_port, nc_log)) sessions[0].cmd_output_safe(client_cmd % (addresses[1], nc_port)) nc_protocol = udp_model and "UDP" or "TCP" nc_connect = False if utils_misc.wait_for( lambda: dump_catch_data(sessions[1], nc_log, "client"), 10, 0, 2, text="Wait '%s' connect" % nc_protocol): nc_connect = True if nc_connect == drop_flow: err_msg = "Error, '%s' flow %s dropped, nc connect should '%s'" raise error.TestError(err_msg % (nc_protocol, (drop_flow and "was" or "was not"), (nc_connect and "failed" or "success"))) logging.info("Correct, '%s' flow %s dropped, and nc connect %s" % (nc_protocol, (drop_flow and "was" or "was not"), (nc_connect and "success" or "failed"))) finally: for session in sessions: session.cmd_output_safe("killall nc || killall ncat") session.cmd("%s %s" % (clean_cmd, nc_log), ignore_all_errors=True) timeout = int(params.get("login_timeout", '360')) clean_cmd = params.get("clean_cmd", "rm -f") sessions = [] addresses = [] vms = [] error.context("Init boot the vms") for vm_name in params.get("vms", "vm1 vm2").split(): vms.append(env.get_vm(vm_name)) for vm in vms: vm.verify_alive() sessions.append(vm.wait_for_login(timeout=timeout)) addresses.append(vm.get_address()) # set openflow rules: br_name = params.get("netdst", "ovs0") f_protocol = params.get("flow", "arp") f_base_options = "%s,nw_src=%s,nw_dst=%s" % (f_protocol, addresses[0], addresses[1]) for session in sessions: session.cmd("service iptables stop; iptables -F", ignore_all_errors=True) try: for drop_flow in [True, False]: if drop_flow: f_command = "add-flow" f_options = f_base_options + ",action=drop" drop_icmp = eval(params.get("drop_icmp", 'True')) drop_tcp = eval(params.get("drop_tcp", 'True')) drop_udp = eval(params.get("drop_udp", 'True')) else: f_command = "mod-flows" f_options = f_base_options + ",action=normal" drop_icmp = False drop_tcp = False drop_udp = False error.base_context("Test prepare") error.context("Do %s %s on %s" % (f_command, f_options, br_name)) utils_net.openflow_manager(br_name, f_command, f_options) error.context("Run tcpdump in guest %s" % vms[1].name, logging.info) run_tcpdump_bg(sessions[1], addresses, f_protocol) error.context("Clean arp cache in both guest", logging.info) arp_entry_clean(sessions[0], addresses[1]) error.base_context("Exec '%s' flow '%s' test" % (f_protocol, drop_flow and "drop" or "normal")) error.context("Ping test form vm1 to vm2", logging.info) ping_test(sessions[0], addresses[1], drop_icmp) error.context("Run nc connect test via tcp", logging.info) nc_connect_test(sessions, addresses, drop_tcp) error.context("Run nc connect test via udp", logging.info) nc_connect_test(sessions, addresses, drop_udp, udp_model=True) error.context("Check tcpdump data catch", logging.info) tcpdump_catch_packet_test(sessions[1], drop_flow) finally: utils_net.openflow_manager(br_name, "del-flows", f_protocol) for session in sessions: session.close()
def run(test, params, env): """ Test Step: 1. Boot up guest using the openvswitch bridge 2. Setup related service in test enviroment(http, ftp etc.)(optional) 3. Access the service in guest 4. Setup access control rules in ovs to disable the access 5. Access the service in guest 6. Setup access control rules in ovs to enable the access 7. Access the service in guest 8. Delete the access control rules in ovs 9. Access the service in guest Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def access_service(access_sys, access_targets, disabled, host_ip, ref=False): err_msg = "" err_type = "" for asys in access_sys: for atgt in access_targets: logging.debug("Try to access target %s from %s" % (atgt, asys)) access_params = access_sys[asys] atgt_disabled = access_params['disabled_%s' % atgt] if asys in vms_tags: vm = env.get_vm(asys) session = vm.wait_for_login(timeout=timeout) run_func = session.cmd remote_src = vm ssh_src_ip = vm.get_address() else: run_func = _system_output remote_src = "localhost" ssh_src_ip = host_ip if atgt in vms_tags: vm = env.get_vm(atgt) access_re_sub_string = vm.wait_for_get_address(0) else: access_re_sub_string = host_ip access_cmd = re.sub("ACCESS_TARGET", access_re_sub_string, access_params['access_cmd']) ref_cmd = re.sub("ACCESS_TARGET", access_re_sub_string, access_params['ref_cmd']) if access_cmd in ["ssh", "telnet"]: if atgt in vms_tags: target_vm = env.get_vm(atgt) target_ip = target_vm.get_address() else: target_vm = "localhost" target_ip = host_ip out = "" out_err = "" try: out = remote_login(access_cmd, target_ip, remote_src, params, host_ip) stat = 0 except remote.LoginError as err: stat = 1 out_err = "Failed to login %s " % atgt out_err += "from %s, err: %s" % (asys, err.output) try: out += remote_login(access_cmd, ssh_src_ip, target_vm, params, host_ip) except remote.LoginError as err: stat += 1 out_err += "Failed to login %s " % asys out_err += "from %s, err: %s" % (atgt, err.output) if out_err: out = out_err else: try: out = run_func(access_cmd, timeout=op_timeout) stat = 0 check_string = access_params.get("check_from_output") if check_string and check_string in out: stat = 1 except aexpect.ShellCmdError as err: out = err.output stat = err.status except aexpect.ShellTimeoutError as err: out = err.output stat = 1 session.close() session = vm.wait_for_login(timeout=timeout) run_func = session.cmd except process.CmdError as err: out = err.result.stderr stat = err.result.exit_status if access_params.get("clean_cmd"): try: run_func(access_params['clean_cmd']) except Exception: pass if disabled and atgt_disabled and stat == 0: err_msg += "Still can access %s after" % atgt err_msg += " disable it from ovs. " err_msg += "Command: %s. " % access_cmd err_msg += "Output: %s" % out if disabled and atgt_disabled and stat != 0: logging.debug("Can not access target as expect.") if not disabled and stat != 0: if ref: err_msg += "Can not access %s at the" % atgt err_msg += " beginning. Please check your setup." err_type = "ref" else: err_msg += "Still can not access %s" % atgt err_msg += " after enable the access" err_msg += "Command: %s. " % access_cmd err_msg += "Output: %s" % out if err_msg: session.close() if err_type == "ref": test.cancel(err_msg) test.fail(err_msg) if not ref_cmd: session.close() return try: out = run_func(ref_cmd, timeout=op_timeout) stat = 0 except aexpect.ShellCmdError as err: out = err.output stat = err.status except aexpect.ShellTimeoutError as err: out = err.output stat = 1 except process.CmdError as err: out = err.result.stderr stat = err.result.exit_status if stat != 0: if ref: err_msg += "Refernce command failed at beginning." err_type = "ref" else: err_msg += "Refernce command failed after setup" err_msg += " the rules" err_msg += "Command: %s. " % ref_cmd err_msg += "Output: %s" % out if err_msg: session.close() if err_type == "ref": test.cancel(err_msg) test.fail(err_msg) if asys in vms_tags: session.close() def get_acl_cmd(protocol, in_port, action, extra_options): acl_cmd = protocol.strip() acl_cmd += ",in_port=%s" % in_port.strip() if extra_options.strip(): acl_cmd += ",%s" % ",".join(extra_options.strip().split()) if action.strip(): acl_cmd += ",action=%s" % action.strip() return acl_cmd def acl_rules_check(acl_rules, acl_setup_cmd): acl_setup_cmd = re.sub("action=", "actions=", acl_setup_cmd) acl_option = re.split(",", acl_setup_cmd) for line in acl_rules.splitlines(): rule = [_.lower() for _ in re.split("[ ,]", line) if _] item_in_rule = 0 for acl_item in acl_option: if acl_item.lower() in rule: item_in_rule += 1 if item_in_rule == len(acl_option): return True return False def remote_login(client, host, src, params_login, host_ip): src_name = src if src != "localhost": src_name = src.name logging.info("Login %s from %s" % (host, src)) port = params_login["target_port"] username = params_login["username"] password = params_login["password"] prompt = params_login["shell_prompt"] linesep = eval("'%s'" % params_login.get("shell_linesep", r"\n")) quit_cmd = params.get("quit_cmd", "exit") if host == host_ip: # Try to login from guest to host. prompt = r"^\[.*\][\#\$]\s*$" linesep = "\n" username = params_login["host_username"] password = params_login["host_password"] quit_cmd = "exit" if client == "ssh": # We only support ssh for Linux in this test cmd = ("ssh -o UserKnownHostsFile=/dev/null " "-o StrictHostKeyChecking=no " "-o PreferredAuthentications=password -p %s %s@%s" % (port, username, host)) elif client == "telnet": cmd = "telnet -l %s %s %s" % (username, host, port) else: raise remote.LoginBadClientError(client) if src == "localhost": logging.debug("Login with command %s" % cmd) session = aexpect.ShellSession(cmd, linesep=linesep, prompt=prompt) else: if params_login.get("os_type") == "windows": if client == "telnet": cmd = "C:\\telnet.py %s %s " % (host, username) cmd += "%s \"%s\" && " % (password, prompt) cmd += "C:\\wait_for_quit.py" cmd = "%s || ping 127.0.0.1 -n 5 -w 1000 > nul" % cmd else: cmd += " || sleep 5" session = src.wait_for_login() logging.debug("Sending login command: %s" % cmd) session.sendline(cmd) try: out = remote.handle_prompts(session, username, password, prompt, timeout, debug=True) except Exception as err: session.close() raise err try: session.cmd(quit_cmd) session.close() except Exception: pass return out def setup_service(setup_target): setup_timeout = int(params.get("setup_timeout", 360)) if setup_target == "localhost": setup_func = _system_output os_type = "linux" else: setup_vm = env.get_vm(setup_target) setup_session = setup_vm.wait_for_login(timeout=timeout) setup_func = setup_session.cmd os_type = params["os_type"] setup_params = params.object_params(os_type) setup_cmd = setup_params.get("setup_cmd", "service SERVICE restart") prepare_cmd = setup_params.get("prepare_cmd") setup_cmd = re.sub("SERVICE", setup_params.get("service", ""), setup_cmd) error_context.context( "Set up %s service in %s" % (setup_params.get("service"), setup_target), logging.info) setup_func(setup_cmd, timeout=setup_timeout) if params.get("copy_ftp_site") and setup_target != "localhost": ftp_site = os.path.join(data_dir.get_deps_dir(), params.get("copy_ftp_site")) ftp_dir = params.get("ftp_dir") setup_vm.copy_files_to(ftp_site, ftp_dir) if prepare_cmd: setup_func(prepare_cmd, timeout=setup_timeout) if setup_target != "localhost": setup_session.close() def stop_service(setup_target): setup_timeout = int(params.get("setup_timeout", 360)) if setup_target == "localhost": setup_func = _system_output os_type = "linux" else: setup_vm = env.get_vm(setup_target) setup_session = setup_vm.wait_for_login(timeout=timeout) setup_func = setup_session.cmd os_type = params["os_type"] setup_params = params.object_params(os_type) stop_cmd = setup_params.get("stop_cmd", "service SERVICE stop") cleanup_cmd = setup_params.get("cleanup_cmd") stop_cmd = re.sub("SERVICE", setup_params.get("service", ""), stop_cmd) error_context.context( "Stop %s service in %s" % (setup_params.get("service"), setup_target), logging.info) if stop_cmd: setup_func(stop_cmd, timeout=setup_timeout) if cleanup_cmd: setup_func(cleanup_cmd, timeout=setup_timeout) if setup_target != "localhost": setup_session.close() timeout = int(params.get("login_timeout", '360')) op_timeout = int(params.get("op_timeout", "360")) acl_protocol = params['acl_protocol'] acl_extra_options = params.get("acl_extra_options", "") for vm in env.get_all_vms(): session = vm.wait_for_login(timeout=timeout) if params.get("disable_iptables") == "yes": session.cmd("iptables -F") #session.cmd_status_output("service iptables stop") if params.get("copy_scripts"): root_dir = data_dir.get_root_dir() script_dir = os.path.join(root_dir, "shared", "scripts") tmp_dir = params.get("tmp_dir", "C:\\") for script in params.get("copy_scripts").split(): script_path = os.path.join(script_dir, script) vm.copy_files_to(script_path, tmp_dir) if params.get("copy_curl") and params.get("os_type") == "windows": curl_win_path = params.get("curl_win_path", "C:\\curl\\") session.cmd("dir {0} || mkdir {0}".format(curl_win_path)) for script in params.get("copy_curl").split(): curl_win_link = os.path.join(data_dir.get_deps_dir("curl"), script) vm.copy_files_to(curl_win_link, curl_win_path, timeout=60) session.close() vms_tags = params.objects("vms") br_name = params.get("netdst") if br_name == "private": br_name = params.get("priv_brname", 'atbr0') for setup_target in params.get("setup_targets", "").split(): setup_service(setup_target) access_targets = params.get("access_targets", "localhost").split() deny_target = params.get("deny_target", "localhost") all_target = params.get("extra_target", "").split() + vms_tags target_port = params["target_port"] vm = env.get_vm(vms_tags[0]) nic = vm.virtnet[0] if_name = nic.ifname params_nic = params.object_params("nic1") if params["netdst"] == "private": params_nic["netdst"] = params_nic.get("priv_brname", "atbr0") host_ip = utils_net.get_host_ip_address(params_nic) if deny_target in vms_tags: deny_vm = env.get_vm(deny_target) deny_vm_ip = deny_vm.wait_for_get_address(0) elif deny_target == "localhost": deny_vm_ip = host_ip if "NW_DST" in acl_extra_options: acl_extra_options = re.sub("NW_DST", deny_vm_ip, acl_extra_options) acl_extra_options = re.sub("TARGET_PORT", target_port, acl_extra_options) access_sys = {} for target in all_target: if target not in access_targets: if target in vms_tags: os_type = params["os_type"] else: os_type = "linux" os_params = params.object_params(os_type) access_param = os_params.object_params(target) check_from_output = access_param.get("check_from_output") access_sys[target] = {} access_sys[target]['access_cmd'] = access_param['access_cmd'] access_sys[target]['ref_cmd'] = access_param.get('ref_cmd', "") access_sys[target]['clean_cmd'] = access_param.get( 'clean_guest', "") if check_from_output: access_sys[target]['check_from_output'] = check_from_output for tgt in access_targets: tgt_param = access_param.object_params(tgt) acl_disabled = tgt_param.get("acl_disabled") == "yes" access_sys[target]['disabled_%s' % tgt] = acl_disabled error_context.context("Try to access target before setup the rules", logging.info) access_service(access_sys, access_targets, False, host_ip, ref=True) error_context.context("Disable the access in ovs", logging.info) br_infos = utils_net.openflow_manager(br_name, "show").stdout.decode() if_port = re.findall(r"(\d+)\(%s\)" % if_name, br_infos) if not if_port: test.cancel("Can not find %s in bridge %s" % (if_name, br_name)) if_port = if_port[0] acl_cmd = get_acl_cmd(acl_protocol, if_port, "drop", acl_extra_options) utils_net.openflow_manager(br_name, "add-flow", acl_cmd) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout.decode() if not acl_rules_check(acl_rules, acl_cmd): test.fail("Can not find the rules from ovs-ofctl: %s" % acl_rules) error_context.context("Try to acess target to exam the disable rules", logging.info) access_service(access_sys, access_targets, True, host_ip) error_context.context("Enable the access in ovs", logging.info) acl_cmd = get_acl_cmd(acl_protocol, if_port, "normal", acl_extra_options) utils_net.openflow_manager(br_name, "mod-flows", acl_cmd) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout.decode() if not acl_rules_check(acl_rules, acl_cmd): test.fail("Can not find the rules from ovs-ofctl: %s" % acl_rules) error_context.context("Try to acess target to exam the enable rules", logging.info) access_service(access_sys, access_targets, False, host_ip) error_context.context("Delete the access rules in ovs", logging.info) acl_cmd = get_acl_cmd(acl_protocol, if_port, "", acl_extra_options) utils_net.openflow_manager(br_name, "del-flows", acl_cmd) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout.decode() if acl_rules_check(acl_rules, acl_cmd): test.fail("Still can find the rules from ovs-ofctl: %s" % acl_rules) error_context.context("Try to acess target to exam after delete the rules", logging.info) access_service(access_sys, access_targets, False, host_ip) for setup_target in params.get("setup_targets", "").split(): stop_service(setup_target)
def run(test, params, env): """ Test Step: 1. Boot up guest using the openvswitch bridge 2. Setup related service in test enviroment(http, ftp etc.)(optional) 3. Access the service in guest 4. Setup access control rules in ovs to disable the access 5. Access the service in guest 6. Setup access control rules in ovs to enable the access 7. Access the service in guest 8. Delete the access control rules in ovs 9. Access the service in guest Params: :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ def access_service(access_sys, access_targets, disabled, host_ip, ref=False): err_msg = "" err_type = "" for asys in access_sys: for atgt in access_targets: logging.debug("Try to access target %s from %s" % (atgt, asys)) access_params = access_sys[asys] atgt_disabled = access_params['disabled_%s' % atgt] if asys in vms_tags: vm = env.get_vm(asys) session = vm.wait_for_login(timeout=timeout) run_func = session.cmd remote_src = vm ssh_src_ip = vm.get_address() else: run_func = _system_output remote_src = "localhost" ssh_src_ip = host_ip if atgt in vms_tags: vm = env.get_vm(atgt) access_re_sub_string = vm.wait_for_get_address(0) else: access_re_sub_string = host_ip access_cmd = re.sub("ACCESS_TARGET", access_re_sub_string, access_params['access_cmd']) ref_cmd = re.sub("ACCESS_TARGET", access_re_sub_string, access_params['ref_cmd']) if access_cmd in ["ssh", "telnet"]: if atgt in vms_tags: target_vm = env.get_vm(atgt) target_ip = target_vm.get_address() else: target_vm = "localhost" target_ip = host_ip out = "" out_err = "" try: out = remote_login(access_cmd, target_ip, remote_src, params, host_ip) stat = 0 except remote.LoginError as err: stat = 1 out_err = "Failed to login %s " % atgt out_err += "from %s, err: %s" % (asys, err.output) try: out += remote_login(access_cmd, ssh_src_ip, target_vm, params, host_ip) except remote.LoginError as err: stat += 1 out_err += "Failed to login %s " % asys out_err += "from %s, err: %s" % (atgt, err.output) if out_err: out = out_err else: try: out = run_func(access_cmd, timeout=op_timeout) stat = 0 check_string = access_params.get("check_from_output") if check_string and check_string in out: stat = 1 except aexpect.ShellCmdError as err: out = err.output stat = err.status except aexpect.ShellTimeoutError as err: out = err.output stat = 1 session.close() session = vm.wait_for_login(timeout=timeout) run_func = session.cmd except process.CmdError as err: out = err.result.stderr stat = err.result.exit_status if access_params.get("clean_cmd"): try: run_func(access_params['clean_cmd']) except Exception: pass if disabled and atgt_disabled and stat == 0: err_msg += "Still can access %s after" % atgt err_msg += " disable it from ovs. " err_msg += "Command: %s. " % access_cmd err_msg += "Output: %s" % out if disabled and atgt_disabled and stat != 0: logging.debug("Can not access target as expect.") if not disabled and stat != 0: if ref: err_msg += "Can not access %s at the" % atgt err_msg += " beginning. Please check your setup." err_type = "ref" else: err_msg += "Still can not access %s" % atgt err_msg += " after enable the access" err_msg += "Command: %s. " % access_cmd err_msg += "Output: %s" % out if err_msg: session.close() if err_type == "ref": test.cancel(err_msg) test.fail(err_msg) if not ref_cmd: session.close() return try: out = run_func(ref_cmd, timeout=op_timeout) stat = 0 except aexpect.ShellCmdError as err: out = err.output stat = err.status except aexpect.ShellTimeoutError as err: out = err.output stat = 1 except process.CmdError as err: out = err.result.stderr stat = err.result.exit_status if stat != 0: if ref: err_msg += "Refernce command failed at beginning." err_type = "ref" else: err_msg += "Refernce command failed after setup" err_msg += " the rules" err_msg += "Command: %s. " % ref_cmd err_msg += "Output: %s" % out if err_msg: session.close() if err_type == "ref": test.cancel(err_msg) test.fail(err_msg) session.close() def get_acl_cmd(protocol, in_port, action, extra_options): acl_cmd = protocol.strip() acl_cmd += ",in_port=%s" % in_port.strip() if extra_options.strip(): acl_cmd += ",%s" % ",".join(extra_options.strip().split()) if action.strip(): acl_cmd += ",action=%s" % action.strip() return acl_cmd def acl_rules_check(acl_rules, acl_setup_cmd): acl_setup_cmd = re.sub("action=", "actions=", acl_setup_cmd) acl_option = re.split(",", acl_setup_cmd) for line in acl_rules.splitlines(): rule = [_.lower() for _ in re.split("[ ,]", line) if _] item_in_rule = 0 for acl_item in acl_option: if acl_item.lower() in rule: item_in_rule += 1 if item_in_rule == len(acl_option): return True return False def remote_login(client, host, src, params_login, host_ip): src_name = src if src != "localhost": src_name = src.name logging.info("Login %s from %s" % (host, src)) port = params_login["target_port"] username = params_login["username"] password = params_login["password"] prompt = params_login["shell_prompt"] linesep = eval("'%s'" % params_login.get("shell_linesep", r"\n")) quit_cmd = params.get("quit_cmd", "exit") if host == host_ip: # Try to login from guest to host. prompt = r"^\[.*\][\#\$]\s*$" linesep = "\n" username = params_login["host_username"] password = params_login["host_password"] quit_cmd = "exit" if client == "ssh": # We only support ssh for Linux in this test cmd = ("ssh -o UserKnownHostsFile=/dev/null " "-o StrictHostKeyChecking=no " "-o PreferredAuthentications=password -p %s %s@%s" % (port, username, host)) elif client == "telnet": cmd = "telnet -l %s %s %s" % (username, host, port) else: raise remote.LoginBadClientError(client) if src == "localhost": logging.debug("Login with command %s" % cmd) session = aexpect.ShellSession(cmd, linesep=linesep, prompt=prompt) else: if params_login.get("os_type") == "windows": if client == "telnet": cmd = "C:\\telnet.py %s %s " % (host, username) cmd += "%s \"%s\" && " % (password, prompt) cmd += "C:\\wait_for_quit.py" cmd = "%s || ping 127.0.0.1 -n 5 -w 1000 > nul" % cmd else: cmd += " || sleep 5" session = src.wait_for_login() logging.debug("Sending login command: %s" % cmd) session.sendline(cmd) try: out = remote.handle_prompts(session, username, password, prompt, timeout, debug=True) except Exception as err: session.close() raise err try: session.cmd(quit_cmd) session.close() except Exception: pass return out def setup_service(setup_target): setup_timeout = int(params.get("setup_timeout", 360)) if setup_target == "localhost": setup_func = _system_output os_type = "linux" else: setup_vm = env.get_vm(setup_target) setup_session = setup_vm.wait_for_login(timeout=timeout) setup_func = setup_session.cmd os_type = params["os_type"] setup_params = params.object_params(os_type) setup_cmd = setup_params.get("setup_cmd", "service SERVICE restart") prepare_cmd = setup_params.get("prepare_cmd") setup_cmd = re.sub("SERVICE", setup_params.get("service", ""), setup_cmd) error_context.context("Set up %s service in %s" % (setup_params.get("service"), setup_target), logging.info) if prepare_cmd: setup_func(prepare_cmd, timeout=setup_timeout) setup_func(setup_cmd, timeout=setup_timeout) if setup_target != "localhost": setup_session.close() def stop_service(setup_target): setup_timeout = int(params.get("setup_timeout", 360)) if setup_target == "localhost": setup_func = _system_output os_type = "linux" else: setup_vm = env.get_vm(setup_target) setup_session = setup_vm.wait_for_login(timeout=timeout) setup_func = setup_session.cmd os_type = params["os_type"] setup_params = params.object_params(os_type) stop_cmd = setup_params.get("stop_cmd", "service SERVICE stop") cleanup_cmd = setup_params.get("cleanup_cmd") stop_cmd = re.sub("SERVICE", setup_params.get("service", ""), stop_cmd) error_context.context("Stop %s service in %s" % (setup_params.get("service"), setup_target), logging.info) if stop_cmd: setup_func(stop_cmd, timeout=setup_timeout) if cleanup_cmd: setup_func(cleanup_cmd, timeout=setup_timeout) if setup_target != "localhost": setup_session.close() timeout = int(params.get("login_timeout", '360')) op_timeout = int(params.get("op_timeout", "360")) acl_protocol = params['acl_protocol'] acl_extra_options = params.get("acl_extra_options", "") for vm in env.get_all_vms(): session = vm.wait_for_login(timeout=timeout) if params.get("disable_iptables") == "yes": session.cmd("iptables -F") #session.cmd_status_output("service iptables stop") if params.get("copy_scripts"): root_dir = data_dir.get_root_dir() script_dir = os.path.join(root_dir, "shared", "scripts") tmp_dir = params.get("tmp_dir", "C:\\") for script in params.get("copy_scripts").split(): script_path = os.path.join(script_dir, script) vm.copy_files_to(script_path, tmp_dir) if params.get("os_type") == "windows": curl_win_path = params.get("curl_win_path", "C:\\curl\\") session.cmd("dir {0} || mkdir {0}".format(curl_win_path)) for script in params.get("copy_curl").split(): curl_win_link = os.path.join(data_dir.get_deps_dir("curl"), script) vm.copy_files_to(curl_win_link, curl_win_path, timeout=60) session.close() vms_tags = params.objects("vms") br_name = params.get("netdst") if br_name == "private": br_name = params.get("priv_brname", 'autotest-prbr0') for setup_target in params.get("setup_targets", "").split(): setup_service(setup_target) access_targets = params.get("access_targets", "localhost").split() deny_target = params.get("deny_target", "localhost") all_target = params.get("extra_target", "").split() + vms_tags target_port = params["target_port"] vm = env.get_vm(vms_tags[0]) nic = vm.virtnet[0] if_name = nic.ifname params_nic = params.object_params("nic1") if params["netdst"] == "private": params_nic["netdst"] = params_nic.get("priv_brname", "atbr0") host_ip = utils_net.get_host_ip_address(params_nic) if deny_target in vms_tags: deny_vm = env.get_vm(deny_target) deny_vm_ip = deny_vm.wait_for_get_address(0) elif deny_target == "localhost": deny_vm_ip = host_ip if "NW_DST" in acl_extra_options: acl_extra_options = re.sub("NW_DST", deny_vm_ip, acl_extra_options) acl_extra_options = re.sub("TARGET_PORT", target_port, acl_extra_options) access_sys = {} for target in all_target: if target not in access_targets: if target in vms_tags: os_type = params["os_type"] else: os_type = "linux" os_params = params.object_params(os_type) access_param = os_params.object_params(target) check_from_output = access_param.get("check_from_output") access_sys[target] = {} access_sys[target]['access_cmd'] = access_param['access_cmd'] access_sys[target]['ref_cmd'] = access_param.get('ref_cmd', "") access_sys[target]['clean_cmd'] = access_param.get('clean_guest', "") if check_from_output: access_sys[target]['check_from_output'] = check_from_output for tgt in access_targets: tgt_param = access_param.object_params(tgt) acl_disabled = tgt_param.get("acl_disabled") == "yes" access_sys[target]['disabled_%s' % tgt] = acl_disabled error_context.context("Try to access target before setup the rules", logging.info) access_service(access_sys, access_targets, False, host_ip, ref=True) error_context.context("Disable the access in ovs", logging.info) br_infos = utils_net.openflow_manager(br_name, "show").stdout if_port = re.findall(r"(\d+)\(%s\)" % if_name, br_infos) if not if_port: test.cancel("Can not find %s in bridge %s" % (if_name, br_name)) if_port = if_port[0] acl_cmd = get_acl_cmd(acl_protocol, if_port, "drop", acl_extra_options) utils_net.openflow_manager(br_name, "add-flow", acl_cmd) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout if not acl_rules_check(acl_rules, acl_cmd): test.fail("Can not find the rules from ovs-ofctl: %s" % acl_rules) error_context.context("Try to acess target to exam the disable rules", logging.info) access_service(access_sys, access_targets, True, host_ip) error_context.context("Enable the access in ovs", logging.info) acl_cmd = get_acl_cmd(acl_protocol, if_port, "normal", acl_extra_options) utils_net.openflow_manager(br_name, "mod-flows", acl_cmd) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout if not acl_rules_check(acl_rules, acl_cmd): test.fail("Can not find the rules from ovs-ofctl: %s" % acl_rules) error_context.context("Try to acess target to exam the enable rules", logging.info) access_service(access_sys, access_targets, False, host_ip) error_context.context("Delete the access rules in ovs", logging.info) acl_cmd = get_acl_cmd(acl_protocol, if_port, "", acl_extra_options) utils_net.openflow_manager(br_name, "del-flows", acl_cmd) acl_rules = utils_net.openflow_manager(br_name, "dump-flows").stdout if acl_rules_check(acl_rules, acl_cmd): test.fail("Still can find the rules from ovs-ofctl: %s" % acl_rules) error_context.context("Try to acess target to exam after delete the rules", logging.info) access_service(access_sys, access_targets, False, host_ip) for setup_target in params.get("setup_targets", "").split(): stop_service(setup_target)