def deleteRoute(logger, destination, gateway, table, version=None): """This function deletes an IP route Args: logger destination-the destination prefix of the route gateway - the address of the nexthop router. table - the table to delete this route from. TABLEID may be a number or a string version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.ROUTE, IpAction.DELETE, destination, IpConstant.VIA, gateway, IpConstant.TABLE, table) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.ROUTE, IpAction.DELETE, destination, IpConstant.VIA, gateway, IpConstant.TABLE, table) rc = Command.executeIp(logger, IpOption.ROUTE, IpAction.DELETE, destination, IpConstant.VIA, gateway, IpConstant.TABLE, table) return rc
def showRoutes(logger, table, version=None): """This function list all routes Args: logger table - show the routes from this table Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.ROUTE, IpAction.SHOW, IpConstant.TABLE, table) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.ROUTE, IpAction.SHOW, IpConstant.TABLE, table) rc = Command.executeIp(logger, IpOption.ROUTE, IpAction.SHOW, IpConstant.TABLE, table) return rc
def deleteRule(logger, source, table, version=None): """This function deletes a rule Args: logger source - select the source prefix to match. table - the routing table identifier to lookup if the rule selector matches. TABLEID may be a number or a string version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.RULE, IpAction.DELETE, IpConstant.FROM, source, IpConstant.TABLE, table) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.RULE, IpAction.DELETE, IpConstant.FROM, source, IpConstant.TABLE, table) rc = Command.executeIp(logger, IpOption.RULE, IpAction.DELETE, IpConstant.FROM, source, IpConstant.TABLE, table) return rc
def flushRules(logger, table, version=None): """This function flushes all rules associated with the table Args: logger table - the routing table identifier to lookup if the rule selector matches. TABLEID may be a number or a string version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.RULE, IpAction.DELETE, IpConstant.TABLE, table) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.RULE, IpAction.DELETE, IpConstant.TABLE, table) rc = Command.executeIp(logger, IpOption.RULE, IpAction.DELETE, IpConstant.TABLE, table) return rc
def deleteAddress(logger, address, device, version=None): """This function deletes an IP address Args: logger address - IP address to dettach device - the name of the device to delete the address from version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.ADDRESS, IpAction.DELETE, address, IpConstant.DEV, device) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.ADDRESS, IpAction.DELETE, address, IpConstant.DEV, device) rc = Command.executeIp(logger, IpOption.ADDRESS, IpAction.DELETE, address, IpConstant.DEV, device) return rc
def sendArpReply(logger, device, destination, count=3, quiet=False, blocking=True): """This function sends ARP REPLY to a neighbour host Args: logger device - Name of network device where to send ARP REPLY packets destination - destination IP to ping count - stop after sending X ARP REQUEST packets quiet - quiet output blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [Arping.ARPING_COMMAND_NAME, Arping.INTERFACE_OPTION, device, Arping.COUNT_OPTION, str(count), Arping.ARP_REPLY_OPTION] if quiet is True: args.append(Arping.QUIET_OPTION) # must set destination as last arg args.append(destination) rc = Command.execute(logger, Arping.ARPING_COMMAND_NAME, args, blocking=blocking) return rc
def __executeIpTablesCmd (self, ipVersion, args, filters=None): commandName = self.IPV4_TABLE_COMMAND_NAME if ipVersion == 6: commandName = self.IPV6_TABLE_COMMAND_NAME args.insert(0,commandName) command = " ".join(args) if filters: for text in filters: command += (" | grep %s" % text) self.__log("iptables-cmd-run").debug4("Run IPv%s Tables Cmd - '%s'", ipVersion, command) # execute command (rc, stdOut, stdErr) = Command.execute(self.__log, "iptables", command) if rc == 0: self.__log("iptables-cmd-stdout").debug3("show output of IPv%s tables command '%s' (rc=%s) - %s", ipVersion, command, rc, stdOut) else: self.__log("iptables-cmd-failed").error("fail to run IPv%s tables command '%s' (rc=%s) - %s", ipVersion, command, rc, stdErr) return (rc,stdOut)
def flushAddresses(logger, device, scope=None, version=None): """This function flushes all IP addresses assigned to a device Args: logger device - the name of the device to flush all addresses version - IPv4 or IPv6 as an integer, 4 or 6 scope - the scope of the area where this address flush is valid: global, site, link, host Return: tuple (rc, stdout, stderr) Raise: None """ args = [] if version: if version == 4: args.append(IpConstant.IPV4) elif version == 6: args.append(IpConstant.IPV6) args += [IpOption.ADDRESS, IpAction.FLUSH, IpConstant.DEV, device] if scope: args += [IpConstant.SCOPE, scope] option = args[0] cmd = args[1:] rc = Command.executeIp(logger, option, *cmd) return rc
def flushDefaultRoute(logger, table, version=None): """This function flushes an existing IP default route Args: logger table - the table to add this route to. TABLEID may be a number or a string version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ args = [] if version: if version == 4: args.append(IpConstant.IPV4) elif version == 6: args.append(IpConstant.IPV6) args += [IpOption.ROUTE, IpAction.FLUSH, IpConstant.DEFAULT] if table: args += [IpConstant.TABLE, table] option = args[0] cmd = args[1:] rc = Command.executeIp(logger, option, *cmd) return rc
def showNeighboursByDevice(logger, device, version=None): """This function list neighbour entries attached to the given device Args: logger device - device name version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ args = [] if version: if version == 4: args.append(IpConstant.IPV4) elif version == 6: args.append(IpConstant.IPV6) args += [IpOption.NEIGHBOUR, IpAction.SHOW, IpConstant.DEV, device] option = args[0] cmd = args[1:] rc = Command.executeIp(logger, option, *cmd) return rc
def showNeighboursByDevice(logger, device, version=None): """This function list neighbour entries attached to the given device Args: logger device - device name version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ args = [] if version: if version == 4: args.append(IpConstant.IPV4) elif version == 6: args.append(IpConstant.IPV6) args += [IpOption.NEIGHBOUR, IpAction.SHOW, IpConstant.DEV, device] option = args[0] cmd = args[1:] rc = Command.executeIp(logger, option, *cmd) return rc
def sendRdiscReply(logger, device, destination, count=3, quiet=False, blocking=True): """This function sends IPv6 router discovery to a neighbour host Args: logger device - Name of network device where to send ICMPv6 Router Discovery packets destination - destination IP to ping count - send ICMPv6 Router Discovery X times quiet - quiet output blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [Ndisc.RDISC6_COMMAND_NAME, Ndisc.COUNT_OPTION, str(count)] if quiet is True: args.append(Ndisc.QUIET_OPTION) # must set <destination> <iface> as last args args.append(destination) args.append(device) rc = Command.execute(logger, Ndisc.RDISC6_COMMAND_NAME, args, blocking=blocking) return rc
def get_ptp_stat(server): measurement_cmd = "pmc -d %s -u -b 2 'GET CURRENT_DATA_SET'" % (PTP_DOMAIN) command = Command(server=server, wait=True, command=measurement_cmd, control=None, timeout=-1, enable=True) try: output = command.execute(server.ssh) # convert multiline text to list and remove useless command header measurement_list = output.replace("\t", "").split("\n")[2:] return [i for i in measurement_list if i != ""] except Exception as e: print(e) return []
def showNeighbours(logger, version=None): """This function list neighbour entries Args: logger version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.NEIGHBOUR, IpAction.SHOW) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.NEIGHBOUR, IpAction.SHOW) rc = Command.executeIp(logger, IpOption.NEIGHBOUR, IpAction.SHOW) return rc
def replaceRoute(logger, destination, gateway=None, table=None, device=None, version=None, scope=None, metric=None, src=None): """This function adds a new IP route or changes an existing IP route Args: logger destination-the destination prefix of the route gateway - the address of the nexthop router. table - the table to add this route to. TABLEID may be a number or a string device - the name specifies network device version - IPv4 or IPv6 as an integer, 4 or 6 scope - the scope of the area where this address is valid: global, site, link, host metric - the preference value of the route. NUMBER is an arbitrary 32bit number. src - the source address to prefer when sending to the destinations covered by the route prefix Return: tuple (rc, stdout, stderr) Raise: None """ args = [] if version: if version == 4: args.append(IpConstant.IPV4) elif version == 6: args.append(IpConstant.IPV6) args += [IpOption.ROUTE, IpAction.REPLACE, destination] if gateway: args += [IpConstant.VIA, gateway] if device: args += [IpConstant.DEV, device] if table: args += [IpConstant.TABLE, table] if scope: args += [IpConstant.SCOPE, scope] if metric: args += [IpConstant.METRIC, str(metric)] if src: args += [IpConstant.SRC, src] option = args[0] cmd = args[1:] rc = Command.executeIp(logger, option, *cmd) return rc
def sendArpRequest(logger, device, destination, count=3, timeout=1, quiet=False, firstReply=False, blocking=True): """This function sends ARP REQUEST to a neighbour host Args: logger device - Name of network device where to send ARP REQUEST packets destination - destination IP to ping count - stop after sending X ARP REQUEST packets timeout - specify a timeout, in seconds, before arping exits quiet - quiet output firstReply - Finish after the first reply confirming that target is alive blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [ Arping.ARPING_COMMAND_NAME, Arping.INTERFACE_OPTION, device, Arping.COUNT_OPTION, str(count), Arping.TIMEOUT_OPTION, str(timeout) ] if quiet is True: args.append(Arping.QUIET_OPTION) if firstReply is True: args.append(Arping.FIRST_REPLY_OPTION) # must set destination as last arg args.append(destination) rc = Command.execute(logger, Arping.ARPING_COMMAND_NAME, args, timeoutSec=(timeout + 3), blocking=blocking) return rc
def __init__(self, config): assert config is not None self.config = config self.num_legs = len(config.leg_order) self.cycle_time_s = None self.state = self.get_idle_state() self.idle_state = self.get_idle_state() self.next_command = None self.next_options = None self._create_actions() self._really_set_command(Command(), Options())
def showRules(logger, version=None): """This function list all rules Args: logger Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.RULE, IpAction.SHOW) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.RULE, IpAction.SHOW) rc = Command.executeIp(logger, IpOption.RULE, IpAction.SHOW) return rc
def showAddresses(logger): """This function list all protocol addresseses Args: logger Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.executeIp(logger, IpOption.ADDRESS, IpAction.SHOW) return rc
def sendNdiscRequest(logger, device, destination, count=3, timeout=1, quiet=False, firstReply=False, blocking=True): """This function sends IPv6 neighbor discovery to a neighbour host Args: logger device - Name of network device where to send ARP REQUEST packets destination - destination IP to ping count - send ICMPv6 Neighbor Discovery X times timeout - specify a timeout, in seconds, before ndisc exits quiet - quiet output firstReply - Exit as soon as the first advertisement is received blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [ Ndisc.NDISC6_COMMAND_NAME, Ndisc.COUNT_OPTION, str(count), Ndisc.TIMEOUT_OPTION, str(int(timeout) * 1000) ] # convert to milisec if quiet is True: args.append(Ndisc.QUIET_OPTION) if firstReply is True: args.append(Ndisc.FIRST_REPLY_OPTION) # must set <destination> <iface> as last args args.append(destination) args.append(device) rc = Command.execute(logger, Ndisc.NDISC6_COMMAND_NAME, args, timeoutSec=(timeout + 3), blocking=blocking) return rc
def showDevices(logger): """This function list all devices Args: logger Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.executeIp(logger, IpOption.LINK, IpAction.SHOW) return rc
def getVendorName(name, logger, vendorid): """This function returns the vendor name""" if vendorid.startswith("0x"): vendorid = vendorid[2:] (rc, stdout, stderr) = Command.execute(logger, name, "grep -E '^%s' %s" % (vendorid,DeviceUtils.HWADDR_DATA_FILE_NAME)) if rc != 0: logger("vendor-name-faild").error("Failed getting '%s' vendor name", vendorid) return None vendorName = stdout[len(vendorid):].strip() return vendorName
def showNeighbours(logger, version=None): """This function list neighbour entries Args: logger version - IPv4 or IPv6 as an integer, 4 or 6 Return: tuple (rc, stdout, stderr) Raise: None """ if version: if version == 4: return Command.executeIp(logger, IpConstant.IPV4, IpOption.NEIGHBOUR, IpAction.SHOW) elif version == 6: return Command.executeIp(logger, IpConstant.IPV6, IpOption.NEIGHBOUR, IpAction.SHOW) rc = Command.executeIp(logger, IpOption.NEIGHBOUR, IpAction.SHOW) return rc
def getChipName(name, logger, deviceid): """This function returns the chip description""" if deviceid.startswith("0x"): deviceid = deviceid[2:] (rc, stdout, stderr) = Command.execute(logger, name, "grep '\< *%s\>' %s" % (deviceid,DeviceUtils.HWADDR_DATA_FILE_NAME)) if rc != 0: logger("chip-name-faild").error("Failed getting '%s' chip name", deviceid) return None chipName = stdout.split(None,1)[1].strip() return chipName
def showAddress(logger, device): """This function list an device protocol addresseses Args: logger device - the name of the device to show Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.executeIp(logger, IpOption.ADDRESS, IpAction.SHOW, IpConstant.DEV, device) return rc
def activateDevice(logger, device): """This function change the state of the device to UP Args: logger device - the name specifies network device to operate on Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.executeIp(logger, IpOption.LINK, IpAction.SET, device, IpConstant.UP) return rc
def showEth(logger, device): """This function shows current settings of the specified device Args: logger device - device name Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.execute(logger, EthTool.ETH_TOOL_COMMAND_NAME, [EthTool.ETH_TOOL_COMMAND_NAME, device]) return rc
def showDeviceStatistics(logger, device): """This function shows a device statistics Args: logger device - the name specifies network device to show Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.executeIp(logger, IpOption.LINK, IpLink.STATISTICS_OPTION, IpAction.SHOW, IpConstant.DEV, device) return rc
def showEthStatistics(logger, device): """This function shows the specified ethernet device for NIC- and driver-specific statistics Args: logger device - device name Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.execute(logger, EthTool.ETH_TOOL_COMMAND_NAME, [EthTool.ETH_TOOL_COMMAND_NAME, EthTool.STATISTICS_OPTION, device]) return rc
def getSpeed(logger, device): """This function returns the device speed in Mb/s""" rc = EthTool.showEth(logger, device) if Command.isReturnOk(rc): output = rc[1].splitlines() for line in output: if line.strip().startswith("Speed"): # e.g. Speed: 1000Mb/s speed = line[8:-4] if speed.isdigit(): return int(speed) return None
def flushRoutes(logger, table=None, device=None, version=None, scope=None, proto=None): """This function flushes all IP routes assigned to a device Args: logger table - the table to add this route to. TABLEID may be a number or a string device - the name specifies network device version - IPv4 or IPv6 as an integer, 4 or 6 scope - the scope of the area where this address is valid: global, site, link, host proto - the routing protocol identifier of this route: kernel, boot, static, etc. Return: tuple (rc, stdout, stderr) Raise: None """ args = [] if version: if version == 4: args.append(IpConstant.IPV4) elif version == 6: args.append(IpConstant.IPV6) args += [IpOption.ROUTE, IpAction.FLUSH] if device: args += [IpConstant.DEV, device] if table: args += [IpConstant.TABLE, table] if scope: args += [IpConstant.SCOPE, scope] if proto: args += [IpConstant.PROTO, proto] option = args[0] cmd = args[1:] rc = Command.executeIp(logger, option, *cmd) return rc
def renameDevice(logger, device, name): """This function change the name of the device Note: This operation is not recommended if the device is running or has some addresses already configured Args: logger device - the name specifies network device to rename name - change the name of the device Return: tuple (rc, stdout, stderr) Raise: None """ rc = Command.executeIp(logger, IpOption.LINK, IpAction.SET, IpConstant.DEV, device, IpConstant.NAME, name) return rc
def sendArpReply(logger, device, destination, count=3, quiet=False, blocking=True): """This function sends ARP REPLY to a neighbour host Args: logger device - Name of network device where to send ARP REPLY packets destination - destination IP to ping count - stop after sending X ARP REQUEST packets quiet - quiet output blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [ Arping.ARPING_COMMAND_NAME, Arping.INTERFACE_OPTION, device, Arping.COUNT_OPTION, str(count), Arping.ARP_REPLY_OPTION ] if quiet is True: args.append(Arping.QUIET_OPTION) # must set destination as last arg args.append(destination) rc = Command.execute(logger, Arping.ARPING_COMMAND_NAME, args, blocking=blocking) return rc
def getStatistics(name, logger, device): """This function returns the device statistics""" statsDir = os.path.join(DeviceUtils.INTERFACE_DIR_NAME, device, DeviceUtils.STATS_DIR_NAME) (rc, stdout, stderr) = Command.execute(logger, name, "grep \"\" *", cwd=statsDir) if rc != 0: logger("device-stats-faild").error("Failed getting '%s' statistics", device) return None statsContainer = {} for pair in stdout.split(): key,value = pair.split(":") statsContainer[key] = value return statsContainer
def sendRdiscReply(logger, device, destination, count=3, quiet=False, blocking=True): """This function sends IPv6 router discovery to a neighbour host Args: logger device - Name of network device where to send ICMPv6 Router Discovery packets destination - destination IP to ping count - send ICMPv6 Router Discovery X times quiet - quiet output blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [Ndisc.RDISC6_COMMAND_NAME, Ndisc.COUNT_OPTION, str(count)] if quiet is True: args.append(Ndisc.QUIET_OPTION) # must set <destination> <iface> as last args args.append(destination) args.append(device) rc = Command.execute(logger, Ndisc.RDISC6_COMMAND_NAME, args, blocking=blocking) return rc
def sendArpRequest(logger, device, destination, count=3, timeout=1, quiet=False, firstReply=False, blocking=True): """This function sends ARP REQUEST to a neighbour host Args: logger device - Name of network device where to send ARP REQUEST packets destination - destination IP to ping count - stop after sending X ARP REQUEST packets timeout - specify a timeout, in seconds, before arping exits quiet - quiet output firstReply - Finish after the first reply confirming that target is alive blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [Arping.ARPING_COMMAND_NAME, Arping.INTERFACE_OPTION, device, Arping.COUNT_OPTION, str(count), Arping.TIMEOUT_OPTION, str(timeout)] if quiet is True: args.append(Arping.QUIET_OPTION) if firstReply is True: args.append(Arping.FIRST_REPLY_OPTION) # must set destination as last arg args.append(destination) rc = Command.execute(logger, Arping.ARPING_COMMAND_NAME, args, timeoutSec=(timeout+3), blocking=blocking) return rc
def sendNdiscRequest(logger, device, destination, count=3, timeout=1, quiet=False, firstReply=False, blocking=True): """This function sends IPv6 neighbor discovery to a neighbour host Args: logger device - Name of network device where to send ARP REQUEST packets destination - destination IP to ping count - send ICMPv6 Neighbor Discovery X times timeout - specify a timeout, in seconds, before ndisc exits quiet - quiet output firstReply - Exit as soon as the first advertisement is received blocking - if True, waits for command to complete Return: tuple (rc, stdout, stderr) Raise: None """ args = [Ndisc.NDISC6_COMMAND_NAME, Ndisc.COUNT_OPTION, str(count), Ndisc.TIMEOUT_OPTION, str(int(timeout)*1000)] # convert to milisec if quiet is True: args.append(Ndisc.QUIET_OPTION) if firstReply is True: args.append(Ndisc.FIRST_REPLY_OPTION) # must set <destination> <iface> as last args args.append(destination) args.append(device) rc = Command.execute(logger, Ndisc.NDISC6_COMMAND_NAME, args, timeoutSec=(timeout+3), blocking=blocking) return rc
def setEth(logger, device, speed=None, fullduplex=True, autoneg=True): """This function changes some or all settings of the specified ethernet device Args: logger device - device name speed - Set speed in Mb/s fullduplex - Sets full or half duplex mode autoneg - Specifies whether autonegotiation should be enabled Return: tuple (rc, stdout, stderr) Raise: None """ args = [EthTool.ETH_TOOL_COMMAND_NAME, EthTool.CHANGE_OPTION, device] if speed: args += [EthTool.SPEED_SETTING, speed] args.append(EthTool.DUPLEX_SETTING) if fullduplex: args.append('full') else: args.append('half') args.append(EthTool.AUTO_NEG_SETTING) if autoneg: args.append('on') else: args.append('off') rc = Command.execute(logger, EthTool.ETH_TOOL_COMMAND_NAME, args) return rc
def __getEthDevicesByAttr(name, logger, key, value): """This function lists all ethernet devices that matches the given attribute""" deviceDir = os.path.join("*", DeviceUtils.DEVICE_DIR_NAME) (rc, stdout, stderr) = Command.execute(logger, name, "grep \"\" %s" % os.path.join(deviceDir,key), cwd=DeviceUtils.INTERFACE_DIR_NAME) if rc != 0: logger("device-attr-faild").error("Failed getting eths attribute: %s", key) return None output = stdout.splitlines() ethList = [] for line in output: attr = line.split(':')[-1] if attr == value: deviceName = line.split('/')[0] ethList.append(deviceName) return ethList
def getPciByIndex(logger, name, vendorid, deviceid, pciIndex): """This function returns the device pci (bus:device.function)""" (rc, stdout, stderr) = Command.execute(logger, name, "/sbin/lspci -n | grep %s:%s" % (vendorid[2:], deviceid[2:])) if rc != 0: logger("device-lspci-faild").error("Failed getting '%s:%s-%s' lspci",vendorid, deviceid, pciIndex) return None # example: # 04:00.0 0200: 8086:10fb (rev 01) # 04:00.1 0200: 8086:10fb (rev 01) # 06:00.0 0200: 8086:10fb (rev 01) output = stdout.splitlines() pci = None if pciIndex < len(output): pci = output[pciIndex].split()[0] else: logger("device-lspci-bad-index").debug1("PCI list contains only %s devices of type '%s:%s' ", len(output), vendorid, deviceid) return pci