def create_guest(self, host_conf, guest_conf): """ Create a guest Args: host_conf: The host_conf (instance of BaseHostConf) guest_conf: The host_conf (instance of BaseGuestConf) """ host = host_conf.host virtctl = guest_conf.virtctl guest_xml = guest_conf.libvirt_xml str_xml = ET.tostring(guest_xml, encoding='utf8', method='xml') virtctl.createXML(str_xml.decode('utf8')) guest_ip_job = host.run("gethostip -d {}".format(guest_conf.name)) guest_ip = guest_ip_job.stdout.strip() if not guest_ip: raise LnstError("Could not determine guest's IP address") guest = self.ctl.connect_host(guest_ip, timeout=60, machine_id="guest1") guest_conf.host = guest for i, vnic in enumerate(guest_conf.virtio_devs): if not vnic.hwaddr: raise LnstError("Virtio NIC HW Address not configured") guest.map_device("eth{}".format(i), dict(hwaddr=vnic.hwaddr)) device = getattr(guest, "eth{}".format(i)) guest_conf.nics.append(device) return guest
def _parse_addr(self, addr): tmp_list = addr.split(':') if len(tmp_list) != 6: raise LnstError("Invalid HWAddress format") res = [] for i in tmp_list: val = int(i, 16) if val > 255 or val < 0: raise LnstError("Invalid HWAddress format") res.append(val) return res
def format_command(self): if self.params.forward_mode == "macswap": testpmd_args = ["dpdk-testpmd", "--no-pci"] else: testpmd_args = ["testpmd"] testpmd_args.extend( ["-c", self.params.coremask, "-n", "4", "--socket-mem", "1024,0"]) for i, nic in enumerate(self.params.nics): if self.params.forward_mode == "mac": testpmd_args.extend(["-w", nic]) elif self.params.forward_mode == "macswap": testpmd_args.extend([ f"--vdev=net_virtio_user{i+1},path=/var/run/openvswitch/{nic}" ]) else: LnstError( "Unsupported forward-mode parameter selected for the TestPMD." ) testpmd_args.extend([ "--", "-i", "--forward-mode", self.params.forward_mode, "--coremask", self.params.pmd_coremask ]) if self.params.forward_mode == "mac": for i, mac in enumerate(self.params.peer_macs): testpmd_args.extend(["--eth-peer", "{},{}".format(i, mac)]) elif self.params.forward_mode == "macswap": testpmd_args.extend(["--port-topology=loop"]) return " ".join(testpmd_args)
def _deconfig_ip_fragmentation(self, config, host): ip_version = config["ip_version"] if ip_version == AF_INET: host.run( "echo {} > /proc/sys/net/ipv4/ipfrag_high_thresh".format( config["original_threshold"] ), job_level=ResultLevel.NORMAL, ) host.run( "echo {} > /proc/sys/net/ipv4/ipfrag_time".format( config["original_time"] ), job_level=ResultLevel.NORMAL, ) elif ip_version == AF_INET6: host.run( "echo {} > /proc/sys/net/ipv6/ip6frag_high_thresh".format( config["original_threshold"] ), job_level=ResultLevel.NORMAL, ) host.run( "echo {} > /proc/sys/net/ipv6/ip6frag_time".format( config["original_time"] ), job_level=ResultLevel.NORMAL, ) else: raise LnstError("Unknown ip version: {}".format(ip_version))
def _parse_addr(addr): addr = addr.split('/') if len(addr) == 1: addr = addr[0] prefixlen = 128 elif len(addr) == 2: addr, prefixlen = addr prefixlen = int(prefixlen) else: raise LnstError("Invalid IPv6 format.") try: type(inet_pton(AF_INET6, addr)) except: raise LnstError("Invalid IPv6 format.") return addr, prefixlen
def packet_assert_test_stop(self): if not self.started_job: raise LnstError("No packet_assert job is running.") self.started_job.kill(signal=signal.SIGINT) self.started_job.wait() result = self.started_job.result self.started_job = None return result
def packet_assert_test_start(self, packet_assert_config): if self.started_job: raise LnstError( "Only 1 packet_assert job is allowed to run at a time.") host = packet_assert_config.host kwargs = self._generate_packet_assert_kwargs(packet_assert_config) packet_assert = PacketAssert(**kwargs) self.started_job = host.prepare_job(packet_assert).start(bg=True)
def obj_setattr(self, obj_ref, name, value): try: obj = self._dynamic_objects[obj_ref] return setattr(obj, name, value) except LnstError: raise except Exception as exc: log_exc_traceback() raise LnstError(exc)
def hwaddress(addr): """Factory method to create a _HWAddress object""" if isinstance(addr, HWAddress): return addr elif isinstance(addr, str): return HWAddress(addr) else: raise LnstError("Value must be a HWAddress or string object." " Not {}".format(type(addr)))
def ping6(src, dst, options={}, expect="pass", bg=False): """ Perform an Icmp6Ping from source to destination Keyword arguments: src -- tuple of (HostAPI, InterfaceAPI/DeviceAPI, ip address index, ip addr selector) dst -- tuple of (HostAPI, InterfaceAPI/DeviceAPI, ip address index, ip addr selector) options -- dictionary of options for the IcmpPing module, can't contain keys 'addr' and 'iface' """ options = dict(options) if 'addr' in options or 'iface' in options: raise LnstError("options can't contain keys 'addr' and 'iface'") if not isinstance(src, tuple) or len(src) < 2 or len(src) > 4: raise LnstError('Invalid source specification') try: if len(src) == 2: h1, if1 = src options["iface"] = if1.get_devname() elif len(src) == 3: h1, if1, addr_index1 = src options["iface"] = if1.get_ip(addr_index1) elif len(src) == 4: h1, if1, addr_index1, addr_selector1 = src options["iface"] = if1.get_ip(addr_index1, selector=addr_selector1) except: raise LnstError('Invalid source specification') if not isinstance(dst, tuple) or len(dst) < 3 or len(dst) > 4: raise LnstError('Invalid destination specification') try: if len(dst) == 3: h2, if2, addr_index2 = dst options["addr"] = if2.get_ip(addr_index2) elif len(dst) == 4: h2, if2, addr_index2, addr_selector2 = dst options["addr"] = if2.get_ip(addr_index2, selector=addr_selector2) except: raise LnstError('Invalid destination specification') ping_mod = ctl.get_module("Icmp6Ping", options=options) return h1.run(ping_mod, expect=expect, bg=bg)
def generate_ping_configurations(self, config): """Base ping test configuration generator The generator loops over all endpoint pairs to test ping between (generated by the :any:`generate_ping_endpoints` method) then over all the selected :any:`ip_versions` and finally over all the IP addresses that fit those criteria. :return: list of Ping configurations to test in parallel :rtype: List[:any:`PingConf`] """ for endpoints in self.generate_ping_endpoints(config): for ipv in self.params.ip_versions: if ipv == "ipv6" and not endpoints.reachable: continue ip_filter = {} if ipv == "ipv4": ip_filter.update(family=AF_INET) elif ipv == "ipv6": ip_filter.update(family=AF_INET6) ip_filter.update(is_link_local=False) endpoint1, endpoint2 = endpoints.endpoints endpoint1_ips = endpoint1.ips_filter(**ip_filter) endpoint2_ips = endpoint2.ips_filter(**ip_filter) if len(endpoint1_ips) != len(endpoint2_ips): raise LnstError( "Source/destination ip lists are of different size.") ping_conf_list = [] for src_addr, dst_addr in zip(endpoint1_ips, endpoint2_ips): pconf = PingConf( client=endpoint1.netns, client_bind=src_addr, destination=endpoint2.netns, destination_address=dst_addr, count=self.params.ping_count, interval=self.params.ping_interval, size=self.params.ping_psize, ) ping_evaluators = self.generate_ping_evaluators( pconf, endpoints) pconf.register_evaluators(ping_evaluators) ping_conf_list.append(pconf) if self.params.ping_bidirect: ping_conf_list.append(self._create_reverse_ping(pconf)) if not self.params.ping_parallel: break yield ping_conf_list
def __init__(self): try: import libvirt from libvirt import libvirtError except ModuleNotFoundError: msg = "Failed to import libvirt, please install libvirt if you want to use the LibvirtControl class." logging.error(msg) raise LnstError(msg) self._libvirt_conn = libvirt.open(None)
def obj_method(self, obj_ref, name, args, kwargs): try: obj = self._dynamic_objects[obj_ref] method = getattr(obj, name) return method(*args, **kwargs) except LnstError: raise except Exception as exc: log_exc_traceback() raise LnstError(exc)
def __init__(self, iterable=[]): for i, item in enumerate(iterable): self._validate_item_type(item) if i == 0: unit = item.unit if item.unit != unit: raise LnstError("PerfList items must have the same unit.") super(PerfList, self).__init__(iterable)
def __setitem__(self, i, item): if isinstance(item, list): if not isinstance(i, slice): raise LnstError("{} accepts list values in slice assignment " "only".format(self.__class__.__name__)) for j in item: self._validate_item(j) else: self._validate_item(item) super(PerfList, self).__setitem__(i, item)
def init_libvirt_con(): try: import libvirt from libvirt import libvirtError except ModuleNotFoundError: msg = "Failed to import libvirt, please install libvirt to use the libvirt network management features." logging.error(msg) raise LnstError(msg) global _libvirt_conn if _libvirt_conn is None: _libvirt_conn = libvirt.open(None)
def ipaddress(addr, flags=None): """Factory method to create a BaseIpAddress object""" if isinstance(addr, BaseIpAddress): return addr elif isinstance(addr, str): try: return Ip4Address(addr, flags) except: return Ip6Address(addr, flags) else: raise LnstError("Value must be a BaseIpAddress or string object." " Not {}".format(type(addr)))
def warmup_configuration(self, ping_config): if len(ping_config) > 255: raise LnstError("Too many warmup elements.") for i, elem in enumerate(ping_config): orig = elem[1] dest = elem[2] orig.ip_add(ipaddress('192.168.{}.1/24'.format(i))) dest.ip_add(ipaddress('192.168.{}.2/24'.format(i))) orig.up() dest.up()
def IpAddress(addr): """Factory method to create a BaseIpAddress object""" if isinstance(addr, BaseIpAddress): return addr #TODO add switches for host, interface etc... elif isinstance(addr, str): try: return Ip4Address(addr) except: return Ip6Address(addr) else: raise LnstError("Value must be a BaseIpAddress or string object." "Not {}".format(type(addr)))
def run(self): self._res_data = {} if not is_installed("tcpdump"): self._res_data["msg"] = "tcpdump is not installed on this machine!" logging.error(self._res_data["msg"]) return False self._prepare_grep_exprs() cmd = self._compose_cmd() logging.debug("compiled command: {}".format(cmd)) packet_assert_process = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, ) try: self.wait_for_interrupt() except: raise LnstError("Could not handle interrupt properly.") stdout, stderr = packet_assert_process.communicate() stdout = stdout.decode() stderr = stderr.decode() self._res_data["stderr"] = stderr # tcpdump always reports information to stderr, there may be actual # errors but also just generic debug information logging.debug(self._res_data["stderr"]) for line in stdout.split("\n"): self._check_line(line) logging.debug("Capturing finised. Received %d packets." % self._p_recv) self._res_data["p_recv"] = self._p_recv if packet_assert_process.returncode != 0: return False else: return True
def generate_ping_configurations(self, config): if not config.encrypt: client_nic = config.endpoint1 server_nic = config.endpoint2 ip_vers = ('ipv4',) else: client_nic = config.host1.msec0 server_nic = config.host2.msec0 ip_vers = self.params.ip_versions count = self.params.ping_count interval = self.params.ping_interval size = self.params.ping_psize common_args = {'count' : count, 'interval' : interval, 'size' : size} for ipv in ip_vers: kwargs = {} if ipv == "ipv4": kwargs.update(family = AF_INET) elif ipv == "ipv6": kwargs.update(family = AF_INET6) kwargs.update(is_link_local = False) client_ips = client_nic.ips_filter(**kwargs) server_ips = server_nic.ips_filter(**kwargs) if ipv == "ipv6": client_ips = client_ips[::-1] server_ips = server_ips[::-1] if len(client_ips) != len(server_ips) or (len(client_ips) * len(server_ips) == 0): raise LnstError("Source/destination ip lists are of " "different size or empty.") for src_addr, dst_addr in zip(client_ips, server_ips): pconf = PingConf(client = client_nic.netns, client_bind = src_addr, destination = server_nic.netns, destination_address = dst_addr, **common_args) yield [pconf]
def run(self): self._res_data = {} if not is_installed("tcpdump"): self._res_data["msg"] = "tcpdump is not installed on this machine!" logging.error(self._res_data["msg"]) return False self._prepare_grep_exprs() cmd = self._compose_cmd() logging.debug("compiled command: {}".format(cmd)) packet_assert_process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) try: self.wait_for_interrupt() except: raise LnstError("Could not handle interrupt properly.") with packet_assert_process.stdout, packet_assert_process.stderr: stderr=packet_assert_process.stderr.read().decode() stdout=packet_assert_process.stdout.read().decode() self._res_data["stderr"] = stderr if self._is_real_err(stderr): self._res_data["msg"] = "errors reported by tcpdump" logging.error(self._res_data["msg"]) logging.error(self._res_data["stderr"]) return False for line in stdout.split("\n"): self._check_line(line) logging.debug("Capturing finised. Received %d packets." % self._p_recv) self._res_data["p_recv"] = self._p_recv return True
def generate_ping_configurations(self, config): for endpoint1, endpoint2 in self.generate_ping_endpoints(config): for ipv in self.params.ip_versions: ip_filter = {} if ipv == "ipv4": ip_filter.update(family=AF_INET) elif ipv == "ipv6": ip_filter.update(family=AF_INET6) ip_filter.update(is_link_local=False) endpoint1_ips = endpoint1.ips_filter(**ip_filter) endpoint2_ips = endpoint2.ips_filter(**ip_filter) if len(endpoint1_ips) != len(endpoint2_ips): raise LnstError( "Source/destination ip lists are of different size.") ping_conf_list = [] for src_addr, dst_addr in zip(endpoint1_ips, endpoint2_ips): pconf = PingConf( client=endpoint1.netns, client_bind=src_addr, destination=endpoint2.netns, destination_address=dst_addr, count=self.params.ping_count, interval=self.params.ping_interval, size=self.params.ping_psize, ) ping_conf_list.append(pconf) if self.params.ping_bidirect: ping_conf_list.append(self._create_reverse_ping(pconf)) if not self.params.ping_parallel: break yield ping_conf_list
def _process_msg(self, msg): if msg["type"] == "command": method = getattr(self._methods, msg["method_name"], None) if method != None: if_manager = self._methods._if_manager if if_manager is not None: args = deviceref_to_device(if_manager, msg["args"]) kwargs = deviceref_to_device(if_manager, msg["kwargs"]) else: args = msg["args"] kwargs = msg["kwargs"] try: result = method(*args, **kwargs) except LnstError as e: log_exc_traceback() response = {"type": "exception", "Exception": e} self._server_handler.send_data_to_ctl(response) return response = {"type": "result", "result": result} response = device_to_deviceref(response) self._server_handler.send_data_to_ctl(response) else: err = LnstError("Method '%s' not supported." % msg["method_name"]) response = {"type": "exception", "Exception": err} self._server_handler.send_data_to_ctl(response) elif msg["type"] == "log": logger = logging.getLogger() record = logging.makeLogRecord(msg["record"]) logger.handle(record) elif msg["type"] == "exception": if msg["cmd_id"] != None: logging.debug("Recieved an exception from command with id: %s" % msg["cmd_id"]) else: logging.debug("Recieved an exception from foreground command") logging.debug(msg["Exception"]) job = self._job_context.get_cmd(msg["job_id"]) job.join() self._job_context.del_cmd(job) self._server_handler.send_data_to_ctl(msg) elif msg["type"] == "job_finished": job = self._job_context.get_job(msg["job_id"]) job.join() job.set_finished(msg["result"]) self._server_handler.send_data_to_ctl(msg) self._job_context.del_job(job) elif msg["type"] == "from_netns": self._server_handler.send_data_to_ctl(msg["data"]) elif msg["type"] == "to_netns": netns = msg["netns"] try: self._server_handler.send_data_to_netns(netns, msg["data"]) except LnstError as e: log_exc_traceback() response = {"type": "exception", "Exception": e} self._server_handler.send_data_to_ctl(response) return else: raise Exception("Recieved unknown command") pipes = self._job_context.get_parent_pipes() self._server_handler.update_connections(pipes)
def _validate_item(self, item): self._validate_item_type(item) if len(self) > 0 and item.unit != self[0].unit: raise LnstError("PerfList items must have the same unit.")
def netperf(src, dst, server_opts={}, client_opts={}, baseline={}, timeout=60): """ Start a Netserver on the given machine and ip address Keyword arguments: src -- tuple of (HostAPI, InterfaceAPI/DeviceAPI, ip address index, ip addr selector) dst -- tuple of (HostAPI, InterfaceAPI/DeviceAPI, ip address index, ip addr selector) server_opts -- dictionary of additional options for the netperf server can't contain 'bind' or 'role' client_opts -- dictionary of additional options for the netperf client can't contain 'bind', 'role', 'netperf_server', 'threshold' or 'threshold_deviation' baseline -- optional dictionary with keys 'threshold' and 'threshold_deviation' that specifies the baseline of the netperf test timeout -- integer number of seconds specifing the maximum amount of time for the test, defaults to 60 """ server_opts = dict(server_opts) if 'bind' in server_opts or 'role' in server_opts: raise LnstError("server_opts can't contain keys 'bind' and 'role'") client_opts = dict(client_opts) if 'bind' in client_opts or\ 'role' in client_opts or\ 'netperf_server' in client_opts: raise LnstError("client_opts can't contain keys 'bind', 'role' "\ "and 'netperf_server'") if not isinstance(src, tuple) or len(src) < 2 or len(src) > 4: raise LnstError('Invalid source specification') try: if len(src) == 3: h1, if1, addr_index1 = src client_ip = if1.get_ip(addr_index1) elif len(src) == 4: h1, if1, addr_index1, addr_selector1 = src client_ip = if1.get_ip(addr_index1, selector=addr_selector1) except: raise LnstError('Invalid source specification') if not isinstance(dst, tuple) or len(dst) < 3 or len(dst) > 4: raise LnstError('Invalid destination specification') try: if len(dst) == 3: h2, if2, addr_index2 = dst server_ip = if2.get_ip(addr_index2) elif len(dst) == 4: h2, if2, addr_index2, addr_selector2 = dst server_ip = if2.get_ip(addr_index2, addr_selector2) except: raise LnstError('Invalid destination specification') server_opts["role"] = "server" server_opts["bind"] = server_ip client_opts["role"] = "client" client_opts["bind"] = client_ip client_opts["netperf_server"] = server_ip if "threshold" in baseline: client_opts["threshold"] = baseline["threshold"] if "threshold_deviation" in baseline: client_opts["threshold_deviation"] = baseline["threshold_deviation"] netserver_mod = ctl.get_module("Netperf", options=server_opts) netclient_mod = ctl.get_module("Netperf", options=client_opts) netserver = h2.run(netserver_mod, bg=True) ctl.wait(2) result = h1.run(netclient_mod, timeout=timeout) netserver.intr() return result
def register_evaluators(self, measurement, evaluators): if measurement not in self.measurements: raise LnstError("Can't register evaluators for an unknown measurement") self._evaluators[measurement] = list(evaluators)
def _validate_item_type(self, item): if (not isinstance(item, PerfInterval) and not isinstance(item, PerfList)): raise LnstError("{} only accepts PerfInterval or PerfList objects." .format(self.__class__.__name__))
def get_dev_by_ip(self, netns, ip): for dev in netns.device_database: if ip in dev.ips: return dev raise LnstError("Could not match ip %s to any device of %s." % (ip, netns.name))
def __init__(self, virt_type=None, hwaddr="", config=None): if not isinstance(virt_type, (VirtioType, None)): raise LnstError('Wrong virtio type') self.type = virt_type # The virtio type self.hwaddr = hwaddr # The MAC address of the device self.config = config # Type-specific configuration