Beispiel #1
0
    def vpp_setup_bidirectional_cross_connect(node, interface1, interface2):
        """Create bidirectional cross-connect between 2 interfaces on vpp node.

        :param node: Node to add bidirectional cross-connect.
        :param interface1: First interface name or sw_if_index.
        :param interface2: Second interface name or sw_if_index.
        :type node: dict
        :type interface1: str or int
        :type interface2: str or int
        """

        if isinstance(interface1, basestring):
            sw_iface1 = Topology().get_interface_sw_index(node, interface1)
        else:
            sw_iface1 = interface1

        if isinstance(interface2, basestring):
            sw_iface2 = Topology().get_interface_sw_index(node, interface2)
        else:
            sw_iface2 = interface2

        with VatTerminal(node) as vat:
            vat.vat_terminal_exec_cmd_from_template('l2_xconnect.vat',
                                                    interface1=sw_iface1,
                                                    interface2=sw_iface2)
            vat.vat_terminal_exec_cmd_from_template('l2_xconnect.vat',
                                                    interface1=sw_iface2,
                                                    interface2=sw_iface1)
Beispiel #2
0
    def vpp_setup_bidirectional_l2_patch(node, interface1, interface2):
        """Create bidirectional l2 patch between 2 interfaces on vpp node.

        :param node: Node to add bidirectional l2 patch.
        :param interface1: First interface name or sw_if_index.
        :param interface2: Second interface name or sw_if_index.
        :type node: dict
        :type interface1: str or int
        :type interface2: str or int
        """

        if isinstance(interface1, basestring):
            sw_iface1 = Topology().get_interface_sw_index(node, interface1)
        else:
            sw_iface1 = interface1

        if isinstance(interface2, basestring):
            sw_iface2 = Topology().get_interface_sw_index(node, interface2)
        else:
            sw_iface2 = interface2

        cmd = 'l2_patch_add_del'
        args1 = dict(rx_sw_if_index=sw_iface1,
                     tx_sw_if_index=sw_iface2,
                     is_add=1)
        args2 = dict(rx_sw_if_index=sw_iface2,
                     tx_sw_if_index=sw_iface1,
                     is_add=1)

        err_msg = 'Failed to add L2 patch between two interfaces on' \
                  ' host {host}'.format(host=node['host'])

        with PapiExecutor(node) as papi_exec:
            papi_exec.add(cmd, **args1).add(cmd, **args2).get_replies(err_msg).\
                verify_replies(err_msg=err_msg)
Beispiel #3
0
    def vpp_setup_bidirectional_l2_patch(node, interface1, interface2):
        """Create bidirectional l2 patch between 2 interfaces on vpp node.

        :param node: Node to add bidirectional l2 patch.
        :param interface1: First interface name or sw_if_index.
        :param interface2: Second interface name or sw_if_index.
        :type node: dict
        :type interface1: str or int
        :type interface2: str or int
        """
        if isinstance(interface1, str):
            sw_iface1 = Topology().get_interface_sw_index(node, interface1)
        else:
            sw_iface1 = interface1

        if isinstance(interface2, str):
            sw_iface2 = Topology().get_interface_sw_index(node, interface2)
        else:
            sw_iface2 = interface2

        cmd = u"l2_patch_add_del"
        args1 = dict(rx_sw_if_index=sw_iface1,
                     tx_sw_if_index=sw_iface2,
                     is_add=True)
        args2 = dict(rx_sw_if_index=sw_iface2,
                     tx_sw_if_index=sw_iface1,
                     is_add=True)
        err_msg = f"Failed to add L2 patch between two interfaces " \
            f"on host {node['host']}"

        with PapiSocketExecutor(node) as papi_exec:
            papi_exec.add(cmd, **args1).add(cmd, **args2).get_replies(err_msg)
    def vpp_get_ipv46_interface_counter(self, node, interface, is_ipv6=True):
        """Return interface IPv4/IPv6 counter.

        :param node: Node to get interface IPv4/IPv6 counter on.
        :param interface: Interface name.
        :param is_ipv6: Specify IP version.
        :type node: dict
        :type interface: str
        :type is_ipv6: bool
        :returns: Interface IPv4/IPv6 counter.
        :rtype: int
        """
        version = 'ip6' if is_ipv6 else 'ip4'
        topo = Topology()
        if_index = topo.get_interface_sw_index(node, interface)
        if if_index is None:
            logger.trace('{i} sw_index not found.'.format(i=interface))
            return 0

        if_counters = self._stats_table.get('interface_counters')
        if if_counters is None or len(if_counters) == 0:
            logger.trace('No interface counters.')
            return 0
        for counter in if_counters:
            if counter['vnet_counter_type'] == version:
                data = counter['data']
                return data[if_index]
        logger.trace('{i} {v} counter not found.'.format(i=interface,
                                                         v=version))
        return 0
