1 # Copyright (c) 2019 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 socket import AF_INET, AF_INET6, inet_ntop, inet_pton
17 from socket import error as inet_error
18 from time import time, sleep
20 from robot.api import logger
22 from resources.libraries.python.Constants import Constants
23 from resources.libraries.python.CpuUtils import CpuUtils
24 from resources.libraries.python.DUTSetup import DUTSetup
25 from resources.libraries.python.PapiExecutor import PapiExecutor
26 from resources.libraries.python.IPUtil import convert_ipv4_netmask_prefix
27 from resources.libraries.python.IPUtil import IPUtil
28 from resources.libraries.python.PapiExecutor import PapiExecutor
29 from resources.libraries.python.parsers.JsonParser import JsonParser
30 from resources.libraries.python.ssh import SSH, exec_cmd_no_error
31 from resources.libraries.python.topology import NodeType, Topology
32 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
33 from resources.libraries.python.VatJsonUtil import VatJsonUtil
34 from resources.libraries.python.VPPUtil import VPPUtil
37 class InterfaceUtil(object):
38 """General utilities for managing interfaces"""
40 __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
43 def set_interface_state(node, interface, state, if_type="key"):
44 """Set interface state on a node.
46 Function can be used for DUTs as well as for TGs.
48 :param node: Node where the interface is.
49 :param interface: Interface key or sw_if_index or name.
50 :param state: One of 'up' or 'down'.
51 :param if_type: Interface type
53 :type interface: str or int
57 :raises ValueError: If the interface type is unknown.
58 :raises ValueError: If the state of interface is unexpected.
59 :raises ValueError: If the node has an unknown node type.
63 if isinstance(interface, basestring):
64 sw_if_index = Topology.get_interface_sw_index(node, interface)
65 iface_name = Topology.get_interface_name(node, interface)
67 sw_if_index = interface
68 elif if_type == "name":
69 iface_key = Topology.get_interface_by_name(node, interface)
70 if iface_key is not None:
71 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
72 iface_name = interface
74 raise ValueError("if_type unknown: {}".format(if_type))
76 if node['type'] == NodeType.DUT:
78 state = 'admin-up link-up'
80 state = 'admin-down link-down'
82 raise ValueError('Unexpected interface state: {}'.format(state))
83 VatExecutor.cmd_from_template(node, 'set_if_state.vat',
84 sw_if_index=sw_if_index, state=state)
85 elif node['type'] == NodeType.TG or node['type'] == NodeType.VM:
86 cmd = 'ip link set {} {}'.format(iface_name, state)
87 exec_cmd_no_error(node, cmd, sudo=True)
89 raise ValueError('Node {} has unknown NodeType: "{}"'
90 .format(node['host'], node['type']))
93 def set_interface_ethernet_mtu(node, iface_key, mtu):
94 """Set Ethernet MTU for specified interface.
96 Function can be used only for TGs.
98 :param node: Node where the interface is.
99 :param iface_key: Interface key from topology file.
100 :param mtu: MTU to set.
105 :raises ValueError: If the node type is "DUT".
106 :raises ValueError: If the node has an unknown node type.
108 if node['type'] == NodeType.DUT:
109 raise ValueError('Node {}: Setting Ethernet MTU for interface '
110 'on DUT nodes not supported', node['host'])
111 elif node['type'] == NodeType.TG:
112 iface_name = Topology.get_interface_name(node, iface_key)
113 cmd = 'ip link set {} mtu {}'.format(iface_name, mtu)
114 exec_cmd_no_error(node, cmd, sudo=True)
116 raise ValueError('Node {} has unknown NodeType: "{}"'
117 .format(node['host'], node['type']))
120 def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
121 """Set default Ethernet MTU on all interfaces on node.
123 Function can be used only for TGs.
125 :param node: Node where to set default MTU.
129 for ifc in node['interfaces']:
130 InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500)
133 def vpp_set_interface_mtu(node, interface, mtu=9200):
134 """Set Ethernet MTU on interface.
136 :param node: VPP node.
137 :param interface: Interface to setup MTU. Default: 9200.
138 :param mtu: Ethernet MTU size in Bytes.
140 :type interface: str or int
143 if isinstance(interface, basestring):
144 sw_if_index = Topology.get_interface_sw_index(node, interface)
146 sw_if_index = interface
149 with VatTerminal(node, json_param=False) as vat:
150 vat.vat_terminal_exec_cmd_from_template(
151 "hw_interface_set_mtu.vat", sw_if_index=sw_if_index,
155 def vpp_set_interfaces_mtu_on_node(node, mtu=9200):
156 """Set Ethernet MTU on all interfaces.
158 :param node: VPP node.
159 :param mtu: Ethernet MTU size in Bytes. Default: 9200.
163 for interface in node['interfaces']:
164 InterfaceUtil.vpp_set_interface_mtu(node, interface, mtu)
167 def vpp_set_interfaces_mtu_on_all_duts(nodes, mtu=9200):
168 """Set Ethernet MTU on all interfaces on all DUTs.
170 :param nodes: VPP nodes.
171 :param mtu: Ethernet MTU size in Bytes. Default: 9200.
175 for node in nodes.values():
176 if node['type'] == NodeType.DUT:
177 InterfaceUtil.vpp_set_interfaces_mtu_on_node(node, mtu)
180 def vpp_node_interfaces_ready_wait(node, timeout=30):
181 """Wait until all interfaces with admin-up are in link-up state.
183 :param node: Node to wait on.
184 :param timeout: Waiting timeout in seconds (optional, default 10s).
188 :raises RuntimeError: If the timeout period value has elapsed.
194 out = InterfaceUtil.vpp_get_interface_data(node)
195 if time() - start > timeout:
196 for interface in out:
197 if interface.get('admin_up_down') == 1:
198 if interface.get('link_up_down') != 1:
199 logger.debug('{0} link-down'.format(
200 interface.get('interface_name')))
201 raise RuntimeError('timeout, not up {0}'.format(not_ready))
203 for interface in out:
204 if interface.get('admin_up_down') == 1:
205 if interface.get('link_up_down') != 1:
206 not_ready.append(interface.get('interface_name'))
210 logger.debug('Interfaces still in link-down state: {0}, '
211 'waiting...'.format(not_ready))
215 def vpp_nodes_interfaces_ready_wait(nodes, timeout=30):
216 """Wait until all interfaces with admin-up are in link-up state for
219 :param nodes: List of nodes to wait on.
220 :param timeout: Seconds to wait per node for all interfaces to come up.
226 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
229 def all_vpp_interfaces_ready_wait(nodes, timeout=30):
230 """Wait until all interfaces with admin-up are in link-up state for all
231 nodes in the topology.
233 :param nodes: Nodes in the topology.
234 :param timeout: Seconds to wait per node for all interfaces to come up.
239 for node in nodes.values():
240 if node['type'] == NodeType.DUT:
241 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
244 def vpp_get_interface_data(node, interface=None):
245 """Get all interface data from a VPP node. If a name or
246 sw_interface_index is provided, return only data for the matching
249 :param node: VPP node to get interface data from.
250 :param interface: Numeric index or name string of a specific interface.
252 :type interface: int or str
253 :returns: List of dictionaries containing data for each interface, or a
254 single dictionary for the specified interface.
256 :raises TypeError: if the data type of interface is neither basestring
259 with VatTerminal(node) as vat:
260 response = vat.vat_terminal_exec_cmd_from_template(
261 "interface_dump.vat")
265 if interface is not None:
266 if isinstance(interface, basestring):
267 param = "interface_name"
268 elif isinstance(interface, int):
269 param = "sw_if_index"
273 if data_if[param] == interface:
279 def vpp_get_interface_name(node, sw_if_index):
280 """Get interface name for the given SW interface index from actual
283 :param node: VPP node to get interface data from.
284 :param sw_if_index: SW interface index of the specific interface.
286 :type sw_if_index: int
287 :returns: Name of the given interface.
291 if_data = InterfaceUtil.vpp_get_interface_data(node, sw_if_index)
292 if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
293 if_data = InterfaceUtil.vpp_get_interface_data(
294 node, if_data['sup_sw_if_index'])
296 if_name = if_data["interface_name"]
302 def vpp_get_interface_mac(node, interface=None):
303 """Get MAC address for the given interface from actual interface dump.
305 :param node: VPP node to get interface data from.
306 :param interface: Numeric index or name string of a specific interface.
308 :type interface: int or str
309 :returns: MAC address.
313 if_data = InterfaceUtil.vpp_get_interface_data(node, interface)
314 if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
315 if_data = InterfaceUtil.vpp_get_interface_data(
316 node, if_data['sup_sw_if_index'])
317 mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]]
319 for item in mac_data:
322 mac_data_nice.append(item)
323 mac = ":".join(mac_data_nice)
327 def vpp_get_interface_ip_addresses(node, interface, ip_version):
328 """Get list of IP addresses from an interface on a VPP node.
330 :param node: VPP node to get data from.
331 :param interface: Name of an interface on the VPP node.
332 :param ip_version: IP protocol version (ipv4 or ipv6).
335 :type ip_version: str
336 :returns: List of dictionaries, each containing IP address, subnet
337 prefix length and also the subnet mask for ipv4 addresses.
338 Note: A single interface may have multiple IP addresses assigned.
343 sw_if_index = Topology.convert_interface_reference(
344 node, interface, "sw_if_index")
346 if isinstance(interface, basestring):
347 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
351 with VatTerminal(node) as vat:
352 response = vat.vat_terminal_exec_cmd_from_template(
353 "ip_address_dump.vat", ip_version=ip_version,
354 sw_if_index=sw_if_index)
358 if ip_version == "ipv4":
360 item["netmask"] = convert_ipv4_netmask_prefix(
361 item["prefix_length"])
365 def tg_set_interface_driver(node, pci_addr, driver):
366 """Set interface driver on the TG node.
368 :param node: Node to set interface driver on (must be TG node).
369 :param pci_addr: PCI address of the interface.
370 :param driver: Driver name.
374 :raises RuntimeError: If unbinding from the current driver fails.
375 :raises RuntimeError: If binding to the new driver fails.
377 old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
378 if old_driver == driver:
384 # Unbind from current driver
385 if old_driver is not None:
386 cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'\
387 .format(pci_addr, old_driver)
388 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
389 if int(ret_code) != 0:
390 raise RuntimeError("'{0}' failed on '{1}'"
391 .format(cmd, node['host']))
393 # Bind to the new driver
394 cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'\
395 .format(pci_addr, driver)
396 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
397 if int(ret_code) != 0:
398 raise RuntimeError("'{0}' failed on '{1}'"
399 .format(cmd, node['host']))
402 def tg_get_interface_driver(node, pci_addr):
403 """Get interface driver from the TG node.
405 :param node: Node to get interface driver on (must be TG node).
406 :param pci_addr: PCI address of the interface.
409 :returns: Interface driver or None if not found.
411 :raises RuntimeError: If PCI rescan or lspci command execution failed.
413 return DUTSetup.get_pci_dev_driver(node, pci_addr)
416 def tg_set_interfaces_udev_rules(node):
417 """Set udev rules for interfaces.
419 Create udev rules file in /etc/udev/rules.d where are rules for each
420 interface used by TG node, based on MAC interface has specific name.
421 So after unbind and bind again to kernel driver interface has same
422 name as before. This must be called after TG has set name for each
423 port in topology dictionary.
425 SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f",
428 :param node: Node to set udev rules on (must be TG node).
430 :raises RuntimeError: If setting of udev rules fails.
435 cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE)
436 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
437 if int(ret_code) != 0:
438 raise RuntimeError("'{0}' failed on '{1}'"
439 .format(cmd, node['host']))
441 for interface in node['interfaces'].values():
442 rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
443 '==\\"' + interface['mac_address'] + '\\", NAME=\\"' + \
444 interface['name'] + '\\"'
445 cmd = 'sh -c "echo \'{0}\' >> {1}"'.format(
446 rule, InterfaceUtil.__UDEV_IF_RULES_FILE)
447 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
448 if int(ret_code) != 0:
449 raise RuntimeError("'{0}' failed on '{1}'"
450 .format(cmd, node['host']))
452 cmd = '/etc/init.d/udev restart'
453 ssh.exec_command_sudo(cmd)
456 def tg_set_interfaces_default_driver(node):
457 """Set interfaces default driver specified in topology yaml file.
459 :param node: Node to setup interfaces driver on (must be TG node).
462 for interface in node['interfaces'].values():
463 InterfaceUtil.tg_set_interface_driver(node,
464 interface['pci_address'],
468 def update_vpp_interface_data_on_node(node):
469 """Update vpp generated interface data for a given node in DICT__nodes.
471 Updates interface names, software if index numbers and any other details
472 generated specifically by vpp that are unknown before testcase run.
473 It does this by dumping interface list to JSON output from all
474 devices using vpp_api_test, and pairing known information from topology
475 (mac address/pci address of interface) to state from VPP.
477 :param node: Node selected from DICT__nodes.
480 vat_executor = VatExecutor()
481 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
482 interface_dump_json = vat_executor.get_script_stdout()
483 VatJsonUtil.update_vpp_interface_data_from_json(node,
487 def update_nic_interface_names(node):
488 """Update interface names based on nic type and PCI address.
490 This method updates interface names in the same format as VPP does.
492 :param node: Node dictionary.
495 for ifc in node['interfaces'].values():
496 if_pci = ifc['pci_address'].replace('.', ':').split(':')
497 bus = '{:x}'.format(int(if_pci[1], 16))
498 dev = '{:x}'.format(int(if_pci[2], 16))
499 fun = '{:x}'.format(int(if_pci[3], 16))
500 loc = '{bus}/{dev}/{fun}'.format(bus=bus, dev=dev, fun=fun)
501 if ifc['model'] == 'Intel-XL710':
502 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
503 elif ifc['model'] == 'Intel-X710':
504 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
505 elif ifc['model'] == 'Intel-X520-DA2':
506 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
507 elif ifc['model'] == 'Cisco-VIC-1385':
508 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
509 elif ifc['model'] == 'Cisco-VIC-1227':
510 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
512 ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc)
515 def update_nic_interface_names_on_all_duts(nodes):
516 """Update interface names based on nic type and PCI address on all DUTs.
518 This method updates interface names in the same format as VPP does.
520 :param nodes: Topology nodes.
523 for node in nodes.values():
524 if node['type'] == NodeType.DUT:
525 InterfaceUtil.update_nic_interface_names(node)
528 def update_tg_interface_data_on_node(node, skip_tg_udev=False):
529 """Update interface name for TG/linux node in DICT__nodes.
532 # for dev in `ls /sys/class/net/`;
533 > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done
534 "52:54:00:9f:82:63": "eth0"
535 "52:54:00:77:ae:a9": "eth1"
536 "52:54:00:e1:8a:0f": "eth2"
537 "00:00:00:00:00:00": "lo"
539 :param node: Node selected from DICT__nodes.
540 :param skip_tg_udev: Skip udev rename on TG node.
542 :type skip_tg_udev: bool
543 :raises RuntimeError: If getting of interface name and MAC fails.
545 # First setup interface driver specified in yaml file
546 InterfaceUtil.tg_set_interfaces_default_driver(node)
548 # Get interface names
552 cmd = ('for dev in `ls /sys/class/net/`; do echo "\\"`cat '
553 '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;')
555 (ret_code, stdout, _) = ssh.exec_command(cmd)
556 if int(ret_code) != 0:
557 raise RuntimeError('Get interface name and MAC failed')
558 tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
559 interfaces = JsonParser().parse_data(tmp)
560 for interface in node['interfaces'].values():
561 name = interfaces.get(interface['mac_address'])
564 interface['name'] = name
566 # Set udev rules for interfaces
568 InterfaceUtil.tg_set_interfaces_udev_rules(node)
571 def iface_update_numa_node(node):
572 """For all interfaces from topology file update numa node based on
573 information from the node.
575 :param node: Node from topology.
578 :raises ValueError: If numa node ia less than 0.
579 :raises RuntimeError: If update of numa node failes.
582 for if_key in Topology.get_node_interfaces(node):
583 if_pci = Topology.get_interface_pci_addr(node, if_key)
585 cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
587 (ret, out, _) = ssh.exec_command(cmd)
592 if CpuUtils.cpu_node_count(node) == 1:
597 logger.trace('Reading numa location failed for: {0}'
600 Topology.set_interface_numa_node(node, if_key,
604 raise RuntimeError('Update numa node failed for: {0}'
608 def update_all_numa_nodes(nodes, skip_tg=False):
609 """For all nodes and all their interfaces from topology file update numa
610 node information based on information from the node.
612 :param nodes: Nodes in the topology.
613 :param skip_tg: Skip TG node
618 for node in nodes.values():
619 if node['type'] == NodeType.DUT:
620 InterfaceUtil.iface_update_numa_node(node)
621 elif node['type'] == NodeType.TG and not skip_tg:
622 InterfaceUtil.iface_update_numa_node(node)
625 def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
628 """Update interface names on all nodes in DICT__nodes.
630 This method updates the topology dictionary by querying interface lists
631 of all nodes mentioned in the topology dictionary.
633 :param nodes: Nodes in the topology.
634 :param skip_tg: Skip TG node.
635 :param skip_tg_udev: Skip udev rename on TG node.
636 :param numa_node: Retrieve numa_node location.
639 :type skip_tg_udev: bool
640 :type numa_node: bool
642 for node_data in nodes.values():
643 if node_data['type'] == NodeType.DUT:
644 InterfaceUtil.update_vpp_interface_data_on_node(node_data)
645 elif node_data['type'] == NodeType.TG and not skip_tg:
646 InterfaceUtil.update_tg_interface_data_on_node(
647 node_data, skip_tg_udev)
650 if node_data['type'] == NodeType.DUT:
651 InterfaceUtil.iface_update_numa_node(node_data)
652 elif node_data['type'] == NodeType.TG and not skip_tg:
653 InterfaceUtil.iface_update_numa_node(node_data)
656 def create_vlan_subinterface(node, interface, vlan):
657 """Create VLAN subinterface on node.
659 :param node: Node to add VLAN subinterface on.
660 :param interface: Interface name on which create VLAN subinterface.
661 :param vlan: VLAN ID of the subinterface to be created.
665 :returns: Name and index of created subinterface.
667 :raises RuntimeError: if it is unable to create VLAN subinterface on the
670 iface_key = Topology.get_interface_by_name(node, interface)
671 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
673 output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
674 sw_if_index=sw_if_index,
676 if output[0]["retval"] == 0:
677 sw_vlan_idx = output[0]["sw_if_index"]
678 logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
679 'created on node {}'.format(sw_vlan_idx,
681 if_key = Topology.add_new_port(node, "vlan_subif")
682 Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
683 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
684 Topology.update_interface_name(node, if_key, ifc_name)
686 raise RuntimeError('Unable to create VLAN subinterface on node {}'
687 .format(node['host']))
689 with VatTerminal(node, False) as vat:
690 vat.vat_terminal_exec_cmd('exec show interfaces')
692 return '{}.{}'.format(interface, vlan), sw_vlan_idx
695 def create_vxlan_interface(node, vni, source_ip, destination_ip):
696 """Create VXLAN interface and return sw if index of created interface.
698 Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT
701 :param node: Node where to create VXLAN interface.
702 :param vni: VXLAN Network Identifier.
703 :param source_ip: Source IP of a VXLAN Tunnel End Point.
704 :param destination_ip: Destination IP of a VXLAN Tunnel End Point.
708 :type destination_ip: str
709 :returns: SW IF INDEX of created interface.
711 :raises RuntimeError: if it is unable to create VxLAN interface on the
714 output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
720 if output["retval"] == 0:
721 sw_if_idx = output["sw_if_index"]
722 if_key = Topology.add_new_port(node, "vxlan_tunnel")
723 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
724 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
725 Topology.update_interface_name(node, if_key, ifc_name)
728 raise RuntimeError("Unable to create VXLAN interface on node {0}"
732 def vxlan_dump(node, interface=None):
733 """Get VxLAN data for the given interface.
735 :param node: VPP node to get interface data from.
736 :param interface: Numeric index or name string of a specific interface.
737 If None, information about all VxLAN interfaces is returned.
739 :type interface: int or str
740 :returns: Dictionary containing data for the given VxLAN interface or if
741 interface=None, the list of dictionaries with all VxLAN interfaces.
743 :raises TypeError: if the data type of interface is neither basestring
746 param = "sw_if_index"
747 if interface is None:
750 elif isinstance(interface, basestring):
751 sw_if_index = Topology.get_interface_sw_index(node, interface)
752 elif isinstance(interface, int):
753 sw_if_index = interface
755 raise TypeError("Wrong interface format {0}".format(interface))
757 with VatTerminal(node) as vat:
758 response = vat.vat_terminal_exec_cmd_from_template(
759 "vxlan_dump.vat", param=param, sw_if_index=sw_if_index)
762 for vxlan in response[0]:
763 if vxlan["sw_if_index"] == sw_if_index:
769 def vhost_user_dump(node):
770 """Get vhost-user data for the given node.
772 :param node: VPP node to get interface data from.
774 :returns: List of dictionaries with all vhost-user interfaces.
777 with VatTerminal(node) as vat:
778 response = vat.vat_terminal_exec_cmd_from_template(
779 "vhost_user_dump.vat")
784 def tap_dump(node, name=None):
785 """Get all TAP interface data from the given node, or data about
786 a specific TAP interface.
788 :param node: VPP node to get data from.
789 :param name: Optional name of a specific TAP interface.
792 :returns: Dictionary of information about a specific TAP interface, or
793 a List of dictionaries containing all TAP data for the given node.
796 with VatTerminal(node) as vat:
797 response = vat.vat_terminal_exec_cmd_from_template(
801 for item in response[0]:
802 if name == item['dev_name']:
807 def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
808 inner_vlan_id=None, type_subif=None):
809 """Create sub-interface on node. It is possible to set required
810 sub-interface type and VLAN tag(s).
812 :param node: Node to add sub-interface.
813 :param interface: Interface name on which create sub-interface.
814 :param sub_id: ID of the sub-interface to be created.
815 :param outer_vlan_id: Optional outer VLAN ID.
816 :param inner_vlan_id: Optional inner VLAN ID.
817 :param type_subif: Optional type of sub-interface. Values supported by
818 VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match]
821 :type interface: str or int
823 :type outer_vlan_id: int
824 :type inner_vlan_id: int
825 :type type_subif: str
826 :returns: Name and index of created sub-interface.
828 :raises RuntimeError: If it is not possible to create sub-interface.
831 outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
832 if outer_vlan_id else ''
834 inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
835 if inner_vlan_id else ''
837 if type_subif is None:
840 if isinstance(interface, basestring):
841 iface_key = Topology.get_interface_by_name(node, interface)
842 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
844 sw_if_index = interface
846 output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
847 sw_if_index=sw_if_index,
849 outer_vlan_id=outer_vlan_id,
850 inner_vlan_id=inner_vlan_id,
851 type_subif=type_subif)
853 if output[0]["retval"] == 0:
854 sw_vlan_idx = output[0]["sw_if_index"]
855 logger.trace('Created subinterface with index {}'
856 .format(sw_vlan_idx))
857 if_key = Topology.add_new_port(node, "subinterface")
858 Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
859 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
860 Topology.update_interface_name(node, if_key, ifc_name)
862 raise RuntimeError('Unable to create sub-interface on node {}'
863 .format(node['host']))
865 with VatTerminal(node, json_param=False) as vat:
866 vat.vat_terminal_exec_cmd('exec show interfaces')
868 name = '{}.{}'.format(interface, sub_id)
869 return name, sw_vlan_idx
872 def create_gre_tunnel_interface(node, source_ip, destination_ip):
873 """Create GRE tunnel interface on node.
875 :param node: VPP node to add tunnel interface.
876 :param source_ip: Source of the GRE tunnel.
877 :param destination_ip: Destination of the GRE tunnel.
880 :type destination_ip: str
881 :returns: Name and index of created GRE tunnel interface.
883 :raises RuntimeError: If unable to create GRE tunnel interface.
887 src_address = inet_pton(AF_INET6, source_ip)
888 dst_address = inet_pton(AF_INET6, destination_ip)
891 src_address = inet_pton(AF_INET, source_ip)
892 dst_address = inet_pton(AF_INET, destination_ip)
895 cmd = 'gre_tunnel_add_del'
896 tunnel = dict(type=0,
897 instance=Constants.BITWISE_NON_ZERO,
902 args = dict(is_add=1,
904 err_msg = 'Failed to create GRE tunnel interface on host {host}'.format(
906 with PapiExecutor(node) as papi_exec:
907 papi_resp = papi_exec.add(cmd, **args).get_replies(err_msg).\
908 verify_reply(err_msg=err_msg)
910 sw_if_idx = papi_resp['sw_if_index']
911 if_key = Topology.add_new_port(node, 'gre_tunnel')
912 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
913 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
914 Topology.update_interface_name(node, if_key, ifc_name)
916 return ifc_name, sw_if_idx
919 def vpp_create_loopback(node):
920 """Create loopback interface on VPP node.
922 :param node: Node to create loopback interface on.
924 :returns: SW interface index.
926 :raises RuntimeError: If it is not possible to create loopback on the
929 out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
930 if out[0].get('retval') == 0:
931 sw_if_idx = out[0].get('sw_if_index')
932 if_key = Topology.add_new_port(node, "loopback")
933 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
934 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
935 Topology.update_interface_name(node, if_key, ifc_name)
938 raise RuntimeError('Create loopback failed on node "{}"'
939 .format(node['host']))
942 def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
943 """Create bond interface on VPP node.
945 :param node: DUT node from topology.
946 :param mode: Link bonding mode.
947 :param load_balance: Load balance (optional, valid for xor and lacp
948 modes, otherwise ignored).
949 :param mac: MAC address to assign to the bond interface (optional).
952 :type load_balance: str
954 :returns: Interface key (name) in topology.
956 :raises RuntimeError: If it is not possible to create bond interface on
959 hw_addr = '' if mac is None else 'hw-addr {mac}'.format(mac=mac)
960 ldb = '' if load_balance is None \
961 else 'lb {ldb}'.format(ldb=load_balance)
963 output = VatExecutor.cmd_from_template(
964 node, 'create_bond_interface.vat', mode=mode, lb=ldb, mac=hw_addr)
966 if output[0].get('retval') == 0:
967 sw_if_idx = output[0].get('sw_if_index')
968 InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
970 if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
973 raise RuntimeError('Create bond interface failed on "{host}"'.
974 format(host=node['host']))
977 def add_eth_interface(node, ifc_name=None, sw_if_idx=None, ifc_pfx=None):
978 """Add ethernet interface to current topology.
980 :param node: DUT node from topology.
981 :param ifc_name: Name of the interface.
982 :param sw_if_idx: SW interface index.
983 :param ifc_pfx: Interface key prefix.
989 if_key = Topology.add_new_port(node, ifc_pfx)
991 vat_executor = VatExecutor()
992 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
993 interface_dump_json = vat_executor.get_script_stdout()
995 if ifc_name and sw_if_idx is None:
996 sw_if_idx = VatJsonUtil.get_interface_sw_index_from_json(
997 interface_dump_json, ifc_name)
998 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
999 if sw_if_idx and ifc_name is None:
1000 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
1001 Topology.update_interface_name(node, if_key, ifc_name)
1002 ifc_mac = VatJsonUtil.get_interface_mac_from_json(
1003 interface_dump_json, sw_if_idx)
1004 Topology.update_interface_mac_address(node, if_key, ifc_mac)
1007 def vpp_create_avf_interface(node, vf_pci_addr, num_rx_queues=None):
1008 """Create AVF interface on VPP node.
1010 :param node: DUT node from topology.
1011 :param vf_pci_addr: Virtual Function PCI address.
1012 :param num_rx_queues: Number of RX queues.
1014 :type vf_pci_addr: str
1015 :type num_rx_queues: int
1016 :returns: Interface key (name) in topology.
1018 :raises RuntimeError: If it is not possible to create AVF interface on
1021 num_rx_queues = 'num-rx-queues {num_rx_queues}'\
1022 .format(num_rx_queues=num_rx_queues) if num_rx_queues else ''
1024 with VatTerminal(node, json_param=False) as vat:
1025 vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat',
1026 vf_pci_addr=vf_pci_addr,
1027 num_rx_queues=num_rx_queues)
1028 output = vat.vat_stdout
1030 if output is not None:
1031 sw_if_idx = int(output.split()[4])
1032 InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
1034 if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
1037 raise RuntimeError('Create AVF interface failed on {host}'.
1038 format(host=node['host']))
1041 def vpp_enslave_physical_interface(node, interface, bond_interface):
1042 """Enslave physical interface to bond interface on VPP node.
1044 :param node: DUT node from topology.
1045 :param interface: Physical interface key from topology file.
1046 :param bond_interface: Load balance
1048 :type interface: str
1049 :type bond_interface: str
1050 :raises RuntimeError: If it is not possible to enslave physical
1051 interface to bond interface on the node.
1053 ifc = Topology.get_interface_sw_index(node, interface)
1054 bond_ifc = Topology.get_interface_sw_index(node, bond_interface)
1056 output = VatExecutor.cmd_from_template(
1057 node, 'enslave_physical_interface.vat', p_int=ifc, b_int=bond_ifc)
1059 retval = output[0].get('retval', None)
1060 if retval is None or int(retval) != 0:
1061 raise RuntimeError('Enslave physical interface {ifc} to bond '
1062 'interface {bond} failed on node "{n}"'
1063 .format(ifc=interface, bond=bond_interface,
1067 def vpp_show_bond_data_on_node(node, details=False):
1068 """Show (detailed) bond information on VPP node.
1070 :param node: DUT node from topology.
1071 :param details: If detailed information is required or not.
1075 cmd = 'exec show bond details' if details else 'exec show bond'
1076 with VatTerminal(node, json_param=False) as vat:
1077 vat.vat_terminal_exec_cmd(cmd)
1080 def vpp_show_bond_data_on_all_nodes(nodes, details=False):
1081 """Show (detailed) bond information on all VPP nodes in DICT__nodes.
1083 :param nodes: Nodes in the topology.
1084 :param details: If detailed information is required or not.
1088 for node_data in nodes.values():
1089 if node_data['type'] == NodeType.DUT:
1090 InterfaceUtil.vpp_show_bond_data_on_node(node_data, details)
1093 def vpp_enable_input_acl_interface(node, interface, ip_version,
1095 """Enable input acl on interface.
1097 :param node: VPP node to setup interface for input acl.
1098 :param interface: Interface to setup input acl.
1099 :param ip_version: Version of IP protocol.
1100 :param table_index: Classify table index.
1102 :type interface: str or int
1103 :type ip_version: str
1104 :type table_index: int
1106 if isinstance(interface, basestring):
1107 sw_if_index = Topology.get_interface_sw_index(node, interface)
1109 sw_if_index = interface
1111 with VatTerminal(node) as vat:
1112 vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
1113 sw_if_index=sw_if_index,
1114 ip_version=ip_version,
1115 table_index=table_index)
1118 def get_interface_classify_table(node, interface):
1119 """Get name of classify table for the given interface.
1121 :param node: VPP node to get data from.
1122 :param interface: Name or sw_if_index of a specific interface.
1124 :type interface: str or int
1125 :returns: Classify table name.
1128 if isinstance(interface, basestring):
1129 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1131 sw_if_index = interface
1133 with VatTerminal(node) as vat:
1134 data = vat.vat_terminal_exec_cmd_from_template(
1135 "classify_interface_table.vat",
1136 sw_if_index=sw_if_index)
1140 def get_interface_vrf_table(node, interface):
1141 """Get vrf ID for the given interface.
1143 :param node: VPP node.
1144 :param interface: Name or sw_if_index of a specific interface.
1146 :type interface: str or int
1147 :returns: vrf ID of the specified interface.
1151 if isinstance(interface, basestring):
1152 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1154 sw_if_index = interface
1156 with VatTerminal(node) as vat:
1157 data = vat.vat_terminal_exec_cmd_from_template(
1158 "interface_vrf_dump.vat",
1159 sw_if_index=sw_if_index)
1160 return data[0]["vrf_id"]
1163 def get_sw_if_index(node, interface_name):
1164 """Get sw_if_index for the given interface from actual interface dump.
1166 :param node: VPP node to get interface data from.
1167 :param interface_name: Name of the specific interface.
1169 :type interface_name: str
1170 :returns: sw_if_index of the given interface.
1174 with VatTerminal(node) as vat:
1175 if_data = vat.vat_terminal_exec_cmd_from_template(
1176 "interface_dump.vat")
1177 for interface in if_data[0]:
1178 if interface["interface_name"] == interface_name:
1179 return interface["sw_if_index"]
1184 def vxlan_gpe_dump(node, interface_name=None):
1185 """Get VxLAN GPE data for the given interface.
1187 :param node: VPP node to get interface data from.
1188 :param interface_name: Name of the specific interface. If None,
1189 information about all VxLAN GPE interfaces is returned.
1191 :type interface_name: str
1192 :returns: Dictionary containing data for the given VxLAN GPE interface
1193 or if interface=None, the list of dictionaries with all VxLAN GPE
1195 :rtype: dict or list
1198 with VatTerminal(node) as vat:
1199 vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
1200 "vxlan_gpe_dump.vat")
1203 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
1205 for vxlan_gpe in vxlan_gpe_data[0]:
1206 if vxlan_gpe["sw_if_index"] == sw_if_index:
1210 return vxlan_gpe_data[0]
1213 def vpp_proxy_arp_interface_enable(node, interface):
1214 """Enable proxy ARP on interface.
1216 :param node: VPP node to enable proxy ARP on interface.
1217 :param interface: Interface to enable proxy ARP.
1219 :type interface: str or int
1221 if isinstance(interface, basestring):
1222 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1224 sw_if_index = interface
1226 with VatTerminal(node) as vat:
1227 vat.vat_terminal_exec_cmd_from_template(
1228 "proxy_arp_intfc_enable.vat",
1229 sw_if_index=sw_if_index)
1232 def vpp_ip_source_check_setup(node, interface):
1233 """Setup Reverse Path Forwarding source check on interface.
1235 :param node: Node to setup RPF source check.
1236 :param interface: Interface name to setup RPF source check.
1238 :type interface: str
1240 with VatTerminal(node) as vat:
1241 vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
1242 interface_name=interface)
1245 def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
1246 """Assign VPP interface to specific VRF/FIB table.
1248 :param node: VPP node where the FIB and interface are located.
1249 :param interface: Interface to be assigned to FIB.
1250 :param table_id: VRF table ID.
1251 :param ipv6: Assign to IPv6 table. Default False.
1253 :type interface: str or int
1257 if isinstance(interface, basestring):
1258 sw_if_index = Topology.get_interface_sw_index(node, interface)
1260 sw_if_index = interface
1262 ipv6 = 'ipv6' if ipv6 else ''
1264 with VatTerminal(node) as vat:
1265 ret = vat.vat_terminal_exec_cmd_from_template(
1266 "set_fib_to_interface.vat",
1267 sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
1269 if ret[0]["retval"] != 0:
1270 raise RuntimeError('Unable to assign interface to FIB node {}.'
1274 def set_linux_interface_mac(node, interface, mac, namespace=None,
1276 """Set MAC address for interface in linux.
1278 :param node: Node where to execute command.
1279 :param interface: Interface in namespace.
1280 :param mac: MAC to be assigned to interface.
1281 :param namespace: Execute command in namespace. Optional
1282 :param vf_id: Virtual Function id. Optional
1284 :type interface: str
1286 :type namespace: str
1289 mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \
1290 if vf_id is not None else 'address {mac}'.format(mac=mac)
1291 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1293 cmd = ('{ns} ip link set {interface} {mac}'.
1294 format(ns=ns_str, interface=interface, mac=mac_str))
1295 exec_cmd_no_error(node, cmd, sudo=True)
1298 def set_linux_interface_trust_on(node, interface, namespace=None,
1300 """Set trust on (promisc) for interface in linux.
1302 :param node: Node where to execute command.
1303 :param interface: Interface in namespace.
1304 :param namespace: Execute command in namespace. Optional
1305 :param vf_id: Virtual Function id. Optional
1307 :type interface: str
1308 :type namespace: str
1311 trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \
1312 if vf_id is not None else 'trust on'
1313 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1315 cmd = ('{ns} ip link set dev {interface} {trust}'.
1316 format(ns=ns_str, interface=interface, trust=trust_str))
1317 exec_cmd_no_error(node, cmd, sudo=True)
1320 def set_linux_interface_spoof_off(node, interface, namespace=None,
1322 """Set spoof off for interface in linux.
1324 :param node: Node where to execute command.
1325 :param interface: Interface in namespace.
1326 :param namespace: Execute command in namespace. Optional
1327 :param vf_id: Virtual Function id. Optional
1329 :type interface: str
1330 :type namespace: str
1333 spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \
1334 if vf_id is not None else 'spoof off'
1335 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1337 cmd = ('{ns} ip link set dev {interface} {spoof}'.
1338 format(ns=ns_str, interface=interface, spoof=spoof_str))
1339 exec_cmd_no_error(node, cmd, sudo=True)
1342 def init_avf_interface(node, ifc_key, numvfs=1, osi_layer='L2'):
1343 """Init PCI device by creating VFs and bind them to vfio-pci for AVF
1344 driver testing on DUT.
1346 :param node: DUT node.
1347 :param ifc_key: Interface key from topology file.
1348 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
1349 :param osi_layer: OSI Layer type to initialize TG with.
1350 Default value "L2" sets linux interface spoof off.
1354 :type osi_layer: str
1355 :returns: Virtual Function topology interface keys.
1361 # Read PCI address and driver.
1362 pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key)
1363 pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":")
1364 uio_driver = Topology.get_uio_driver(node)
1365 kernel_driver = Topology.get_interface_driver(node, ifc_key)
1366 current_driver = DUTSetup.get_pci_dev_driver(
1367 node, pf_pci_addr.replace(':', r'\:'))
1369 VPPUtil.stop_vpp_service(node)
1370 if current_driver != kernel_driver:
1371 # PCI device must be re-bound to kernel driver before creating VFs.
1372 DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True)
1373 # Stop VPP to prevent deadlock.
1374 # Unbind from current driver.
1375 DUTSetup.pci_driver_unbind(node, pf_pci_addr)
1376 # Bind to kernel driver.
1377 DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver)
1379 # Initialize PCI VFs
1380 DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs)
1383 # Set MAC address and bind each virtual function to uio driver.
1384 for vf_id in range(numvfs):
1385 vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2],
1386 pf_mac_addr[3], pf_mac_addr[4],
1387 pf_mac_addr[5], "{:02x}".format(vf_id)])
1389 pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\
1390 format(pci=pf_pci_addr)
1391 InterfaceUtil.set_linux_interface_trust_on(node, pf_dev,
1393 if osi_layer == 'L2':
1394 InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev,
1396 InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr,
1399 DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id)
1400 DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver)
1402 # Add newly created ports into topology file
1403 vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key)
1404 vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
1405 vf_ifc_key = Topology.add_new_port(node, vf_ifc_name)
1406 Topology.update_interface_name(node, vf_ifc_key,
1407 vf_ifc_name+str(vf_id+1))
1408 Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr)
1409 Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr)
1410 vf_ifc_keys.append(vf_ifc_key)
1415 def vpp_create_multiple_vxlan_ipv4_tunnels(
1416 node, node_vxlan_if, node_vlan_if, op_node, op_node_if,
1417 n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, ip_limit,
1419 """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on
1422 Put each pair of VXLAN tunnel interface and VLAN sub-interface to
1423 separate bridge-domain.
1425 :param node: VPP node to create VXLAN tunnel interfaces.
1426 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1428 :param node_vlan_if: VPP node interface key to create VLAN
1430 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1431 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1433 :param n_tunnels: Number of tunnel interfaces to create.
1434 :param vni_start: VNI start ID.
1435 :param src_ip_start: VXLAN tunnel source IP address start.
1436 :param dst_ip_start: VXLAN tunnel destination IP address start.
1437 :param ip_step: IP address incremental step.
1438 :param ip_limit: IP address limit.
1439 :param bd_id_start: Bridge-domain ID start.
1441 :type node_vxlan_if: str
1442 :type node_vlan_if: str
1444 :type op_node_if: str
1445 :type n_tunnels: int
1446 :type vni_start: int
1447 :type src_ip_start: str
1448 :type dst_ip_start: str
1451 :type bd_id_start: int
1453 # configure IPs, create VXLAN interfaces and VLAN sub-interfaces
1454 vxlan_count = InterfaceUtil.vpp_create_vxlan_and_vlan_interfaces(
1455 node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start,
1456 src_ip_start, dst_ip_start, ip_step, ip_limit)
1458 # update topology with VXLAN interfaces and VLAN sub-interfaces data
1459 # and put interfaces up
1460 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_up(
1461 node, vxlan_count, node_vlan_if)
1463 # configure bridge domains, ARPs and routes
1464 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1465 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1466 ip_step, bd_id_start)
1469 def vpp_create_vxlan_and_vlan_interfaces(
1470 node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start,
1471 src_ip_start, dst_ip_start, ip_step, ip_limit):
1473 Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP
1476 :param node: VPP node.
1477 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1479 :param node_vlan_if: VPP node interface key to create VLAN
1481 :param vxlan_count: Number of tunnel interfaces to create.
1482 :param vni_start: VNI start ID.
1483 :param src_ip_start: VXLAN tunnel source IP address start.
1484 :param dst_ip_start: VXLAN tunnel destination IP address start.
1485 :param ip_step: IP address incremental step.
1486 :param ip_limit: IP address limit.
1488 :type node_vxlan_if: str
1489 :type node_vlan_if: str
1490 :type vxlan_count: int
1491 :type vni_start: int
1492 :type src_ip_start: str
1493 :type dst_ip_start: str
1496 :returns: Number of created VXLAN interfaces.
1501 src_ip_start_int = IPUtil.ip_to_int(src_ip_start)
1502 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1503 ip_limit_int = IPUtil.ip_to_int(ip_limit)
1505 tmp_fn = '/tmp/create_vxlan_interfaces.config'
1506 for i in range(0, vxlan_count):
1507 src_ip_int = src_ip_start_int + i * ip_step
1508 dst_ip_int = dst_ip_start_int + i * ip_step
1509 if src_ip_int > ip_limit_int or dst_ip_int > ip_limit_int:
1510 logger.warn("Can't do more iterations - IPv4 address limit "
1511 "has been reached.")
1514 src_ip = IPUtil.int_to_ip(src_ip_int)
1515 dst_ip = IPUtil.int_to_ip(dst_ip_int)
1517 'sw_interface_add_del_address sw_if_index {sw_idx} {ip}/32\n'
1518 .format(sw_idx=Topology.get_interface_sw_index(
1519 node, node_vxlan_if), ip=src_ip))
1521 'vxlan_add_del_tunnel src {src_ip} dst {dst_ip} vni {vni}\n'
1522 .format(src_ip=src_ip, dst_ip=dst_ip, vni=vni_start+i))
1524 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n'
1525 .format(sw_idx=Topology.get_interface_sw_index(
1526 node, node_vlan_if), vlan=i+1))
1528 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1533 def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
1535 Update topology with VXLAN interfaces and VLAN sub-interfaces data
1536 and put interfaces up.
1538 :param node: VPP node.
1539 :param vxlan_count: Number of tunnel interfaces.
1540 :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
1543 :type vxlan_count: int
1544 :type node_vlan_if: str
1546 with VatTerminal(node) as vat_ter:
1547 if_data = vat_ter.vat_terminal_exec_cmd_from_template(
1548 'interface_dump.vat')[0]
1550 tmp_fn = '/tmp/put_subinterfaces_up.config'
1552 for i in range(0, vxlan_count):
1553 vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
1554 vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
1556 vxlan_subif_idx = None
1557 vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
1558 vlan_subif_name = '{if_name}.{vlan}'.format(
1559 if_name=Topology.get_interface_name(
1560 node, node_vlan_if), vlan=i+1)
1563 for data in if_data:
1564 if_name = data['interface_name']
1565 if not vxlan_found and if_name == vxlan_subif_name:
1566 vxlan_subif_idx = data['sw_if_index']
1568 elif not vlan_found and if_name == vlan_subif_name:
1569 vlan_idx = data['sw_if_index']
1571 if vxlan_found and vlan_found:
1573 Topology.update_interface_sw_if_index(
1574 node, vxlan_subif_key, vxlan_subif_idx)
1575 Topology.update_interface_name(
1576 node, vxlan_subif_key, vxlan_subif_name)
1578 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1579 .format(sw_idx=vxlan_subif_idx))
1580 Topology.update_interface_sw_if_index(
1581 node, vlan_subif_key, vlan_idx)
1582 Topology.update_interface_name(
1583 node, vlan_subif_key, vlan_subif_name)
1585 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1586 .format(sw_idx=vlan_idx))
1588 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1591 def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1592 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1593 ip_step, bd_id_start):
1595 Configure ARPs and routes for VXLAN interfaces and put each pair of
1596 VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
1598 :param node: VPP node.
1599 :param node_vxlan_if: VPP node interface key where VXLAN tunnel
1600 interfaces have been created.
1601 :param vxlan_count: Number of tunnel interfaces.
1602 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1603 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1605 :param dst_ip_start: VXLAN tunnel destination IP address start.
1606 :param ip_step: IP address incremental step.
1607 :param bd_id_start: Bridge-domain ID start.
1609 :type node_vxlan_if: str
1610 :type vxlan_count: int
1613 :type dst_ip_start: str
1615 :type bd_id_start: int
1617 sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
1619 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1621 tmp_fn = '/tmp/configure_routes_and_bridge_domains.config'
1623 for i in range(0, vxlan_count):
1624 dst_ip = IPUtil.int_to_ip(dst_ip_start_int + i * ip_step)
1626 'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} mac {mac}\n'
1627 .format(sw_idx=sw_idx_vxlan, ip=dst_ip,
1628 mac=Topology.get_interface_mac(op_node, op_node_if)))
1630 'ip_add_del_route {ip}/32 via {ip} sw_if_index {sw_idx}'
1631 ' resolve-attempts 10 count 1\n'.format(
1632 ip=dst_ip, sw_idx=sw_idx_vxlan))
1633 bd_id = bd_id_start + i
1636 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1637 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1638 node, 'vxlan_tunnel{nr}'.format(nr=subif_id)), bd_id=bd_id))
1640 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1641 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1642 node, 'vlan_subif{nr}'.format(nr=subif_id)), bd_id=bd_id))
1644 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1647 def vpp_sw_interface_rx_placement_dump(node):
1648 """Dump VPP interface RX placement on node.
1650 :param node: Node to run command on.
1652 :returns: Thread mapping information as a list of dictionaries.
1656 cmd = 'sw_interface_rx_placement_dump'
1657 cmd_reply = 'sw_interface_rx_placement_details'
1658 err_msg = "Failed to run '{cmd}' PAPI command on host {host}!".format(
1659 cmd=cmd, host=node['host'])
1660 with PapiExecutor(node) as papi_exec:
1661 for ifc in node['interfaces'].values():
1662 if ifc['vpp_sw_index'] is not None:
1663 papi_exec.add(cmd, sw_if_index=ifc['vpp_sw_index'])
1664 papi_resp = papi_exec.get_dump(err_msg)
1665 thr_mapping = [s[cmd_reply] for r in papi_resp.reply
1666 for s in r['api_reply']]
1667 return sorted(thr_mapping, key=lambda k: k['sw_if_index'])
1670 def vpp_sw_interface_set_rx_placement(node, sw_if_index, queue_id,
1672 """Set interface RX placement to worker on node.
1674 :param node: Node to run command on.
1675 :param sw_if_index: VPP SW interface index.
1676 :param queue_id: VPP interface queue ID.
1677 :param worker_id: VPP worker ID (indexing from 0).
1679 :type sw_if_index: int
1681 :type worker_id: int
1682 :raises RuntimeError: If failed to run command on host or if no API
1686 cmd = 'sw_interface_set_rx_placement'
1687 cmd_reply = 'sw_interface_set_rx_placement_reply'
1688 err_msg = "Failed to run '{cmd}' PAPI command on host {host}!".format(
1689 host=node['host'], cmd=cmd)
1690 args = dict(sw_if_index=sw_if_index, queue_id=queue_id,
1691 worker_id=worker_id)
1692 with PapiExecutor(node) as papi_exec:
1693 papi_resp = papi_exec.add(cmd, **args).execute_should_pass(err_msg)
1694 data = papi_resp.reply[0]['api_reply'][cmd_reply]
1695 if data['retval'] != 0:
1696 raise RuntimeError("Failed to set interface RX placement "
1697 "to worker on host {host}".
1698 format(host=node['host']))
1701 def vpp_round_robin_rx_placement(node, prefix):
1702 """Set Round Robin interface RX placement on all worker threads
1705 :param node: Topology nodes.
1706 :param prefix: Interface name prefix.
1711 worker_cnt = len(VPPUtil.vpp_show_threads(node)) - 1
1712 for placement in InterfaceUtil.vpp_sw_interface_rx_placement_dump(node):
1713 for interface in node['interfaces'].values():
1714 if placement['sw_if_index'] == interface['vpp_sw_index'] \
1715 and prefix in interface['name']:
1716 InterfaceUtil.vpp_sw_interface_set_rx_placement(
1717 node, placement['sw_if_index'], placement['queue_id'],
1718 worker_id % worker_cnt)
1722 def vpp_round_robin_rx_placement_on_all_duts(nodes, prefix):
1723 """Set Round Robin interface RX placement on all worker threads
1726 :param nodes: Topology nodes.
1727 :param prefix: Interface name prefix.
1731 for node in nodes.values():
1732 if node['type'] == NodeType.DUT:
1733 InterfaceUtil.vpp_round_robin_rx_placement(node, prefix)