def create_or_del_networks(pf_name, params, remote_virsh_session=None, is_del=False): """ Create or delete network on local or remote :param params: Dictionary with the test parameters :param pf_name: The name of PF :param remote_virsh_session: The virsh session object to the remote host :param is_del: Whether the networks should be deleted :raise: test.fail when fails to define/start network """ net_bridge_name = params.get("net_bridge_name", "host-bridge") net_bridge_fwd = params.get("net_bridge_fwd", '{"mode": "bridge"}') bridge_name = params.get("bridge_name", "br0") bridge_dict = {"net_name": net_bridge_name, "net_forward": net_bridge_fwd, "net_bridge": '{"name": "%s"}' % bridge_name} net_list = [bridge_dict] enable_hostdev_iface = "yes" == params.get("enable_hostdev_iface", "no") if enable_hostdev_iface: net_hostdev_name = params.get("net_hostdev_name", "hostdev-net") net_hostdev_fwd = params.get("net_hostdev_fwd", '{"mode": "hostdev", "managed": "yes"}') net_dict = {"net_name": net_hostdev_name, "net_forward": net_hostdev_fwd, "net_forward_pf": '{"dev": "%s"}' % pf_name} net_list.append(net_dict) if not is_del: for net_params in net_list: net_dev = libvirt.create_net_xml(net_params.get("net_name"), net_params) if not remote_virsh_session: if net_dev.get_active(): net_dev.undefine() net_dev.define() net_dev.start() else: remote.scp_to_remote(server_ip, '22', server_user, server_pwd, net_dev.xml, net_dev.xml, limit="", log_filename=None, timeout=600, interface=None) remote_virsh_session.net_define(net_dev.xml, **virsh_args) remote_virsh_session.net_start(net_params.get("net_name"), **virsh_args) else: virsh_session = virsh if remote_virsh_session: virsh_session = remote_virsh_session for nname in [n_dict.get("net_name") for n_dict in net_list]: if nname not in virsh_session.net_state_dict(): continue virsh_session.net_destroy(nname, debug=True, ignore_status=True) virsh_session.net_undefine(nname, debug=True, ignore_status=True)
def create_or_del_network(net_dict, is_del=False, remote_args=None): """ Create or delete network on local or remote :param net_dict: Dictionary with the network parameters :param is_del: Whether the networks should be deleted :param remote_args: The parameters for remote """ remote_virsh_session = None if remote_args: remote_virsh_session = virsh.VirshPersistent(**remote_args) if not is_del: net_dev = libvirt.create_net_xml(net_dict.get("net_name"), net_dict) if not remote_virsh_session: if net_dev.get_active(): net_dev.undefine() net_dev.define() net_dev.start() else: remote_ip = remote_args.get("remote_ip") remote_user = remote_args.get("remote_user") remote_pwd = remote_args.get("remote_pwd") if not all([remote_ip, remote_user, remote_pwd]): raise exceptions.TestError( "remote_[ip|user|pwd] are necessary!") remote.scp_to_remote(remote_ip, '22', remote_user, remote_pwd, net_dev.xml, net_dev.xml, limit="", log_filename=None, timeout=600, interface=None) remote_virsh_session.net_define(net_dev.xml, debug=True) remote_virsh_session.net_start(net_dict.get("net_name"), debug=True) remote.run_remote_cmd("rm -rf %s" % net_dev.xml, remote_args) else: virsh_session = virsh if remote_virsh_session: virsh_session = remote_virsh_session if net_dict.get("net_name") in virsh_session.net_state_dict(): virsh_session.net_destroy(net_dict.get("net_name"), debug=True, ignore_status=True) virsh_session.net_undefine(net_dict.get("net_name"), debug=True, ignore_status=True) if remote_virsh_session: remote_virsh_session.close_session()
def prepare_network(net_name, **kwargs): """ Prepare a new network for test by creating net xml, defining network and starting network :param net_name: net to be created :param kwargs: params of net :return: """ new_net = libvirt.create_net_xml(net_name, kwargs) virsh.net_define(new_net.xml, debug=True, ignore_status=False) virsh.net_start(net_name, debug=True, ignore_status=False) logging.debug(virsh.net_dumpxml(net_name).stdout_text)
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 interafce xml options. 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 prepare_pxe_boot(): """ Prepare tftp server and pxe boot files """ pkg_list = ["syslinux", "tftp-server", "tftp", "ipxe-roms-qemu", "wget"] # Try to install required packages if not utils_misc.yum_install(pkg_list): raise error.TestError("Failed ot install " "required packages") boot_initrd = params.get("boot_initrd", "EXAMPLE_INITRD") boot_vmlinuz = params.get("boot_vmlinuz", "EXAMPLE_VMLINUZ") if boot_initrd.count("EXAMPLE") or boot_vmlinuz.count("EXAMPLE"): raise error.TestNAError("Please provide initrd/vmlinuz URL") # Download pxe boot images utils.run("wget %s -O %s/initrd.img" % (boot_initrd, tftp_root)) utils.run("wget %s -O %s/vmlinuz" % (boot_vmlinuz, tftp_root)) utils.run("cp -f /usr/share/syslinux/pxelinux.0 {0};" " mkdir -m 777 -p {0}/pxelinux.cfg".format(tftp_root)) pxe_file = "%s/pxelinux.cfg/default" % tftp_root boot_txt = """ DISPLAY boot.txt DEFAULT rhel LABEL rhel kernel vmlinuz append initrd=initrd.img PROMPT 1 TIMEOUT 3""" with open(pxe_file, 'w') as p_file: p_file.write(boot_txt) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if pxe_boot: # Config boot console for pxe boot osxml = vm_xml.VMOSXML() osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" osxml.bios_reboot_timeout = "-1" osxml.boots = ['network'] del vmxml.os vmxml.os = osxml xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_bandwidth = {} iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) if iface_inbound: iface_bandwidth["inbound"] = iface_inbound if iface_outbound: iface_bandwidth["outbound"] = iface_outbound if iface_bandwidth: bandwidth = iface.new_bandwidth(**iface_bandwidth) iface.bandwidth = bandwidth iface_type = params.get("iface_type", "network") iface.type_name = iface_type source = ast.literal_eval(iface_source) if not source: source = {"network": "default"} net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and source.has_key('dev') and source['dev'] not in net_ifs): logging.warn("Source device %s is not a interface" " of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def run_dnsmasq_default_test(key, value=None, exists=True): """ Test dnsmasq configuration. """ conf_file = "/var/lib/libvirt/dnsmasq/default.conf" if not os.path.exists(conf_file): raise error.TestNAError("Can't find default.conf file") configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if value: config = "%s=%s" % (key, value) else: config = key if not configs.count(config): if exists: raise error.TestFail("Can't find %s=%s in configuration" " file" % (key, value)) else: if not exists: raise error.TestFail("Found %s=%s in configuration" " file" % (key, value)) def run_dnsmasq_addnhosts_test(hostip, hostnames): """ Test host ip and names configuration """ conf_file = "/var/lib/libvirt/dnsmasq/default.addnhosts" hosts_re = ".*".join(hostnames) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not re.search(r"%s.*%s" % (hostip, hosts_re), configs, re.M): raise error.TestFail("Can't find '%s' in configuration" " file" % hostip) def run_dnsmasq_host_test(iface_mac, guest_ip, guest_name): """ Test host name and ip configuration for dnsmasq """ conf_file = "/var/lib/libvirt/dnsmasq/default.hostsfile" config = "%s,%s,%s" % (iface_mac, guest_ip, guest_name) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not configs.count(config): raise error.TestFail("Can't find host configuration" " in file %s" % conf_file) def check_class_rules(ifname, rule_id, bandwidth): """ Check bandwidth settings via 'tc class' output """ cmd = "tc class show dev %s" % ifname class_output = utils.run(cmd).stdout logging.debug("Bandwidth class output: %s", class_output) class_pattern = (r"class htb %s.*rate (\d+)Kbit ceil" " (\d+)Kbit burst (\d+)(K?M?)b.*" % rule_id) se = re.search(class_pattern, class_output, re.M) if not se: raise error.TestFail("Can't find outbound setting" " for htb %s" % rule_id) logging.debug("bandwidth from tc output:%s" % str(se.groups())) ceil = None if bandwidth.has_key("floor"): ceil = int(bandwidth["floor"]) * 8 elif bandwidth.has_key("average"): ceil = int(bandwidth["average"]) * 8 if ceil: assert int(se.group(1)) == ceil if bandwidth.has_key("peak"): assert int(se.group(2)) == int(bandwidth["peak"]) * 8 if bandwidth.has_key("burst"): if se.group(4) == 'M': tc_burst = int(se.group(3)) * 1024 else: tc_burst = int(se.group(3)) assert tc_burst == int(bandwidth["burst"]) def check_filter_rules(ifname, bandwidth): """ Check bandwidth settings via 'tc filter' output """ cmd = "tc -d filter show dev %s parent ffff:" % ifname filter_output = utils.run(cmd).stdout logging.debug("Bandwidth filter output: %s", filter_output) if not filter_output.count("filter protocol all pref"): raise error.TestFail("Can't find 'protocol all' settings" " in filter rules") filter_pattern = ".*police.*rate (\d+)Kbit burst (\d+)(K?M?)b.*" se = re.search(r"%s" % filter_pattern, filter_output, re.M) if not se: raise error.TestFail("Can't find any filter policy") logging.debug("bandwidth from tc output:%s" % str(se.groups())) logging.debug("bandwidth from setting:%s" % str(bandwidth)) if bandwidth.has_key("average"): assert int(se.group(1)) == int(bandwidth["average"]) * 8 if bandwidth.has_key("burst"): if se.group(3) == 'M': tc_burst = int(se.group(2)) * 1024 else: tc_burst = int(se.group(2)) assert tc_burst == int(bandwidth["burst"]) def check_host_routes(): """ Check network routes on host """ for rt in routes: try: route = ast.literal_eval(rt) addr = "%s/%s" % (route["address"], route["prefix"]) cmd = "ip route list %s" % addr if route.has_key("family") and route["family"] == "ipv6": cmd = "ip -6 route list %s" % addr output = utils.run(cmd).stdout match_obj = re.search(r"via (\S+).*metric (\d+)", output) if match_obj: via_addr = match_obj.group(1) metric = match_obj.group(2) logging.debug("via address %s for %s, matric is %s" % (via_addr, addr, metric)) assert via_addr == route["gateway"] if route.has_key("metric"): assert metric == route["metric"] except KeyError: pass def run_bandwidth_test(check_net=False, check_iface=False): """ Test bandwidth option for network or interface by tc command. """ iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) net_inbound = ast.literal_eval(net_bandwidth_inbound) net_outbound = ast.literal_eval(net_bandwidth_outbound) net_bridge_name = ast.literal_eval(net_bridge)["name"] iface_name = libvirt.get_ifname_host(vm_name, iface_mac) try: if check_net and net_inbound: # Check qdisc rules cmd = "tc -d qdisc show dev %s" % net_bridge_name qdisc_output = utils.run(cmd).stdout logging.debug("Bandwidth qdisc output: %s", qdisc_output) if not qdisc_output.count("qdisc ingress ffff:"): raise error.TestFail("Can't find ingress setting") check_class_rules(net_bridge_name, "1:1", {"average": net_inbound["average"], "peak": net_inbound["peak"]}) check_class_rules(net_bridge_name, "1:2", net_inbound) # Check filter rules on bridge interface if check_net and net_outbound: check_filter_rules(net_bridge_name, net_outbound) # Check class rules on interface inbound settings if check_iface and iface_inbound: check_class_rules(iface_name, "1:1", {'average': iface_inbound['average'], 'peak': iface_inbound['peak'], 'burst': iface_inbound['burst']}) if iface_inbound.has_key("floor"): if not libvirt_version.version_compare(1, 0, 1): raise error.TestNAError("Not supported Qos" " options 'floor'") check_class_rules(net_bridge_name, "1:3", {'floor': iface_inbound["floor"]}) # Check filter rules on interface outbound settings if check_iface and iface_outbound: check_filter_rules(iface_name, iface_outbound) except AssertionError: utils.log_last_traceback() raise error.TestFail("Failed to check network bandwidth") def check_name_ip(session): """ Check dns resolving on guest """ # Check if bind-utils is installed if not utils_misc.yum_install(['bind-utils'], session): raise error.TestError("Failed to install bind-utils" " on guest") # Run host command to check if hostname can be resolved if not guest_ipv4 and not guest_ipv6: raise error.TestFail("No ip address found from parameters") guest_ip = guest_ipv4 if guest_ipv4 else guest_ipv6 cmd = "host %s | grep %s" % (guest_name, guest_ip) if session.cmd_status(cmd): raise error.TestFail("Can't resolve name %s on guest" % guest_name) def check_ipt_rules(check_ipv4=True, check_ipv6=False): """ Check iptables for network/interface """ br_name = ast.literal_eval(net_bridge)["name"] net_forward = ast.literal_eval(params.get("net_forward", "{}")) net_ipv4 = params.get("net_ipv4") net_ipv6 = params.get("net_ipv6") ipt_rules = ("FORWARD -i {0} -o {0} -j ACCEPT".format(br_name), "FORWARD -o %s -j REJECT --reject-with icmp" % br_name, "FORWARD -i %s -j REJECT --reject-with icmp" % br_name) net_dev_in = "" net_dev_out = "" if net_forward.has_key("dev"): net_dev_in = " -i %s" % net_forward["dev"] net_dev_out = " -o %s" % net_forward["dev"] if check_ipv4: ipv4_rules = list(ipt_rules) ctr_rule = "" nat_rules = [] if net_forward.has_key("mode") and net_forward["mode"] == "nat": nat_port = ast.literal_eval(params.get("nat_port")) p_start = nat_port["start"] p_end = nat_port["end"] ctr_rule = " -m .* RELATED,ESTABLISHED" nat_rules = [("POSTROUTING -s {0} ! -d {0} -p tcp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp" " -j MASQUERADE".format(net_ipv4))] if nat_rules: ipv4_rules.extend(nat_rules) if (net_ipv4 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s%s -j ACCEPT" % (net_ipv4, net_dev_in, br_name, ctr_rule)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv4, br_name, net_dev_out))] ipv4_rules.extend(rules) output = utils.run("iptables-save").stdout.strip() logging.debug("iptables: %s", output) for ipt in ipv4_rules: if not re.findall(r"%s" % ipt, output, re.M): raise error.TestFail("Can't find iptable rule:\n%s" % ipt) if check_ipv6: ipv6_rules = list(ipt_rules) if (net_ipv6 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s -j ACCEPT" % (net_ipv6, net_dev_in, br_name)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv6, br_name, net_dev_out))] ipv6_rules.extend(rules) output = utils.run("ip6tables-save").stdout.strip() logging.debug("iptables: %s", output) for ipt in ipv6_rules: if not output.count(ipt): raise error.TestFail("Can't find ipbtable rule:\n%s" % ipt) def run_ip_test(session, ip_ver): """ Check iptables on host and ipv6 address on guest """ if ip_ver == "ipv6": # Clean up iptables rules for guest to get ipv6 address session.cmd_status("ip6tables -F") # It may take some time to get the ip address def get_ip_func(): return utils_net.get_guest_ip_addr(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) if not get_ip_func(): utils_net.restart_guest_network(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) vm_ip = get_ip_func() logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: raise error.TestFail("Can't find ip address on guest") ip_gateway = net_ip_address if ip_ver == "ipv6": ip_gateway = net_ipv6_address # Cleanup ip6talbes on host for ping6 test utils.run("ip6tables -F") if ip_gateway and not routes: ping_s, _ = ping(dest=ip_gateway, count=5, timeout=10, session=session) if ping_s: raise error.TestFail("Failed to ping gateway address: %s" % ip_gateway) def run_guest_libvirt(session): """ Check guest libvirt network """ # Try to install required packages if not utils_misc.yum_install(['libvirt'], session): raise error.TestError("Failed ot install libvirt" " package on guest") result = True # Try to load tun module first session.cmd("lsmod | grep tun || modprobe tun") # Check network state on guest cmd = ("service libvirtd restart; virsh net-info default" " | grep 'Active:.*no'") if session.cmd_status(cmd): result = False logging.error("Default network isn't in inactive state") # Try to start default network on guest, check error messages if result: cmd = "virsh net-start default" status, output = session.cmd_status_output(cmd) logging.debug("Run command on guest exit %s, output %s" % (status, output)) if not status or not output.count("already in use"): result = False logging.error("Failed to see network messges on guest") if session.cmd_status("yum -y remove libvirt*"): logging.error("Failed to remove libvirt packages on guest") if not result: raise error.TestFail("Check libvirt network on guest failed") start_error = "yes" == params.get("start_error", "no") define_error = "yes" == params.get("define_error", "no") restart_error = "yes" == params.get("restart_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") net_domain = params.get("net_domain") net_ip_address = params.get("net_ip_address") net_ipv6_address = params.get("net_ipv6_address") net_dns_forward = params.get("net_dns_forward") net_dns_txt = params.get("net_dns_txt") net_dns_srv = params.get("net_dns_srv") net_dns_hostip = params.get("net_dns_hostip") net_dns_hostnames = params.get("net_dns_hostnames", "").split() dhcp_start_ipv4 = params.get("dhcp_start_ipv4") dhcp_end_ipv4 = params.get("dhcp_end_ipv4") guest_name = params.get("guest_name") guest_ipv4 = params.get("guest_ipv4") guest_ipv6 = params.get("guest_ipv6") tftp_root = params.get("tftp_root") pxe_boot = "yes" == params.get("pxe_boot", "no") routes = params.get("routes", "").split() net_bandwidth_inbound = params.get("net_bandwidth_inbound", "{}") net_bandwidth_outbound = params.get("net_bandwidth_outbound", "{}") iface_bandwidth_inbound = params.get("iface_bandwidth_inbound", "{}") iface_bandwidth_outbound = params.get("iface_bandwidth_outbound", "{}") iface_num = params.get("iface_num", "1") iface_source = params.get("iface_source", "{}") multiple_guests = params.get("multiple_guests") create_network = "yes" == params.get("create_network", "no") attach_iface = "yes" == params.get("attach_iface", "no") serial_login = "******" == params.get("serial_login", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_bridge = "yes" == params.get("test_bridge", "no") test_dnsmasq = "yes" == params.get("test_dnsmasq", "no") test_dhcp_range = "yes" == params.get("test_dhcp_range", "no") test_dns_host = "yes" == params.get("test_dns_host", "no") test_qos_bandwidth = "yes" == params.get("test_qos_bandwidth", "no") test_pg_bandwidth = "yes" == params.get("test_portgroup_bandwidth", "no") test_qos_remove = "yes" == params.get("test_qos_remove", "no") test_ipv4_address = "yes" == params.get("test_ipv4_address", "no") test_ipv6_address = "yes" == params.get("test_ipv6_address", "no") test_guest_libvirt = "yes" == params.get("test_guest_libvirt", "no") username = params.get("username") password = params.get("password") # Destroy VM 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) vms_list = [] if "floor" in ast.literal_eval(iface_bandwidth_inbound): if not libvirt_version.version_compare(1, 0, 1): raise error.TestNAError("Not supported Qos" " options 'floor'") # Build the xml and run test. try: if test_dnsmasq: # Check the settings before modifying network xml if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed", exists=False) run_dnsmasq_default_test("local", "//", exists=False) if net_domain: run_dnsmasq_default_test("domain", net_domain, exists=False) run_dnsmasq_default_test("expand-hosts", exists=False) # Prepare pxe boot directory if pxe_boot: prepare_pxe_boot() # Edit the network xml or create a new one. if create_network: net_ifs = utils_net.get_net_if(state="UP") # Check forward device is valid or not, # if it's not in host interface list, try to set # forward device to first active interface of host forward = ast.literal_eval(params.get("net_forward", "{}")) if (forward.has_key('mode') and forward['mode'] in ['passthrough', 'private', 'bridge', 'macvtap'] and forward.has_key('dev') and forward['dev'] not in net_ifs): logging.warn("Forward device %s is not a interface" " of host, reset to %s", forward['dev'], net_ifs[0]) forward['dev'] = net_ifs[0] params["net_forward"] = str(forward) forward_iface = params.get("forward_iface") if forward_iface: interface = [x for x in forward_iface.split()] # The guest will use first interface of the list, # check if it's valid or not, if it's not in host # interface list, try to set forward interface to # first active interface of host. if interface[0] not in net_ifs: logging.warn("Forward interface %s is not a " " interface of host, reset to %s", interface[0], net_ifs[0]) interface[0] = net_ifs[0] params["forward_iface"] = " ".join(interface) netxml = libvirt.create_net_xml(net_name, params) try: netxml.sync() except xcepts.LibvirtXMLError, details: logging.info(str(details)) if define_error: pass else: raise error.TestFail("Failed to define network") # Edit the interface xml. if change_iface_option: modify_iface_xml() # Attach interface if needed if attach_iface: iface_type = params.get("iface_type", "network") iface_model = params.get("iface_model", "virtio") for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) options = ("%s %s --model %s --config" % (iface_type, net_name, iface_model)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: logging.error("Command output %s" % ret.stdout.strip()) raise error.TestFail("Failed to attach-interface") if multiple_guests: # Clone more vms for testing for i in range(int(multiple_guests)): guest_name = "%s_%s" % (vm_name, i) timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout) vms_list.append(vm.clone(guest_name)) if test_bridge: bridge = ast.literal_eval(net_bridge) br_if = utils_net.Interface(bridge['name']) if not br_if.is_up(): raise error.TestFail("Bridge interface isn't up") if test_dnsmasq: # Check the settings in dnsmasq config file if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed") run_dnsmasq_default_test("local", "//") if net_domain: run_dnsmasq_default_test("domain", net_domain) run_dnsmasq_default_test("expand-hosts") if net_bridge: bridge = ast.literal_eval(net_bridge) run_dnsmasq_default_test("interface", bridge['name']) if bridge.has_key('stp') and bridge['stp'] == 'on': if bridge.has_key('delay'): br_delay = float(bridge['delay']) cmd = ("brctl showstp %s | grep 'bridge forward delay'" % bridge['name']) out = utils.run(cmd, ignore_status=False).stdout.strip() logging.debug("brctl showstp output: %s", out) pattern = (r"\s*forward delay\s+(\d+.\d+)\s+bridge" " forward delay\s+(\d+.\d+)") match_obj = re.search(pattern, out, re.M) if not match_obj or len(match_obj.groups()) != 2: raise error.TestFail("Can't see forward delay" " messages from command") elif (float(match_obj.groups()[0]) != br_delay or float(match_obj.groups()[1]) != br_delay): raise error.TestFail("Foward delay setting" " can't take effect") if dhcp_start_ipv4 and dhcp_end_ipv4: run_dnsmasq_default_test("dhcp-range", "%s,%s" % (dhcp_start_ipv4, dhcp_end_ipv4)) if guest_name and guest_ipv4: run_dnsmasq_host_test(iface_mac, guest_ipv4, guest_name) if test_dns_host: if net_dns_txt: dns_txt = ast.literal_eval(net_dns_txt) run_dnsmasq_default_test("txt-record", "%s,%s" % (dns_txt["name"], dns_txt["value"])) if net_dns_srv: dns_srv = ast.literal_eval(net_dns_srv) run_dnsmasq_default_test("srv-host", "_%s._%s.%s,%s,%s,%s,%s" % (dns_srv["service"], dns_srv["protocol"], dns_srv["domain"], dns_srv["target"], dns_srv["port"], dns_srv["priority"], dns_srv["weight"])) if net_dns_hostip and net_dns_hostnames: run_dnsmasq_addnhosts_test(net_dns_hostip, net_dns_hostnames) # Run bandwidth test for network if test_qos_bandwidth: run_bandwidth_test(check_net=True) # Check routes if needed if routes: check_host_routes() try: # Start the VM. vm.start() if start_error: raise error.TestFail("VM started unexpectedly") if pxe_boot: # Just check network boot messages here vm.serial_console.read_until_output_matches( ["Loading vmlinuz", "Loading initrd.img"], utils_misc.strip_console_codes) output = vm.serial_console.get_stripped_output() logging.debug("Boot messages: %s", output) else: if serial_login: session = vm.wait_for_serial_login(username=username, password=password) else: session = vm.wait_for_login() if test_dhcp_range: dhcp_range = int(params.get("dhcp_range", "252")) utils_net.restart_guest_network(session, iface_mac) vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip and dhcp_range: raise error.TestFail("Guest has invalid ip address") elif vm_ip and not dhcp_range: raise error.TestFail("Guest has ip address: %s" % vm_ip) dhcp_range = dhcp_range - 1 for vms in vms_list: # Start other VMs. vms.start() sess = vms.wait_for_serial_login() vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) vms_ip = utils_net.get_guest_ip_addr(sess, vms_mac) if not vms_ip and dhcp_range: raise error.TestFail("Guest has invalid ip address") elif vms_ip and not dhcp_range: # Get IP address on guest should return Null # if it exceeds the dhcp range raise error.TestFail("Guest has ip address: %s" % vms_ip) dhcp_range = dhcp_range - 1 if vms_ip: ping_s, _ = ping(dest=vm_ip, count=5, timeout=10, session=sess) if ping_s: raise error.TestFail("Failed to ping, src: %s, " "dst: %s" % (vms_ip, vm_ip)) sess.close() # Check dnsmasq settings if take affect in guest if guest_ipv4: check_name_ip(session) # Run bandwidth test for interface if test_qos_bandwidth: run_bandwidth_test(check_iface=True) # Run bandwidth test for portgroup if test_pg_bandwidth: pg_bandwidth_inbound = params.get( "portgroup_bandwidth_inbound", "").split() pg_bandwidth_outbound = params.get( "portgroup_bandwidth_outbound", "").split() pg_name = params.get("portgroup_name", "").split() pg_default = params.get("portgroup_default", "").split() iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if_source = ast.literal_eval(iface_source) if if_source.has_key("portgroup"): pg = if_source["portgroup"] else: pg = "default" for (name, df, bw_ib, bw_ob) in zip(pg_name, pg_default, pg_bandwidth_inbound, pg_bandwidth_outbound): if pg == name: inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) elif pg == "default" and df == "yes": inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) else: continue # Interface bandwidth settings will # overwriting portgroup settings if iface_inbound: inbound = iface_inbound if iface_outbound: outbound = iface_outbound check_class_rules(iface_name, "1:1", inbound) check_filter_rules(iface_name, outbound) if test_qos_remove: # Remove the bandwidth settings in network xml logging.debug("Removing network bandwidth settings...") netxml_backup.sync() vm.destroy(gracefully=False) # Should fail to start vm vm.start() if restart_error: raise error.TestFail("VM started unexpectedly") if test_ipv6_address: check_ipt_rules(check_ipv6=True) run_ip_test(session, "ipv6") if test_ipv4_address: check_ipt_rules(check_ipv4=True) run_ip_test(session, "ipv4") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError, details: logging.info(str(details)) if start_error or restart_error: pass else: raise error.TestFail('VM Failed to start for some reason!')
def run(test, params, env): """ Test interafce xml options. 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) host_arch = platform.machine() def prepare_pxe_boot(): """ Prepare tftp server and pxe boot files """ pkg_list = ["syslinux", "tftp-server", "tftp", "ipxe-roms-qemu", "wget"] # Try to install required packages if not utils_package.package_install(pkg_list): test.error("Failed ot install required packages") boot_initrd = params.get("boot_initrd", "EXAMPLE_INITRD") boot_vmlinuz = params.get("boot_vmlinuz", "EXAMPLE_VMLINUZ") if boot_initrd.count("EXAMPLE") or boot_vmlinuz.count("EXAMPLE"): test.cancel("Please provide initrd/vmlinuz URL") # Download pxe boot images process.system("wget %s -O %s/initrd.img" % (boot_initrd, tftp_root)) process.system("wget %s -O %s/vmlinuz" % (boot_vmlinuz, tftp_root)) process.system("cp -f /usr/share/syslinux/pxelinux.0 {0};" " mkdir -m 777 -p {0}/pxelinux.cfg".format(tftp_root), shell=True) ldlinux_file = "/usr/share/syslinux/ldlinux.c32" if os.path.exists(ldlinux_file): process.system("cp -f {0} {1}".format(ldlinux_file, tftp_root), shell=True) pxe_file = "%s/pxelinux.cfg/default" % tftp_root boot_txt = """ DISPLAY boot.txt DEFAULT rhel LABEL rhel kernel vmlinuz append initrd=initrd.img PROMPT 1 TIMEOUT 3""" with open(pxe_file, 'w') as p_file: p_file.write(boot_txt) def modify_iface_xml(sync=True): """ Modify interface xml options :param sync: whether or not sync vmxml after the iface xml modified, default to be True """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if pxe_boot: # Config boot console for pxe boot osxml = vm_xml.VMOSXML() osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" if utils_misc.compare_qemu_version(4, 0, 0, False): osxml.bios_reboot_timeout = "-1" osxml.boots = ['network'] del vmxml.os vmxml.os = osxml xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if not sync: params.setdefault('original_iface', vmxml.devices[iface_index]) iface_bandwidth = {} iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) if iface_inbound: iface_bandwidth["inbound"] = iface_inbound if iface_outbound: iface_bandwidth["outbound"] = iface_outbound if iface_bandwidth: bandwidth = iface.new_bandwidth(**iface_bandwidth) iface.bandwidth = bandwidth iface_type = params.get("iface_type", "network") iface.type_name = iface_type source = ast.literal_eval(iface_source) if not source: source = {"network": "default"} net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and 'dev' in source and source['dev'] not in net_ifs): logging.warning("Source device %s is not a interface of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] del iface.source iface.source = source if iface_model: iface.model = get_iface_model(iface_model, host_arch) if iface_rom: iface.rom = eval(iface_rom) if iface_boot: vmxml.remove_all_boots() iface.boot = iface_boot logging.debug("New interface xml file: %s", iface) if sync: vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() else: return iface def get_iface_model(iface_model, host_arch): """ Return iface_model. In case of s390x modify iface_model and log the change. :param iface_model: iface_model from params :param host_arch: host architecture, e.g. s390x :return: //interface/model@type """ if 's390x' == host_arch: logging.debug("On s390x only valid model type are the virtio(-*)." " Using virtio and ignoring config value %s" % iface_model) return "virtio" else: return iface_model def run_dnsmasq_default_test(key, value=None, exists=True, name="default"): """ Test dnsmasq configuration. :param key: key in conf file to check :param value: value in conf file to check :param exists: check the key:value exist or not :param name: The name of conf file """ conf_file = "/var/lib/libvirt/dnsmasq/%s.conf" % name if not os.path.exists(conf_file): test.cancel("Can't find %s.conf file" % name) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if value: config = "%s=%s" % (key, value) else: config = key if not configs.count(config): if exists: test.fail("Can't find %s=%s in configuration file" % (key, value)) else: if not exists: test.fail("Found %s=%s in configuration file" % (key, value)) def run_dnsmasq_addnhosts_test(hostip, hostnames): """ Test host ip and names configuration """ conf_file = "/var/lib/libvirt/dnsmasq/default.addnhosts" hosts_re = ".*".join(hostnames) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not re.search(r"%s.*%s" % (hostip, hosts_re), configs, re.M): test.fail("Can't find '%s' in configuration file" % hostip) def run_dnsmasq_host_test(iface_mac, guest_ip, guest_name): """ Test host name and ip configuration for dnsmasq """ conf_file = "/var/lib/libvirt/dnsmasq/default.hostsfile" config = "%s,%s,%s" % (iface_mac, guest_ip, guest_name) configs = "" with open(conf_file, 'r') as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not configs.count(config): test.fail("Can't find host configuration in file %s" % conf_file) def check_class_rules(ifname, rule_id, bandwidth): """ Check bandwidth settings via 'tc class' output """ cmd = "tc class show dev %s" % ifname class_output = process.run(cmd, shell=True).stdout_text logging.debug("Bandwidth class output: %s", class_output) class_pattern = (r"class htb %s.*rate (\d+)(K?M?)bit ceil (\d+)(K?M?)bit burst (\d+)(K?M?)b.*" % rule_id) se = re.search(class_pattern, class_output, re.M) if not se: test.fail("Can't find outbound setting for htb %s" % rule_id) logging.debug("bandwidth from tc output:%s" % str(se.groups())) rate = None if "floor" in bandwidth: rate = int(bandwidth["floor"]) * 8 elif "average" in bandwidth: rate = int(bandwidth["average"]) * 8 if rate: if se.group(2) == 'M': rate_check = int(se.group(1)) * 1000 else: rate_check = int(se.group(1)) assert rate_check == rate if "peak" in bandwidth: if se.group(4) == 'M': ceil_check = int(se.group(3)) * 1000 else: ceil_check = int(se.group(3)) assert ceil_check == int(bandwidth["peak"]) * 8 if "burst" in bandwidth: if se.group(6) == 'M': tc_burst = int(se.group(5)) * 1024 else: tc_burst = int(se.group(5)) assert tc_burst == int(bandwidth["burst"]) def check_filter_rules(ifname, bandwidth, expect_none=False): """ Check bandwidth settings via 'tc filter' output :param ifname: name of iface to be checked :param bandwidth: bandwidth to be match with :param expect_none: whether or not expect nothing in output, default to be False :return: if expect nothing from the output, return True if the output is empty, else return False """ cmd = "tc -d filter show dev %s parent ffff:" % ifname filter_output = process.run(cmd, shell=True).stdout_text logging.debug("Bandwidth filter output: %s", filter_output) if expect_none: return not filter_output.strip() if not filter_output.count("filter protocol all pref"): test.fail("Can't find 'protocol all' settings in filter rules") filter_pattern = r".*police.*rate (\d+)(K?M?)bit burst (\d+)(K?M?)b.*" se = re.search(r"%s" % filter_pattern, filter_output, re.M) if not se: test.fail("Can't find any filter policy") logging.debug("bandwidth from tc output:%s" % str(se.groups())) logging.debug("bandwidth from setting:%s" % str(bandwidth)) if "average" in bandwidth: if se.group(2) == 'M': tc_average = int(se.group(1)) * 1000 else: tc_average = int(se.group(1)) assert tc_average == int(bandwidth["average"]) * 8 if "burst" in bandwidth: if se.group(4) == 'M': tc_burst = int(se.group(3)) * 1024 else: tc_burst = int(se.group(3)) assert tc_burst == int(bandwidth["burst"]) def check_host_routes(): """ Check network routes on host """ for rt in routes: try: route = ast.literal_eval(rt) addr = "%s/%s" % (route["address"], route["prefix"]) cmd = "ip route list %s" % addr if "family" in route and route["family"] == "ipv6": cmd = "ip -6 route list %s" % addr output = process.run(cmd, shell=True).stdout_text match_obj = re.search(r"via (\S+).*metric (\d+)", output) if match_obj: via_addr = match_obj.group(1) metric = match_obj.group(2) logging.debug("via address %s for %s, matric is %s" % (via_addr, addr, metric)) assert via_addr == route["gateway"] if "metric" in route: assert metric == route["metric"] except KeyError: pass def run_bandwidth_test(check_net=False, check_iface=False): """ Test bandwidth option for network or interface by tc command. """ iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) net_inbound = ast.literal_eval(net_bandwidth_inbound) net_outbound = ast.literal_eval(net_bandwidth_outbound) net_bridge_name = ast.literal_eval(net_bridge)["name"] iface_name = libvirt.get_ifname_host(vm_name, iface_mac) try: if check_net and net_inbound: # Check qdisc rules cmd = "tc -d qdisc show dev %s" % net_bridge_name qdisc_output = process.run(cmd, shell=True).stdout_text logging.debug("Bandwidth qdisc output: %s", qdisc_output) if not qdisc_output.count("qdisc ingress ffff:"): test.fail("Can't find ingress setting") check_class_rules(net_bridge_name, "1:1", {"average": net_inbound["average"], "peak": net_inbound["peak"]}) check_class_rules(net_bridge_name, "1:2", net_inbound) # Check filter rules on bridge interface if check_net and net_outbound: check_filter_rules(net_bridge_name, net_outbound) # Check class rules on interface inbound settings if check_iface and iface_inbound: check_class_rules(iface_name, "1:1", {'average': iface_inbound['average'], 'peak': iface_inbound['peak'], 'burst': iface_inbound['burst']}) if "floor" in iface_inbound: if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") check_class_rules(net_bridge_name, "1:3", {'floor': iface_inbound["floor"]}) # Check filter rules on interface outbound settings if check_iface and iface_outbound: check_filter_rules(iface_name, iface_outbound) except AssertionError: stacktrace.log_exc_info(sys.exc_info()) test.fail("Failed to check network bandwidth") def check_name_ip(session): """ Check dns resolving on guest """ # Check if bind-utils is installed if "ubuntu" in vm.get_distro().lower(): pkg = "bind9" else: pkg = "bind-utils" if not utils_package.package_install(pkg, session): test.error("Failed to install bind-utils on guest") # Run host command to check if hostname can be resolved if not guest_ipv4 and not guest_ipv6: test.fail("No ip address found from parameters") guest_ip = guest_ipv4 if guest_ipv4 else guest_ipv6 cmd = "host %s | grep %s" % (guest_name, guest_ip) if session.cmd_status(cmd): test.fail("Can't resolve name %s on guest" % guest_name) def check_ipt_rules(check_ipv4=True, check_ipv6=False): """ Check iptables for network/interface """ br_name = ast.literal_eval(net_bridge)["name"] net_forward = ast.literal_eval(params.get("net_forward", "{}")) net_ipv4 = params.get("net_ipv4") net_ipv6 = params.get("net_ipv6") net_dev_in = "" net_dev_out = "" if "dev" in net_forward: net_dev_in = " -i %s" % net_forward["dev"] net_dev_out = " -o %s" % net_forward["dev"] if libvirt_version.version_compare(5, 1, 0): input_chain = "LIBVIRT_INP" output_chain = "LIBVIRT_OUT" postrouting_chain = "LIBVIRT_PRT" forward_filter = "LIBVIRT_FWX" forward_in = "LIBVIRT_FWI" forward_out = "LIBVIRT_FWO" else: input_chain = "INPUT" output_chain = "OUTPUT" postrouting_chain = "POSTROUTING" forward_filter = "FORWARD" forward_in = "FORWARD" forward_out = "FORWARD" ipt_rules = ( "%s -i %s -p udp -m udp --dport 53 -j ACCEPT" % (input_chain, br_name), "%s -i %s -p tcp -m tcp --dport 53 -j ACCEPT" % (input_chain, br_name), "{0} -i {1} -o {1} -j ACCEPT".format(forward_filter, br_name), "%s -o %s -j REJECT --reject-with icmp" % (forward_in, br_name), "%s -i %s -j REJECT --reject-with icmp" % (forward_out, br_name)) if check_ipv4: ipv4_rules = list(ipt_rules) ipv4_rules.extend( ["%s -i %s -p udp -m udp --dport 67 -j ACCEPT" % (input_chain, br_name), "%s -i %s -p tcp -m tcp --dport 67 -j ACCEPT" % (input_chain, br_name), "%s -o %s -p udp -m udp --dport 68 -j ACCEPT" % (output_chain, br_name), "%s -o %s -p udp -m udp --dport 68 " "-j CHECKSUM --checksum-fill" % (postrouting_chain, br_name)]) ctr_rule = "" nat_rules = [] if "mode" in net_forward and net_forward["mode"] == "nat": nat_port = ast.literal_eval(params.get("nat_port")) p_start = nat_port["start"] p_end = nat_port["end"] ctr_rule = " -m .* RELATED,ESTABLISHED" nat_rules = [("{0} -s {1} ! -d {1} -p tcp -j MASQUERADE" " --to-ports {2}-{3}".format(postrouting_chain, net_ipv4, p_start, p_end)), ("{0} -s {1} ! -d {1} -p udp -j MASQUERADE" " --to-ports {2}-{3}".format(postrouting_chain, net_ipv4, p_start, p_end)), ("{0} -s {1} ! -d {1}" " -j MASQUERADE".format(postrouting_chain, net_ipv4))] if nat_rules: ipv4_rules.extend(nat_rules) if (net_ipv4 and "mode" in net_forward and net_forward["mode"] in ["nat", "route"]): rules = [("%s -d %s%s -o %s%s -j ACCEPT" % (forward_in, net_ipv4, net_dev_in, br_name, ctr_rule)), ("%s -s %s -i %s%s -j ACCEPT" % (forward_out, net_ipv4, br_name, net_dev_out))] ipv4_rules.extend(rules) output = process.run('iptables-save', shell=True).stdout_text logging.debug("iptables: %s", output) if "mode" in net_forward and net_forward["mode"] == "open": if re.search(r"%s|%s" % (net_ipv4, br_name), output, re.M): test.fail("Find iptable rule for open mode") utils_libvirtd.libvirtd_restart() output_again = process.run('iptables-save', shell=True).stdout_text if re.search(r"%s|%s" % (net_ipv4, br_name), output_again, re.M): test.fail("Find iptable rule for open mode after restart " "libvirtd") else: logging.info("Can't find iptable rule for open mode as expected") else: for ipt in ipv4_rules: if not re.search(r"%s" % ipt, output, re.M): test.fail("Can't find iptable rule:\n%s" % ipt) return ipv4_rules if check_ipv6: ipv6_rules = list(ipt_rules) ipt6_rules.extend([ ("INPUT -i %s -p udp -m udp --dport 547 -j ACCEPT" % br_name)]) if (net_ipv6 and "mode" in net_forward and net_forward["mode"] in ["nat", "route"]): rules = [("%s -d %s%s -o %s -j ACCEPT" % (forward_in, net_ipv6, net_dev_in, br_name)), ("%s -s %s -i %s%s -j ACCEPT" % (forward_out, net_ipv6, br_name, net_dev_out))] ipv6_rules.extend(rules) output = process.run("ip6tables-save", shell=True).stdout_text logging.debug("ip6tables: %s", output) if "mode" in net_forward and net_forward["mode"] == "open": if re.search(r"%s|%s" % (net_ipv6, br_name), output, re.M): test.fail("Find ip6table rule for open mode") utils_libvirtd.libvirtd_restart() output_again = process.run('ip6tables-save', shell=True).stdout_text if re.search(r"%s|%s" % (net_ipv6, br_name), output_again, re.M): test.fail("Find ip6table rule for open mode after restart " "libvirtd") else: for ipt in ipv6_rules: if not re.search(r"%s" % ipt, output, re.M): test.fail("Can't find ip6table rule:\n%s" % ipt) return ipv6_rules def run_ip_test(session, ip_ver): """ Check iptables on host and ipv6 address on guest """ if ip_ver == "ipv6": # Clean up iptables rules for guest to get ipv6 address session.cmd_status("ip6tables -F") # It may take some time to get the ip address def get_ip_func(): return utils_net.get_guest_ip_addr(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) if not get_ip_func(): utils_net.restart_guest_network(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) vm_ip = get_ip_func() logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: test.fail("Can't find ip address on guest") ip_gateway = net_ip_address if ip_ver == "ipv6": ip_gateway = net_ipv6_address # Cleanup ip6talbes on host for ping6 test process.system("ip6tables -F") if ip_gateway and not routes: ping_s, _ = ping(dest=ip_gateway, count=5, timeout=10, session=session) if ping_s: test.fail("Failed to ping gateway address: %s" % ip_gateway) def run_guest_libvirt(session): """ Check guest libvirt network """ # Try to install required packages if "ubuntu" in vm.get_distro().lower(): pkg = "libvirt-bin" else: pkg = "libvirt" if not utils_package.package_install(pkg, session): test.error("Failed to install libvirt package on guest") # Try to load tun module first session.cmd("lsmod | grep tun || modprobe tun") # Check network state on guest cmd = ("service libvirtd restart; virsh net-info default" " | grep 'Active:.*yes'") if session.cmd_status(cmd): test.fail("'default' network isn't in active state") # Try to destroy&start default network on guest for opt in ['net-destroy', 'net-start']: cmd = "virsh %s default" % opt status, output = session.cmd_status_output(cmd) logging.debug("Run %s on guest exit %s, output %s" % (cmd, status, output)) if status: test.fail(output) if not utils_package.package_remove("libvirt*", session): test.error("Failed to remove libvirt packages on guest") start_error = "yes" == params.get("start_error", "no") define_error = "yes" == params.get("define_error", "no") restart_error = "yes" == params.get("restart_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") net_domain = params.get("net_domain") net_ip_address = params.get("net_ip_address") net_ipv6_address = params.get("net_ipv6_address") net_dns_forward = params.get("net_dns_forward") net_dns_txt = params.get("net_dns_txt") net_dns_srv = params.get("net_dns_srv") net_dns_hostip = params.get("net_dns_hostip") net_dns_hostnames = params.get("net_dns_hostnames", "").split() dhcp_start_ipv4 = params.get("dhcp_start_ipv4") dhcp_end_ipv4 = params.get("dhcp_end_ipv4") dhcp_start_ipv6 = params.get("dhcp_start_ipv6") dhcp_end_ipv6 = params.get("dhcp_end_ipv6") guest_name = params.get("guest_name") guest_ipv4 = params.get("guest_ipv4") guest_ipv6 = params.get("guest_ipv6") tftp_root = params.get("tftp_root") pxe_boot = "yes" == params.get("pxe_boot", "no") routes = params.get("routes", "").split() net_bandwidth_inbound = params.get("net_bandwidth_inbound", "{}") net_bandwidth_outbound = params.get("net_bandwidth_outbound", "{}") iface_bandwidth_inbound = params.get("iface_bandwidth_inbound", "{}") iface_bandwidth_outbound = params.get("iface_bandwidth_outbound", "{}") iface_num = params.get("iface_num", "1") iface_source = params.get("iface_source", "{}") iface_rom = params.get("iface_rom") iface_boot = params.get("iface_boot") iface_model = params.get("iface_model") multiple_guests = params.get("multiple_guests") create_network = "yes" == params.get("create_network", "no") attach_iface = "yes" == params.get("attach_iface", "no") serial_login = "******" == params.get("serial_login", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_bridge = "yes" == params.get("test_bridge", "no") test_dnsmasq = "yes" == params.get("test_dnsmasq", "no") test_dhcp_range = "yes" == params.get("test_dhcp_range", "no") test_dns_host = "yes" == params.get("test_dns_host", "no") test_qos_bandwidth = "yes" == params.get("test_qos_bandwidth", "no") test_pg_bandwidth = "yes" == params.get("test_portgroup_bandwidth", "no") test_qos_remove = "yes" == params.get("test_qos_remove", "no") test_ipv4_address = "yes" == params.get("test_ipv4_address", "no") test_ipv6_address = "yes" == params.get("test_ipv6_address", "no") test_guest_libvirt = "yes" == params.get("test_guest_libvirt", "no") test_dns_forwarders = "yes" == params.get("test_dns_forwarders", "no") net_no_bridge = "yes" == params.get("no_bridge", "no") net_no_mac = "yes" == params.get("no_mac", "no") net_no_ip = "yes" == params.get("no_ip", "no") net_with_dev = "yes" == params.get("with_dev", "no") update_device = 'yes' == params.get('update_device', 'no') remove_bandwidth = 'yes' == params.get('remove_bandwidth', 'no') loop = int(params.get('loop', 0)) username = params.get("username") password = params.get("password") forward = ast.literal_eval(params.get("net_forward", "{}")) boot_failure = "yes" == params.get("boot_failure", "no") test_netmask = "yes" == params.get("test_netmask", "no") ipt_rules = [] ipt6_rules = [] define_macvtap = "yes" == params.get("define_macvtap", "no") net_dns_forwarders = params.get("net_dns_forwarders", "").split() # Destroy VM first if vm.is_alive() and not update_device: 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) vms_list = [] if "floor" in ast.literal_eval(iface_bandwidth_inbound): if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") # Enabling IPv6 forwarding with RA routes without accept_ra set to 2 # is likely to cause routes loss sysctl_cmd = 'sysctl net.ipv6.conf.all.accept_ra' original_accept_ra = process.run(sysctl_cmd + ' -n', shell=True).stdout_text if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + '=2') # Build the xml and run test. try: if test_dnsmasq: # Check the settings before modifying network xml if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed", exists=False) run_dnsmasq_default_test("local", "//", exists=False) if net_domain: run_dnsmasq_default_test("domain", net_domain, exists=False) run_dnsmasq_default_test("expand-hosts", exists=False) # Prepare pxe boot directory if pxe_boot: prepare_pxe_boot() # Edit the network xml or create a new one. if create_network: net_ifs = utils_net.get_net_if(state="UP") # Check forward device is valid or not, # if it's not in host interface list, try to set # forward device to first active interface of host if ('mode' in forward and forward['mode'] in ['passthrough', 'private', 'bridge', 'macvtap'] and 'dev' in forward and forward['dev'] not in net_ifs): logging.warning("Forward device %s is not a interface of host, reset to %s", forward['dev'], net_ifs[0]) forward['dev'] = net_ifs[0] params["net_forward"] = str(forward) if define_macvtap: for i in [0, 2, 4]: cmd = "ip l add li %s macvtap%s type macvtap" % (forward['dev'], i) process.run(cmd, shell=True, verbose=True) process.run("ip l", shell=True, verbose=True) forward_iface = params.get("forward_iface") if forward_iface: interface = [x for x in forward_iface.split()] # The guest will use first interface of the list, # check if it's valid or not, if it's not in host # interface list, try to set forward interface to # first active interface of host. if interface[0] not in net_ifs: logging.warning("Forward interface %s is not a interface of host, reset to %s", interface[0], net_ifs[0]) interface[0] = net_ifs[0] params["forward_iface"] = " ".join(interface) netxml = libvirt.create_net_xml(net_name, params) if "mode" in forward and forward["mode"] == "open": netxml.mac = utils_net.generate_mac_address_simple() try: if net_no_bridge: netxml.del_bridge() if net_no_ip: netxml.del_ip() netxml.del_ip() if net_no_mac: netxml.del_mac() except xcepts.LibvirtXMLNotFoundError: pass if net_with_dev: net_forward = netxml.forward net_forward.update({"dev": net_ifs[0]}) netxml.forward = net_forward logging.info("netxml before define is %s", netxml) try: netxml.sync() except xcepts.LibvirtXMLError as details: logging.info(str(details)) if define_error: return else: test.fail("Failed to define network") # Check open mode network xml if "mode" in forward and forward["mode"] == "open": netxml_new = NetworkXML.new_from_net_dumpxml(net_name) logging.info("netxml after define is %s", netxml_new) try: if net_no_bridge: net_bridge = str(netxml_new.bridge) if net_no_mac: netxml_new.mac except xcepts.LibvirtXMLNotFoundError as details: test.fail("Failed to check %s xml: %s" % (net_name, details)) logging.info("mac/bridge still exist even if removed before define") # Edit the interface xml. if change_iface_option: try: if update_device: updated_iface = modify_iface_xml(sync=False) virsh.update_device(vm_name, updated_iface.xml, ignore_status=False, debug=True) else: modify_iface_xml() except xcepts.LibvirtXMLError as details: logging.info(str(details)) if define_error: if not str(details).count("Failed to define"): test.fail("VM sync failed msg not expected") return else: test.fail("Failed to sync VM") # Attach interface if needed if attach_iface: iface_type = params.get("iface_type", "network") for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) options = ("%s %s --model %s --config" % (iface_type, net_name, iface_model)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: logging.error("Command output %s" % ret.stdout.strip()) test.fail("Failed to attach-interface") if multiple_guests: # Clone more vms for testing for i in range(int(multiple_guests)): guest_name = "%s_%s" % (vm_name, i) timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout) vms_list.append(vm.clone(guest_name)) if test_bridge: bridge = ast.literal_eval(net_bridge) br_if = utils_net.Interface(bridge['name']) if not br_if.is_up(): test.fail("Bridge interface isn't up") if test_dnsmasq: # Check dnsmasq process dnsmasq_cmd = process.run("ps -aux|grep dnsmasq", shell=True).stdout_text logging.debug(dnsmasq_cmd) if not re.search("dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/%s.conf" % net_name, dnsmasq_cmd): test.fail("Can not find dnsmasq process or the process is not correct") # Check the settings in dnsmasq config file if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed") run_dnsmasq_default_test("local", "//") if net_domain: run_dnsmasq_default_test("domain", net_domain) run_dnsmasq_default_test("expand-hosts") if net_bridge: bridge = ast.literal_eval(net_bridge) run_dnsmasq_default_test("interface", bridge['name'], name=net_name) if 'stp' in bridge and bridge['stp'] == 'on': if 'delay' in bridge and bridge['delay'] != '0': # network xml forward delay value in seconds, while on # host, check by ip command, the value is in second*100 br_delay = int(bridge['delay']) * 100 logging.debug("Expect forward_delay is %s ms" % br_delay) cmd = ("ip -d link sh %s | grep 'bridge forward_delay'" % bridge['name']) out = process.run( cmd, shell=True, ignore_status=False).stdout_text logging.debug("bridge statistics output: %s", out) pattern = (r"\s*bridge forward_delay\s+(\d+)") match_obj = re.search(pattern, out, re.M) if not match_obj: test.fail("Can't see forward delay messages from command") elif int(match_obj.group(1)) != br_delay: test.fail("Foward delay setting can't take effect") else: logging.debug("Foward delay set successfully!") if dhcp_start_ipv4 and dhcp_end_ipv4: run_dnsmasq_default_test("dhcp-range", "%s,%s" % (dhcp_start_ipv4, dhcp_end_ipv4), name=net_name) if dhcp_start_ipv6 and dhcp_end_ipv6: run_dnsmasq_default_test("dhcp-range", "%s,%s,64" % (dhcp_start_ipv6, dhcp_end_ipv6), name=net_name) if guest_name and guest_ipv4: run_dnsmasq_host_test(iface_mac, guest_ipv4, guest_name) if test_netmask and libvirt_version.version_compare(5, 1, 0): run_dnsmasq_default_test("dhcp-range", "192.168.122.2,192.168.122.254,255.255.252.0") # check the left part in dnsmasq conf run_dnsmasq_default_test("strict-order", name=net_name) if libvirt_version.version_compare(6, 0, 0): run_dnsmasq_default_test("pid-file", "/run/libvirt/network/%s.pid" % net_name, name=net_name) else: run_dnsmasq_default_test("pid-file", "/var/run/libvirt/network/%s.pid" % net_name, name=net_name) run_dnsmasq_default_test("except-interface", "lo", name=net_name) run_dnsmasq_default_test("bind-dynamic", name=net_name) run_dnsmasq_default_test("dhcp-no-override", name=net_name) if dhcp_start_ipv6 and dhcp_start_ipv4: run_dnsmasq_default_test("dhcp-lease-max", "493", name=net_name) else: range_num = int(params.get("dhcp_range", "252")) run_dnsmasq_default_test("dhcp-lease-max", str(range_num + 1), name=net_name) run_dnsmasq_default_test("dhcp-hostsfile", "/var/lib/libvirt/dnsmasq/%s.hostsfile" % net_name, name=net_name) run_dnsmasq_default_test("addn-hosts", "/var/lib/libvirt/dnsmasq/%s.addnhosts" % net_name, name=net_name) if dhcp_start_ipv6: run_dnsmasq_default_test("enable-ra", name=net_name) if test_dns_host: if net_dns_txt: dns_txt = ast.literal_eval(net_dns_txt) run_dnsmasq_default_test("txt-record", "%s,%s" % (dns_txt["name"], dns_txt["value"])) if net_dns_srv: dns_srv = ast.literal_eval(net_dns_srv) run_dnsmasq_default_test("srv-host", "_%s._%s.%s,%s,%s,%s,%s" % (dns_srv["service"], dns_srv["protocol"], dns_srv["domain"], dns_srv["target"], dns_srv["port"], dns_srv["priority"], dns_srv["weight"])) if net_dns_hostip and net_dns_hostnames: run_dnsmasq_addnhosts_test(net_dns_hostip, net_dns_hostnames) if test_dns_forwarders: if net_name == "isolatedtest": run_dnsmasq_default_test("no-resolv", name=net_name) else: net_dns_forwarder = [ast.literal_eval(x) for x in net_dns_forwarders] for forwarder in net_dns_forwarder: if ('domain' in forwarder) and ('addr' in forwarder): run_dnsmasq_default_test("server", "/%s/%s" % (forwarder['domain'], forwarder['addr'])) elif "domain" in forwarder: run_dnsmasq_default_test("server", "/%s/#" % forwarder['domain']) elif "addr" in forwarder: run_dnsmasq_default_test("server", "%s" % forwarder['addr']) run_dnsmasq_default_test("no-resolv") # Run bandwidth test for network if test_qos_bandwidth and not update_device: run_bandwidth_test(check_net=True) # If to remove bandwidth from iface, # update iface xml to the original one if remove_bandwidth: ori_iface = params['original_iface'] logging.debug(ori_iface) virsh.update_device(vm_name, ori_iface.xml, ignore_status=False, debug=True) # Check routes if needed if routes: check_host_routes() try: # Start the VM. if not update_device: vm.start() if start_error: test.fail("VM started unexpectedly") if define_macvtap: cmd = "ls /sys/devices/virtual/net" output = process.run(cmd, shell=True, verbose=True).stdout_text macvtap_list = re.findall(r'macvtap0|macvtap1|macvtap2|macvtap3' r'|macvtap4|macvtap5|macvtap6|macvtap7', output) logging.debug("The macvtap_list is %s" % macvtap_list) if set(macvtap_list) != set(['macvtap' + str(x) for x in range(8)]): test.fail("Existing macvtap device %s is not expected! should be macvtap(0-7)" % macvtap_list) if pxe_boot: # Just check network boot messages here try: vm.serial_console.read_until_output_matches( ["Loading vmlinuz", "Loading initrd.img"], utils_misc.strip_console_codes) except ExpectTimeoutError as details: if boot_failure: logging.info("Fail to boot from pxe as expected") else: test.fail("Fail to boot from pxe") else: if serial_login: session = vm.wait_for_serial_login(username=username, password=password) else: session = vm.wait_for_login() if test_dhcp_range: dhcp_range = int(params.get("dhcp_range", "252")) utils_net.restart_guest_network(session, iface_mac) vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vm_ip and not dhcp_range: test.fail("Guest has ip address: %s" % vm_ip) dhcp_range = dhcp_range - 1 for vms in vms_list: # Start other VMs. vms.start() sess = vms.wait_for_serial_login() vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) vms_ip = utils_net.get_guest_ip_addr(sess, vms_mac) if not vms_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vms_ip and not dhcp_range: # Get IP address on guest should return Null # if it exceeds the dhcp range test.fail("Guest has ip address: %s" % vms_ip) dhcp_range = dhcp_range - 1 if vms_ip: ping_s, _ = ping(dest=vm_ip, count=5, timeout=10, session=sess) if ping_s: test.fail("Failed to ping, src: %s, " "dst: %s" % (vms_ip, vm_ip)) sess.close() # Check dnsmasq settings if take affect in guest if guest_ipv4: check_name_ip(session) # Run bandwidth test for interface if test_qos_bandwidth: run_bandwidth_test(check_iface=True) # Run bandwidth test for portgroup if test_pg_bandwidth: pg_bandwidth_inbound = params.get( "portgroup_bandwidth_inbound", "").split() pg_bandwidth_outbound = params.get( "portgroup_bandwidth_outbound", "").split() pg_name = params.get("portgroup_name", "").split() pg_default = params.get("portgroup_default", "").split() iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if_source = ast.literal_eval(iface_source) if "portgroup" in if_source: pg = if_source["portgroup"] else: pg = "default" for (name, df, bw_ib, bw_ob) in zip(pg_name, pg_default, pg_bandwidth_inbound, pg_bandwidth_outbound): if pg == name: inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) elif pg == "default" and df == "yes": inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) else: continue # Interface bandwidth settings will # overwriting portgroup settings if iface_inbound: inbound = iface_inbound if iface_outbound: outbound = iface_outbound check_class_rules(iface_name, "1:1", inbound) check_filter_rules(iface_name, outbound) if test_qos_remove: # Remove the bandwidth settings in network xml logging.debug("Removing network bandwidth settings...") netxml_backup.sync() vm.destroy(gracefully=False) # Should fail to start vm vm.start() if restart_error: test.fail("VM started unexpectedly") if test_ipv6_address: ipt6_rules = check_ipt_rules(check_ipv4=False, check_ipv6=True) if not ("mode" in forward and forward["mode"] == "open"): run_ip_test(session, "ipv6") if test_ipv4_address: ipt_rules = check_ipt_rules(check_ipv4=True) if not ("mode" in forward and forward["mode"] == "open"): run_ip_test(session, "ipv4") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError as details: logging.info(str(details)) if not (start_error or restart_error): test.fail('VM failed to start:\n%s' % details) # Destroy created network and check iptable rules if net_name != "default": virsh.net_destroy(net_name) if ipt_rules: output_des = process.run('iptables-save', shell=True).stdout_text for ipt in ipt_rules: if re.search(r"%s" % ipt, output_des, re.M): test.fail("Find iptable rule %s after net destroyed" % ipt) if ipt6_rules: output_des = process.run('ip6tables-save', shell=True).stdout_text for ipt in ipt6_rules: if re.search(r"%s" % ipt, output_des, re.M): test.fail("Find ip6table rule %s after net destroyed" % ipt) if remove_bandwidth: iface_name = libvirt.get_ifname_host(vm_name, iface_mac) cur_xml = virsh.dumpxml(vm_name).stdout_text logging.debug(cur_xml) if 'bandwidth' in cur_xml: test.fail('bandwidth still in xml') if not check_filter_rules(iface_name, 0, expect_none=True): test.fail('There should be nothing in output') if update_device and loop: loop -= 1 if loop: # Rerun this procedure again with updated params # Reset params of the corresponding loop loop_prefix = 'loop' + str(loop) + '_' for k in {k: v for k, v in params.items() if k.startswith(loop_prefix)}: params[k.lstrip(loop_prefix)] = params[k] params['loop'] = str(loop) run(test, params, env) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) for vms in vms_list: virsh.remove_domain(vms.name, "--remove-all-storage") 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) vmxml_backup.sync() if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + "=%s" % original_accept_ra) if define_macvtap: cmd = "ip l del macvtap0; ip l del macvtap2; ip l del macvtap4" process.run(cmd, shell=True, verbose=True)
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 interface devices update """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) network_name = params.get('network_name', 'default') new_network_name = params.get("net_name") expect_error = "yes" == params.get("status_error", "no") expect_err_msg = params.get("expect_err_msg") iface_driver = params.get("iface_driver") iface_driver_host = params.get("iface_driver_host") iface_driver_guest = params.get("iface_driver_guest") iface_model = params.get("iface_model") iface_mtu = params.get("iface_mtu") iface_rom = params.get("iface_rom") iface_filter = params.get("iface_filter") iface_boot = params.get('iface_boot') iface_coalesce = params.get('iface_coalesce') new_iface_driver = params.get("new_iface_driver") new_iface_driver_host = params.get("new_iface_driver_host") new_iface_driver_guest = params.get("new_iface_driver_guest") new_iface_model = params.get("new_iface_model") new_iface_rom = params.get("new_iface_rom") new_iface_inbound = params.get("new_iface_inbound") new_iface_outbound = params.get("new_iface_outbound") new_iface_link = params.get("new_iface_link") new_iface_source = params.get("new_iface_source") new_iface_target = params.get("new_iface_target") new_iface_addr = params.get("new_iface_addr") new_iface_filter = params.get("new_iface_filter") new_iface_mtu = params.get("new_iface_mtu") new_iface_type = params.get("new_iface_type") create_new_net = "yes" == params.get("create_new_net") new_iface_alias = params.get("new_iface_alias") new_iface_coalesce = params.get('new_iface_coalesce') cold_update = "yes" == params.get("cold_update", "no") del_addr = "yes" == params.get("del_address") del_rom = "yes" == params.get("del_rom") del_filter = "yes" == params.get("del_filter") check_libvirtd = "yes" == params.get("check_libvirtd") new_iface_filter_parameters = eval( params.get("new_iface_filter_parameters", "{}")) rules = eval(params.get("rules", "{}")) del_mac = "yes" == params.get("del_mac", "no") del_coalesce = 'yes' == params.get('del_coalesce', 'no') del_net_bandwidth = 'yes' == params.get('del_net_bandwidth', 'no') # Backup the vm xml for recover at last vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) netxml_backup = network_xml.NetworkXML.new_from_net_dumpxml(network_name) try: # Prepare network netxml = network_xml.NetworkXML.new_from_net_dumpxml(network_name) logging.debug('Network xml before update:\n%s', netxml) if del_net_bandwidth: netxml.del_element('/bandwidth') logging.debug('Network xml after update:\n%s', netxml) # According to the different os find different file for rom if (iface_rom and "file" in eval(iface_rom) and "%s" in eval(iface_rom)['file']): if rpm.RpmBackend().check_installed('ipxe-roms-qemu', '20200823'): logging.debug("Update the file path since " "ipxe-20200823-5:") iface_rom_new = iface_rom.replace('qemu-kvm', 'ipxe/qemu') iface_rom = iface_rom_new if os.path.exists(eval(iface_rom)['file'] % "pxe"): iface_rom = iface_rom % "pxe" elif os.path.exists(eval(iface_rom)['file'] % "efi"): iface_rom = iface_rom % "efi" else: logging.error("Can not find suitable rom file") iface_dict_bef = {} iface_dict_aft = {} names = locals() # Collect need update items in 2 dicts for both start vm before and after update_list_bef = [ "driver", 'driver_host', 'driver_guest', "model", "mtu", "rom", "filter", 'boot', 'coalesce' ] for update_item_bef in update_list_bef: if names['iface_' + update_item_bef]: iface_dict_bef.update( {update_item_bef: names['iface_' + update_item_bef]}) update_list_aft = [ "driver", "driver_host", "driver_guest", "model", "rom", "inbound", "outbound", "link", "source", "target", "addr", "filter", "mtu", "type", "alias", "filter_parameters", "coalesce" ] for update_item_aft in update_list_aft: if names["new_iface_" + update_item_aft]: iface_dict_aft.update( {update_item_aft: names["new_iface_" + update_item_aft]}) logging.info("iface_dict_bef is %s, iface_dict_aft is %s", iface_dict_bef, iface_dict_aft) del_list = [ "del_addr", "del_rom", "del_filter", "del_mac", "del_coalesce" ] for del_item in del_list: if names[del_item]: iface_dict_aft.update({del_item: names[del_item]}) # Operations before updating vm's iface xml if iface_boot: disk_boot = params.get('disk_book', 1) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) # Remove os boot config vm_os = vmxml.os vm_os.del_boots() vmxml.os = vm_os # Add boot config to disk disk = vmxml.get_devices('disk')[0] target_dev = disk.target.get('dev', '') logging.debug('Will set boot order %s to device %s', disk_boot, target_dev) vmxml.set_boot_order_by_target_dev(target_dev, disk_boot) vmxml.sync() # Update vm interface with items in iface_dict_bef and start it if iface_dict_bef: libvirt.modify_vm_iface(vm_name, "update_iface", iface_dict_bef) logging.info("vm xml is %s", vm.get_xml()) if not cold_update: vm.start() if iface_mtu: # Do check for mtu size after start vm target_dev = libvirt.get_interface_details(vm_name)[0]['interface'] cmd = "ip link show %s | grep 'mtu %s'" % (target_dev, eval(iface_mtu)['size']) def check_mtu(): """ Check the mtu setting take effect for interface """ ret = process.run(cmd, ignore_status=True, shell=True) if ret.exit_status: test.fail("Can not find mtu setting in cmd result") check_mtu() utils_libvirtd.libvirtd_restart() check_mtu() # Create new network if need if create_new_net: new_net_xml = libvirt.create_net_xml(new_network_name, params) new_net_xml.sync() # Do update for iface_driver logging.info('Creating new iface xml.') new_iface_xml = libvirt.modify_vm_iface(vm_name, "get_xml", iface_dict_aft) bef_pid = process.getoutput("pidof -s libvirtd") ret = virsh.update_device(vm_name, new_iface_xml, ignore_status=True, debug=True) libvirt.check_exit_status(ret, expect_error) if check_libvirtd: aft_pid = process.getoutput("pidof -s libvirtd") if aft_pid != bef_pid: test.fail("libvirtd crash after update-device!") else: logging.info("libvirtd do not crash after update-device!") if expect_error: real_err_msg = ret.stderr.strip() if not re.search(expect_err_msg, real_err_msg, re.IGNORECASE): test.fail("The real error msg:'%s' does not match expect one:" '%s' % (real_err_msg, expect_err_msg)) else: logging.info("Get expect result: %s", real_err_msg) else: if new_iface_inbound: iface_bandwidth = {} iface_bandwidth = vm_xml.VMXML.get_iftune_params(vm_name) for bound_para in ["inbound", "outbound"]: for tune_para in ["average", "peak", "burst"]: get_value = iface_bandwidth.get(bound_para).get( tune_para) expect_value = eval(names["new_iface_" + bound_para]).get(tune_para) logging.info("Get value for %s:%s is %s, expect is %s", bound_para, tune_para, get_value, expect_value) if get_value != expect_value: test.fail("Get value is not equal to expect") vmxml_aft = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_aft = list(vmxml_aft.get_iface_all().values())[0] if new_iface_link: iface_link_value = iface_aft.find('link').get('state') if iface_link_value == new_iface_link: logging.info("Find link state is %s in xml", new_iface_link) # Checking the statue in guest mac_addr = iface_aft.find('mac').get('address') state_map = "%s.*\n.*%s" % (iface_link_value.upper(), mac_addr) session = vm.wait_for_serial_login() logging.info("ip link output:%s", session.cmd_output("ip link")) if_name = utils_net.get_net_if(runner=session.cmd_output, state=state_map)[0] if not check_iface_link(session, mac_addr, new_iface_link): test.fail('iface link check inside vm failed.') session.close() if if_name: logging.info("Find iface state %s for %s", iface_link_value, mac_addr) else: test.fail( "Can not find iface with mac %s and state %s" % (mac_addr, iface_link_value)) else: test.fail( "Check fail to get link state, expect %s, but get %s" % (iface_link_value, new_iface_link)) if create_new_net and new_iface_source: iface_source_value = iface_aft.find('source').get('network') if iface_source_value == eval(new_iface_source)['network']: logging.info("Get %s in xml as set", iface_source_value) else: test.fail("Get source %s is not equal to set %s" % (iface_source_value, new_iface_source)) if new_iface_filter: iface_filter_value = iface_aft.find('filterref').get('filter') if iface_filter_value == new_iface_filter: logging.info("Get %s in xml as set", iface_filter_value) else: test.fail("Get filter %s is not equal to set %s" % (iface_filter_value, new_iface_filter)) if new_iface_filter_parameters: ebtables_outputs = process.run("ebtables -t nat -L", shell=True).stdout_text for rule in rules: if rule not in ebtables_outputs: test.fail( "Can not find the corresponding rule after update filter with parameters!" ) if del_filter: # if the filter is deleted, it should not exists in the xml and the rules should be deleted as well iface_filter_value = iface_aft.find('filterref') if iface_filter_value is not None: test.fail("After delete, the filter still exists: %s" % iface_filter_value) ebtables_outputs = process.run("ebtables -t nat -L", shell=True).stdout_text logging.debug("after nwfilter deleted, ebtables rules are %s" % ebtables_outputs) time.sleep(5) entries_num = re.findall(r'entries:\s+(\d)', ebtables_outputs) for i in entries_num: if i != '0': test.fail("After delete, the rules are still exists!") if new_iface_alias: iface_alias_value = iface_aft.find('alias').get('name') if iface_alias_value == eval(new_iface_alias)['name']: logging.info("Get %s in xml as set", iface_alias_value) else: test.fail("Get alias %s is not equal to set %s" % (iface_alias_value, new_iface_alias)) if 'update_coalesce' in params['name'] or new_iface_coalesce: iface_coalesce_val = iface_aft.find('coalesce').find( 'rx').find('frames').get('max') if iface_coalesce_val == str(eval(new_iface_coalesce)['max']): logging.info('coalesce update check PASS.') else: test.fail('coalesce value not updated.') if del_coalesce: if iface_aft.find('coalesce') is None: logging.info('coalesce delete check PASS.') else: test.fail('coalesce not deleted.') finally: vmxml_backup.sync() netxml_backup.sync() if create_new_net: new_net_xml.undefine()
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 interface devices update """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) new_network_name = params.get("net_name") expect_error = "yes" == params.get("status_error", "no") expect_err_msg = params.get("expect_err_msg") iface_driver = params.get("iface_driver") iface_model = params.get("iface_model") iface_mtu = params.get("iface_mtu") iface_rom = params.get("iface_rom") iface_filter = params.get("iface_filter") new_iface_driver = params.get("new_iface_driver") new_iface_driver_host = params.get("new_iface_driver_host") new_iface_driver_guest = params.get("new_iface_driver_guest") new_iface_model = params.get("new_iface_model") new_iface_rom = params.get("new_iface_rom") new_iface_inbound = params.get("new_iface_inbound") new_iface_outbound = params.get("new_iface_outbound") new_iface_link = params.get("new_iface_link") new_iface_source = params.get("new_iface_source") new_iface_target = params.get("new_iface_target") new_iface_addr = params.get("new_iface_addr") new_iface_filter = params.get("new_iface_filter") new_iface_mtu = params.get("new_iface_mtu") new_iface_type = params.get("new_iface_type") create_new_net = "yes" == params.get("create_new_net") new_iface_alias = params.get("new_iface_alias") cold_update = "yes" == params.get("cold_update", "no") del_addr = "yes" == params.get("del_address") del_rom = "yes" == params.get("del_rom") del_filter = "yes" == params.get("del_filter") # Backup the vm xml for recover at last vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: # According to the different os find different file for rom if (iface_rom and "file" in eval(iface_rom) and "%s" in eval(iface_rom)['file']): if os.path.exists(eval(iface_rom)['file'] % "pxe"): iface_rom = iface_rom % "pxe" elif os.path.exists(eval(iface_rom)['file'] % "efi"): iface_rom = iface_rom % "efi" else: logging.error("Can not find suitable rom file") iface_dict_bef = {} iface_dict_aft = {} names = locals() # Collect need update items in 2 dicts for both start vm before and after update_list_bef = ["driver", "model", "mtu", "rom", "filter"] for update_item_bef in update_list_bef: if names['iface_' + update_item_bef]: iface_dict_bef.update( {update_item_bef: names['iface_' + update_item_bef]}) update_list_aft = [ "driver", "driver_host", "driver_guest", "model", "rom", "inbound", "outbound", "link", "source", "target", "addr", "filter", "mtu", "type", "alias" ] for update_item_aft in update_list_aft: if names["new_iface_" + update_item_aft]: iface_dict_aft.update( {update_item_aft: names["new_iface_" + update_item_aft]}) logging.info("iface_dict_bef is %s, iface_dict_aft is %s", iface_dict_bef, iface_dict_aft) del_list = ["del_addr", "del_rom", "del_filter"] for del_item in del_list: if names[del_item]: iface_dict_aft.update({del_item: "True"}) # Update vm interface with items in iface_dict_bef and start it if iface_dict_bef: libvirt.modify_vm_iface(vm_name, "update_iface", iface_dict_bef) logging.info("vm xml is %s", vm.get_xml()) if not cold_update: vm.start() if iface_mtu: # Do check for mtu size after start vm target_dev = libvirt.get_interface_details(vm_name)[0]['interface'] cmd = "ip link show %s | grep 'mtu %s'" % (target_dev, eval(iface_mtu)['size']) def check_mtu(): """ Check the mtu setting take effect for interface """ ret = process.run(cmd, ignore_status=True, shell=True) if ret.exit_status: test.fail("Can not find mtu setting in cmd result") check_mtu() utils_libvirtd.libvirtd_restart() check_mtu() # Create new network if need if create_new_net: new_net_xml = libvirt.create_net_xml(new_network_name, params) new_net_xml.sync() # Do update for iface_driver new_iface_xml = libvirt.modify_vm_iface(vm_name, "get_xml", iface_dict_aft) ret = virsh.update_device(vm_name, new_iface_xml, ignore_status=True, debug=True) libvirt.check_exit_status(ret, expect_error) if expect_error: real_err_msg = ret.stderr.strip() if not re.search(expect_err_msg, real_err_msg, re.IGNORECASE): test.fail("The real error msg:'%s' does not match expect one:" '%s' % (real_err_msg, expect_err_msg)) else: logging.info("Get expect result: %s", real_err_msg) else: if new_iface_inbound: iface_bandwidth = {} iface_bandwidth = vm_xml.VMXML.get_iftune_params(vm_name) for bound_para in ["inbound", "outbound"]: for tune_para in ["average", "peak", "burst"]: get_value = iface_bandwidth.get(bound_para).get( tune_para) expect_value = eval(names["new_iface_" + bound_para]).get(tune_para) logging.info("Get value for %s:%s is %s, expect is %s", bound_para, tune_para, get_value, expect_value) if get_value != expect_value: test.fail("Get value is not equal to expect") vmxml_aft = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_aft = list(vmxml_aft.get_iface_all().values())[0] if new_iface_link: iface_link_value = iface_aft.find('link').get('state') if iface_link_value == new_iface_link: logging.info("Find link state is %s in xml", new_iface_link) # Checking the statue in guest mac_addr = iface_aft.find('mac').get('address') state_map = "%s.*\n.*%s" % (iface_link_value.upper(), mac_addr) session = vm.wait_for_serial_login() logging.info("ip link output:%s", session.cmd_output("ip link")) if_name = utils_net.get_net_if(runner=session.cmd_output, state=state_map)[0] session.close() if if_name: logging.info("Find iface state %s for %s", iface_link_value, mac_addr) else: test.fail( "Can not find iface with mac %s and state %s" % (mac_addr, iface_link_value)) else: test.fail( "Check fail to get link state, expect %s, but get %s" % (iface_link_value, new_iface_link)) if create_new_net and new_iface_source: iface_source_value = iface_aft.find('source').get('network') if iface_source_value == eval(new_iface_source)['network']: logging.info("Get %s in xml as set", iface_source_value) else: test.fail("Get source %s is not equal to set %s" % (iface_source_value, new_iface_source)) if new_iface_filter: iface_filter_value = iface_aft.find('filterref').get('filter') if iface_filter_value == new_iface_filter: logging.info("Get %s in xml as set", iface_filter_value) else: test.fail("Get filter %s is not equal to set %s" % (iface_filter_value, new_iface_filter)) if del_filter: iface_filter_value = iface_aft.find('filterref') if iface_filter_value: logging.debug("After delete, the filter still exists: %s", iface_filter_value) if new_iface_alias: iface_alias_value = iface_aft.find('alias').get('name') if iface_alias_value == eval(new_iface_alias)['name']: logging.info("Get %s in xml as set", iface_alias_value) else: test.fail("Get alias %s is not equal to set %s" % (iface_alias_value, new_iface_alias)) finally: vmxml_backup.sync() if create_new_net: new_net_xml.undefine()
def run(test, params, env): """ Test interafce xml options. 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 prepare_pxe_boot(): """ Prepare tftp server and pxe boot files """ pkg_list = ["syslinux", "tftp-server", "tftp", "ipxe-roms-qemu", "wget"] # Try to install required packages if not utils_package.package_install(pkg_list): test.error("Failed ot install required packages") boot_initrd = params.get("boot_initrd", "EXAMPLE_INITRD") boot_vmlinuz = params.get("boot_vmlinuz", "EXAMPLE_VMLINUZ") if boot_initrd.count("EXAMPLE") or boot_vmlinuz.count("EXAMPLE"): test.cancel("Please provide initrd/vmlinuz URL") # Download pxe boot images process.system("wget %s -O %s/initrd.img" % (boot_initrd, tftp_root)) process.system("wget %s -O %s/vmlinuz" % (boot_vmlinuz, tftp_root)) process.system("cp -f /usr/share/syslinux/pxelinux.0 {0};" " mkdir -m 777 -p {0}/pxelinux.cfg".format(tftp_root), shell=True) pxe_file = "%s/pxelinux.cfg/default" % tftp_root boot_txt = """ DISPLAY boot.txt DEFAULT rhel LABEL rhel kernel vmlinuz append initrd=initrd.img PROMPT 1 TIMEOUT 3""" with open(pxe_file, 'w') as p_file: p_file.write(boot_txt) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if pxe_boot: # Config boot console for pxe boot osxml = vm_xml.VMOSXML() osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" osxml.bios_reboot_timeout = "-1" osxml.boots = ['network'] del vmxml.os vmxml.os = osxml xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_bandwidth = {} iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) if iface_inbound: iface_bandwidth["inbound"] = iface_inbound if iface_outbound: iface_bandwidth["outbound"] = iface_outbound if iface_bandwidth: bandwidth = iface.new_bandwidth(**iface_bandwidth) iface.bandwidth = bandwidth iface_type = params.get("iface_type", "network") iface.type_name = iface_type source = ast.literal_eval(iface_source) if not source: source = {"network": "default"} net_ifs = utils_net.get_net_if(state="UP") # Check source device is valid or not, # if it's not in host interface list, try to set # source device to first active interface of host if (iface.type_name == "direct" and source.has_key('dev') and source['dev'] not in net_ifs): logging.warn("Source device %s is not a interface" " of host, reset to %s", source['dev'], net_ifs[0]) source['dev'] = net_ifs[0] del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def run_dnsmasq_default_test(key, value=None, exists=True): """ Test dnsmasq configuration. """ conf_file = "/var/lib/libvirt/dnsmasq/default.conf" if not os.path.exists(conf_file): test.cancel("Can't find default.conf file") configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if value: config = "%s=%s" % (key, value) else: config = key if not configs.count(config): if exists: test.fail("Can't find %s=%s in configuration file" % (key, value)) else: if not exists: test.fail("Found %s=%s in configuration file" % (key, value)) def run_dnsmasq_addnhosts_test(hostip, hostnames): """ Test host ip and names configuration """ conf_file = "/var/lib/libvirt/dnsmasq/default.addnhosts" hosts_re = ".*".join(hostnames) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not re.search(r"%s.*%s" % (hostip, hosts_re), configs, re.M): test.fail("Can't find '%s' in configuration file" % hostip) def run_dnsmasq_host_test(iface_mac, guest_ip, guest_name): """ Test host name and ip configuration for dnsmasq """ conf_file = "/var/lib/libvirt/dnsmasq/default.hostsfile" config = "%s,%s,%s" % (iface_mac, guest_ip, guest_name) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not configs.count(config): test.fail("Can't find host configuration in file %s" % conf_file) def check_class_rules(ifname, rule_id, bandwidth): """ Check bandwidth settings via 'tc class' output """ cmd = "tc class show dev %s" % ifname class_output = process.system_output(cmd) logging.debug("Bandwidth class output: %s", class_output) class_pattern = (r"class htb %s.*rate (\d+)Kbit ceil" " (\d+)Kbit burst (\d+)(K?M?)b.*" % rule_id) se = re.search(class_pattern, class_output, re.M) if not se: test.fail("Can't find outbound setting for htb %s" % rule_id) logging.debug("bandwidth from tc output:%s" % str(se.groups())) ceil = None if bandwidth.has_key("floor"): ceil = int(bandwidth["floor"]) * 8 elif bandwidth.has_key("average"): ceil = int(bandwidth["average"]) * 8 if ceil: assert int(se.group(1)) == ceil if bandwidth.has_key("peak"): assert int(se.group(2)) == int(bandwidth["peak"]) * 8 if bandwidth.has_key("burst"): if se.group(4) == 'M': tc_burst = int(se.group(3)) * 1024 else: tc_burst = int(se.group(3)) assert tc_burst == int(bandwidth["burst"]) def check_filter_rules(ifname, bandwidth): """ Check bandwidth settings via 'tc filter' output """ cmd = "tc -d filter show dev %s parent ffff:" % ifname filter_output = process.system_output(cmd) logging.debug("Bandwidth filter output: %s", filter_output) if not filter_output.count("filter protocol all pref"): test.fail("Can't find 'protocol all' settings in filter rules") filter_pattern = ".*police.*rate (\d+)Kbit burst (\d+)(K?M?)b.*" se = re.search(r"%s" % filter_pattern, filter_output, re.M) if not se: test.fail("Can't find any filter policy") logging.debug("bandwidth from tc output:%s" % str(se.groups())) logging.debug("bandwidth from setting:%s" % str(bandwidth)) if bandwidth.has_key("average"): assert int(se.group(1)) == int(bandwidth["average"]) * 8 if bandwidth.has_key("burst"): if se.group(3) == 'M': tc_burst = int(se.group(2)) * 1024 else: tc_burst = int(se.group(2)) assert tc_burst == int(bandwidth["burst"]) def check_host_routes(): """ Check network routes on host """ for rt in routes: try: route = ast.literal_eval(rt) addr = "%s/%s" % (route["address"], route["prefix"]) cmd = "ip route list %s" % addr if route.has_key("family") and route["family"] == "ipv6": cmd = "ip -6 route list %s" % addr output = process.system_output(cmd) match_obj = re.search(r"via (\S+).*metric (\d+)", output) if match_obj: via_addr = match_obj.group(1) metric = match_obj.group(2) logging.debug("via address %s for %s, matric is %s" % (via_addr, addr, metric)) assert via_addr == route["gateway"] if route.has_key("metric"): assert metric == route["metric"] except KeyError: pass def run_bandwidth_test(check_net=False, check_iface=False): """ Test bandwidth option for network or interface by tc command. """ iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) net_inbound = ast.literal_eval(net_bandwidth_inbound) net_outbound = ast.literal_eval(net_bandwidth_outbound) net_bridge_name = ast.literal_eval(net_bridge)["name"] iface_name = libvirt.get_ifname_host(vm_name, iface_mac) try: if check_net and net_inbound: # Check qdisc rules cmd = "tc -d qdisc show dev %s" % net_bridge_name qdisc_output = process.system_output(cmd) logging.debug("Bandwidth qdisc output: %s", qdisc_output) if not qdisc_output.count("qdisc ingress ffff:"): test.fail("Can't find ingress setting") check_class_rules(net_bridge_name, "1:1", {"average": net_inbound["average"], "peak": net_inbound["peak"]}) check_class_rules(net_bridge_name, "1:2", net_inbound) # Check filter rules on bridge interface if check_net and net_outbound: check_filter_rules(net_bridge_name, net_outbound) # Check class rules on interface inbound settings if check_iface and iface_inbound: check_class_rules(iface_name, "1:1", {'average': iface_inbound['average'], 'peak': iface_inbound['peak'], 'burst': iface_inbound['burst']}) if iface_inbound.has_key("floor"): if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") check_class_rules(net_bridge_name, "1:3", {'floor': iface_inbound["floor"]}) # Check filter rules on interface outbound settings if check_iface and iface_outbound: check_filter_rules(iface_name, iface_outbound) except AssertionError: stacktrace.log_exc_info(sys.exc_info()) test.fail("Failed to check network bandwidth") def check_name_ip(session): """ Check dns resolving on guest """ # Check if bind-utils is installed if not utils_package.package_install(['bind-utils'], session): test.error("Failed to install bind-utils on guest") # Run host command to check if hostname can be resolved if not guest_ipv4 and not guest_ipv6: test.fail("No ip address found from parameters") guest_ip = guest_ipv4 if guest_ipv4 else guest_ipv6 cmd = "host %s | grep %s" % (guest_name, guest_ip) if session.cmd_status(cmd): test.fail("Can't resolve name %s on guest" % guest_name) def check_ipt_rules(check_ipv4=True, check_ipv6=False): """ Check iptables for network/interface """ br_name = ast.literal_eval(net_bridge)["name"] net_forward = ast.literal_eval(params.get("net_forward", "{}")) net_ipv4 = params.get("net_ipv4") net_ipv6 = params.get("net_ipv6") ipt_rules = ("FORWARD -i {0} -o {0} -j ACCEPT".format(br_name), "FORWARD -o %s -j REJECT --reject-with icmp" % br_name, "FORWARD -i %s -j REJECT --reject-with icmp" % br_name) net_dev_in = "" net_dev_out = "" if net_forward.has_key("dev"): net_dev_in = " -i %s" % net_forward["dev"] net_dev_out = " -o %s" % net_forward["dev"] if check_ipv4: ipv4_rules = list(ipt_rules) ctr_rule = "" nat_rules = [] if net_forward.has_key("mode") and net_forward["mode"] == "nat": nat_port = ast.literal_eval(params.get("nat_port")) p_start = nat_port["start"] p_end = nat_port["end"] ctr_rule = " -m .* RELATED,ESTABLISHED" nat_rules = [("POSTROUTING -s {0} ! -d {0} -p tcp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp" " -j MASQUERADE".format(net_ipv4))] if nat_rules: ipv4_rules.extend(nat_rules) if (net_ipv4 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s%s -j ACCEPT" % (net_ipv4, net_dev_in, br_name, ctr_rule)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv4, br_name, net_dev_out))] ipv4_rules.extend(rules) output = process.system_output('iptables-save') logging.debug("iptables: %s", output) for ipt in ipv4_rules: if not re.findall(r"%s" % ipt, output, re.M): test.fail("Can't find iptable rule:\n%s" % ipt) if check_ipv6: ipv6_rules = list(ipt_rules) if (net_ipv6 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s -j ACCEPT" % (net_ipv6, net_dev_in, br_name)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv6, br_name, net_dev_out))] ipv6_rules.extend(rules) output = process.system_output("ip6tables-save") logging.debug("iptables: %s", output) for ipt in ipv6_rules: if not output.count(ipt): test.fail("Can't find ipbtable rule:\n%s" % ipt) def run_ip_test(session, ip_ver): """ Check iptables on host and ipv6 address on guest """ if ip_ver == "ipv6": # Clean up iptables rules for guest to get ipv6 address session.cmd_status("ip6tables -F") # It may take some time to get the ip address def get_ip_func(): return utils_net.get_guest_ip_addr(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) if not get_ip_func(): utils_net.restart_guest_network(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 5) vm_ip = get_ip_func() logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: test.fail("Can't find ip address on guest") ip_gateway = net_ip_address if ip_ver == "ipv6": ip_gateway = net_ipv6_address # Cleanup ip6talbes on host for ping6 test process.system("ip6tables -F") if ip_gateway and not routes: ping_s, _ = ping(dest=ip_gateway, count=5, timeout=10, session=session) if ping_s: test.fail("Failed to ping gateway address: %s" % ip_gateway) def run_guest_libvirt(session): """ Check guest libvirt network """ # Try to install required packages if not utils_package.package_install(['libvirt'], session): test.error("Failed ot install libvirt package on guest") # Try to load tun module first session.cmd("lsmod | grep tun || modprobe tun") # Check network state on guest cmd = ("service libvirtd restart; virsh net-info default" " | grep 'Active:.*yes'") if session.cmd_status(cmd): test.fail("'default' network isn't in active state") # Try to destroy&start default network on guest for opt in ['net-destroy', 'net-start']: cmd = "virsh %s default" % opt status, output = session.cmd_status_output(cmd) logging.debug("Run %s on guest exit %s, output %s" % (cmd, status, output)) if status: test.fail(output) if not utils_package.package_remove("libvirt*", session): test.error("Failed to remove libvirt packages on guest") start_error = "yes" == params.get("start_error", "no") define_error = "yes" == params.get("define_error", "no") restart_error = "yes" == params.get("restart_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") net_domain = params.get("net_domain") net_ip_address = params.get("net_ip_address") net_ipv6_address = params.get("net_ipv6_address") net_dns_forward = params.get("net_dns_forward") net_dns_txt = params.get("net_dns_txt") net_dns_srv = params.get("net_dns_srv") net_dns_hostip = params.get("net_dns_hostip") net_dns_hostnames = params.get("net_dns_hostnames", "").split() dhcp_start_ipv4 = params.get("dhcp_start_ipv4") dhcp_end_ipv4 = params.get("dhcp_end_ipv4") guest_name = params.get("guest_name") guest_ipv4 = params.get("guest_ipv4") guest_ipv6 = params.get("guest_ipv6") tftp_root = params.get("tftp_root") pxe_boot = "yes" == params.get("pxe_boot", "no") routes = params.get("routes", "").split() net_bandwidth_inbound = params.get("net_bandwidth_inbound", "{}") net_bandwidth_outbound = params.get("net_bandwidth_outbound", "{}") iface_bandwidth_inbound = params.get("iface_bandwidth_inbound", "{}") iface_bandwidth_outbound = params.get("iface_bandwidth_outbound", "{}") iface_num = params.get("iface_num", "1") iface_source = params.get("iface_source", "{}") multiple_guests = params.get("multiple_guests") create_network = "yes" == params.get("create_network", "no") attach_iface = "yes" == params.get("attach_iface", "no") serial_login = "******" == params.get("serial_login", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_bridge = "yes" == params.get("test_bridge", "no") test_dnsmasq = "yes" == params.get("test_dnsmasq", "no") test_dhcp_range = "yes" == params.get("test_dhcp_range", "no") test_dns_host = "yes" == params.get("test_dns_host", "no") test_qos_bandwidth = "yes" == params.get("test_qos_bandwidth", "no") test_pg_bandwidth = "yes" == params.get("test_portgroup_bandwidth", "no") test_qos_remove = "yes" == params.get("test_qos_remove", "no") test_ipv4_address = "yes" == params.get("test_ipv4_address", "no") test_ipv6_address = "yes" == params.get("test_ipv6_address", "no") test_guest_libvirt = "yes" == params.get("test_guest_libvirt", "no") username = params.get("username") password = params.get("password") # Destroy VM 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) vms_list = [] if "floor" in ast.literal_eval(iface_bandwidth_inbound): if not libvirt_version.version_compare(1, 0, 1): test.cancel("Not supported Qos options 'floor'") # Enabling IPv6 forwarding with RA routes without accept_ra set to 2 # is likely to cause routes loss sysctl_cmd = 'sysctl net.ipv6.conf.all.accept_ra' original_accept_ra = process.system_output(sysctl_cmd + ' -n') if test_ipv6_address and original_accept_ra != '2': process.system(sysctl_cmd + '=2') # Build the xml and run test. try: if test_dnsmasq: # Check the settings before modifying network xml if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed", exists=False) run_dnsmasq_default_test("local", "//", exists=False) if net_domain: run_dnsmasq_default_test("domain", net_domain, exists=False) run_dnsmasq_default_test("expand-hosts", exists=False) # Prepare pxe boot directory if pxe_boot: prepare_pxe_boot() # Edit the network xml or create a new one. if create_network: net_ifs = utils_net.get_net_if(state="UP") # Check forward device is valid or not, # if it's not in host interface list, try to set # forward device to first active interface of host forward = ast.literal_eval(params.get("net_forward", "{}")) if (forward.has_key('mode') and forward['mode'] in ['passthrough', 'private', 'bridge', 'macvtap'] and forward.has_key('dev') and forward['dev'] not in net_ifs): logging.warn("Forward device %s is not a interface" " of host, reset to %s", forward['dev'], net_ifs[0]) forward['dev'] = net_ifs[0] params["net_forward"] = str(forward) forward_iface = params.get("forward_iface") if forward_iface: interface = [x for x in forward_iface.split()] # The guest will use first interface of the list, # check if it's valid or not, if it's not in host # interface list, try to set forward interface to # first active interface of host. if interface[0] not in net_ifs: logging.warn("Forward interface %s is not a " " interface of host, reset to %s", interface[0], net_ifs[0]) interface[0] = net_ifs[0] params["forward_iface"] = " ".join(interface) netxml = libvirt.create_net_xml(net_name, params) try: netxml.sync() except xcepts.LibvirtXMLError, details: logging.info(str(details)) if define_error: pass else: test.fail("Failed to define network") # Edit the interface xml. if change_iface_option: modify_iface_xml() # Attach interface if needed if attach_iface: iface_type = params.get("iface_type", "network") iface_model = params.get("iface_model", "virtio") for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) options = ("%s %s --model %s --config" % (iface_type, net_name, iface_model)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: logging.error("Command output %s" % ret.stdout.strip()) test.fail("Failed to attach-interface") if multiple_guests: # Clone more vms for testing for i in range(int(multiple_guests)): guest_name = "%s_%s" % (vm_name, i) timeout = params.get("clone_timeout", 360) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True, timeout=timeout) vms_list.append(vm.clone(guest_name)) if test_bridge: bridge = ast.literal_eval(net_bridge) br_if = utils_net.Interface(bridge['name']) if not br_if.is_up(): test.fail("Bridge interface isn't up") if test_dnsmasq: # Check the settings in dnsmasq config file if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed") run_dnsmasq_default_test("local", "//") if net_domain: run_dnsmasq_default_test("domain", net_domain) run_dnsmasq_default_test("expand-hosts") if net_bridge: bridge = ast.literal_eval(net_bridge) run_dnsmasq_default_test("interface", bridge['name']) if bridge.has_key('stp') and bridge['stp'] == 'on': if bridge.has_key('delay'): br_delay = float(bridge['delay']) cmd = ("brctl showstp %s | grep 'bridge forward delay'" % bridge['name']) out = process.system_output( cmd, shell=True, ignore_status=False) logging.debug("brctl showstp output: %s", out) pattern = (r"\s*forward delay\s+(\d+.\d+)\s+bridge" " forward delay\s+(\d+.\d+)") match_obj = re.search(pattern, out, re.M) if not match_obj or len(match_obj.groups()) != 2: test.fail("Can't see forward delay messages from command") elif (float(match_obj.groups()[0]) != br_delay or float(match_obj.groups()[1]) != br_delay): test.fail("Foward delay setting can't take effect") if dhcp_start_ipv4 and dhcp_end_ipv4: run_dnsmasq_default_test("dhcp-range", "%s,%s" % (dhcp_start_ipv4, dhcp_end_ipv4)) if guest_name and guest_ipv4: run_dnsmasq_host_test(iface_mac, guest_ipv4, guest_name) if test_dns_host: if net_dns_txt: dns_txt = ast.literal_eval(net_dns_txt) run_dnsmasq_default_test("txt-record", "%s,%s" % (dns_txt["name"], dns_txt["value"])) if net_dns_srv: dns_srv = ast.literal_eval(net_dns_srv) run_dnsmasq_default_test("srv-host", "_%s._%s.%s,%s,%s,%s,%s" % (dns_srv["service"], dns_srv["protocol"], dns_srv["domain"], dns_srv["target"], dns_srv["port"], dns_srv["priority"], dns_srv["weight"])) if net_dns_hostip and net_dns_hostnames: run_dnsmasq_addnhosts_test(net_dns_hostip, net_dns_hostnames) # Run bandwidth test for network if test_qos_bandwidth: run_bandwidth_test(check_net=True) # Check routes if needed if routes: check_host_routes() try: # Start the VM. vm.start() if start_error: test.fail("VM started unexpectedly") if pxe_boot: # Just check network boot messages here vm.serial_console.read_until_output_matches( ["Loading vmlinuz", "Loading initrd.img"], utils_misc.strip_console_codes) output = vm.serial_console.get_stripped_output() logging.debug("Boot messages: %s", output) else: if serial_login: session = vm.wait_for_serial_login(username=username, password=password) else: session = vm.wait_for_login() if test_dhcp_range: dhcp_range = int(params.get("dhcp_range", "252")) utils_net.restart_guest_network(session, iface_mac) vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vm_ip and not dhcp_range: test.fail("Guest has ip address: %s" % vm_ip) dhcp_range = dhcp_range - 1 for vms in vms_list: # Start other VMs. vms.start() sess = vms.wait_for_serial_login() vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) vms_ip = utils_net.get_guest_ip_addr(sess, vms_mac) if not vms_ip and dhcp_range: test.fail("Guest has invalid ip address") elif vms_ip and not dhcp_range: # Get IP address on guest should return Null # if it exceeds the dhcp range test.fail("Guest has ip address: %s" % vms_ip) dhcp_range = dhcp_range - 1 if vms_ip: ping_s, _ = ping(dest=vm_ip, count=5, timeout=10, session=sess) if ping_s: test.fail("Failed to ping, src: %s, " "dst: %s" % (vms_ip, vm_ip)) sess.close() # Check dnsmasq settings if take affect in guest if guest_ipv4: check_name_ip(session) # Run bandwidth test for interface if test_qos_bandwidth: run_bandwidth_test(check_iface=True) # Run bandwidth test for portgroup if test_pg_bandwidth: pg_bandwidth_inbound = params.get( "portgroup_bandwidth_inbound", "").split() pg_bandwidth_outbound = params.get( "portgroup_bandwidth_outbound", "").split() pg_name = params.get("portgroup_name", "").split() pg_default = params.get("portgroup_default", "").split() iface_inbound = ast.literal_eval(iface_bandwidth_inbound) iface_outbound = ast.literal_eval(iface_bandwidth_outbound) iface_name = libvirt.get_ifname_host(vm_name, iface_mac) if_source = ast.literal_eval(iface_source) if if_source.has_key("portgroup"): pg = if_source["portgroup"] else: pg = "default" for (name, df, bw_ib, bw_ob) in zip(pg_name, pg_default, pg_bandwidth_inbound, pg_bandwidth_outbound): if pg == name: inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) elif pg == "default" and df == "yes": inbound = ast.literal_eval(bw_ib) outbound = ast.literal_eval(bw_ob) else: continue # Interface bandwidth settings will # overwriting portgroup settings if iface_inbound: inbound = iface_inbound if iface_outbound: outbound = iface_outbound check_class_rules(iface_name, "1:1", inbound) check_filter_rules(iface_name, outbound) if test_qos_remove: # Remove the bandwidth settings in network xml logging.debug("Removing network bandwidth settings...") netxml_backup.sync() vm.destroy(gracefully=False) # Should fail to start vm vm.start() if restart_error: test.fail("VM started unexpectedly") if test_ipv6_address: check_ipt_rules(check_ipv6=True) run_ip_test(session, "ipv6") if test_ipv4_address: check_ipt_rules(check_ipv4=True) run_ip_test(session, "ipv4") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError as details: logging.info(str(details)) if not (start_error or restart_error): test.fail('VM failed to start:\n%s' % details)
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 interafce xml options. 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 prepare_pxe_boot(): """ Prepare tftp server and pxe boot files """ pkg_list = ["syslinux", "tftp-server", "tftp", "ipxe-roms-qemu", "wget"] # Try to install required packages if not utils_misc.yum_install(pkg_list): raise error.TestNAError("Failed ot install " "required packages") boot_initrd = params.get("boot_initrd") boot_vmlinuz = params.get("boot_vmlinuz") # Download pxe boot images utils.run("wget %s -O %s/initrd.img" % (boot_initrd, tftp_root)) utils.run("wget %s -O %s/vmlinuz" % (boot_vmlinuz, tftp_root)) utils.run("cp -f /usr/share/syslinux/pxelinux.0 {0};" " mkdir -m 777 -p {0}/pxelinux.cfg".format(tftp_root)) pxe_file = "%s/pxelinux.cfg/default" % tftp_root boot_txt = """ DISPLAY boot.txt DEFAULT rhel LABEL rhel kernel vmlinuz append initrd=initrd.img PROMPT 1 TIMEOUT 3""" with open(pxe_file, 'w') as p_file: p_file.write(boot_txt) def modify_iface_xml(): """ Modify interface xml options """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if pxe_boot: # Config boot console for pxe boot osxml = vm_xml.VMOSXML() osxml.type = vmxml.os.type osxml.arch = vmxml.os.arch osxml.machine = vmxml.os.machine osxml.loader = "/usr/share/seabios/bios.bin" osxml.bios_useserial = "yes" osxml.bios_reboot_timeout = "-1" osxml.boots = ['network'] del vmxml.os vmxml.os = osxml xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] iface_bandwidth = {} iface_inbound = eval(iface_bandwidth_inbound) iface_outbound = eval(iface_bandwidth_outbound) if iface_inbound: iface_bandwidth["inbound"] = iface_inbound if iface_outbound: iface_bandwidth["outbound"] = iface_outbound if iface_bandwidth: bandwidth = iface.new_bandwidth(**iface_bandwidth) iface.bandwidth = bandwidth iface_source = params.get("iface_source") if iface_source: source = eval(iface_source) if source: iface.source = source logging.debug("New interface xml file: %s", iface) vmxml.devices = xml_devices vmxml.xmltreefile.write() vmxml.sync() def run_dnsmasq_default_test(key, value=None, exists=True): """ Test dnsmasq configuration. """ conf_file = "/var/lib/libvirt/dnsmasq/default.conf" configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if value: config = "%s=%s" % (key, value) else: config = key if not configs.count(config): if exists: raise error.TestFail("Can't find %s=%s in configuration" " file" % (key, value)) else: if not exists: raise error.TestFail("Found %s=%s in configuration" " file" % (key, value)) def run_dnsmasq_addnhosts_test(hostip, hostnames): """ Test host ip and names configuration """ conf_file = "/var/lib/libvirt/dnsmasq/default.addnhosts" hosts_re = ".*".join(hostnames) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not re.search(r"%s.*%s" % (hostip, hosts_re), configs, re.M): raise error.TestFail("Can't find '%s' in configuration" " file" % hostip) def run_dnsmasq_host_test(iface_mac, guest_ip, guest_name): """ Test host name and ip configuration for dnsmasq """ conf_file = "/var/lib/libvirt/dnsmasq/default.hostsfile" config = "%s,%s,%s" % (iface_mac, guest_ip, guest_name) configs = "" with open(conf_file) as f: configs = f.read() logging.debug("configs in file %s: %s", conf_file, configs) if not configs.count(config): raise error.TestFail("Can't find host configuration" " in file %s" % conf_file) def check_class_rules(ifname, rule_id, bandwidth): """ Check bandwidth settings via 'tc class' output """ cmd = "tc class show dev %s" % ifname class_output = utils.run(cmd).stdout logging.debug("Bandwidth class output: %s", class_output) class_pattern = (r"class htb %s.*rate (\d+)Kbit ceil" " (\d+)Kbit burst (\d+)(K?M?)b.*" % rule_id) se = re.search(class_pattern, class_output, re.M) if not se: raise error.TestFail("Can't find outbound setting" " for htb %s" % rule_id) logging.debug("bandwidth from tc output:%s" % str(se.groups())) ceil = None if bandwidth.has_key("floor"): ceil = int(bandwidth["floor"]) * 8 elif bandwidth.has_key("average"): ceil = int(bandwidth["average"]) * 8 if ceil: assert int(se.group(1)) == ceil if bandwidth.has_key("peak"): assert int(se.group(2)) == int(bandwidth["peak"]) * 8 if bandwidth.has_key("burst"): if se.group(4) == 'M': tc_burst = int(se.group(3)) * 1024 else: tc_burst = int(se.group(3)) assert tc_burst == int(bandwidth["burst"]) def check_filter_rules(ifname, bandwidth): """ Check bandwidth settings via 'tc filter' output """ cmd = "tc -d filter show dev %s parent ffff:" % ifname filter_output = utils.run(cmd).stdout logging.debug("Bandwidth filter output: %s", filter_output) if not filter_output.count("filter protocol all pref"): raise error.TestFail("Can't find 'protocol all' settings" " in filter rules") filter_pattern = ".*police.*rate (\d+)Kbit burst (\d+)Kb.*" se = re.search(r"%s" % filter_pattern, filter_output, re.M) if not se: raise error.TestFail("Can't find any filter policy") logging.debug("bandwidth from tc output:%s" % str(se.groups())) if bandwidth.has_key("average"): assert int(se.group(1)) == int(bandwidth["average"]) * 8 if bandwidth.has_key("burst"): assert int(se.group(2)) == int(bandwidth["burst"]) def run_bandwidth_test(check_net=False, check_iface=False): """ Test bandwidth option for network or interface by tc command. """ iface_inbound = eval(iface_bandwidth_inbound) iface_outbound = eval(iface_bandwidth_outbound) net_inbound = eval(net_bandwidth_inbound) net_outbound = eval(net_bandwidth_outbound) net_bridge_name = eval(net_bridge)["name"] iface_name = libvirt.get_ifname_host(vm_name, iface_mac) try: if check_net and net_inbound: # Check qdisc rules cmd = "tc -d qdisc show dev %s" % net_bridge_name qdisc_output = utils.run(cmd).stdout logging.debug("Bandwidth qdisc output: %s", qdisc_output) if not qdisc_output.count("qdisc ingress ffff:"): raise error.TestFail("Can't find ingress setting") check_class_rules(net_bridge_name, "1:1", {"average": net_inbound["average"], "peak": net_inbound["peak"]}) check_class_rules(net_bridge_name, "1:2", net_inbound) # Check filter rules on bridge interface if check_net and net_outbound: check_filter_rules(net_bridge_name, net_outbound) # Check class rules on interface inbound settings if check_iface and iface_inbound: check_class_rules(iface_name, "1:1", {'average': iface_inbound['average'], 'peak': iface_inbound['peak'], 'burst': iface_inbound['burst']}) if iface_inbound.has_key("floor"): check_class_rules(net_bridge_name, "1:3", {'floor': iface_inbound["floor"]}) # Check filter rules on interface outbound settings if check_iface and iface_outbound: check_filter_rules(iface_name, iface_outbound) except AssertionError: utils.log_last_traceback() raise error.TestFail("Failed to check network bandwidth") def check_name_ip(session): """ Check dns resolving on guest """ # Check if bind-utils is installed if not utils_misc.yum_install(['bind-utils'], session): raise error.TestNAError("Failed to install bind-utils" " on guest") # Run host command to check if hostname can be resolved if not guest_ipv4 and not guest_ipv6: raise error.TestFail("No ip address found from parameters") guest_ip = guest_ipv4 if guest_ipv4 else guest_ipv6 cmd = "host %s | grep %s" % (guest_name, guest_ip) if session.cmd_status(cmd): raise error.TestFail("Can't resolve name %s on guest" % guest_name) def check_ipt_rules(check_ipv4=True, check_ipv6=False): """ Check iptables for network/interface """ br_name = eval(net_bridge)["name"] net_forward = eval(params.get("net_forward", "{}")) net_ipv4 = params.get("net_ipv4") net_ipv6 = params.get("net_ipv6") ipt_rules = ("FORWARD -i {0} -o {0} -j ACCEPT".format(br_name), "FORWARD -o %s -j REJECT --reject-with icmp" % br_name, "FORWARD -i %s -j REJECT --reject-with icmp" % br_name) net_dev_in = "" net_dev_out = "" if net_forward.has_key("dev"): net_dev_in = " -i %s" % net_forward["dev"] net_dev_out = " -o %s" % net_forward["dev"] if check_ipv4: ipv4_rules = list(ipt_rules) ctr_rule = "" nat_rules = [] if net_forward.has_key("mode") and net_forward["mode"] == "nat": nat_port = eval(params.get("nat_port")) p_start = nat_port["start"] p_end = nat_port["end"] ctr_rule = " -m conntrack --ctstate RELATED,ESTABLISHED" nat_rules = ["POSTROUTING -s %s -d 224.0.0.0/24 -j RETURN" % net_ipv4, "POSTROUTING -s %s -d 255.255.255.255/32 -j RETURN" % net_ipv4, ("POSTROUTING -s {0} ! -d {0} -p tcp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp -j MASQUERADE" " --to-ports {1}-{2}".format(net_ipv4, p_start, p_end)), ("POSTROUTING -s {0} ! -d {0} -p udp" " -j MASQUERADE".format(net_ipv4))] if nat_rules: ipv4_rules.extend(nat_rules) if (net_ipv4 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s%s -j ACCEPT" % (net_ipv4, net_dev_in, br_name, ctr_rule)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv4, br_name, net_dev_out))] ipv4_rules.extend(rules) output = utils.run("iptables-save").stdout.strip() logging.debug("iptables: %s", output) for ipt in ipv4_rules: if not output.count(ipt): raise error.TestFail("Can't find iptable rule:\n%s" % ipt) if check_ipv6: ipv6_rules = list(ipt_rules) if (net_ipv6 and net_forward.has_key("mode") and net_forward["mode"] in ["nat", "route"]): rules = [("FORWARD -d %s%s -o %s -j ACCEPT" % (net_ipv6, net_dev_in, br_name)), ("FORWARD -s %s -i %s%s -j ACCEPT" % (net_ipv6, br_name, net_dev_out))] ipv6_rules.extend(rules) output = utils.run("ip6tables-save").stdout.strip() logging.debug("iptables: %s", output) for ipt in ipv6_rules: if not output.count(ipt): raise error.TestFail("Can't find ipbtable rule:\n%s" % ipt) def run_ip_test(session, ip_ver): """ Check iptables on host and ipv6 address on guest """ if ip_ver == "ipv6": # Clean up iptables rules for guest to get ipv6 address session.cmd_status("ip6tables -F") utils_net.restart_guest_network(session, iface_mac, ip_version=ip_ver) # It may take some time to get the ip address def get_ip_func(): return utils_net.get_guest_ip_addr(session, iface_mac, ip_version=ip_ver) utils_misc.wait_for(get_ip_func, 10) vm_ip = get_ip_func() logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: raise error.TestFail("Can't find ip address on guest") ping_cmd = "ping -c 5" ip_gateway = net_ip_address if ip_ver == "ipv6": ping_cmd = "ping6 -c 5" ip_gateway = net_ipv6_address if ip_gateway: if utils.system("%s %s" % (ping_cmd, ip_gateway), ignore_status=True): raise error.TestFail("Failed to ping gateway address: %s" % ip_gateway) def run_guest_libvirt(session): """ Check guest libvirt network """ # Try to install required packages if not utils_misc.yum_install(['libvirt'], session): raise error.TestNAError("Failed ot install libvirt" " package on guest") result = True # Check network state on guest cmd = ("service libvirtd restart; virsh net-info default" " | grep 'Active:.*no'") if session.cmd_status(cmd): result = False logging.error("Default network isn't in inactive state") # Try to start default network on guest, check error messages if result: cmd = "virsh net-start default" status, output = session.cmd_status_output(cmd) logging.debug("Run command on guest exit %s, output %s" % (status, output)) if not status or not output.count("already in use"): result = False logging.error("Failed to see network messges on guest") if session.cmd_status("rpm -e libvirt"): logging.error("Failed to remove libvirt packages on guest") if not result: raise error.TestFail("Check libvirt network on guest failed") start_error = "yes" == params.get("start_error", "no") restart_error = "yes" == params.get("restart_error", "no") # network specific attributes. net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") net_domain = params.get("net_domain") net_ip_address = params.get("net_ip_address") net_ipv6_address = params.get("net_ipv6_address") net_dns_forward = params.get("net_dns_forward") net_dns_txt = params.get("net_dns_txt") net_dns_srv = params.get("net_dns_srv") net_dns_hostip = params.get("net_dns_hostip") net_dns_hostnames = params.get("net_dns_hostnames", "").split() dhcp_start_ipv4 = params.get("dhcp_start_ipv4") dhcp_end_ipv4 = params.get("dhcp_end_ipv4") guest_name = params.get("guest_name") guest_ipv4 = params.get("guest_ipv4") guest_ipv6 = params.get("guest_ipv6") tftp_root = params.get("tftp_root") pxe_boot = "yes" == params.get("pxe_boot", "no") net_bandwidth_inbound = params.get("net_bandwidth_inbound", "{}") net_bandwidth_outbound = params.get("net_bandwidth_outbound", "{}") iface_bandwidth_inbound = params.get("iface_bandwidth_inbound", "{}") iface_bandwidth_outbound = params.get("iface_bandwidth_outbound", "{}") multiple_guests = params.get("multiple_guests") create_network = "yes" == params.get("create_network", "no") serial_login = "******" == params.get("serial_login", "no") change_iface_option = "yes" == params.get("change_iface_option", "no") test_bridge = "yes" == params.get("test_bridge", "no") test_dnsmasq = "yes" == params.get("test_dnsmasq", "no") test_dhcp_range = "yes" == params.get("test_dhcp_range", "no") test_dns_host = "yes" == params.get("test_dns_host", "no") test_qos_bandwidth = "yes" == params.get("test_qos_bandwidth", "no") test_qos_remove = "yes" == params.get("test_qos_remove", "no") test_ipv4_address = "yes" == params.get("test_ipv4_address", "no") test_ipv6_address = "yes" == params.get("test_ipv6_address", "no") test_guest_libvirt = "yes" == params.get("test_guest_libvirt", "no") if serial_login: # Set serial console for serial login if vm.is_dead(): vm.start() session = vm.wait_for_login() # Set console option vm.set_kernel_console("ttyS0", "115200") # Shutdown here for sync fs vm.shutdown() else: 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) vms_list = [] # Build the xml and run test. try: if test_dnsmasq: # Check the settings before modifying network xml if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed", exists=False) run_dnsmasq_default_test("local", "//", exists=False) if net_domain: run_dnsmasq_default_test("domain", net_domain, exists=False) run_dnsmasq_default_test("expand-hosts", exists=False) # Prepare pxe boot directory if pxe_boot: prepare_pxe_boot() # Edit the network xml or create a new one. if create_network: libvirt.create_net_xml(net_name, params) # Edit the interface xml. if change_iface_option: modify_iface_xml() if multiple_guests: # Clone more vms for testing for i in range(int(multiple_guests)): guest_name = "%s_%s" % (vm_name, i) utils_libguestfs.virt_clone_cmd(vm_name, guest_name, True) vms_list.append(vm.clone(guest_name)) if test_bridge: bridge = eval(net_bridge) br_if = utils_net.Interface(bridge['name']) if not br_if.is_up(): raise error.TestFail("Bridge interface isn't up") if test_dnsmasq: # Check the settings in dnsmasq config file if net_dns_forward == "no": run_dnsmasq_default_test("domain-needed") run_dnsmasq_default_test("local", "//") if net_domain: run_dnsmasq_default_test("domain", net_domain) run_dnsmasq_default_test("expand-hosts") if net_bridge: bridge = eval(net_bridge) run_dnsmasq_default_test("interface", bridge['name']) if bridge.has_key('stp') and bridge['stp'] == 'on': if bridge.has_key('delay'): br_delay = float(bridge['delay']) cmd = ("brctl showstp %s | grep 'bridge forward delay'" % bridge['name']) out = utils.run(cmd, ignore_status=False).stdout.strip() logging.debug("brctl showstp output: %s", out) pattern = (r"\s*forward delay\s+(\d+.\d+)\s+bridge" " forward delay\s+(\d+.\d+)") match_obj = re.search(pattern, out, re.M) if not match_obj or len(match_obj.groups()) != 2: raise error.TestFail("Can't see forward delay" " messages from command") elif (float(match_obj.groups()[0]) != br_delay or float(match_obj.groups()[1]) != br_delay): raise error.TestFail("Foward delay setting" " can't take effect") if dhcp_start_ipv4 and dhcp_end_ipv4: run_dnsmasq_default_test("dhcp-range", "%s,%s" % (dhcp_start_ipv4, dhcp_end_ipv4)) if guest_name and guest_ipv4: run_dnsmasq_host_test(iface_mac, guest_ipv4, guest_name) if test_dns_host: if net_dns_txt: dns_txt = eval(net_dns_txt) run_dnsmasq_default_test("txt-record", "%s,%s" % (dns_txt["name"], dns_txt["value"])) if net_dns_srv: dns_srv = eval(net_dns_srv) run_dnsmasq_default_test("srv-host", "_%s._%s.%s,%s,%s,%s,%s" % (dns_srv["service"], dns_srv["protocol"], dns_srv["domain"], dns_srv["target"], dns_srv["port"], dns_srv["priority"], dns_srv["weight"])) if net_dns_hostip and net_dns_hostnames: run_dnsmasq_addnhosts_test(net_dns_hostip, net_dns_hostnames) # Run bandwidth test for network if test_qos_bandwidth: run_bandwidth_test(check_net=True) try: # Start the VM. vm.start() if start_error: raise error.TestFail("VM started unexpectedly") if pxe_boot: # Just check network boot messages here vm.serial_console.read_until_output_matches( ["Loading vmlinuz", "Loading initrd.img"], utils_misc.strip_console_codes) output = vm.serial_console.get_stripped_output() logging.debug("Boot messages: %s", output) else: if serial_login: session = vm.wait_for_serial_login() else: session = vm.wait_for_login() if test_dhcp_range: # First vm should have a valid ip address utils_net.restart_guest_network(session, iface_mac) vm_ip = utils_net.get_guest_ip_addr(session, iface_mac) logging.debug("Guest has ip: %s", vm_ip) if not vm_ip: raise error.TestFail("Guest has invalid ip address") # Other vms cloudn't get the ip address for vms in vms_list: # Start other VMs. vms.start() sess = vms.wait_for_serial_login() vms_mac = vms.get_virsh_mac_address() # restart guest network to get ip addr utils_net.restart_guest_network(sess, vms_mac) vms_ip = utils_net.get_guest_ip_addr(sess, vms_mac) if vms_ip: # Get IP address on guest should return Null raise error.TestFail("Guest has ip address: %s" % vms_ip) sess.close() # Check dnsmasq settings if take affect in guest if guest_ipv4: check_name_ip(session) # Run bandwidth test for interface if test_qos_bandwidth: run_bandwidth_test(check_iface=True) if test_qos_remove: # Remove the bandwidth settings in network xml logging.debug("Removing network bandwidth settings...") netxml_backup.sync() vm.destroy(gracefully=False) # Should fail to start vm vm.start() if restart_error: raise error.TestFail("VM started unexpectedly") if test_ipv4_address: check_ipt_rules(check_ipv4=True) run_ip_test(session, "ipv4") if test_ipv6_address: check_ipt_rules(check_ipv6=True) run_ip_test(session, "ipv6") if test_guest_libvirt: run_guest_libvirt(session) session.close() except virt_vm.VMStartError, details: logging.info(str(details)) if start_error or restart_error: pass else: raise error.TestFail('VM Failed to start for some reason!') finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) for vms in vms_list: virsh.remove_domain(vms.name, "--remove-all-storage") 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) vmxml_backup.sync()
def run(test, params, env): """ Test interface devices update """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) new_network_name = params.get("net_name") expect_error = "yes" == params.get("status_error", "no") expect_err_msg = params.get("expect_err_msg") iface_driver = params.get("iface_driver") iface_model = params.get("iface_model") iface_mtu = params.get("iface_mtu") iface_rom = params.get("iface_rom") new_iface_driver = params.get("new_iface_driver") new_iface_driver_host = params.get("new_iface_driver_host") new_iface_driver_guest = params.get("new_iface_driver_guest") new_iface_model = params.get("new_iface_model") new_iface_rom = params.get("new_iface_rom") new_iface_inbound = params.get("new_iface_inbound") new_iface_outbound = params.get("new_iface_outbound") new_iface_link = params.get("new_iface_link") new_iface_source = params.get("new_iface_source") new_iface_target = params.get("new_iface_target") new_iface_addr = params.get("new_iface_addr") new_iface_filter = params.get("new_iface_filter") new_iface_mtu = params.get("new_iface_mtu") new_iface_type = params.get("new_iface_type") create_new_net = "yes" == params.get("create_new_net") new_iface_alias = params.get("new_iface_alias") cold_update = "yes" == params.get("cold_update", "no") del_addr = "yes" == params.get("del_address") del_rom = "yes" == params.get("del_rom") # Backup the vm xml for recover at last vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) try: # According to the different os find different file for rom if (iface_rom and "file" in eval(iface_rom) and "%s" in eval(iface_rom)['file']): if os.path.exists(eval(iface_rom)['file'] % "pxe"): iface_rom = iface_rom % "pxe" elif os.path.exists(eval(iface_rom)['file'] % "efi"): iface_rom = iface_rom % "efi" else: logging.error("Can not find suitable rom file") iface_dict_bef = {} iface_dict_aft = {} names = locals() # Collect need update items in 2 dicts for both start vm before and after update_list_bef = [ "driver", "model", "mtu", "rom" ] for update_item_bef in update_list_bef: if names['iface_'+update_item_bef]: iface_dict_bef.update({update_item_bef: names['iface_'+update_item_bef]}) update_list_aft = [ "driver", "driver_host", "driver_guest", "model", "rom", "inbound", "outbound", "link", "source", "target", "addr", "filter", "mtu", "type", "alias"] for update_item_aft in update_list_aft: if names["new_iface_"+update_item_aft]: iface_dict_aft.update({update_item_aft: names["new_iface_"+update_item_aft]}) logging.info("iface_dict_bef is %s, iface_dict_aft is %s", iface_dict_bef, iface_dict_aft) del_list = ["del_addr", "del_rom"] for del_item in del_list: if names[del_item]: iface_dict_aft.update({del_item: "True"}) # Update vm interface with items in iface_dict_bef and start it if iface_dict_bef: libvirt.modify_vm_iface(vm_name, "update_iface", iface_dict_bef) logging.info("vm xml is %s", vm.get_xml()) if not cold_update: vm.start() if iface_mtu: # Do check for mtu size after start vm target_dev = libvirt.get_interface_details(vm_name)[0]['interface'] cmd = "ip link show %s | grep 'mtu %s'" % (target_dev, eval(iface_mtu)['size']) def check_mtu(): """ Check the mtu setting take effect for interface """ ret = process.run(cmd, ignore_status=True, shell=True) if ret.exit_status: test.fail("Can not find mtu setting in cmd result") check_mtu() utils_libvirtd.libvirtd_restart() check_mtu() # Create new network if need if create_new_net: new_net_xml = libvirt.create_net_xml(new_network_name, params) new_net_xml.sync() # Do update for iface_driver new_iface_xml = libvirt.modify_vm_iface(vm_name, "get_xml", iface_dict_aft) ret = virsh.update_device(vm_name, new_iface_xml, ignore_status=True, debug=True) libvirt.check_exit_status(ret, expect_error) if expect_error: real_err_msg = ret.stderr.strip() if not re.search(expect_err_msg, real_err_msg, re.IGNORECASE): test.fail("The real error msg:'%s' does not match expect one:" '%s' % (real_err_msg, expect_err_msg)) else: logging.info("Get expect result: %s", real_err_msg) else: if new_iface_inbound: iface_bandwidth = {} iface_bandwidth = vm_xml.VMXML.get_iftune_params(vm_name) for bound_para in ["inbound", "outbound"]: for tune_para in ["average", "peak", "burst"]: get_value = iface_bandwidth.get(bound_para).get(tune_para) expect_value = eval(names["new_iface_"+bound_para]).get(tune_para) logging.info("Get value for %s:%s is %s, expect is %s", bound_para, tune_para, get_value, expect_value) if get_value != expect_value: test.fail("Get value is not equal to expect") vmxml_aft = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_aft = list(vmxml_aft.get_iface_all().values())[0] if new_iface_link: iface_link_value = iface_aft.find('link').get('state') if iface_link_value == new_iface_link: logging.info("Find link state is %s in xml", new_iface_link) # Checking the statue in guest mac_addr = iface_aft.find('mac').get('address') state_map = "%s.*\n.*%s" % (iface_link_value.upper(), mac_addr) session = vm.wait_for_serial_login() logging.info("ip link output:%s", session.cmd_output("ip link")) if_name = utils_net.get_net_if(runner=session.cmd_output, state=state_map)[0] session.close() if if_name: logging.info("Find iface state %s for %s", iface_link_value, mac_addr) else: test.fail("Can not find iface with mac %s and state %s" % (mac_addr, iface_link_value)) else: test.fail("Check fail to get link state, expect %s, but get %s" % (iface_link_value, new_iface_link)) if create_new_net and new_iface_source: iface_source_value = iface_aft.find('source').get('network') if iface_source_value == eval(new_iface_source)['network']: logging.info("Get %s in xml as set", iface_source_value) else: test.fail("Get source %s is not equal to set %s" % (iface_source_value, new_iface_source)) if new_iface_filter: iface_filter_value = iface_aft.find('filterref').get('filter') if iface_filter_value == new_iface_filter: logging.info("Get %s in xml as set", iface_filter_value) else: test.fail("Get filter %s is not equal to set %s" % (iface_filter_value, new_iface_filter)) if new_iface_alias: iface_alias_value = iface_aft.find('alias').get('name') if iface_alias_value == eval(new_iface_alias)['name']: logging.info("Get %s in xml as set", iface_alias_value) else: test.fail("Get alias %s is not equal to set %s" % (iface_alias_value, new_iface_alias)) finally: vmxml_backup.sync() if create_new_net: new_net_xml.undefine()
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()