Beispiel #5
0
    def vpp_nodes_set_ipv4_addresses(nodes, nodes_addr):
        """Set IPv4 addresses on all VPP nodes in topology.

        :param nodes: Nodes of the test topology.
        :param nodes_addr: Available nodes IPv4 addresses.
        :type nodes: dict
        :type nodes_addr: dict
        :returns: Affected interfaces as list of (node, interface) tuples.
        :rtype: list
        """
        interfaces = []
        for net in nodes_addr.values():
            for port in net['ports'].values():
                host = port.get('node')
                if host is None:
                    continue
                topo = Topology()
                node = topo.get_node_by_hostname(nodes, host)
                if node is None:
                    continue
                if node['type'] != NodeType.DUT:
                    continue
                iface_key = topo.get_interface_by_name(node, port['if'])
                get_node(node).set_ip(iface_key, port['addr'], net['prefix'])
                interfaces.append((node, port['if']))

        return interfaces
Beispiel #6
0
    def get_sw_if_index(self, interface):
        """Get sw_if_index of specified interface from current node.

        :param interface: Interface name.
        :type interface: str
        :returns: sw_if_index of the interface or None.
        :rtype: int
        """
        return Topology().get_interface_sw_index(self.node_info, interface)
Beispiel #7
0
    def compute_path(self, always_same_link=True):
        """Compute path for added nodes.

        .. note:: First add at least two nodes to the topology.

        :param always_same_link: If True use always same link between two nodes
            in path. If False use different link (if available)
            between two nodes if one link was used before.
        :type always_same_link: bool
        :raises RuntimeError: If not enough nodes for path.
        """
        nodes = self._nodes
        if len(nodes) < 2:
            raise RuntimeError(u"Not enough nodes to compute path")

        for idx in range(0, len(nodes) - 1):
            topo = Topology()
            node1 = nodes[idx]
            node2 = nodes[idx + 1]
            n1_list = self._nodes_filter[idx]
            n2_list = self._nodes_filter[idx + 1]
            links = topo.get_active_connecting_links(node1,
                                                     node2,
                                                     filter_list_node1=n1_list,
                                                     filter_list_node2=n2_list)
            if not links:
                raise RuntimeError(
                    f"No link between {node1[u'host']} and {node2[u'host']}")

            # Not using set operations, as we need deterministic order.
            if always_same_link:
                l_set = [link for link in links if link in self._links]
            else:
                l_set = [link for link in links if link not in self._links]
                if not l_set:
                    raise RuntimeError(
                        f"No free link between {node1[u'host']} and "
                        f"{node2[u'host']}, all links already used")

            if not l_set:
                link = links[0]
            else:
                link = l_set[0]

            self._links.append(link)
            interface1 = topo.get_interface_by_link_name(node1, link)
            interface2 = topo.get_interface_by_link_name(node2, link)
            self._path.append((interface1, node1))
            self._path.append((interface2, node2))

        self._path_iter.extend(self._path)
        self._path_iter.reverse()
