def cleanup_ovs_ports(netdst, ports): """ Clean up created ovs ports in this case :param netdst: netdst get from command line :param ports: existing ports need to be remain before this test """ host_bridge = utils_net.find_bridge_manager(netdst) if utils_net.ovs_br_exists(netdst) is True: ports = set(host_bridge.list_ports(netdst)) - set(ports) for p in ports: utils_net.find_bridge_manager(netdst).del_port(netdst, p)
def run(test, params, env): """ Test tap device deleted after vm quit with error 1) Boot a with invaild params. 1) Check qemu-kvm quit with error. 2) Check vm tap device delete from ovs bridge. :param test: Kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ netdst = params.get("netdst") if not utils_net.ovs_br_exists(netdst): test.cancel("%s isn't an openvswith bridge" % netdst) host_bridge = utils_net.find_bridge_manager(netdst) deps_dir = data_dir.get_deps_dir("ovs") nic_script = utils_misc.get_path(deps_dir, params["nic_script"]) nic_downscript = utils_misc.get_path(deps_dir, params["nic_downscript"]) params["nic_script"] = nic_script params["nic_downscript"] = nic_downscript params["qemu_command_prefix"] = "export SHELL=/usr/bin/bash;" params["start_vm"] = "yes" params["nettype"] = "bridge" params["nic_model"] = "virtio-net-pci" ports = set(host_bridge.list_ports(netdst)) try: env_process.preprocess_vm(test, params, env, params["main_vm"]) env.get_vm(params["main_vm"]) except virt_vm.VMCreateError: ports = set(host_bridge.list_ports(netdst)) - ports if ports: for p in ports: host_bridge.del_port(netdst, p) test.fail("%s not delete after qemu quit." % ports) else: test.fail("Qemu should quit with error")
def run(test, params, env): """ Enslave a port which is already a member of ovs into another 1) Check current ovs bridge and list the ports in it 2) Create a new ovs bridge 3) Enslave one port which is a member of current ovs bridge into the new one 4) Delete the new ovs bridge :param test: Kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment. """ netdst = params["netdst"] if utils_net.ovs_br_exists(netdst) is not True: test.cancel("%s isn't an openvswith bridge" % netdst) new_br_name = params.get("new_ovs_bridge_name", "temp_ovs_bridge") host_bridge = utils_net.find_bridge_manager(netdst) if host_bridge.br_exist(new_br_name) is True: host_bridge.del_br(new_br_name) host_bridge.add_br(new_br_name) error_context.context("OVS bridge %s created." % new_br_name, logging.info) try: ports = host_bridge.list_ports(netdst) host_bridge.add_port(new_br_name, ports[0]) except process.CmdError as e: if "already exists on bridge" not in e.result.stderr_text: test.fail("Port %s should not be enslaved to another bridge." " Output: %s" % (ports[0], e.result.stderr_text)) else: test.fail("Add port cmd successfully excuted. However, port %s " "should not be enslaved to another bridge." % ports[0]) finally: host_bridge.del_br(new_br_name)
def run(test, params, env): """ Test openvswitch support for network. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_type = params.get("iface_type") if iface_type: iface.type_name = iface_type source = eval(iface_source) if source: del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model iface_virtualport = params.get("iface_virtualport") if iface_virtualport: iface.virtualport_type = iface_virtualport logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def check_ovs_port(ifname, brname): """ Check OVS port that created by libvirt """ pg_name = params.get("porgroup_name", "").split() pg_vlan = params.get("portgroup_vlan", "").split() if_source = eval(iface_source) port_vlan = {} if if_source.has_key("portgroup"): pg = if_source["portgroup"] for (name, vlan) in zip(pg_name, pg_vlan): if pg == name: port_vlan = eval(vlan) # Check bridge name by port name _, bridge = utils_net.find_current_bridge(ifname) assert bridge == brname # Get port info from ovs-vsctl output cmd = "ovs-vsctl list port %s" % ifname output = utils.run(cmd).stdout logging.debug("ovs port output: %s", output) for line in output.splitlines(): if line.count("tag"): tag_info = line.rsplit(':') if (port_vlan.has_key("id") and tag_info[0] == "tag"): assert port_vlan["id"] == tag_info[1] elif line.count("vlan_mode"): mode_info = line.rsplit(':') if (port_vlan.has_key("nativeMode") and mode_info[0] == "vlan_mode"): assert (port_vlan["nativeMode"] == "native-%s" % mode_info[1]) start_error = "yes" == params.get("start_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") iface_source = params.get("iface_source", "{}") create_network = "yes" == params.get("create_network", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_ovs_port = "yes" == params.get("test_ovs_port", "no") # Destroy the guest first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) params["guest_mac"] = iface_mac vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bridge_name = eval(net_bridge)['name'] # Build the xml and run test. try: # Edit the network xml or create a new one. if create_network: # Try to add ovs bridge first if not utils_net.ovs_br_exists(bridge_name): utils_net.add_ovs_bridge(bridge_name) netxml = libvirt.create_net_xml(net_name, params) netxml.sync() # Edit the interface xml. if change_iface_option: # Try to add bridge if needed source = eval(iface_source) if source: if source.has_key("bridge"): if not utils_net.ovs_br_exists(source["bridge"]): utils_net.add_ovs_bridge(source["bridge"]) modify_iface_xml() try: # Start the VM. vm.start() if start_error: raise error.TestFail("VM started unexpectedly") iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if test_ovs_port: check_ovs_port(iface_name, bridge_name) except virt_vm.VMStartError, details: logging.info(str(details)) if start_error: pass else: raise error.TestFail('VM Failed to start for some reason!') finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) # Try to recovery ovs bridge if utils_net.ovs_br_exists(bridge_name): utils_net.del_ovs_bridge(bridge_name) vmxml_backup.sync()
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)
def run(test, params, env): """ Since 3.3.0, Coalesce setting is supported. This case is to set coalesce and check for 4 network types and each guest interface type. Only network/bridge guest interface type take effect for setting interface coalesce. For each host network type, guest can use bridge/network interface type to set coalesce except macvtap network type. Execute 'ethtool -c ${interface}|grep "rx-frames"' and anylize the output to check whether coalesce setting take effect or not. For macvtap network type, guest can start but query coalesce will fail. 1. For default host network network definition is below: <network> <name>default</name> <bridge name="virbr0"/> <forward/> <ip address="192.168.122.1" netmask="255.255.255.0"> <dhcp> <range start="192.168.122.2" end="192.168.122.254"/> </dhcp> </ip> </network> This is default network. 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:a7:4d:f7'/> <source bridge='virbr0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: <interface type='network'> <source network='default'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 2. For bridge host network This mode need true bridge in host network. 'nmcli con add type bridge con-name br0 ifname br0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='br0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for bridge br0 'virsh net-define net-br0.xml' 'virsh net-dumpxml net-br0' <network> <name>net-br0</name> <forward mode='bridge'/> <bridge name='br0'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-br0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 3. For openvswitch bridge host network This mode need true openvswitch bridge in host network. 'ovs-vsctl add-br ovsbr0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='ovsbr0'/> <virtualport type='openvswitch'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for openvswitch bridge ovsbr0 'virsh net-define net-ovsbr0.xml' 'virsh net-dumpxml net-ovsbr0' <network> <name>net-ovs0</name> <forward mode='bridge'/> <bridge name='ovsbr0'/> <virtualport type='openvswitch'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-ovs0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 4. For macvtap bridge mode on host network For this mode, first, create one virtual network. Note, should set dev to one ture physical interface. 'virsh net-define net-br-macvtap.xml' 'virsh net-dumpxml net-br-macvtap' <network> <name>net-br-macvtap</name> <forward dev='eno1' mode='bridge'> <interface dev='eno1'/> </forward> </network> Set guest to use this macvtap network and set coalesc <interface type='network'> <mac address='52:54:00:6e:f4:f1'/> <source network='net-br-macvtap'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> Steps in this test: 1. Prepare test environment,destroy or suspend a VM. 2. Prepare network if necessary. 3. Edit guest interface with definite network and set coalesce. 4. Start guest and check whether coalesce setting take effect. 5. Recover network and guest. """ if not libvirt_version.version_compare(3, 3, 0): test.skip( "Coalesce setting is only supported by libvirt3.3.0 and above") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def get_first_phy_iface(): """ Get first physical network interface from output of 'ls /sys/class/net' #ls /sys/class/net eno1 lo virbr0 virbr0-nic :return: interface name """ interface = '' lines = process.run('ls /sys/class/net').stdout_text.splitlines() interfaces = lines[0].split() for iface in interfaces: if iface != 'lo' and 'vir' not in iface: interface = iface break if interface == '': test.fail("There is no physical network interface") return interface def modify_iface_xml(): """ Modify interface xml options Two methods to modify domain interfae: 1. modify guest xml, define it 2. attach one interface for running guest :return: 0 for successful negative case test.fail is fail for positive/negative case None for successful positive case """ if hotplug_iface: iface = Interface(iface_type) else: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if iface_type == 'network': iface.type_name = iface_type source = {iface_type: net_name} elif iface_type == 'bridge' and bridge_name: iface.type_name = iface_type source = {iface_type: bridge_name} elif iface_type == 'direct': iface.type_name = iface_type source = {'dev': interface, 'mode': 'bridge'} if source: del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model iface.coalesce = {'max': coalesce_value} if network_type == "ovsbridge" and iface_type == "bridge": iface.virtualport_type = "openvswitch" if not hotplug_iface: vmxml.devices = xml_devices vmxml.xmltreefile.write() try: vmxml.sync() except xcepts.LibvirtXMLError as details: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") else: if not vm.is_alive(): vm.start() # Wait guest boot completely time.sleep(2) try: ret = virsh.attach_device(vm_name, iface.xml, ignore_status=False, debug=True) except process.CmdError as error: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") start_error = "yes" == params.get("start_error", "no") status_error = "yes" == params.get("status_error", "no") # Get coalesce value. expect_coalesce = params.get("expect_coalesce", "") coalesce_value = params.get("coalesce", "15") if expect_coalesce == '': expect_coalesce = coalesce_value # Network specific attributes. network_type = params.get("network_type", "default") net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") # Get guest interface type iface_type = params.get("iface_type", "network") # Whether attach interface hotplug_iface = "yes" == params.get("hotplug_iface", "no") error_info = params.get("error_info", "") # Destroy the guest first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Build the xml and run test. try: interface = get_first_phy_iface() # Prepare network for specific network type. # Create bridge/ovsbridge for host bridge/ovsbridge network type if network_type == "default" and iface_type == "bridge": bridge_name = "virbr0" elif network_type == "bridge": bridge_name = eval(net_bridge)['name'] bridge = utils_net.Bridge() # Try to add bridge if not exist if bridge_name not in bridge.list_br(): bridge.add_bridge(bridge_name) elif network_type == 'ovsbridge': bridge_name = eval(net_bridge)['name'] # Try to add ovs bridge if not exist if not utils_net.ovs_br_exists(bridge_name): utils_net.add_ovs_bridge(bridge_name) if iface_type == "network": # Define virtual network if not exist for 'network' type of guest interface network = NetworkXML() network.name = net_name # Prepare virtual network required parameters params['net_forward'] = "{'mode':'bridge'}" if network_type == "ovsbridge": params['net_virtualport'] = "openvswitch" if network_type == "macvtap": # For bridge type of macvtap network, one true physical interface shold be added # Check whether physical interface has been added into one bridge. if yes, skip macvtap test # If interface already added to a bridge, the output of the nmcli # command will include "connection.slave-type: bridge" out = process.run('nmcli dev show %s' % interface).stdout_text con_l = re.findall(r'GENERAL.CONNECTION:(.+?)\n', out) if not con_l: test.cancel("no connection for the interface") else: con = con_l[0].strip() if "bridge" not in process.run('nmcli con show "%s"' % con).stdout_text: params['forward_iface'] = interface params[ 'net_forward'] = "{'mode':'bridge', 'dev': '%s'}" % interface else: test.cancel( "interface %s has been added into one brige, but macvtap" "need also add this interface, so current network can't" "suit macvtap testing" % interface) if not network.exists(): netxml = libvirt.create_net_xml(net_name, params) netxml.define() netxml.start() virsh.net_dumpxml(network.name, debug=True) # Edit the interface xml. # For successful negative case, return 0 to specify PASS result directly ret = modify_iface_xml() if ret == 0: return 0 try: # Get all interface link_before = set( process.run('ls /sys/class/net').stdout_text.splitlines()) # Start the VM. vm.start() if start_error: raise test.fail("VM started unexpectedly") # Get guest virtual network interface link_after = set( process.run('ls /sys/class/net').stdout_text.splitlines()) newinterface = (link_after - link_before).pop() out = process.run('ethtool -c %s' % newinterface, ignore_status=True) if network_type == 'macvtap': # Currently, output coalesce for macvtap is not supported err_msg = "Cannot get device coalesce settings: Operation not supported" std_msg = "Coalesce parameters for %s:" % newinterface if err_msg not in out.stderr_text or std_msg not in out.stdout_text: test.fail("coalesce setting on %s failed." % network_type) else: # Get coalesce value and check it is true if out.exit_status == 0: for line in out.stdout_text.splitlines(): if 'rx-frames:' in line: coalesce = line.split(':')[1].strip() if expect_coalesce != coalesce: test.fail("coalesce setting failed for %s" % network_type) break else: test.fail("coalesce setting on %s failed." % network_type) except virt_vm.VMStartError as details: logging.info(str(details)) if not start_error: test.fail('VM failed to start:\n%s' % details) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) # Try to recovery bridge if network_type == "bridge" and bridge_name: if bridge_name in bridge.list_br(): bridge.del_bridge(bridge_name) elif network_type == "ovsbridge" and bridge_name: if utils_net.ovs_br_exists(bridge_name): utils_net.del_ovs_bridge(bridge_name) vmxml_backup.sync()
def run(test, params, env): """ Test openvswitch support for network. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index(xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_type = params.get("iface_type") if iface_type: iface.type_name = iface_type source = eval(iface_source) if source: del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model iface_virtualport = params.get("iface_virtualport") if iface_virtualport: iface.virtualport_type = iface_virtualport logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def check_ovs_port(ifname, brname): """ Check OVS port that created by libvirt """ pg_name = params.get("porgroup_name", "").split() pg_vlan = params.get("portgroup_vlan", "").split() if_source = eval(iface_source) port_vlan = {} if if_source.has_key("portgroup"): pg = if_source["portgroup"] for (name, vlan) in zip(pg_name, pg_vlan): if pg == name: port_vlan = eval(vlan) # Check bridge name by port name _, bridge = utils_net.find_current_bridge(ifname) assert bridge == brname # Get port info from ovs-vsctl output cmd = "ovs-vsctl list port %s" % ifname output = utils.run(cmd).stdout logging.debug("ovs port output: %s", output) for line in output.splitlines(): if line.count("tag"): tag_info = line.rsplit(":") if port_vlan.has_key("id") and tag_info[0] == "tag": assert port_vlan["id"] == tag_info[1] elif line.count("vlan_mode"): mode_info = line.rsplit(":") if port_vlan.has_key("nativeMode") and mode_info[0] == "vlan_mode": assert port_vlan["nativeMode"] == "native-%s" % mode_info[1] start_error = "yes" == params.get("start_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") iface_source = params.get("iface_source", "{}") create_network = "yes" == params.get("create_network", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_ovs_port = "yes" == params.get("test_ovs_port", "no") # Destroy the guest first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) params["guest_mac"] = iface_mac vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bridge_name = eval(net_bridge)["name"] # Build the xml and run test. try: # Edit the network xml or create a new one. if create_network: # Try to add ovs bridge first if not utils_net.ovs_br_exists(bridge_name): utils_net.add_ovs_bridge(bridge_name) netxml = libvirt.create_net_xml(net_name, params) netxml.sync() # Edit the interface xml. if change_iface_option: # Try to add bridge if needed source = eval(iface_source) if source: if source.has_key("bridge"): if not utils_net.ovs_br_exists(source["bridge"]): utils_net.add_ovs_bridge(source["bridge"]) modify_iface_xml() try: # Start the VM. vm.start() if start_error: raise error.TestFail("VM started unexpectedly") iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if test_ovs_port: check_ovs_port(iface_name, bridge_name) except virt_vm.VMStartError, details: logging.info(str(details)) if start_error: pass else: raise error.TestFail("VM Failed to start for some reason!") finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) # Try to recovery ovs bridge if utils_net.ovs_br_exists(bridge_name): utils_net.del_ovs_bridge(bridge_name) vmxml_backup.sync()
def run(test, params, env): """ Expose host MTU to guest test 1) Boot up guest with param 'host_mtu=4000' in nic part 2) Disable NetworkManager in guest 3) set mtu of guest tap (eg: tap0) and physical nic (eg: eno1) to 4000 in host 4) check the mtu in guest 5) ping from guest to external host with packet size 3972 :param test: kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment """ def cleanup_ovs_ports(netdst, ports): """ Clean up created ovs ports in this case :param netdst: netdst get from command line :param ports: existing ports need to be remain before this test """ host_bridge = utils_net.find_bridge_manager(netdst) if utils_net.ovs_br_exists(netdst) is True: ports = set(host_bridge.list_ports(netdst)) - set(ports) for p in ports: utils_net.find_bridge_manager(netdst).del_port(netdst, p) netdst = params.get("netdst", "switch") mtu_value = params.get_numeric("mtu_value") host_bridge = utils_net.find_bridge_manager(netdst) localhost = LocalHost() try: if netdst in utils_net.Bridge().list_br(): host_hw_interface = utils_net.Bridge().list_iface(netdst)[0] else: host_hw_interface = host_bridge.list_ports(netdst) tmp_ports = re.findall(r"t[0-9]{1,}-[a-zA-Z0-9]{6}", ' '.join(host_hw_interface)) if tmp_ports: for p in tmp_ports: host_bridge.del_port(netdst, p) host_hw_interface = host_bridge.list_ports(netdst) except IndexError: host_hw_interface = netdst params["start_vm"] = "yes" env_process.preprocess_vm(test, params, env, params["main_vm"]) vm = env.get_vm(params["main_vm"]) vm.verify_alive() vm_iface = vm.get_ifname() # Get host interface original mtu value before setting if netdst in utils_net.Bridge().list_br(): host_hw_iface = NetworkInterface(host_hw_interface, localhost) elif utils_net.ovs_br_exists(netdst) is True: host_hw_iface = NetworkInterface(' '.join(host_hw_interface), localhost) host_mtu_origin = host_hw_iface.get_mtu() set_mtu_host(vm_iface, mtu_value) host_hw_iface.set_mtu(mtu_value) os_type = params.get("os_type", "linux") login_timeout = float(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) host_ip = utils_net.get_ip_address_by_interface(params["netdst"]) if os_type == "linux": session.cmd_output_safe(params["nm_stop_cmd"]) guest_ifname = utils_net.get_linux_ifname(session, vm.get_mac_address()) output = session.cmd_output_safe(params["check_linux_mtu_cmd"] % guest_ifname) error_context.context(output, logging.info) match_string = "mtu %s" % params["mtu_value"] if match_string not in output: test.fail("host mtu %s not exposed to guest" % params["mtu_value"]) elif os_type == "windows": connection_id = utils_net.get_windows_nic_attribute( session, "macaddress", vm.get_mac_address(), "netconnectionid") output = session.cmd_output_safe(params["check_win_mtu_cmd"] % connection_id) error_context.context(output, logging.info) lines = output.strip().splitlines() lines_len = len(lines) line_table = lines[0].split(' ') line_value = lines[2].split(' ') while '' in line_table: line_table.remove('') while '' in line_value: line_value.remove('') index = 0 for name in line_table: if re.findall("MTU", name): break index += 1 guest_mtu_value = line_value[index] logging.info("MTU is %s", guest_mtu_value) if not int(guest_mtu_value) == mtu_value: test.fail("Host mtu %s is not exposed to " "guest!" % params["mtu_value"]) logging.info("Ping from guest to host with packet size 3972") status, output = utils_test.ping(host_ip, 10, packetsize=3972, timeout=30, session=session) ratio = utils_test.get_loss_ratio(output) if ratio != 0: test.fail("Loss ratio is %s", ratio) # Restore host mtu after finish testing set_mtu_host(vm_iface, host_mtu_origin) host_hw_iface.set_mtu(host_mtu_origin) if netdst not in utils_net.Bridge().list_br(): cleanup_ovs_ports(netdst, host_hw_interface) session.close()
def run(test, params, env): """ Since 3.3.0, Coalesce setting is supported. This case is to set coalesce and check for 4 network types and each guest interface type. Only network/bridge guest interface type take effect for setting interface coalesce. For each host network type, guest can use bridge/network interface type to set coalesce except macvtap network type. Execute 'ethtool -c ${interface}|grep "rx-frames"' and anylize the output to check whether coalesce setting take effect or not. For macvtap network type, guest can start but query coalesce will fail. 1. For default host network network definition is below: <network> <name>default</name> <bridge name="virbr0"/> <forward/> <ip address="192.168.122.1" netmask="255.255.255.0"> <dhcp> <range start="192.168.122.2" end="192.168.122.254"/> </dhcp> </ip> </network> This is default network. 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:a7:4d:f7'/> <source bridge='virbr0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: <interface type='network'> <source network='default'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 2. For bridge host network This mode need true bridge in host network. 'nmcli con add type bridge con-name br0 ifname br0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='br0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for bridge br0 'virsh net-define net-br0.xml' 'virsh net-dumpxml net-br0' <network> <name>net-br0</name> <forward mode='bridge'/> <bridge name='br0'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-br0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 3. For openvswitch bridge host network This mode need true openvswitch bridge in host network. 'ovs-vsctl add-br ovsbr0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='ovsbr0'/> <virtualport type='openvswitch'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for openvswitch bridge ovsbr0 'virsh net-define net-ovsbr0.xml' 'virsh net-dumpxml net-ovsbr0' <network> <name>net-ovs0</name> <forward mode='bridge'/> <bridge name='ovsbr0'/> <virtualport type='openvswitch'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-ovs0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 4. For macvtap bridge mode on host network For this mode, first, create one virtual network. Note, should set dev to one ture physical interface. 'virsh net-define net-br-macvtap.xml' 'virsh net-dumpxml net-br-macvtap' <network> <name>net-br-macvtap</name> <forward dev='eno1' mode='bridge'> <interface dev='eno1'/> </forward> </network> Set guest to use this macvtap network and set coalesc <interface type='network'> <mac address='52:54:00:6e:f4:f1'/> <source network='net-br-macvtap'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> Steps in this test: 1. Prepare test environment,destroy or suspend a VM. 2. Prepare network if necessary. 3. Edit guest interface with definite network and set coalesce. 4. Start guest and check whether coalesce setting take effect. 5. Recover network and guest. """ if not libvirt_version.version_compare(3, 3, 0): test.skip("Coalesce setting is only supported by libvirt3.3.0 and above") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def get_first_phy_iface(): """ Get first physical network interface from output of 'ls /sys/class/net' #ls /sys/class/net eno1 lo virbr0 virbr0-nic :return: interface name """ interface = '' lines = process.run('ls /sys/class/net').stdout_text.splitlines() interfaces = lines[0].split() for iface in interfaces: if iface != 'lo' and 'vir' not in iface: interface = iface break if interface == '': test.fail("There is no physical network interface") return interface def modify_iface_xml(): """ Modify interface xml options Two methods to modify domain interfae: 1. modify guest xml, define it 2. attach one interface for running guest :return: 0 for successful negative case test.fail is fail for positive/negative case None for successful positive case """ if hotplug_iface: iface = Interface(iface_type) else: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if iface_type == 'network': iface.type_name = iface_type source = {iface_type: net_name} elif iface_type == 'bridge' and bridge_name: iface.type_name = iface_type source = {iface_type: bridge_name} elif iface_type == 'direct': iface.type_name = iface_type source = {'dev': interface, 'mode': 'bridge'} if source: del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model iface.coalesce = {'max': coalesce_value} if network_type == "ovsbridge" and iface_type == "bridge": iface.virtualport_type = "openvswitch" if not hotplug_iface: vmxml.devices = xml_devices vmxml.xmltreefile.write() try: vmxml.sync() except xcepts.LibvirtXMLError as details: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") else: if not vm.is_alive(): vm.start() # Wait guest boot completely time.sleep(2) try: ret = virsh.attach_device(vm_name, iface.xml, ignore_status=False, debug=True) except process.CmdError as error: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") start_error = "yes" == params.get("start_error", "no") status_error = "yes" == params.get("status_error", "no") # Get coalesce value. expect_coalesce = params.get("expect_coalesce", "") coalesce_value = params.get("coalesce", "15") if expect_coalesce == '': expect_coalesce = coalesce_value # Network specific attributes. network_type = params.get("network_type", "default") net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") # Get guest interface type iface_type = params.get("iface_type", "network") # Whether attach interface hotplug_iface = "yes" == params.get("hotplug_iface", "no") error_info = params.get("error_info", "") # Destroy the guest first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Build the xml and run test. try: interface = get_first_phy_iface() # Prepare network for specific network type. # Create bridge/ovsbridge for host bridge/ovsbridge network type if network_type == "default" and iface_type == "bridge": bridge_name = "virbr0" elif network_type == "bridge": bridge_name = eval(net_bridge)['name'] bridge = utils_net.Bridge() # Try to add bridge if not exist if bridge_name not in bridge.list_br(): bridge.add_bridge(bridge_name) elif network_type == 'ovsbridge': bridge_name = eval(net_bridge)['name'] # Try to add ovs bridge if not exist if not utils_net.ovs_br_exists(bridge_name): utils_net.add_ovs_bridge(bridge_name) if iface_type == "network": # Define virtual network if not exist for 'network' type of guest interface network = NetworkXML() network.name = net_name # Prepare virtual network required parameters params['net_forward'] = "{'mode':'bridge'}" if network_type == "ovsbridge": params['net_virtualport'] = "openvswitch" if network_type == "macvtap": # For bridge type of macvtap network, one true physical interface shold be added # Check whether physical interface has been added into one bridge. if yes, skip macvtap test # If interface already added to a bridge, the output of the nmcli # command will include "connection.slave-type: bridge" out = process.run('nmcli dev show %s' % interface).stdout_text con_l = re.findall(r'GENERAL.CONNECTION:(.+?)\n', out) if not con_l: test.cancel("no connection for the interface") else: con = con_l[0].strip() if "bridge" not in process.run('nmcli con show "%s"' % con).stdout_text: params['forward_iface'] = interface params['net_forward'] = "{'mode':'bridge', 'dev': '%s'}" % interface else: test.cancel("interface %s has been added into one brige, but macvtap" "need also add this interface, so current network can't" "suit macvtap testing" % interface) if not network.exists(): netxml = libvirt.create_net_xml(net_name, params) netxml.define() netxml.start() virsh.net_dumpxml(network.name, debug=True) # Edit the interface xml. # For successful negative case, return 0 to specify PASS result directly ret = modify_iface_xml() if ret == 0: return 0 try: # Get all interface link_before = set(process.run('ls /sys/class/net').stdout_text.splitlines()) # Start the VM. vm.start() if start_error: raise test.fail("VM started unexpectedly") # Get guest virtual network interface link_after = set(process.run('ls /sys/class/net').stdout_text.splitlines()) newinterface = (link_after - link_before).pop() out = process.run('ethtool -c %s' % newinterface, ignore_status=True) if network_type == 'macvtap': # Currently, output coalesce for macvtap is not supported err_msg = "Cannot get device coalesce settings: Operation not supported" std_msg = "Coalesce parameters for %s:" % newinterface if err_msg not in out.stderr_text or std_msg not in out.stdout_text: test.fail("coalesce setting on %s failed." % network_type) else: # Get coalesce value and check it is true if out.exit_status == 0: for line in out.stdout_text.splitlines(): if 'rx-frames:' in line: coalesce = line.split(':')[1].strip() if expect_coalesce != coalesce: test.fail("coalesce setting failed for %s" % network_type) break else: test.fail("coalesce setting on %s failed." % network_type) except virt_vm.VMStartError as details: logging.info(str(details)) if not start_error: test.fail('VM failed to start:\n%s' % details) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) # Try to recovery bridge if network_type == "bridge" and bridge_name: if bridge_name in bridge.list_br(): bridge.del_bridge(bridge_name) elif network_type == "ovsbridge" and bridge_name: if utils_net.ovs_br_exists(bridge_name): utils_net.del_ovs_bridge(bridge_name) vmxml_backup.sync()
def run(test, params, env): """ Expose host MTU to guest test 1) Boot up guest with param 'host_mtu=4000' in nic part 2) Disable NetworkManager in guest 3) set mtu of guest tap (eg: tap0) and physical nic (eg: eno1) to 4000 in host 4) check the mtu in guest 5) ping from guest to external host with packet size 3972 :param test: kvm test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment """ def cleanup_ovs_ports(netdst, ports): """ Clean up created ovs ports in this case :param netdst: netdst get from command line :param ports: existing ports need to be remain before this test """ host_bridge = utils_net.find_bridge_manager(netdst) if utils_net.ovs_br_exists(netdst) is True: ports = set(host_bridge.list_ports(netdst)) - set(ports) for p in ports: utils_net.find_bridge_manager(netdst).del_port(netdst, p) netdst = params.get("netdst", "switch") host_bridge = utils_net.find_bridge_manager(netdst) if netdst in utils_net.Bridge().list_br(): host_hw_interface = utils_net.Bridge().list_iface(netdst)[0] else: host_hw_interface = host_bridge.list_ports(netdst) tmp_ports = re.findall(r"t[0-9]{1,}-[a-zA-Z0-9]{6}", ' '.join(host_hw_interface)) if tmp_ports: for p in tmp_ports: host_bridge.del_port(netdst, p) host_hw_interface = host_bridge.list_ports(netdst) params["start_vm"] = "yes" env_process.preprocess_vm(test, params, env, params["main_vm"]) vm = env.get_vm(params["main_vm"]) vm.verify_alive() vm_iface = vm.get_ifname() # Get host interface original mtu value before setting if netdst in utils_net.Bridge().list_br(): host_hw_iface = utils_net.Interface(host_hw_interface) elif utils_net.ovs_br_exists(netdst) is True: host_hw_iface = utils_net.Interface(' '.join(host_hw_interface)) host_mtu_origin = host_hw_iface.get_mtu() utils_net.Interface(vm_iface).set_mtu(int(params["mtu_value"])) host_hw_iface.set_mtu(int(params["mtu_value"])) os_type = params.get("os_type", "linux") login_timeout = float(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=login_timeout) host_ip = utils_net.get_ip_address_by_interface(params["netdst"]) if os_type == "linux": session.cmd_output_safe(params["nm_stop_cmd"]) guest_ifname = utils_net.get_linux_ifname(session, vm.get_mac_address()) output = session.cmd_output_safe( params["check_linux_mtu_cmd"] % guest_ifname) error_context.context(output, logging.info) match_string = "mtu %s" % params["mtu_value"] if match_string not in output: test.fail("host mtu %s not exposed to guest" % params["mtu_value"]) elif os_type == "windows": connection_id = utils_net.get_windows_nic_attribute( session, "macaddress", vm.get_mac_address(), "netconnectionid") output = session.cmd_output_safe( params["check_win_mtu_cmd"] % connection_id) error_context.context(output, logging.info) lines = output.strip().splitlines() lines_len = len(lines) line_table = lines[0].split(' ') line_value = lines[2].split(' ') while '' in line_table: line_table.remove('') while '' in line_value: line_value.remove('') index = 0 for name in line_table: if re.findall("MTU", name): break index += 1 mtu_value = line_value[index] logging.info("MTU is %s", mtu_value) if not int(mtu_value) == int(params["mtu_value"]): test.fail("Host mtu %s is not exposed to " "guest!" % params["mtu_value"]) logging.info("Ping from guest to host with packet size 3972") status, output = utils_test.ping(host_ip, 10, packetsize=3972, timeout=30, session=session) ratio = utils_test.get_loss_ratio(output) if ratio != 0: test.fail("Loss ratio is %s", ratio) # Restore host mtu after finish testing utils_net.Interface(vm_iface).set_mtu(host_mtu_origin) host_hw_iface.set_mtu(host_mtu_origin) if netdst not in utils_net.Bridge().list_br(): cleanup_ovs_ports(netdst, host_hw_interface) session.close()
def run(test, params, env): """ Test openvswitch support for network. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) # install openvswitch on host. if distro.detect().name == 'Ubuntu': pkg = "openvswitch-switch" else: pkg = "openvswitch" ovs_service = service.Factory.create_service(pkg) if not shutil.which('ovs-vsctl') and not utils_package.package_install( pkg): test.cancel("Failed to install dependency package %s" " on host" % pkg) if not ovs_service.status(): logging.debug("Restart %s service.." % pkg) ovs_service.restart() def check_ovs_port(ifname, brname): """ Check OVS port that created by libvirt """ pg_name = params.get("porgroup_name", "").split() pg_vlan = params.get("portgroup_vlan", "").split() if_source = eval(iface_source) port_vlan = {} if "portgroup" in if_source: pg = if_source["portgroup"] for (name, vlan) in zip(pg_name, pg_vlan): if pg == name: port_vlan = eval(vlan) # Check bridge name by port name _, bridge = utils_net.find_current_bridge(ifname) assert bridge == brname # Get port info from ovs-vsctl output cmd = "ovs-vsctl list port %s" % ifname output = process.run(cmd, shell=True).stdout_text logging.debug("ovs port output: %s", output) for line in output.splitlines(): if line.count("tag"): tag_info = line.rsplit(':') if ("id" in port_vlan and tag_info[0] == "tag"): assert port_vlan["id"] == tag_info[1] elif line.count("vlan_mode"): mode_info = line.rsplit(':') if ("nativeMode" in port_vlan and mode_info[0] == "vlan_mode"): assert (port_vlan["nativeMode"] == "native-%s" % mode_info[1]) start_error = "yes" == params.get("start_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") iface_source = params.get("iface_source", "{}") create_network = "yes" == params.get("create_network", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_ovs_port = "yes" == params.get("test_ovs_port", "no") iface_inbound = params.get("iface_bandwidth_inbound") iface_outbound = params.get("iface_bandwidth_outbound") test_qos = "yes" == params.get("test_qos", "no") hotplug = "yes" == params.get("hotplug", "no") iface_type = params.get("iface_type", "bridge") iface_model = params.get("iface_model", "virtio") iface_virtualport = params.get("iface_virtualport") live_add_qos = "yes" == params.get("live_add_qos", 'no') libvirt_version.is_libvirt_feature_supported(params) # Destroy the guest first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) params["guest_mac"] = iface_mac vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bridge_name = eval(net_bridge)['name'] # Build the xml and run test. try: # Edit the network xml or create a new one. if create_network: # Try to add ovs bridge first if not utils_net.ovs_br_exists(bridge_name): utils_net.add_ovs_bridge(bridge_name) netxml = libvirt.create_net_xml(net_name, params) netxml.sync() # Edit the interface xml. if change_iface_option: # Try to add bridge if needed source = eval(iface_source) if source: if "bridge" in source: if not utils_net.ovs_br_exists(source["bridge"]): utils_net.add_ovs_bridge(source["bridge"]) iface_dict = { 'type': iface_type, 'model': iface_model, 'source': iface_source, 'virtualport_type': iface_virtualport, 'inbound': iface_inbound, 'outbound': iface_outbound } if live_add_qos: iface_dict.pop('inbound') iface_dict.pop('outbound') if not hotplug: libvirt.modify_vm_iface(vm_name, 'update_iface', iface_dict) else: iface_attach_xml = os.path.join(data_dir.get_data_dir(), "iface_attach.xml") shutil.copyfile( libvirt.modify_vm_iface(vm_name, 'get_xml', iface_dict), iface_attach_xml) libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') try: # Start the VM. vm.start() if start_error: test.fail("VM started unexpectedly") if hotplug: virsh.attach_device(vm_name, iface_attach_xml, debug=True, ignore_status=False) iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if test_ovs_port: check_ovs_port(iface_name, bridge_name) if live_add_qos: inbound_opt = ",".join(re.findall(r'[0-9]+', iface_inbound)) outbount_opt = ",".join(re.findall(r'[0-9]+', iface_outbound)) virsh.domiftune(vm_name, iface_name, inbound=inbound_opt, outbound=outbount_opt, debug=True, ignore_status=False) if test_qos: iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) tap_name = libvirt.get_ifname_host(vm_name, iface_mac) logging.info("Test inbound:") res1 = utils_net.check_class_rules( tap_name, "1:1", ast.literal_eval(iface_inbound)) logging.info("Test outbound:") res2 = utils_net.check_filter_rules( tap_name, ast.literal_eval(iface_outbound)) if not res1 or not res2: test.fail("Qos test fail!") except virt_vm.VMStartError as details: logging.info(str(details)) if not start_error: test.fail('VM failed to start:\n%s' % details) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) # Try to recovery ovs bridge if utils_net.ovs_br_exists(bridge_name): utils_net.del_ovs_bridge(bridge_name) if "iface_attach_xml" in locals(): os.remove(iface_attach_xml) vmxml_backup.sync()