1 # Copyright (c) 2018 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Interface util library."""
16 from time import time, sleep
18 from robot.api import logger
20 from resources.libraries.python.CpuUtils import CpuUtils
21 from resources.libraries.python.DUTSetup import DUTSetup
22 from resources.libraries.python.PapiExecutor import PapiExecutor
23 from resources.libraries.python.PapiErrors import PapiError
24 from resources.libraries.python.IPUtil import convert_ipv4_netmask_prefix
25 from resources.libraries.python.IPUtil import IPUtil
26 from resources.libraries.python.parsers.JsonParser import JsonParser
27 from resources.libraries.python.ssh import SSH, exec_cmd_no_error
28 from resources.libraries.python.topology import NodeType, Topology
29 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
30 from resources.libraries.python.VatJsonUtil import VatJsonUtil
31 from resources.libraries.python.VPPUtil import VPPUtil
34 class InterfaceUtil(object):
35 """General utilities for managing interfaces"""
37 __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
40 def set_interface_state(node, interface, state, if_type="key"):
41 """Set interface state on a node.
43 Function can be used for DUTs as well as for TGs.
45 :param node: Node where the interface is.
46 :param interface: Interface key or sw_if_index or name.
47 :param state: One of 'up' or 'down'.
48 :param if_type: Interface type
50 :type interface: str or int
54 :raises ValueError: If the interface type is unknown.
55 :raises ValueError: If the state of interface is unexpected.
56 :raises ValueError: If the node has an unknown node type.
60 if isinstance(interface, basestring):
61 sw_if_index = Topology.get_interface_sw_index(node, interface)
62 iface_name = Topology.get_interface_name(node, interface)
64 sw_if_index = interface
65 elif if_type == "name":
66 iface_key = Topology.get_interface_by_name(node, interface)
67 if iface_key is not None:
68 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
69 iface_name = interface
71 raise ValueError("if_type unknown: {}".format(if_type))
73 if node['type'] == NodeType.DUT:
75 state = 'admin-up link-up'
77 state = 'admin-down link-down'
79 raise ValueError('Unexpected interface state: {}'.format(state))
80 VatExecutor.cmd_from_template(node, 'set_if_state.vat',
81 sw_if_index=sw_if_index, state=state)
82 elif node['type'] == NodeType.TG or node['type'] == NodeType.VM:
83 cmd = 'ip link set {} {}'.format(iface_name, state)
84 exec_cmd_no_error(node, cmd, sudo=True)
86 raise ValueError('Node {} has unknown NodeType: "{}"'
87 .format(node['host'], node['type']))
90 def set_interface_ethernet_mtu(node, iface_key, mtu):
91 """Set Ethernet MTU for specified interface.
93 Function can be used only for TGs.
95 :param node: Node where the interface is.
96 :param iface_key: Interface key from topology file.
97 :param mtu: MTU to set.
102 :raises ValueError: If the node type is "DUT".
103 :raises ValueError: If the node has an unknown node type.
105 if node['type'] == NodeType.DUT:
106 raise ValueError('Node {}: Setting Ethernet MTU for interface '
107 'on DUT nodes not supported', node['host'])
108 elif node['type'] == NodeType.TG:
109 iface_name = Topology.get_interface_name(node, iface_key)
110 cmd = 'ip link set {} mtu {}'.format(iface_name, mtu)
111 exec_cmd_no_error(node, cmd, sudo=True)
113 raise ValueError('Node {} has unknown NodeType: "{}"'
114 .format(node['host'], node['type']))
117 def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
118 """Set default Ethernet MTU on all interfaces on node.
120 Function can be used only for TGs.
122 :param node: Node where to set default MTU.
126 for ifc in node['interfaces']:
127 InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500)
130 def vpp_set_interface_mtu(node, interface, mtu=9200):
131 """Set Ethernet MTU on interface.
133 :param node: VPP node.
134 :param interface: Interface to setup MTU. Default: 9200.
135 :param mtu: Ethernet MTU size in Bytes.
137 :type interface: str or int
140 if isinstance(interface, basestring):
141 sw_if_index = Topology.get_interface_sw_index(node, interface)
143 sw_if_index = interface
146 with VatTerminal(node, json_param=False) as vat:
147 vat.vat_terminal_exec_cmd_from_template(
148 "hw_interface_set_mtu.vat", sw_if_index=sw_if_index,
152 def vpp_set_interfaces_mtu_on_node(node, mtu=9200):
153 """Set Ethernet MTU on all interfaces.
155 :param node: VPP node.
156 :param mtu: Ethernet MTU size in Bytes. Default: 9200.
160 for interface in node['interfaces']:
161 InterfaceUtil.vpp_set_interface_mtu(node, interface, mtu)
164 def vpp_set_interfaces_mtu_on_all_duts(nodes, mtu=9200):
165 """Set Ethernet MTU on all interfaces on all DUTs.
167 :param nodes: VPP nodes.
168 :param mtu: Ethernet MTU size in Bytes. Default: 9200.
172 for node in nodes.values():
173 if node['type'] == NodeType.DUT:
174 InterfaceUtil.vpp_set_interfaces_mtu_on_node(node, mtu)
177 def vpp_node_interfaces_ready_wait(node, timeout=30):
178 """Wait until all interfaces with admin-up are in link-up state.
180 :param node: Node to wait on.
181 :param timeout: Waiting timeout in seconds (optional, default 10s).
185 :raises RuntimeError: If the timeout period value has elapsed.
191 out = InterfaceUtil.vpp_get_interface_data(node)
192 if time() - start > timeout:
193 for interface in out:
194 if interface.get('admin_up_down') == 1:
195 if interface.get('link_up_down') != 1:
196 logger.debug('{0} link-down'.format(
197 interface.get('interface_name')))
198 raise RuntimeError('timeout, not up {0}'.format(not_ready))
200 for interface in out:
201 if interface.get('admin_up_down') == 1:
202 if interface.get('link_up_down') != 1:
203 not_ready.append(interface.get('interface_name'))
207 logger.debug('Interfaces still in link-down state: {0}, '
208 'waiting...'.format(not_ready))
212 def vpp_nodes_interfaces_ready_wait(nodes, timeout=30):
213 """Wait until all interfaces with admin-up are in link-up state for
216 :param nodes: List of nodes to wait on.
217 :param timeout: Seconds to wait per node for all interfaces to come up.
223 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
226 def all_vpp_interfaces_ready_wait(nodes, timeout=30):
227 """Wait until all interfaces with admin-up are in link-up state for all
228 nodes in the topology.
230 :param nodes: Nodes in the topology.
231 :param timeout: Seconds to wait per node for all interfaces to come up.
236 for node in nodes.values():
237 if node['type'] == NodeType.DUT:
238 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
241 def vpp_get_interface_data(node, interface=None):
242 """Get all interface data from a VPP node. If a name or
243 sw_interface_index is provided, return only data for the matching
246 :param node: VPP node to get interface data from.
247 :param interface: Numeric index or name string of a specific interface.
249 :type interface: int or str
250 :returns: List of dictionaries containing data for each interface, or a
251 single dictionary for the specified interface.
253 :raises TypeError: if the data type of interface is neither basestring
256 with VatTerminal(node) as vat:
257 response = vat.vat_terminal_exec_cmd_from_template(
258 "interface_dump.vat")
262 if interface is not None:
263 if isinstance(interface, basestring):
264 param = "interface_name"
265 elif isinstance(interface, int):
266 param = "sw_if_index"
270 if data_if[param] == interface:
276 def vpp_get_interface_name(node, sw_if_index):
277 """Get interface name for the given SW interface index from actual
280 :param node: VPP node to get interface data from.
281 :param sw_if_index: SW interface index of the specific interface.
283 :type sw_if_index: int
284 :returns: Name of the given interface.
288 if_data = InterfaceUtil.vpp_get_interface_data(node, sw_if_index)
289 if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
290 if_data = InterfaceUtil.vpp_get_interface_data(
291 node, if_data['sup_sw_if_index'])
293 if_name = if_data["interface_name"]
299 def vpp_get_interface_mac(node, interface=None):
300 """Get MAC address for the given interface from actual interface dump.
302 :param node: VPP node to get interface data from.
303 :param interface: Numeric index or name string of a specific interface.
305 :type interface: int or str
306 :returns: MAC address.
310 if_data = InterfaceUtil.vpp_get_interface_data(node, interface)
311 if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
312 if_data = InterfaceUtil.vpp_get_interface_data(
313 node, if_data['sup_sw_if_index'])
314 mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]]
316 for item in mac_data:
319 mac_data_nice.append(item)
320 mac = ":".join(mac_data_nice)
324 def vpp_get_interface_ip_addresses(node, interface, ip_version):
325 """Get list of IP addresses from an interface on a VPP node.
327 :param node: VPP node to get data from.
328 :param interface: Name of an interface on the VPP node.
329 :param ip_version: IP protocol version (ipv4 or ipv6).
332 :type ip_version: str
333 :returns: List of dictionaries, each containing IP address, subnet
334 prefix length and also the subnet mask for ipv4 addresses.
335 Note: A single interface may have multiple IP addresses assigned.
340 sw_if_index = Topology.convert_interface_reference(
341 node, interface, "sw_if_index")
343 if isinstance(interface, basestring):
344 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
348 with VatTerminal(node) as vat:
349 response = vat.vat_terminal_exec_cmd_from_template(
350 "ip_address_dump.vat", ip_version=ip_version,
351 sw_if_index=sw_if_index)
355 if ip_version == "ipv4":
357 item["netmask"] = convert_ipv4_netmask_prefix(
358 item["prefix_length"])
362 def tg_set_interface_driver(node, pci_addr, driver):
363 """Set interface driver on the TG node.
365 :param node: Node to set interface driver on (must be TG node).
366 :param pci_addr: PCI address of the interface.
367 :param driver: Driver name.
371 :raises RuntimeError: If unbinding from the current driver fails.
372 :raises RuntimeError: If binding to the new driver fails.
374 old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
375 if old_driver == driver:
381 # Unbind from current driver
382 if old_driver is not None:
383 cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'\
384 .format(pci_addr, old_driver)
385 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
386 if int(ret_code) != 0:
387 raise RuntimeError("'{0}' failed on '{1}'"
388 .format(cmd, node['host']))
390 # Bind to the new driver
391 cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'\
392 .format(pci_addr, driver)
393 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
394 if int(ret_code) != 0:
395 raise RuntimeError("'{0}' failed on '{1}'"
396 .format(cmd, node['host']))
399 def tg_get_interface_driver(node, pci_addr):
400 """Get interface driver from the TG node.
402 :param node: Node to get interface driver on (must be TG node).
403 :param pci_addr: PCI address of the interface.
406 :returns: Interface driver or None if not found.
408 :raises RuntimeError: If PCI rescan or lspci command execution failed.
410 return DUTSetup.get_pci_dev_driver(node, pci_addr)
413 def tg_set_interfaces_udev_rules(node):
414 """Set udev rules for interfaces.
416 Create udev rules file in /etc/udev/rules.d where are rules for each
417 interface used by TG node, based on MAC interface has specific name.
418 So after unbind and bind again to kernel driver interface has same
419 name as before. This must be called after TG has set name for each
420 port in topology dictionary.
422 SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f",
425 :param node: Node to set udev rules on (must be TG node).
427 :raises RuntimeError: If setting of udev rules fails.
432 cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE)
433 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
434 if int(ret_code) != 0:
435 raise RuntimeError("'{0}' failed on '{1}'"
436 .format(cmd, node['host']))
438 for interface in node['interfaces'].values():
439 rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
440 '==\\"' + interface['mac_address'] + '\\", NAME=\\"' + \
441 interface['name'] + '\\"'
442 cmd = 'sh -c "echo \'{0}\' >> {1}"'.format(
443 rule, InterfaceUtil.__UDEV_IF_RULES_FILE)
444 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
445 if int(ret_code) != 0:
446 raise RuntimeError("'{0}' failed on '{1}'"
447 .format(cmd, node['host']))
449 cmd = '/etc/init.d/udev restart'
450 ssh.exec_command_sudo(cmd)
453 def tg_set_interfaces_default_driver(node):
454 """Set interfaces default driver specified in topology yaml file.
456 :param node: Node to setup interfaces driver on (must be TG node).
459 for interface in node['interfaces'].values():
460 InterfaceUtil.tg_set_interface_driver(node,
461 interface['pci_address'],
465 def update_vpp_interface_data_on_node(node):
466 """Update vpp generated interface data for a given node in DICT__nodes.
468 Updates interface names, software if index numbers and any other details
469 generated specifically by vpp that are unknown before testcase run.
470 It does this by dumping interface list to JSON output from all
471 devices using vpp_api_test, and pairing known information from topology
472 (mac address/pci address of interface) to state from VPP.
474 :param node: Node selected from DICT__nodes.
477 vat_executor = VatExecutor()
478 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
479 interface_dump_json = vat_executor.get_script_stdout()
480 VatJsonUtil.update_vpp_interface_data_from_json(node,
484 def update_nic_interface_names(node):
485 """Update interface names based on nic type and PCI address.
487 This method updates interface names in the same format as VPP does.
489 :param node: Node dictionary.
492 for ifc in node['interfaces'].values():
493 if_pci = ifc['pci_address'].replace('.', ':').split(':')
494 bus = '{:x}'.format(int(if_pci[1], 16))
495 dev = '{:x}'.format(int(if_pci[2], 16))
496 fun = '{:x}'.format(int(if_pci[3], 16))
497 loc = '{bus}/{dev}/{fun}'.format(bus=bus, dev=dev, fun=fun)
498 if ifc['model'] == 'Intel-XL710':
499 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
500 elif ifc['model'] == 'Intel-X710':
501 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
502 elif ifc['model'] == 'Intel-X520-DA2':
503 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
504 elif ifc['model'] == 'Cisco-VIC-1385':
505 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
506 elif ifc['model'] == 'Cisco-VIC-1227':
507 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
509 ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc)
512 def update_nic_interface_names_on_all_duts(nodes):
513 """Update interface names based on nic type and PCI address on all DUTs.
515 This method updates interface names in the same format as VPP does.
517 :param nodes: Topology nodes.
520 for node in nodes.values():
521 if node['type'] == NodeType.DUT:
522 InterfaceUtil.update_nic_interface_names(node)
525 def update_tg_interface_data_on_node(node, skip_tg_udev=False):
526 """Update interface name for TG/linux node in DICT__nodes.
529 # for dev in `ls /sys/class/net/`;
530 > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done
531 "52:54:00:9f:82:63": "eth0"
532 "52:54:00:77:ae:a9": "eth1"
533 "52:54:00:e1:8a:0f": "eth2"
534 "00:00:00:00:00:00": "lo"
536 :param node: Node selected from DICT__nodes.
537 :param skip_tg_udev: Skip udev rename on TG node.
539 :type skip_tg_udev: bool
540 :raises RuntimeError: If getting of interface name and MAC fails.
542 # First setup interface driver specified in yaml file
543 InterfaceUtil.tg_set_interfaces_default_driver(node)
545 # Get interface names
549 cmd = ('for dev in `ls /sys/class/net/`; do echo "\\"`cat '
550 '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;')
552 (ret_code, stdout, _) = ssh.exec_command(cmd)
553 if int(ret_code) != 0:
554 raise RuntimeError('Get interface name and MAC failed')
555 tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
556 interfaces = JsonParser().parse_data(tmp)
557 for interface in node['interfaces'].values():
558 name = interfaces.get(interface['mac_address'])
561 interface['name'] = name
563 # Set udev rules for interfaces
565 InterfaceUtil.tg_set_interfaces_udev_rules(node)
568 def iface_update_numa_node(node):
569 """For all interfaces from topology file update numa node based on
570 information from the node.
572 :param node: Node from topology.
575 :raises ValueError: If numa node ia less than 0.
576 :raises RuntimeError: If update of numa node failes.
579 for if_key in Topology.get_node_interfaces(node):
580 if_pci = Topology.get_interface_pci_addr(node, if_key)
582 cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
584 (ret, out, _) = ssh.exec_command(cmd)
589 if CpuUtils.cpu_node_count(node) == 1:
594 logger.trace('Reading numa location failed for: {0}'
597 Topology.set_interface_numa_node(node, if_key,
601 raise RuntimeError('Update numa node failed for: {0}'
605 def update_all_numa_nodes(nodes, skip_tg=False):
606 """For all nodes and all their interfaces from topology file update numa
607 node information based on information from the node.
609 :param nodes: Nodes in the topology.
610 :param skip_tg: Skip TG node
615 for node in nodes.values():
616 if node['type'] == NodeType.DUT:
617 InterfaceUtil.iface_update_numa_node(node)
618 elif node['type'] == NodeType.TG and not skip_tg:
619 InterfaceUtil.iface_update_numa_node(node)
622 def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
625 """Update interface names on all nodes in DICT__nodes.
627 This method updates the topology dictionary by querying interface lists
628 of all nodes mentioned in the topology dictionary.
630 :param nodes: Nodes in the topology.
631 :param skip_tg: Skip TG node.
632 :param skip_tg_udev: Skip udev rename on TG node.
633 :param numa_node: Retrieve numa_node location.
636 :type skip_tg_udev: bool
637 :type numa_node: bool
639 for node_data in nodes.values():
640 if node_data['type'] == NodeType.DUT:
641 InterfaceUtil.update_vpp_interface_data_on_node(node_data)
642 elif node_data['type'] == NodeType.TG and not skip_tg:
643 InterfaceUtil.update_tg_interface_data_on_node(
644 node_data, skip_tg_udev)
647 if node_data['type'] == NodeType.DUT:
648 InterfaceUtil.iface_update_numa_node(node_data)
649 elif node_data['type'] == NodeType.TG and not skip_tg:
650 InterfaceUtil.iface_update_numa_node(node_data)
653 def create_vlan_subinterface(node, interface, vlan):
654 """Create VLAN subinterface on node.
656 :param node: Node to add VLAN subinterface on.
657 :param interface: Interface name on which create VLAN subinterface.
658 :param vlan: VLAN ID of the subinterface to be created.
662 :returns: Name and index of created subinterface.
664 :raises RuntimeError: if it is unable to create VLAN subinterface on the
667 iface_key = Topology.get_interface_by_name(node, interface)
668 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
670 output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
671 sw_if_index=sw_if_index,
673 if output[0]["retval"] == 0:
674 sw_vlan_idx = output[0]["sw_if_index"]
675 logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
676 'created on node {}'.format(sw_vlan_idx,
678 if_key = Topology.add_new_port(node, "vlan_subif")
679 Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
680 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
681 Topology.update_interface_name(node, if_key, ifc_name)
683 raise RuntimeError('Unable to create VLAN subinterface on node {}'
684 .format(node['host']))
686 with VatTerminal(node, False) as vat:
687 vat.vat_terminal_exec_cmd('exec show interfaces')
689 return '{}.{}'.format(interface, vlan), sw_vlan_idx
692 def create_vxlan_interface(node, vni, source_ip, destination_ip):
693 """Create VXLAN interface and return sw if index of created interface.
695 Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT
698 :param node: Node where to create VXLAN interface.
699 :param vni: VXLAN Network Identifier.
700 :param source_ip: Source IP of a VXLAN Tunnel End Point.
701 :param destination_ip: Destination IP of a VXLAN Tunnel End Point.
705 :type destination_ip: str
706 :returns: SW IF INDEX of created interface.
708 :raises RuntimeError: if it is unable to create VxLAN interface on the
711 output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
717 if output["retval"] == 0:
718 sw_if_idx = output["sw_if_index"]
719 if_key = Topology.add_new_port(node, "vxlan_tunnel")
720 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
721 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
722 Topology.update_interface_name(node, if_key, ifc_name)
725 raise RuntimeError("Unable to create VXLAN interface on node {0}"
729 def vxlan_dump(node, interface=None):
730 """Get VxLAN data for the given interface.
732 :param node: VPP node to get interface data from.
733 :param interface: Numeric index or name string of a specific interface.
734 If None, information about all VxLAN interfaces is returned.
736 :type interface: int or str
737 :returns: Dictionary containing data for the given VxLAN interface or if
738 interface=None, the list of dictionaries with all VxLAN interfaces.
740 :raises TypeError: if the data type of interface is neither basestring
743 param = "sw_if_index"
744 if interface is None:
747 elif isinstance(interface, basestring):
748 sw_if_index = Topology.get_interface_sw_index(node, interface)
749 elif isinstance(interface, int):
750 sw_if_index = interface
752 raise TypeError("Wrong interface format {0}".format(interface))
754 with VatTerminal(node) as vat:
755 response = vat.vat_terminal_exec_cmd_from_template(
756 "vxlan_dump.vat", param=param, sw_if_index=sw_if_index)
759 for vxlan in response[0]:
760 if vxlan["sw_if_index"] == sw_if_index:
766 def vhost_user_dump(node):
767 """Get vhost-user data for the given node.
769 :param node: VPP node to get interface data from.
771 :returns: List of dictionaries with all vhost-user interfaces.
774 with VatTerminal(node) as vat:
775 response = vat.vat_terminal_exec_cmd_from_template(
776 "vhost_user_dump.vat")
781 def tap_dump(node, name=None):
782 """Get all TAP interface data from the given node, or data about
783 a specific TAP interface.
785 :param node: VPP node to get data from.
786 :param name: Optional name of a specific TAP interface.
789 :returns: Dictionary of information about a specific TAP interface, or
790 a List of dictionaries containing all TAP data for the given node.
793 with VatTerminal(node) as vat:
794 response = vat.vat_terminal_exec_cmd_from_template(
798 for item in response[0]:
799 if name == item['dev_name']:
804 def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
805 inner_vlan_id=None, type_subif=None):
806 """Create sub-interface on node. It is possible to set required
807 sub-interface type and VLAN tag(s).
809 :param node: Node to add sub-interface.
810 :param interface: Interface name on which create sub-interface.
811 :param sub_id: ID of the sub-interface to be created.
812 :param outer_vlan_id: Optional outer VLAN ID.
813 :param inner_vlan_id: Optional inner VLAN ID.
814 :param type_subif: Optional type of sub-interface. Values supported by
815 VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match]
818 :type interface: str or int
820 :type outer_vlan_id: int
821 :type inner_vlan_id: int
822 :type type_subif: str
823 :returns: Name and index of created sub-interface.
825 :raises RuntimeError: If it is not possible to create sub-interface.
828 outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
829 if outer_vlan_id else ''
831 inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
832 if inner_vlan_id else ''
834 if type_subif is None:
837 if isinstance(interface, basestring):
838 iface_key = Topology.get_interface_by_name(node, interface)
839 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
841 sw_if_index = interface
843 output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
844 sw_if_index=sw_if_index,
846 outer_vlan_id=outer_vlan_id,
847 inner_vlan_id=inner_vlan_id,
848 type_subif=type_subif)
850 if output[0]["retval"] == 0:
851 sw_vlan_idx = output[0]["sw_if_index"]
852 logger.trace('Created subinterface with index {}'
853 .format(sw_vlan_idx))
854 if_key = Topology.add_new_port(node, "subinterface")
855 Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
856 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
857 Topology.update_interface_name(node, if_key, ifc_name)
859 raise RuntimeError('Unable to create sub-interface on node {}'
860 .format(node['host']))
862 with VatTerminal(node, json_param=False) as vat:
863 vat.vat_terminal_exec_cmd('exec show interfaces')
865 name = '{}.{}'.format(interface, sub_id)
866 return name, sw_vlan_idx
869 def create_gre_tunnel_interface(node, source_ip, destination_ip):
870 """Create GRE tunnel interface on node.
872 :param node: VPP node to add tunnel interface.
873 :param source_ip: Source of the GRE tunnel.
874 :param destination_ip: Destination of the GRE tunnel.
877 :type destination_ip: str
878 :returns: Name and index of created GRE tunnel interface.
880 :raises RuntimeError: If unable to create GRE tunnel interface.
882 output = VatExecutor.cmd_from_template(node, "create_gre.vat",
887 if output["retval"] == 0:
888 sw_if_idx = output["sw_if_index"]
890 vat_executor = VatExecutor()
891 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
892 interface_dump_json = vat_executor.get_script_stdout()
893 name = VatJsonUtil.get_interface_name_from_json(
894 interface_dump_json, sw_if_idx)
896 if_key = Topology.add_new_port(node, "gre_tunnel")
897 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
898 Topology.update_interface_name(node, if_key, name)
900 return name, sw_if_idx
902 raise RuntimeError('Unable to create GRE tunnel on node {}.'
906 def vpp_create_loopback(node):
907 """Create loopback interface on VPP node.
909 :param node: Node to create loopback interface on.
911 :returns: SW interface index.
913 :raises RuntimeError: If it is not possible to create loopback on the
916 out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
917 if out[0].get('retval') == 0:
918 sw_if_idx = out[0].get('sw_if_index')
919 if_key = Topology.add_new_port(node, "loopback")
920 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
921 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
922 Topology.update_interface_name(node, if_key, ifc_name)
925 raise RuntimeError('Create loopback failed on node "{}"'
926 .format(node['host']))
929 def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
930 """Create bond interface on VPP node.
932 :param node: DUT node from topology.
933 :param mode: Link bonding mode.
934 :param load_balance: Load balance (optional, valid for xor and lacp
935 modes, otherwise ignored).
936 :param mac: MAC address to assign to the bond interface (optional).
939 :type load_balance: str
941 :returns: Interface key (name) in topology.
943 :raises RuntimeError: If it is not possible to create bond interface on
946 hw_addr = '' if mac is None else 'hw-addr {mac}'.format(mac=mac)
947 ldb = '' if load_balance is None \
948 else 'lb {ldb}'.format(ldb=load_balance)
950 output = VatExecutor.cmd_from_template(
951 node, 'create_bond_interface.vat', mode=mode, lb=ldb, mac=hw_addr)
953 if output[0].get('retval') == 0:
954 sw_if_idx = output[0].get('sw_if_index')
955 InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
957 if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
960 raise RuntimeError('Create bond interface failed on "{host}"'.
961 format(host=node['host']))
964 def add_eth_interface(node, ifc_name=None, sw_if_idx=None, ifc_pfx=None):
965 """Add ethernet interface to current topology.
967 :param node: DUT node from topology.
968 :param ifc_name: Name of the interface.
969 :param sw_if_idx: SW interface index.
970 :param ifc_pfx: Interface key prefix.
976 if_key = Topology.add_new_port(node, ifc_pfx)
978 vat_executor = VatExecutor()
979 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
980 interface_dump_json = vat_executor.get_script_stdout()
982 if ifc_name and sw_if_idx is None:
983 sw_if_idx = VatJsonUtil.get_interface_sw_index_from_json(
984 interface_dump_json, ifc_name)
985 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
986 if sw_if_idx and ifc_name is None:
987 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
988 Topology.update_interface_name(node, if_key, ifc_name)
989 ifc_mac = VatJsonUtil.get_interface_mac_from_json(
990 interface_dump_json, sw_if_idx)
991 Topology.update_interface_mac_address(node, if_key, ifc_mac)
994 def vpp_create_avf_interface(node, vf_pci_addr):
995 """Create AVF interface on VPP node.
997 :param node: DUT node from topology.
998 :param vf_pci_addr: Virtual Function PCI address.
1000 :type vf_pci_addr: str
1001 :returns: Interface key (name) in topology.
1003 :raises RuntimeError: If it is not possible to create AVF interface on
1006 with VatTerminal(node, json_param=False) as vat:
1007 vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat',
1008 vf_pci_addr=vf_pci_addr)
1009 output = vat.vat_stdout
1011 if output is not None:
1012 sw_if_idx = int(output.split()[4])
1013 InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
1015 if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
1018 raise RuntimeError('Create AVF interface failed on {host}'.
1019 format(host=node['host']))
1022 def vpp_enslave_physical_interface(node, interface, bond_interface):
1023 """Enslave physical interface to bond interface on VPP node.
1025 :param node: DUT node from topology.
1026 :param interface: Physical interface key from topology file.
1027 :param bond_interface: Load balance
1029 :type interface: str
1030 :type bond_interface: str
1031 :raises RuntimeError: If it is not possible to enslave physical
1032 interface to bond interface on the node.
1034 ifc = Topology.get_interface_sw_index(node, interface)
1035 bond_ifc = Topology.get_interface_sw_index(node, bond_interface)
1037 output = VatExecutor.cmd_from_template(
1038 node, 'enslave_physical_interface.vat', p_int=ifc, b_int=bond_ifc)
1040 retval = output[0].get('retval', None)
1041 if retval is None or int(retval) != 0:
1042 raise RuntimeError('Enslave physical interface {ifc} to bond '
1043 'interface {bond} failed on node "{n}"'
1044 .format(ifc=interface, bond=bond_interface,
1048 def vpp_show_bond_data_on_node(node, details=False):
1049 """Show (detailed) bond information on VPP node.
1051 :param node: DUT node from topology.
1052 :param details: If detailed information is required or not.
1056 cmd = 'exec show bond details' if details else 'exec show bond'
1057 with VatTerminal(node, json_param=False) as vat:
1058 vat.vat_terminal_exec_cmd(cmd)
1061 def vpp_show_bond_data_on_all_nodes(nodes, details=False):
1062 """Show (detailed) bond information on all VPP nodes in DICT__nodes.
1064 :param nodes: Nodes in the topology.
1065 :param details: If detailed information is required or not.
1069 for node_data in nodes.values():
1070 if node_data['type'] == NodeType.DUT:
1071 InterfaceUtil.vpp_show_bond_data_on_node(node_data, details)
1074 def vpp_enable_input_acl_interface(node, interface, ip_version,
1076 """Enable input acl on interface.
1078 :param node: VPP node to setup interface for input acl.
1079 :param interface: Interface to setup input acl.
1080 :param ip_version: Version of IP protocol.
1081 :param table_index: Classify table index.
1083 :type interface: str or int
1084 :type ip_version: str
1085 :type table_index: int
1087 if isinstance(interface, basestring):
1088 sw_if_index = Topology.get_interface_sw_index(node, interface)
1090 sw_if_index = interface
1092 with VatTerminal(node) as vat:
1093 vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
1094 sw_if_index=sw_if_index,
1095 ip_version=ip_version,
1096 table_index=table_index)
1099 def get_interface_classify_table(node, interface):
1100 """Get name of classify table for the given interface.
1102 :param node: VPP node to get data from.
1103 :param interface: Name or sw_if_index of a specific interface.
1105 :type interface: str or int
1106 :returns: Classify table name.
1109 if isinstance(interface, basestring):
1110 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1112 sw_if_index = interface
1114 with VatTerminal(node) as vat:
1115 data = vat.vat_terminal_exec_cmd_from_template(
1116 "classify_interface_table.vat",
1117 sw_if_index=sw_if_index)
1121 def get_interface_vrf_table(node, interface):
1122 """Get vrf ID for the given interface.
1124 :param node: VPP node.
1125 :param interface: Name or sw_if_index of a specific interface.
1127 :type interface: str or int
1128 :returns: vrf ID of the specified interface.
1132 if isinstance(interface, basestring):
1133 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1135 sw_if_index = interface
1137 with VatTerminal(node) as vat:
1138 data = vat.vat_terminal_exec_cmd_from_template(
1139 "interface_vrf_dump.vat",
1140 sw_if_index=sw_if_index)
1141 return data[0]["vrf_id"]
1144 def get_sw_if_index(node, interface_name):
1145 """Get sw_if_index for the given interface from actual interface dump.
1147 :param node: VPP node to get interface data from.
1148 :param interface_name: Name of the specific interface.
1150 :type interface_name: str
1151 :returns: sw_if_index of the given interface.
1155 with VatTerminal(node) as vat:
1156 if_data = vat.vat_terminal_exec_cmd_from_template(
1157 "interface_dump.vat")
1158 for interface in if_data[0]:
1159 if interface["interface_name"] == interface_name:
1160 return interface["sw_if_index"]
1165 def vxlan_gpe_dump(node, interface_name=None):
1166 """Get VxLAN GPE data for the given interface.
1168 :param node: VPP node to get interface data from.
1169 :param interface_name: Name of the specific interface. If None,
1170 information about all VxLAN GPE interfaces is returned.
1172 :type interface_name: str
1173 :returns: Dictionary containing data for the given VxLAN GPE interface
1174 or if interface=None, the list of dictionaries with all VxLAN GPE
1176 :rtype: dict or list
1179 with VatTerminal(node) as vat:
1180 vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
1181 "vxlan_gpe_dump.vat")
1184 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
1186 for vxlan_gpe in vxlan_gpe_data[0]:
1187 if vxlan_gpe["sw_if_index"] == sw_if_index:
1191 return vxlan_gpe_data[0]
1194 def vpp_proxy_arp_interface_enable(node, interface):
1195 """Enable proxy ARP on interface.
1197 :param node: VPP node to enable proxy ARP on interface.
1198 :param interface: Interface to enable proxy ARP.
1200 :type interface: str or int
1202 if isinstance(interface, basestring):
1203 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1205 sw_if_index = interface
1207 with VatTerminal(node) as vat:
1208 vat.vat_terminal_exec_cmd_from_template(
1209 "proxy_arp_intfc_enable.vat",
1210 sw_if_index=sw_if_index)
1213 def vpp_ip_source_check_setup(node, interface):
1214 """Setup Reverse Path Forwarding source check on interface.
1216 :param node: Node to setup RPF source check.
1217 :param interface: Interface name to setup RPF source check.
1219 :type interface: str
1221 with VatTerminal(node) as vat:
1222 vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
1223 interface_name=interface)
1226 def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
1227 """Assign VPP interface to specific VRF/FIB table.
1229 :param node: VPP node where the FIB and interface are located.
1230 :param interface: Interface to be assigned to FIB.
1231 :param table_id: VRF table ID.
1232 :param ipv6: Assign to IPv6 table. Default False.
1234 :type interface: str or int
1238 if isinstance(interface, basestring):
1239 sw_if_index = Topology.get_interface_sw_index(node, interface)
1241 sw_if_index = interface
1243 ipv6 = 'ipv6' if ipv6 else ''
1245 with VatTerminal(node) as vat:
1246 ret = vat.vat_terminal_exec_cmd_from_template(
1247 "set_fib_to_interface.vat",
1248 sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
1250 if ret[0]["retval"] != 0:
1251 raise RuntimeError('Unable to assign interface to FIB node {}.'
1255 def set_linux_interface_mac(node, interface, mac, namespace=None,
1257 """Set MAC address for interface in linux.
1259 :param node: Node where to execute command.
1260 :param interface: Interface in namespace.
1261 :param mac: MAC to be assigned to interface.
1262 :param namespace: Execute command in namespace. Optional
1263 :param vf_id: Virtual Function id. Optional
1265 :type interface: str
1267 :type namespace: str
1270 mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \
1271 if vf_id is not None else 'address {mac}'.format(mac=mac)
1272 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1274 cmd = ('{ns} ip link set {interface} {mac}'.
1275 format(ns=ns_str, interface=interface, mac=mac_str))
1276 exec_cmd_no_error(node, cmd, sudo=True)
1279 def set_linux_interface_trust_on(node, interface, namespace=None,
1281 """Set trust on (promisc) for interface in linux.
1283 :param node: Node where to execute command.
1284 :param interface: Interface in namespace.
1285 :param namespace: Execute command in namespace. Optional
1286 :param vf_id: Virtual Function id. Optional
1288 :type interface: str
1289 :type namespace: str
1292 trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \
1293 if vf_id is not None else 'trust on'
1294 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1296 cmd = ('{ns} ip link set dev {interface} {trust}'.
1297 format(ns=ns_str, interface=interface, trust=trust_str))
1298 exec_cmd_no_error(node, cmd, sudo=True)
1301 def set_linux_interface_spoof_off(node, interface, namespace=None,
1303 """Set spoof off for interface in linux.
1305 :param node: Node where to execute command.
1306 :param interface: Interface in namespace.
1307 :param namespace: Execute command in namespace. Optional
1308 :param vf_id: Virtual Function id. Optional
1310 :type interface: str
1311 :type namespace: str
1314 spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \
1315 if vf_id is not None else 'spoof off'
1316 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1318 cmd = ('{ns} ip link set dev {interface} {spoof}'.
1319 format(ns=ns_str, interface=interface, spoof=spoof_str))
1320 exec_cmd_no_error(node, cmd, sudo=True)
1323 def init_avf_interface(node, ifc_key, numvfs=1, topology_type='L2'):
1324 """Init PCI device by creating VFs and bind them to vfio-pci for AVF
1325 driver testing on DUT.
1327 :param node: DUT node.
1328 :param ifc_key: Interface key from topology file.
1329 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
1330 :param topology_type: Topology type.
1334 :type topology_type: str
1335 :returns: Virtual Function topology interface keys.
1341 # Read PCI address and driver.
1342 pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key)
1343 pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":")
1344 uio_driver = Topology.get_uio_driver(node)
1345 kernel_driver = Topology.get_interface_driver(node, ifc_key)
1346 current_driver = DUTSetup.get_pci_dev_driver(
1347 node, pf_pci_addr.replace(':', r'\:'))
1349 VPPUtil.stop_vpp_service(node)
1350 if current_driver != kernel_driver:
1351 # PCI device must be re-bound to kernel driver before creating VFs.
1352 DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True)
1353 # Stop VPP to prevent deadlock.
1354 # Unbind from current driver.
1355 DUTSetup.pci_driver_unbind(node, pf_pci_addr)
1356 # Bind to kernel driver.
1357 DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver)
1359 # Initialize PCI VFs
1360 DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs)
1363 # Set MAC address and bind each virtual function to uio driver.
1364 for vf_id in range(numvfs):
1365 vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2],
1366 pf_mac_addr[3], pf_mac_addr[4],
1367 pf_mac_addr[5], "{:02x}".format(vf_id)])
1369 pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\
1370 format(pci=pf_pci_addr)
1371 InterfaceUtil.set_linux_interface_trust_on(node, pf_dev,
1373 if topology_type == 'L2':
1374 InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev,
1376 InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr,
1379 DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id)
1380 DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver)
1382 # Add newly created ports into topology file
1383 vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key)
1384 vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
1385 vf_ifc_key = Topology.add_new_port(node, vf_ifc_name)
1386 Topology.update_interface_name(node, vf_ifc_key,
1387 vf_ifc_name+str(vf_id+1))
1388 Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr)
1389 Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr)
1390 vf_ifc_keys.append(vf_ifc_key)
1395 def vpp_create_multiple_vxlan_ipv4_tunnels(
1396 node, node_vxlan_if, node_vlan_if, op_node, op_node_if,
1397 n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, ip_limit,
1399 """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on
1402 Put each pair of VXLAN tunnel interface and VLAN sub-interface to
1403 separate bridge-domain.
1405 :param node: VPP node to create VXLAN tunnel interfaces.
1406 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1408 :param node_vlan_if: VPP node interface key to create VLAN
1410 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1411 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1413 :param n_tunnels: Number of tunnel interfaces to create.
1414 :param vni_start: VNI start ID.
1415 :param src_ip_start: VXLAN tunnel source IP address start.
1416 :param dst_ip_start: VXLAN tunnel destination IP address start.
1417 :param ip_step: IP address incremental step.
1418 :param ip_limit: IP address limit.
1419 :param bd_id_start: Bridge-domain ID start.
1421 :type node_vxlan_if: str
1422 :type node_vlan_if: str
1424 :type op_node_if: str
1425 :type n_tunnels: int
1426 :type vni_start: int
1427 :type src_ip_start: str
1428 :type dst_ip_start: str
1431 :type bd_id_start: int
1433 # configure IPs, create VXLAN interfaces and VLAN sub-interfaces
1434 vxlan_count = InterfaceUtil.vpp_create_vxlan_and_vlan_interfaces(
1435 node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start,
1436 src_ip_start, dst_ip_start, ip_step, ip_limit)
1438 # update topology with VXLAN interfaces and VLAN sub-interfaces data
1439 # and put interfaces up
1440 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_up(
1441 node, vxlan_count, node_vlan_if)
1443 # configure bridge domains, ARPs and routes
1444 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1445 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1446 ip_step, bd_id_start)
1449 def vpp_create_vxlan_and_vlan_interfaces(
1450 node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start,
1451 src_ip_start, dst_ip_start, ip_step, ip_limit):
1453 Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP
1456 :param node: VPP node.
1457 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1459 :param node_vlan_if: VPP node interface key to create VLAN
1461 :param vxlan_count: Number of tunnel interfaces to create.
1462 :param vni_start: VNI start ID.
1463 :param src_ip_start: VXLAN tunnel source IP address start.
1464 :param dst_ip_start: VXLAN tunnel destination IP address start.
1465 :param ip_step: IP address incremental step.
1466 :param ip_limit: IP address limit.
1468 :type node_vxlan_if: str
1469 :type node_vlan_if: str
1470 :type vxlan_count: int
1471 :type vni_start: int
1472 :type src_ip_start: str
1473 :type dst_ip_start: str
1476 :returns: Number of created VXLAN interfaces.
1481 src_ip_start_int = IPUtil.ip_to_int(src_ip_start)
1482 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1483 ip_limit_int = IPUtil.ip_to_int(ip_limit)
1485 tmp_fn = '/tmp/create_vxlan_interfaces.config'
1486 for i in range(0, vxlan_count):
1487 src_ip_int = src_ip_start_int + i * ip_step
1488 dst_ip_int = dst_ip_start_int + i * ip_step
1489 if src_ip_int > ip_limit_int or dst_ip_int > ip_limit_int:
1490 logger.warn("Can't do more iterations - IPv4 address limit "
1491 "has been reached.")
1494 src_ip = IPUtil.int_to_ip(src_ip_int)
1495 dst_ip = IPUtil.int_to_ip(dst_ip_int)
1497 'sw_interface_add_del_address sw_if_index {sw_idx} {ip}/32\n'
1498 .format(sw_idx=Topology.get_interface_sw_index(
1499 node, node_vxlan_if), ip=src_ip))
1501 'vxlan_add_del_tunnel src {src_ip} dst {dst_ip} vni {vni}\n'
1502 .format(src_ip=src_ip, dst_ip=dst_ip, vni=vni_start+i))
1504 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n'
1505 .format(sw_idx=Topology.get_interface_sw_index(
1506 node, node_vlan_if), vlan=i+1))
1508 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1513 def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
1515 Update topology with VXLAN interfaces and VLAN sub-interfaces data
1516 and put interfaces up.
1518 :param node: VPP node.
1519 :param vxlan_count: Number of tunnel interfaces.
1520 :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
1523 :type vxlan_count: int
1524 :type node_vlan_if: str
1526 with VatTerminal(node) as vat_ter:
1527 if_data = vat_ter.vat_terminal_exec_cmd_from_template(
1528 'interface_dump.vat')[0]
1530 tmp_fn = '/tmp/put_subinterfaces_up.config'
1532 for i in range(0, vxlan_count):
1533 vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
1534 vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
1536 vxlan_subif_idx = None
1537 vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
1538 vlan_subif_name = '{if_name}.{vlan}'.format(
1539 if_name=Topology.get_interface_name(
1540 node, node_vlan_if), vlan=i+1)
1543 for data in if_data:
1544 if_name = data['interface_name']
1545 if not vxlan_found and if_name == vxlan_subif_name:
1546 vxlan_subif_idx = data['sw_if_index']
1548 elif not vlan_found and if_name == vlan_subif_name:
1549 vlan_idx = data['sw_if_index']
1551 if vxlan_found and vlan_found:
1553 Topology.update_interface_sw_if_index(
1554 node, vxlan_subif_key, vxlan_subif_idx)
1555 Topology.update_interface_name(
1556 node, vxlan_subif_key, vxlan_subif_name)
1558 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1559 .format(sw_idx=vxlan_subif_idx))
1560 Topology.update_interface_sw_if_index(
1561 node, vlan_subif_key, vlan_idx)
1562 Topology.update_interface_name(
1563 node, vlan_subif_key, vlan_subif_name)
1565 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1566 .format(sw_idx=vlan_idx))
1568 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1571 def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1572 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1573 ip_step, bd_id_start):
1575 Configure ARPs and routes for VXLAN interfaces and put each pair of
1576 VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
1578 :param node: VPP node.
1579 :param node_vxlan_if: VPP node interface key where VXLAN tunnel
1580 interfaces have been created.
1581 :param vxlan_count: Number of tunnel interfaces.
1582 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1583 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1585 :param dst_ip_start: VXLAN tunnel destination IP address start.
1586 :param ip_step: IP address incremental step.
1587 :param bd_id_start: Bridge-domain ID start.
1589 :type node_vxlan_if: str
1590 :type vxlan_count: int
1593 :type dst_ip_start: str
1595 :type bd_id_start: int
1597 sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
1599 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1601 tmp_fn = '/tmp/configure_routes_and_bridge_domains.config'
1603 for i in range(0, vxlan_count):
1604 dst_ip = IPUtil.int_to_ip(dst_ip_start_int + i * ip_step)
1606 'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} mac {mac}\n'
1607 .format(sw_idx=sw_idx_vxlan, ip=dst_ip,
1608 mac=Topology.get_interface_mac(op_node, op_node_if)))
1610 'ip_add_del_route {ip}/32 via {ip} sw_if_index {sw_idx}'
1611 ' resolve-attempts 10 count 1\n'.format(
1612 ip=dst_ip, sw_idx=sw_idx_vxlan))
1613 bd_id = bd_id_start + i
1616 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1617 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1618 node, 'vxlan_tunnel{nr}'.format(nr=subif_id)), bd_id=bd_id))
1620 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1621 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1622 node, 'vlan_subif{nr}'.format(nr=subif_id)), bd_id=bd_id))
1624 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1627 def vpp_sw_interface_rx_placement_dump(node):
1628 """Dump VPP interface RX placement on node.
1630 :param node: Node to run command on.
1632 :returns: Thread mapping information as a list of dictionaries.
1634 :raises RuntimeError: If failed to run command on host.
1635 :raises PapiError: If no API reply received.
1638 for ifc in node['interfaces'].values():
1639 if ifc['vpp_sw_index'] is not None:
1640 api = dict(api_name='sw_interface_rx_placement_dump')
1641 api_args = dict(sw_if_index=ifc['vpp_sw_index'])
1642 api['api_args'] = api_args
1643 api_data.append(api)
1645 with PapiExecutor(node) as papi_executor:
1646 papi_executor.execute_papi(api_data)
1648 papi_executor.papi_should_have_passed()
1649 api_reply = papi_executor.get_papi_reply()
1650 except AssertionError:
1651 raise RuntimeError('Failed to run {api_name} on host '
1652 '{host}!'.format(host=node['host'], **api))
1655 thr_mapping = [s['sw_interface_rx_placement_details'] \
1656 for r in api_reply for s in r['api_reply']]
1657 return sorted(thr_mapping, key=lambda k: k['sw_if_index'])
1659 raise PapiError('No reply received for {api_name} on host {host}!'.
1660 format(host=node['host'], **api))
1663 def vpp_sw_interface_set_rx_placement(node, sw_if_index, queue_id,
1665 """Set interface RX placement to worker on node.
1667 :param node: Node to run command on.
1668 :param sw_if_index: VPP SW interface index.
1669 :param queue_id: VPP interface queue ID.
1670 :param worker_id: VPP worker ID (indexing from 0).
1672 :type sw_if_index: int
1674 :type worker_id: int
1675 :raises RuntimeError: If failed to run command on host.
1676 :raises PapiError: If no API reply received.
1679 api = dict(api_name='sw_interface_set_rx_placement')
1680 api_args = dict(sw_if_index=sw_if_index, queue_id=queue_id,
1681 worker_id=worker_id)
1682 api['api_args'] = api_args
1683 api_data.append(api)
1685 with PapiExecutor(node) as papi_executor:
1686 papi_executor.execute_papi(api_data)
1688 papi_executor.papi_should_have_passed()
1689 api_reply = papi_executor.get_papi_reply()
1690 except AssertionError:
1691 raise RuntimeError('Failed to run {api_name} on host '
1692 '{host}!'.format(host=node['host'], **api))
1695 raise PapiError('No reply received for {api_name} on host {host}!'.
1696 format(host=node['host'], **api))
1699 def vpp_round_robin_rx_placement(node, prefix):
1700 """Set Round Robin interface RX placement on all worker threads
1703 :param node: Topology nodes.
1704 :param prefix: Interface name prefix.
1709 worker_cnt = len(VPPUtil.vpp_show_threads(node)) - 1
1710 for placement in InterfaceUtil.vpp_sw_interface_rx_placement_dump(node):
1711 for interface in node['interfaces'].values():
1712 if placement['sw_if_index'] == interface['vpp_sw_index'] \
1713 and prefix in interface['name']:
1714 InterfaceUtil.vpp_sw_interface_set_rx_placement(
1715 node, placement['sw_if_index'], placement['queue_id'],
1716 worker_id % worker_cnt)
1720 def vpp_round_robin_rx_placement_on_all_duts(nodes, prefix):
1721 """Set Round Robin interface RX placement on all worker threads
1724 :param nodes: Topology nodes.
1725 :param prefix: Interface name prefix.
1729 for node in nodes.values():
1730 if node['type'] == NodeType.DUT:
1731 InterfaceUtil.vpp_round_robin_rx_placement(node, prefix)