Beispiel #8
0
    def compute_path(self, always_same_link=True):
        """Compute path for added nodes.

        .. note:: First add at least two nodes to the topology.

        :param always_same_link: If True use always same link between two nodes
            in path. If False use different link (if available)
            between two nodes if one link was used before.
        :type always_same_link: bool
        :raises RuntimeError: If not enough nodes for path.
        """
        nodes = self._nodes
        if len(nodes) < 2:
            raise RuntimeError('Not enough nodes to compute path')

        for idx in range(0, len(nodes) - 1):
            topo = Topology()
            node1 = nodes[idx]
            node2 = nodes[idx + 1]
            n1_list = self._nodes_filter[idx]
            n2_list = self._nodes_filter[idx + 1]
            links = topo.get_active_connecting_links(node1, node2,
                                                     filter_list_node1=n1_list,
                                                     filter_list_node2=n2_list)
            if not links:
                raise RuntimeError('No link between {0} and {1}'.format(
                    node1['host'], node2['host']))

            if always_same_link:
                l_set = set(links).intersection(self._links)
            else:
                l_set = set(links).difference(self._links)
                if not l_set:
                    raise RuntimeError(
                        'No free link between {0} and {1}, all links already '
                        'used'.format(node1['host'], node2['host']))

            if not l_set:
                link = links.pop()
            else:
                link = l_set.pop()

            self._links.append(link)
            interface1 = topo.get_interface_by_link_name(node1, link)
            interface2 = topo.get_interface_by_link_name(node2, link)
            self._path.append((interface1, node1))
            self._path.append((interface2, node2))

        self._path_iter.extend(self._path)
        self._path_iter.reverse()
def get_variables(nodes, networks=IPV4_NETWORKS[:]):
    """Special robot framework method that returns dictionary nodes_ipv4_addr,
    mapping of node and interface name to IPv4 address.

    :param nodes: Nodes of the test topology.
    :param networks: List of available IPv4 networks.
    :type nodes: dict
    :type networks: list

    .. note::
       Robot framework calls it automatically.
    """
    topo = Topology()
    links = topo.get_links(nodes)

    if len(links) > len(networks):
        raise Exception('Not enough available IPv4 networks for topology.')

    ip4_n = IPv4NetworkGenerator(networks)

    nets = {}

    for link in links:
        ip4_net = ip4_n.next_network()
        net_hosts = ip4_net.hosts()
        port_idx = 0
        ports = {}
        for node in nodes.values():
            if_key = topo.get_interface_by_link_name(node, link)
            if_name = topo.get_interface_name(node, if_key)
            if if_name is not None:
                port = {
                    'addr': str(next(net_hosts)),
                    'node': node['host'],
                    'if': if_name
                }
                port_idx += 1
                port_id = 'port{0}'.format(port_idx)
                ports.update({port_id: port})
        nets.update({
            link: {
                'net_addr': str(ip4_net.network_address),
                'prefix': ip4_net.prefixlen,
                'ports': ports
            }
        })

    return {'DICT__nodes_ipv4_addr': nets}
Beispiel #10
0
    def generate_duplicate_lisp_locator_set_data(node, locator_set_number):
        """Generate a list of lisp locator_set we want set to VPP and
        then check if it is set correctly. Some locator_sets are duplicated.

        :param node: VPP node.
        :param locator_set_number: Generate n locator_set.
        :type node: dict
        :type locator_set_number: str
        :returns: list of lisp locator_set, list of lisp locator_set expected
        from VAT.
        :rtype: tuple
        """

        topo = Topology()
        locator_set_list = []
        locator_set_list_vat = []
        i = 0
        for num in range(0, int(locator_set_number)):
            locator_list = []
            for interface in node['interfaces'].values():
                link = interface.get('link')
                i += 1
                if link is None:
                    continue

                if_name = topo.get_interface_by_link_name(node, link)
                sw_if_index = topo.get_interface_sw_index(node, if_name)
                if if_name is not None:
                    l_name = 'ls{0}'.format(num)
                    locator = {
                        'locator-index': sw_if_index,
                        'priority': i,
                        'weight': i
                    }
                    locator_list.append(locator)
                    locator_set = {
                        'locator-set': l_name,
                        'locator': locator_list
                    }
                    locator_set_list.append(locator_set)

                    locator_set_vat = {"ls_name": l_name, "ls_index": num}
                    locator_set_list_vat.append(locator_set_vat)

        return locator_set_list, locator_set_list_vat
