diff options
Diffstat (limited to 'resources')
-rw-r--r-- | resources/libraries/python/InterfaceSetup.py | 182 | ||||
-rw-r--r-- | resources/libraries/python/InterfaceUtil.py | 237 | ||||
-rw-r--r-- | resources/libraries/python/TGSetup.py | 4 | ||||
-rw-r--r-- | resources/libraries/python/VatConfigGenerator.py | 58 | ||||
-rw-r--r-- | resources/libraries/python/VatJsonUtil.py | 102 | ||||
-rw-r--r-- | resources/libraries/python/topology.py | 176 | ||||
-rw-r--r-- | resources/libraries/robot/default.robot | 5 | ||||
-rw-r--r-- | resources/libraries/robot/vxlan.robot | 4 |
8 files changed, 345 insertions, 423 deletions
diff --git a/resources/libraries/python/InterfaceSetup.py b/resources/libraries/python/InterfaceSetup.py deleted file mode 100644 index 946c8fc8fd..0000000000 --- a/resources/libraries/python/InterfaceSetup.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright (c) 2016 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Interface setup library.""" - -from ssh import SSH -from robot.api.deco import keyword -from resources.libraries.python.VatExecutor import VatExecutor - - -class InterfaceSetup(object): - """Interface setup utilities.""" - - __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules' - - @staticmethod - def tg_set_interface_driver(node, pci_addr, driver): - """Set interface driver on the TG node. - - :param node: Node to set interface driver on (must be TG node). - :param pci_addr: PCI address of the interface. - :param driver: Driver name. - :type node: dict - :type pci_addr: str - :type driver: str - """ - old_driver = InterfaceSetup.tg_get_interface_driver(node, pci_addr) - if old_driver == driver: - return - - ssh = SSH() - ssh.connect(node) - - # Unbind from current driver - if old_driver is not None: - cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'.format( - pci_addr, old_driver) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, - node['host'])) - - # Bind to the new driver - cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'.format( - pci_addr, driver) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) - - @staticmethod - def tg_get_interface_driver(node, pci_addr): - """Get interface driver from the TG node. - - :param node: Node to get interface driver on (must be TG node). - :param pci_addr: PCI address of the interface. - :type node: dict - :type pci_addr: str - :return: Interface driver or None if not found. - :rtype: str - - .. note:: - # lspci -vmmks 0000:00:05.0 - Slot: 00:05.0 - Class: Ethernet controller - Vendor: Red Hat, Inc - Device: Virtio network device - SVendor: Red Hat, Inc - SDevice: Device 0001 - PhySlot: 5 - Driver: virtio-pci - """ - ssh = SSH() - ssh.connect(node) - - cmd = 'lspci -vmmks {0}'.format(pci_addr) - - (ret_code, stdout, _) = ssh.exec_command(cmd) - if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) - - for line in stdout.splitlines(): - if len(line) == 0: - continue - (name, value) = line.split("\t", 1) - if name == 'Driver:': - return value - - return None - - @staticmethod - def tg_set_interfaces_udev_rules(node): - """Set udev rules for interfaces. - - Create udev rules file in /etc/udev/rules.d where are rules for each - interface used by TG node, based on MAC interface has specific name. - So after unbind and bind again to kernel driver interface has same - name as before. This must be called after TG has set name for each - port in topology dictionary. - udev rule example - SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f", - NAME="eth1" - - :param node: Node to set udev rules on (must be TG node). - :type node: dict - """ - ssh = SSH() - ssh.connect(node) - - cmd = 'rm -f {0}'.format(InterfaceSetup.__UDEV_IF_RULES_FILE) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) - - for if_k, if_v in node['interfaces'].items(): - if if_k == 'mgmt': - continue - rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \ - '==\\"' + if_v['mac_address'] + '\\", NAME=\\"' + \ - if_v['name'] + '\\"' - cmd = 'sh -c "echo \'{0}\' >> {1}"'.format( - rule, InterfaceSetup.__UDEV_IF_RULES_FILE) - (ret_code, _, _) = ssh.exec_command_sudo(cmd) - if int(ret_code) != 0: - raise Exception("'{0}' failed on '{1}'".format(cmd, - node['host'])) - - cmd = '/etc/init.d/udev restart' - ssh.exec_command_sudo(cmd) - - @staticmethod - def tg_set_interfaces_default_driver(node): - """Set interfaces default driver specified in topology yaml file. - - :param node: Node to setup interfaces driver on (must be TG node). - :type node: dict - """ - for if_k, if_v in node['interfaces'].items(): - if if_k == 'mgmt': - continue - InterfaceSetup.tg_set_interface_driver(node, if_v['pci_address'], - if_v['driver']) - - @staticmethod - def create_vxlan_interface(node, vni, source_ip, destination_ip): - """Create VXLAN interface and return index of created interface - - Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT - command on the node. - - :param node: Node where to create VXLAN interface - :param vni: VXLAN Network Identifier - :param source_ip: Source IP of a VXLAN Tunnel End Point - :param destination_ip: Destination IP of a VXLAN Tunnel End Point - :type node: dict - :type vni: int - :type source_ip: str - :type destination_ip: str - :return: SW IF INDEX of created interface - :rtype: int - """ - - output = VatExecutor.cmd_from_template(node, "vxlan_create.vat", - src=source_ip, - dst=destination_ip, - vni=vni) - output = output[0] - - if output["retval"] == 0: - return output["sw_if_index"] - else: - raise RuntimeError('Unable to create VXLAN interface on node {}'.\ - format(node)) diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py index 25503c08df..4631ccce7a 100644 --- a/resources/libraries/python/InterfaceUtil.py +++ b/resources/libraries/python/InterfaceUtil.py @@ -14,15 +14,22 @@ """Interface util library""" from time import time, sleep + from robot.api import logger + +from resources.libraries.python.ssh import SSH from resources.libraries.python.ssh import exec_cmd_no_error from resources.libraries.python.topology import NodeType, Topology from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal +from resources.libraries.python.VatJsonUtil import VatJsonUtil +from resources.libraries.python.parsers.JsonParser import JsonParser class InterfaceUtil(object): """General utilities for managing interfaces""" + __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules' + @staticmethod def set_interface_state(node, interface, state): """Set interface state on a node. @@ -191,3 +198,233 @@ class InterfaceUtil(object): return data_if return data + + @staticmethod + def tg_set_interface_driver(node, pci_addr, driver): + """Set interface driver on the TG node. + + :param node: Node to set interface driver on (must be TG node). + :param pci_addr: PCI address of the interface. + :param driver: Driver name. + :type node: dict + :type pci_addr: str + :type driver: str + """ + old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr) + if old_driver == driver: + return + + ssh = SSH() + ssh.connect(node) + + # Unbind from current driver + if old_driver is not None: + cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'.format( + pci_addr, old_driver) + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if int(ret_code) != 0: + raise Exception("'{0}' failed on '{1}'".format(cmd, + node['host'])) + + # Bind to the new driver + cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'.format( + pci_addr, driver) + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if int(ret_code) != 0: + raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) + + @staticmethod + def tg_get_interface_driver(node, pci_addr): + """Get interface driver from the TG node. + + :param node: Node to get interface driver on (must be TG node). + :param pci_addr: PCI address of the interface. + :type node: dict + :type pci_addr: str + :return: Interface driver or None if not found. + :rtype: str + + .. note:: + # lspci -vmmks 0000:00:05.0 + Slot: 00:05.0 + Class: Ethernet controller + Vendor: Red Hat, Inc + Device: Virtio network device + SVendor: Red Hat, Inc + SDevice: Device 0001 + PhySlot: 5 + Driver: virtio-pci + """ + ssh = SSH() + ssh.connect(node) + + cmd = 'lspci -vmmks {0}'.format(pci_addr) + + (ret_code, stdout, _) = ssh.exec_command(cmd) + if int(ret_code) != 0: + raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) + + for line in stdout.splitlines(): + if len(line) == 0: + continue + (name, value) = line.split("\t", 1) + if name == 'Driver:': + return value + + return None + + @staticmethod + def tg_set_interfaces_udev_rules(node): + """Set udev rules for interfaces. + + Create udev rules file in /etc/udev/rules.d where are rules for each + interface used by TG node, based on MAC interface has specific name. + So after unbind and bind again to kernel driver interface has same + name as before. This must be called after TG has set name for each + port in topology dictionary. + udev rule example + SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f", + NAME="eth1" + + :param node: Node to set udev rules on (must be TG node). + :type node: dict + """ + ssh = SSH() + ssh.connect(node) + + cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE) + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if int(ret_code) != 0: + raise Exception("'{0}' failed on '{1}'".format(cmd, node['host'])) + + for interface in node['interfaces'].values(): + rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \ + '==\\"' + interface['mac_address'] + '\\", NAME=\\"' + \ + interface['name'] + '\\"' + cmd = 'sh -c "echo \'{0}\' >> {1}"'.format( + rule, InterfaceUtil.__UDEV_IF_RULES_FILE) + (ret_code, _, _) = ssh.exec_command_sudo(cmd) + if int(ret_code) != 0: + raise Exception("'{0}' failed on '{1}'".format(cmd, + node['host'])) + + cmd = '/etc/init.d/udev restart' + ssh.exec_command_sudo(cmd) + + @staticmethod + def tg_set_interfaces_default_driver(node): + """Set interfaces default driver specified in topology yaml file. + + :param node: Node to setup interfaces driver on (must be TG node). + :type node: dict + """ + for interface in node['interfaces'].values(): + InterfaceUtil.tg_set_interface_driver(node, + interface['pci_address'], + interface['driver']) + + @staticmethod + def update_vpp_interface_data_on_node(node): + """Update vpp generated interface data for a given node in DICT__nodes + + Updates interface names, software if index numbers and any other details + generated specifically by vpp that are unknown before testcase run. + It does this by dumping interface list to JSON output from all + devices using vpp_api_test, and pairing known information from topology + (mac address/pci address of interface) to state from VPP. + + :param node: Node selected from DICT__nodes + :type node: dict + """ + vat_executor = VatExecutor() + vat_executor.execute_script_json_out("dump_interfaces.vat", node) + interface_dump_json = vat_executor.get_script_stdout() + VatJsonUtil.update_vpp_interface_data_from_json(node, + interface_dump_json) + + @staticmethod + def update_tg_interface_data_on_node(node): + """Update interface name for TG/linux node in DICT__nodes. + + :param node: Node selected from DICT__nodes. + :type node: dict + + .. note:: + # for dev in `ls /sys/class/net/`; + > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done + "52:54:00:9f:82:63": "eth0" + "52:54:00:77:ae:a9": "eth1" + "52:54:00:e1:8a:0f": "eth2" + "00:00:00:00:00:00": "lo" + + .. todo:: parse lshw -json instead + """ + # First setup interface driver specified in yaml file + InterfaceUtil.tg_set_interfaces_default_driver(node) + + # Get interface names + ssh = SSH() + ssh.connect(node) + + cmd = ('for dev in `ls /sys/class/net/`; do echo "\\"`cat ' + '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;') + + (ret_code, stdout, _) = ssh.exec_command(cmd) + if int(ret_code) != 0: + raise Exception('Get interface name and MAC failed') + tmp = "{" + stdout.rstrip().replace('\n', ',') + "}" + interfaces = JsonParser().parse_data(tmp) + for interface in node['interfaces'].values(): + name = interfaces.get(interface['mac_address']) + if name is None: + continue + interface['name'] = name + + # Set udev rules for interfaces + InterfaceUtil.tg_set_interfaces_udev_rules(node) + + @staticmethod + def update_all_interface_data_on_all_nodes(nodes): + """Update interface names on all nodes in DICT__nodes. + + This method updates the topology dictionary by querying interface lists + of all nodes mentioned in the topology dictionary. + + :param nodes: Nodes in the topology. + :type nodes: dict + """ + for node_data in nodes.values(): + if node_data['type'] == NodeType.DUT: + InterfaceUtil.update_vpp_interface_data_on_node(node_data) + elif node_data['type'] == NodeType.TG: + InterfaceUtil.update_tg_interface_data_on_node(node_data) + + @staticmethod + def create_vxlan_interface(node, vni, source_ip, destination_ip): + """Create VXLAN interface and return sw if index of created interface. + + Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT + command on the node. + + :param node: Node where to create VXLAN interface. + :param vni: VXLAN Network Identifier. + :param source_ip: Source IP of a VXLAN Tunnel End Point. + :param destination_ip: Destination IP of a VXLAN Tunnel End Point. + :type node: dict + :type vni: int + :type source_ip: str + :type destination_ip: str + :return: SW IF INDEX of created interface. + :rtype: int + """ + output = VatExecutor.cmd_from_template(node, "vxlan_create.vat", + src=source_ip, + dst=destination_ip, + vni=vni) + output = output[0] + + if output["retval"] == 0: + return output["sw_if_index"] + else: + raise RuntimeError('Unable to create VXLAN interface on node {}' + .format(node)) diff --git a/resources/libraries/python/TGSetup.py b/resources/libraries/python/TGSetup.py index 3e372e9464..05c8b1d177 100644 --- a/resources/libraries/python/TGSetup.py +++ b/resources/libraries/python/TGSetup.py @@ -14,7 +14,7 @@ """TG Setup library.""" from topology import NodeType -from InterfaceSetup import InterfaceSetup +from InterfaceUtil import InterfaceUtil class TGSetup(object): @@ -29,4 +29,4 @@ class TGSetup(object): """ for node in nodes.values(): if node['type'] == NodeType.TG: - InterfaceSetup.tg_set_interfaces_default_driver(node) + InterfaceUtil.tg_set_interfaces_default_driver(node) diff --git a/resources/libraries/python/VatConfigGenerator.py b/resources/libraries/python/VatConfigGenerator.py deleted file mode 100644 index 98be9d3448..0000000000 --- a/resources/libraries/python/VatConfigGenerator.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2016 Cisco and/or its affiliates. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Can be used to generate VAT scripts from VAT template files.""" - -from robot.api import logger - - -class VatConfigGenerator(object): - """Generates VAT configuration scripts from VAT script template files. - """ - def __init__(self): - pass - - @staticmethod - def generate_vat_config_file(template_file, env_var_dict, out_file): - """ Write VAT configuration script to out file. - - Generates VAT configuration script from template using - dictionary containing environment variables - :param template_file: file that contains the VAT script template - :param env_var_dict: python dictionary that maps test - environment variables - """ - - template_data = open(template_file).read() - logger.trace("Loaded template file: \n '{0}'".format(template_data)) - generated_config = template_data.format(**env_var_dict) - logger.trace("Generated script file: \n '{0}'".format(generated_config)) - with open(out_file, 'w') as work_file: - work_file.write(generated_config) - - @staticmethod - def generate_vat_config_string(template_file, env_var_dict): - """ Return wat config string generated from template. - - Generates VAT configuration script from template using - dictionary containing environment variables - :param template_file: file that contains the VAT script template - :param env_var_dict: python dictionary that maps test - environment variables - """ - - template_data = open(template_file).read() - logger.trace("Loaded template file: \n '{0}'".format(template_data)) - generated_config = template_data.format(**env_var_dict) - logger.trace("Generated script file: \n '{0}'".format(generated_config)) - return generated_config diff --git a/resources/libraries/python/VatJsonUtil.py b/resources/libraries/python/VatJsonUtil.py new file mode 100644 index 0000000000..36c50533fc --- /dev/null +++ b/resources/libraries/python/VatJsonUtil.py @@ -0,0 +1,102 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utilities to work with JSON data format from VAT.""" + +from robot.api import logger + +from resources.libraries.python.parsers.JsonParser import JsonParser + + +class VatJsonUtil(object): + """Utilities to work with JSON data format from VAT.""" + + @staticmethod + def _convert_mac_to_number_list(mac_address): + """Convert MAC address string to list of decimal numbers. + + Converts a ":" separated MAC address to decimal number list as used + in JSON interface dump. + + :param mac_address: MAC address. + :type mac_address: str + :return: List representation of MAC address. + :rtype: list + """ + list_mac = [] + for num in mac_address.split(":"): + list_mac.append(int(num, 16)) + return list_mac + + @staticmethod + def get_vpp_interface_by_mac(interfaces_list, mac_address): + """Return interface dictionary from interface_list by MAC address. + + Extracts interface dictionary from all of the interfaces in interfaces + list parsed from json according to mac_address of the interface. + + :param interfaces_list: Interfaces parsed from JSON. + :param mac_address: MAC address of interface we are looking for. + :type interfaces_list: dict + :type mac_address: str + :return: Interface from JSON. + :rtype: dict + """ + interface_dict = {} + list_mac_address = VatJsonUtil._convert_mac_to_number_list(mac_address) + logger.trace("MAC address {0} converted to list {1}." + .format(mac_address, list_mac_address)) + for interface in interfaces_list: + # TODO: create vat json integrity checking and move there + if "l2_address" not in interface: + raise KeyError( + "key l2_address not found in interface dict." + "Probably input list is not parsed from correct VAT " + "json output.") + if "l2_address_length" not in interface: + raise KeyError( + "key l2_address_length not found in interface " + "dict. Probably input list is not parsed from correct " + "VAT json output.") + mac_from_json = interface["l2_address"][:6] + if mac_from_json == list_mac_address: + if interface["l2_address_length"] != 6: + raise ValueError("l2_address_length value is not 6.") + interface_dict = interface + break + return interface_dict + + @staticmethod + def update_vpp_interface_data_from_json(node, interface_dump_json): + """Update vpp node data in node__DICT from json interface dump. + + This method updates vpp interface names and sw if indexes according to + interface MAC addresses found in interface_dump_json. + + :param node: Node dictionary. + :param interface_dump_json: JSON output from dump_interface_list VAT + command. + :type node: dict + :type interface_dump_json: str + """ + interface_list = JsonParser().parse_data(interface_dump_json) + for ifc in node['interfaces'].values(): + if_mac = ifc['mac_address'] + interface_dict = VatJsonUtil.get_vpp_interface_by_mac( + interface_list, if_mac) + if not interface_dict: + raise Exception('Interface {0} not found by MAC {1}' + .format(ifc, if_mac)) + ifc['name'] = interface_dict["interface_name"] + ifc['vpp_sw_index'] = interface_dict["sw_if_index"] + ifc['mtu'] = interface_dict["mtu"] diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py index 7a27173d40..d04d584623 100644 --- a/resources/libraries/python/topology.py +++ b/resources/libraries/python/topology.py @@ -13,10 +13,6 @@ """Defines nodes and topology structure.""" -from resources.libraries.python.parsers.JsonParser import JsonParser -from resources.libraries.python.VatExecutor import VatExecutor -from resources.libraries.python.ssh import SSH -from resources.libraries.python.InterfaceSetup import InterfaceSetup from robot.api import logger from robot.libraries.BuiltIn import BuiltIn from robot.api.deco import keyword @@ -137,8 +133,6 @@ class Topology(object): This method returns the interface names asociated with given links for a given node. - The resulting dictionary can be then used to with VatConfigGenerator - to generate a VAT script with proper interface names. :param link_names: list of names of the link that a interface is connected to. :param node: the node topology directory @@ -169,176 +163,6 @@ class Topology(object): return self._get_interface_by_key_value(node, "vpp_sw_index", sw_index) @staticmethod - def convert_mac_to_number_list(mac_address): - """Convert mac address string to list of decimal numbers. - - Converts a : separated mac address to decimal number list as used - in json interface dump. - :param mac_address: string mac address - :return: list representation of mac address - """ - - list_mac = [] - for num in mac_address.split(":"): - list_mac.append(int(num, 16)) - return list_mac - - def _extract_vpp_interface_by_mac(self, interfaces_list, mac_address): - """Return interface dictionary from interface_list by mac address. - - Extracts interface dictionary from all of the interfaces in interfaces - list parsed from json according to mac_address of the interface - :param interfaces_list: dictionary of all interfaces parsed from json - :param mac_address: string mac address of interface we are looking for - :return: interface dictionary from json - """ - - interface_dict = {} - list_mac_address = self.convert_mac_to_number_list(mac_address) - logger.trace(str(list_mac_address)) - for interface in interfaces_list: - # TODO: create vat json integrity checking and move there - if "l2_address" not in interface: - raise KeyError( - "key l2_address not found in interface dict." - "Probably input list is not parsed from correct VAT " - "json output.") - if "l2_address_length" not in interface: - raise KeyError( - "key l2_address_length not found in interface " - "dict. Probably input list is not parsed from correct " - "VAT json output.") - mac_from_json = interface["l2_address"][:6] - if mac_from_json == list_mac_address: - if interface["l2_address_length"] != 6: - raise ValueError("l2_address_length value is not 6.") - interface_dict = interface - break - return interface_dict - - def vpp_interface_name_from_json_by_mac(self, json_data, mac_address): - """Return vpp interface name string from VAT interface dump json output - - Extracts the name given to an interface by VPP. - These interface names differ from what you would see if you - used the ipconfig or similar command. - Required json data can be obtained by calling : - VatExecutor.execute_script_json_out("dump_interfaces.vat", node) - :param json_data: string json data from sw_interface_dump VAT command - :param mac_address: string containing mac address of interface - whose vpp name we wish to discover. - :return: string vpp interface name - """ - - interfaces_list = JsonParser().parse_data(json_data) - # TODO: checking if json data is parsed correctly - interface_dict = self._extract_vpp_interface_by_mac(interfaces_list, - mac_address) - interface_name = interface_dict["interface_name"] - return interface_name - - def _update_node_interface_data_from_json(self, node, interface_dump_json): - """Update node vpp data in node__DICT from json interface dump. - - This method updates vpp interface names and sw indexexs according to - interface mac addresses found in interface_dump_json - :param node: node dictionary - :param interface_dump_json: json output from dump_interface_list VAT - command - """ - - interface_list = JsonParser().parse_data(interface_dump_json) - for ifc in node['interfaces'].values(): - if 'link' not in ifc: - continue - if_mac = ifc['mac_address'] - interface_dict = self._extract_vpp_interface_by_mac(interface_list, - if_mac) - if not interface_dict: - raise Exception('Interface {0} not found by MAC {1}'. - format(ifc, if_mac)) - ifc['name'] = interface_dict["interface_name"] - ifc['vpp_sw_index'] = interface_dict["sw_if_index"] - ifc['mtu'] = interface_dict["mtu"] - - def update_vpp_interface_data_on_node(self, node): - """Update vpp generated interface data for a given node in DICT__nodes - - Updates interface names, software index numbers and any other details - generated specifically by vpp that are unknown before testcase run. - :param node: Node selected from DICT__nodes - """ - - vat_executor = VatExecutor() - vat_executor.execute_script_json_out("dump_interfaces.vat", node) - interface_dump_json = vat_executor.get_script_stdout() - self._update_node_interface_data_from_json(node, - interface_dump_json) - - @staticmethod - def update_tg_interface_data_on_node(node): - """Update interface name for TG/linux node in DICT__nodes - - :param node: Node selected from DICT__nodes. - :type node: dict - - .. note:: - # for dev in `ls /sys/class/net/`; - > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done - "52:54:00:9f:82:63": "eth0" - "52:54:00:77:ae:a9": "eth1" - "52:54:00:e1:8a:0f": "eth2" - "00:00:00:00:00:00": "lo" - - .. todo:: parse lshw -json instead - """ - # First setup interface driver specified in yaml file - InterfaceSetup.tg_set_interfaces_default_driver(node) - - # Get interface names - ssh = SSH() - ssh.connect(node) - - cmd = 'for dev in `ls /sys/class/net/`; do echo "\\"`cat ' \ - '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;' - - (ret_code, stdout, _) = ssh.exec_command(cmd) - if int(ret_code) != 0: - raise Exception('Get interface name and MAC failed') - tmp = "{" + stdout.rstrip().replace('\n', ',') + "}" - interfaces = JsonParser().parse_data(tmp) - for if_k, if_v in node['interfaces'].items(): - if if_k == 'mgmt': - continue - name = interfaces.get(if_v['mac_address']) - if name is None: - continue - if_v['name'] = name - - # Set udev rules for interfaces - InterfaceSetup.tg_set_interfaces_udev_rules(node) - - def update_all_interface_data_on_all_nodes(self, nodes): - """Update interface names on all nodes in DICT__nodes - - :param nodes: Nodes in the topology. - :type nodes: dict - - This method updates the topology dictionary by querying interface lists - of all nodes mentioned in the topology dictionary. - It does this by dumping interface list to json output from all devices - using vpp_api_test, and pairing known information from topology - (mac address/pci address of interface) to state from VPP. - For TG/linux nodes add interface name only. - """ - - for node_data in nodes.values(): - if node_data['type'] == NodeType.DUT: - self.update_vpp_interface_data_on_node(node_data) - elif node_data['type'] == NodeType.TG: - self.update_tg_interface_data_on_node(node_data) - - @staticmethod def get_interface_sw_index(node, interface): """Get VPP sw_index for the interface. diff --git a/resources/libraries/robot/default.robot b/resources/libraries/robot/default.robot index d085825a04..dae515423b 100644 --- a/resources/libraries/robot/default.robot +++ b/resources/libraries/robot/default.robot @@ -13,8 +13,9 @@ *** Settings *** | Variables | resources/libraries/python/topology.py -| Library | resources/libraries/python/DUTSetup.py -| Library | resources/libraries/python/TGSetup.py +| Library | resources.libraries.python.topology.Topology +| Library | resources.libraries.python.DUTSetup +| Library | resources.libraries.python.TGSetup | Library | Collections *** Keywords *** diff --git a/resources/libraries/robot/vxlan.robot b/resources/libraries/robot/vxlan.robot index e855f2499d..1f3b141470 100644 --- a/resources/libraries/robot/vxlan.robot +++ b/resources/libraries/robot/vxlan.robot @@ -14,15 +14,13 @@ *** Settings *** | Library | Collections | Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/interfaces.robot | Resource | resources/libraries/robot/bridge_domain.robot | Resource | resources/libraries/robot/l2_xconnect.robot | Library | resources.libraries.python.L2Util | Library | resources.libraries.python.IPUtil | Library | resources.libraries.python.IPv4Util | Library | resources.libraries.python.IPv4Setup -| Library | resources.libraries.python.InterfaceSetup -| Library | resources.libraries.python.InterfaceUtil -| Library | resources.libraries.python.topology.Topology | Library | resources.libraries.python.NodePath |