Beispiel #11
0
    def nodes_clear_ipv6_addresses(self, nodes, nodes_addr):
        """Remove IPv6 addresses from all VPP nodes in topology.

        :param nodes: Nodes of the test topology.
        :param nodes_addr: Available nodes IPv6 addresses.
        :type nodes: dict
        :type nodes_addr: dict
        """
        for net in nodes_addr.values():
            for port in net['ports'].values():
                host = port.get('node')
                if host is None:
                    continue
                topo = Topology()
                node = topo.get_node_by_hostname(nodes, host)
                if node is None:
                    continue
                if node['type'] == NodeType.DUT:
                    self.vpp_del_if_ipv6_addr(node, port['if'], port['addr'],
                                              net['prefix'])
Beispiel #12
0
    def create_bridge_domain_vat_dict(node, link_names, bd_id):
        """Create dictionary that can be used in l2 bridge domain template.

        The resulting dictionary looks like this:
        'interface1': interface name of first interface
        'interface2': interface name of second interface
        'bd_id': bridge domain index

        :param node: Node data dictionary.
        :param link_names: List of names of links the bridge domain should be
            connecting.
        :param bd_id: Bridge domain index number.
        :type node: dict
        :type link_names: list
        :returns: Dictionary used to generate l2 bridge domain VAT configuration
            from template file.
        :rtype: dict
        """
        bd_dict = Topology().get_interfaces_by_link_names(node, link_names)
        bd_dict['bd_id'] = bd_id
        return bd_dict
Beispiel #13
0
    def initialize_traffic_generator(self,
                                     tg_node,
                                     tg_if1,
                                     tg_if2,
                                     tg_if1_adj_node,
                                     tg_if1_adj_if,
                                     tg_if2_adj_node,
                                     tg_if2_adj_if,
                                     test_type,
                                     tg_if1_dst_mac=None,
                                     tg_if2_dst_mac=None):
        """TG initialization.

        :param tg_node: Traffic generator node.
        :param tg_if1: TG - name of first interface.
        :param tg_if2: TG - name of second interface.
        :param tg_if1_adj_node: TG if1 adjecent node.
        :param tg_if1_adj_if: TG if1 adjecent interface.
        :param tg_if2_adj_node: TG if2 adjecent node.
        :param tg_if2_adj_if: TG if2 adjecent interface.
        :param test_type: 'L2' or 'L3' - src/dst MAC address.
        :param tg_if1_dst_mac: Interface 1 destination MAC address.
        :param tg_if2_dst_mac: Interface 2 destination MAC address.
        :type tg_node: dict
        :type tg_if1: str
        :type tg_if2: str
        :type tg_if1_adj_node: dict
        :type tg_if1_adj_if: str
        :type tg_if2_adj_node: dict
        :type tg_if2_adj_if: str
        :type test_type: str
        :type tg_if1_dst_mac: str
        :type tg_if2_dst_mac: str
        :returns: nothing
        :raises: RuntimeError in case of issue during initialization.
        """

        topo = Topology()

        if tg_node['type'] != NodeType.TG:
            raise RuntimeError('Node type is not a TG')
        self._node = tg_node

        if tg_node['subtype'] == NodeSubTypeTG.TREX:
            trex_path = "/opt/trex-core-2.25"

            ssh = SSH()
            ssh.connect(tg_node)

            (ret, stdout, stderr) = ssh.exec_command(
                "sudo -E sh -c '{}/resources/tools/t-rex/"
                "t-rex-installer.sh'".format(Constants.REMOTE_FW_DIR),
                timeout=1800)
            if int(ret) != 0:
                logger.error('trex installation failed: {0}'.format(stdout +
                                                                    stderr))
                raise RuntimeError('Installation of TG failed')

            if1_pci = topo.get_interface_pci_addr(tg_node, tg_if1)
            if2_pci = topo.get_interface_pci_addr(tg_node, tg_if2)
            if1_mac = topo.get_interface_mac(tg_node, tg_if1)
            if2_mac = topo.get_interface_mac(tg_node, tg_if2)

            if test_type == 'L2':
                if1_adj_mac = if2_mac
                if2_adj_mac = if1_mac
            elif test_type == 'L3':
                if1_adj_mac = topo.get_interface_mac(tg_if1_adj_node,
                                                     tg_if1_adj_if)
                if2_adj_mac = topo.get_interface_mac(tg_if2_adj_node,
                                                     tg_if2_adj_if)
            else:
                raise ValueError("test_type unknown")

            if tg_if1_dst_mac is not None and tg_if2_dst_mac is not None:
                if1_adj_mac = tg_if1_dst_mac
                if2_adj_mac = tg_if2_dst_mac

            if min(if1_pci, if2_pci) != if1_pci:
                if1_mac, if2_mac = if2_mac, if1_mac
                if1_pci, if2_pci = if2_pci, if1_pci
                if1_adj_mac, if2_adj_mac = if2_adj_mac, if1_adj_mac
                self._ifaces_reordered = True

            if1_mac_hex = "0x" + if1_mac.replace(":", ",0x")
            if2_mac_hex = "0x" + if2_mac.replace(":", ",0x")
            if1_adj_mac_hex = "0x" + if1_adj_mac.replace(":", ",0x")
            if2_adj_mac_hex = "0x" + if2_adj_mac.replace(":", ",0x")

            (ret, stdout, stderr) = ssh.exec_command(
                "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
                "- port_limit      : 2\n"
                "  version         : 2\n"
                "  interfaces      : [\"{}\",\"{}\"]\n"
                "  port_info       :\n"
                "          - dest_mac        :   [{}]\n"
                "            src_mac         :   [{}]\n"
                "          - dest_mac        :   [{}]\n"
                "            src_mac         :   [{}]\n"
                "EOF'"\
                .format(if1_pci, if2_pci,
                        if1_adj_mac_hex, if1_mac_hex,
                        if2_adj_mac_hex, if2_mac_hex))
            if int(ret) != 0:
                logger.error("failed to create t-rex config: {}"\
                .format(stdout + stderr))
                raise RuntimeError('trex config generation error')

            max_startup_retries = 3
            while max_startup_retries > 0:
                # kill T-rex only if it is already running
                (ret, _, _) = ssh.exec_command(
                    "sh -c 'pgrep t-rex && sudo pkill t-rex && sleep 3'")

                # configure T-rex
                (ret, stdout, stderr) = ssh.exec_command(
                    "sh -c 'cd {0}/scripts/ && sudo ./trex-cfg'"\
                    .format(trex_path))
                if int(ret) != 0:
                    logger.error('trex-cfg failed: {0}'.format(stdout +
                                                               stderr))
                    raise RuntimeError('trex-cfg failed')

                # start T-rex
                (ret, _, _) = ssh.exec_command(
                    "sh -c 'cd {0}/scripts/ && "
                    "sudo nohup ./t-rex-64 -i -c 7 --iom 0 > /dev/null 2>&1 &'"
                    "> /dev/null"\
                    .format(trex_path))
                if int(ret) != 0:
                    raise RuntimeError('t-rex-64 startup failed')

                # get T-rex server info
                (ret, _, _) = ssh.exec_command(
                    "sh -c 'sleep 3; "
                    "{0}/resources/tools/t-rex/t-rex-server-info.py'"\
                    .format(Constants.REMOTE_FW_DIR),
                    timeout=120)
                if int(ret) == 0:
                    # If we get info T-rex is running
                    return
                # try again
                max_startup_retries -= 1
            # after max retries T-rex is still not responding to API
            # critical error occurred
            raise RuntimeError('t-rex-64 startup failed')