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, num_rx_queues=None):
995 """Create AVF interface on VPP node.
997 :param node: DUT node from topology.
998 :param vf_pci_addr: Virtual Function PCI address.
999 :param num_rx_queues: Number of RX queues.
1001 :type vf_pci_addr: str
1002 :type num_rx_queues: int
1003 :returns: Interface key (name) in topology.
1005 :raises RuntimeError: If it is not possible to create AVF interface on
1008 num_rx_queues = 'num-rx-queues {num_rx_queues}'\
1009 .format(num_rx_queues=num_rx_queues) if num_rx_queues else ''
1011 with VatTerminal(node, json_param=False) as vat:
1012 vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat',
1013 vf_pci_addr=vf_pci_addr,
1014 num_rx_queues=num_rx_queues)
1015 output = vat.vat_stdout
1017 if output is not None:
1018 sw_if_idx = int(output.split()[4])
1019 InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
1021 if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
1024 raise RuntimeError('Create AVF interface failed on {host}'.
1025 format(host=node['host']))
1028 def vpp_enslave_physical_interface(node, interface, bond_interface):
1029 """Enslave physical interface to bond interface on VPP node.
1031 :param node: DUT node from topology.
1032 :param interface: Physical interface key from topology file.
1033 :param bond_interface: Load balance
1035 :type interface: str
1036 :type bond_interface: str
1037 :raises RuntimeError: If it is not possible to enslave physical
1038 interface to bond interface on the node.
1040 ifc = Topology.get_interface_sw_index(node, interface)
1041 bond_ifc = Topology.get_interface_sw_index(node, bond_interface)
1043 output = VatExecutor.cmd_from_template(
1044 node, 'enslave_physical_interface.vat', p_int=ifc, b_int=bond_ifc)
1046 retval = output[0].get('retval', None)
1047 if retval is None or int(retval) != 0:
1048 raise RuntimeError('Enslave physical interface {ifc} to bond '
1049 'interface {bond} failed on node "{n}"'
1050 .format(ifc=interface, bond=bond_interface,
1054 def vpp_show_bond_data_on_node(node, details=False):
1055 """Show (detailed) bond information on VPP node.
1057 :param node: DUT node from topology.
1058 :param details: If detailed information is required or not.
1062 cmd = 'exec show bond details' if details else 'exec show bond'
1063 with VatTerminal(node, json_param=False) as vat:
1064 vat.vat_terminal_exec_cmd(cmd)
1067 def vpp_show_bond_data_on_all_nodes(nodes, details=False):
1068 """Show (detailed) bond information on all VPP nodes in DICT__nodes.
1070 :param nodes: Nodes in the topology.
1071 :param details: If detailed information is required or not.
1075 for node_data in nodes.values():
1076 if node_data['type'] == NodeType.DUT:
1077 InterfaceUtil.vpp_show_bond_data_on_node(node_data, details)
1080 def vpp_enable_input_acl_interface(node, interface, ip_version,
1082 """Enable input acl on interface.
1084 :param node: VPP node to setup interface for input acl.
1085 :param interface: Interface to setup input acl.
1086 :param ip_version: Version of IP protocol.
1087 :param table_index: Classify table index.
1089 :type interface: str or int
1090 :type ip_version: str
1091 :type table_index: int
1093 if isinstance(interface, basestring):
1094 sw_if_index = Topology.get_interface_sw_index(node, interface)
1096 sw_if_index = interface
1098 with VatTerminal(node) as vat:
1099 vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
1100 sw_if_index=sw_if_index,
1101 ip_version=ip_version,
1102 table_index=table_index)
1105 def get_interface_classify_table(node, interface):
1106 """Get name of classify table for the given interface.
1108 :param node: VPP node to get data from.
1109 :param interface: Name or sw_if_index of a specific interface.
1111 :type interface: str or int
1112 :returns: Classify table name.
1115 if isinstance(interface, basestring):
1116 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1118 sw_if_index = interface
1120 with VatTerminal(node) as vat:
1121 data = vat.vat_terminal_exec_cmd_from_template(
1122 "classify_interface_table.vat",
1123 sw_if_index=sw_if_index)
1127 def get_interface_vrf_table(node, interface):
1128 """Get vrf ID for the given interface.
1130 :param node: VPP node.
1131 :param interface: Name or sw_if_index of a specific interface.
1133 :type interface: str or int
1134 :returns: vrf ID of the specified interface.
1138 if isinstance(interface, basestring):
1139 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1141 sw_if_index = interface
1143 with VatTerminal(node) as vat:
1144 data = vat.vat_terminal_exec_cmd_from_template(
1145 "interface_vrf_dump.vat",
1146 sw_if_index=sw_if_index)
1147 return data[0]["vrf_id"]
1150 def get_sw_if_index(node, interface_name):
1151 """Get sw_if_index for the given interface from actual interface dump.
1153 :param node: VPP node to get interface data from.
1154 :param interface_name: Name of the specific interface.
1156 :type interface_name: str
1157 :returns: sw_if_index of the given interface.
1161 with VatTerminal(node) as vat:
1162 if_data = vat.vat_terminal_exec_cmd_from_template(
1163 "interface_dump.vat")
1164 for interface in if_data[0]:
1165 if interface["interface_name"] == interface_name:
1166 return interface["sw_if_index"]
1171 def vxlan_gpe_dump(node, interface_name=None):
1172 """Get VxLAN GPE data for the given interface.
1174 :param node: VPP node to get interface data from.
1175 :param interface_name: Name of the specific interface. If None,
1176 information about all VxLAN GPE interfaces is returned.
1178 :type interface_name: str
1179 :returns: Dictionary containing data for the given VxLAN GPE interface
1180 or if interface=None, the list of dictionaries with all VxLAN GPE
1182 :rtype: dict or list
1185 with VatTerminal(node) as vat:
1186 vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
1187 "vxlan_gpe_dump.vat")
1190 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
1192 for vxlan_gpe in vxlan_gpe_data[0]:
1193 if vxlan_gpe["sw_if_index"] == sw_if_index:
1197 return vxlan_gpe_data[0]
1200 def vpp_proxy_arp_interface_enable(node, interface):
1201 """Enable proxy ARP on interface.
1203 :param node: VPP node to enable proxy ARP on interface.
1204 :param interface: Interface to enable proxy ARP.
1206 :type interface: str or int
1208 if isinstance(interface, basestring):
1209 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1211 sw_if_index = interface
1213 with VatTerminal(node) as vat:
1214 vat.vat_terminal_exec_cmd_from_template(
1215 "proxy_arp_intfc_enable.vat",
1216 sw_if_index=sw_if_index)
1219 def vpp_ip_source_check_setup(node, interface):
1220 """Setup Reverse Path Forwarding source check on interface.
1222 :param node: Node to setup RPF source check.
1223 :param interface: Interface name to setup RPF source check.
1225 :type interface: str
1227 with VatTerminal(node) as vat:
1228 vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
1229 interface_name=interface)
1232 def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
1233 """Assign VPP interface to specific VRF/FIB table.
1235 :param node: VPP node where the FIB and interface are located.
1236 :param interface: Interface to be assigned to FIB.
1237 :param table_id: VRF table ID.
1238 :param ipv6: Assign to IPv6 table. Default False.
1240 :type interface: str or int
1244 if isinstance(interface, basestring):
1245 sw_if_index = Topology.get_interface_sw_index(node, interface)
1247 sw_if_index = interface
1249 ipv6 = 'ipv6' if ipv6 else ''
1251 with VatTerminal(node) as vat:
1252 ret = vat.vat_terminal_exec_cmd_from_template(
1253 "set_fib_to_interface.vat",
1254 sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
1256 if ret[0]["retval"] != 0:
1257 raise RuntimeError('Unable to assign interface to FIB node {}.'
1261 def set_linux_interface_mac(node, interface, mac, namespace=None,
1263 """Set MAC address for interface in linux.
1265 :param node: Node where to execute command.
1266 :param interface: Interface in namespace.
1267 :param mac: MAC to be assigned to interface.
1268 :param namespace: Execute command in namespace. Optional
1269 :param vf_id: Virtual Function id. Optional
1271 :type interface: str
1273 :type namespace: str
1276 mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \
1277 if vf_id is not None else 'address {mac}'.format(mac=mac)
1278 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1280 cmd = ('{ns} ip link set {interface} {mac}'.
1281 format(ns=ns_str, interface=interface, mac=mac_str))
1282 exec_cmd_no_error(node, cmd, sudo=True)
1285 def set_linux_interface_trust_on(node, interface, namespace=None,
1287 """Set trust on (promisc) for interface in linux.
1289 :param node: Node where to execute command.
1290 :param interface: Interface in namespace.
1291 :param namespace: Execute command in namespace. Optional
1292 :param vf_id: Virtual Function id. Optional
1294 :type interface: str
1295 :type namespace: str
1298 trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \
1299 if vf_id is not None else 'trust on'
1300 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1302 cmd = ('{ns} ip link set dev {interface} {trust}'.
1303 format(ns=ns_str, interface=interface, trust=trust_str))
1304 exec_cmd_no_error(node, cmd, sudo=True)
1307 def set_linux_interface_spoof_off(node, interface, namespace=None,
1309 """Set spoof off for interface in linux.
1311 :param node: Node where to execute command.
1312 :param interface: Interface in namespace.
1313 :param namespace: Execute command in namespace. Optional
1314 :param vf_id: Virtual Function id. Optional
1316 :type interface: str
1317 :type namespace: str
1320 spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \
1321 if vf_id is not None else 'spoof off'
1322 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1324 cmd = ('{ns} ip link set dev {interface} {spoof}'.
1325 format(ns=ns_str, interface=interface, spoof=spoof_str))
1326 exec_cmd_no_error(node, cmd, sudo=True)
1329 def init_avf_interface(node, ifc_key, numvfs=1, topology_type='L2'):
1330 """Init PCI device by creating VFs and bind them to vfio-pci for AVF
1331 driver testing on DUT.
1333 :param node: DUT node.
1334 :param ifc_key: Interface key from topology file.
1335 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
1336 :param topology_type: Topology type.
1340 :type topology_type: str
1341 :returns: Virtual Function topology interface keys.
1347 # Read PCI address and driver.
1348 pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key)
1349 pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":")
1350 uio_driver = Topology.get_uio_driver(node)
1351 kernel_driver = Topology.get_interface_driver(node, ifc_key)
1352 current_driver = DUTSetup.get_pci_dev_driver(
1353 node, pf_pci_addr.replace(':', r'\:'))
1355 VPPUtil.stop_vpp_service(node)
1356 if current_driver != kernel_driver:
1357 # PCI device must be re-bound to kernel driver before creating VFs.
1358 DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True)
1359 # Stop VPP to prevent deadlock.
1360 # Unbind from current driver.
1361 DUTSetup.pci_driver_unbind(node, pf_pci_addr)
1362 # Bind to kernel driver.
1363 DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver)
1365 # Initialize PCI VFs
1366 DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs)
1369 # Set MAC address and bind each virtual function to uio driver.
1370 for vf_id in range(numvfs):
1371 vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2],
1372 pf_mac_addr[3], pf_mac_addr[4],
1373 pf_mac_addr[5], "{:02x}".format(vf_id)])
1375 pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\
1376 format(pci=pf_pci_addr)
1377 InterfaceUtil.set_linux_interface_trust_on(node, pf_dev,
1379 if topology_type == 'L2':
1380 InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev,
1382 InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr,
1385 DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id)
1386 DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver)
1388 # Add newly created ports into topology file
1389 vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key)
1390 vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
1391 vf_ifc_key = Topology.add_new_port(node, vf_ifc_name)
1392 Topology.update_interface_name(node, vf_ifc_key,
1393 vf_ifc_name+str(vf_id+1))
1394 Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr)
1395 Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr)
1396 vf_ifc_keys.append(vf_ifc_key)
1401 def vpp_create_multiple_vxlan_ipv4_tunnels(
1402 node, node_vxlan_if, node_vlan_if, op_node, op_node_if,
1403 n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, ip_limit,
1405 """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on
1408 Put each pair of VXLAN tunnel interface and VLAN sub-interface to
1409 separate bridge-domain.
1411 :param node: VPP node to create VXLAN tunnel interfaces.
1412 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1414 :param node_vlan_if: VPP node interface key to create VLAN
1416 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1417 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1419 :param n_tunnels: Number of tunnel interfaces to create.
1420 :param vni_start: VNI start ID.
1421 :param src_ip_start: VXLAN tunnel source IP address start.
1422 :param dst_ip_start: VXLAN tunnel destination IP address start.
1423 :param ip_step: IP address incremental step.
1424 :param ip_limit: IP address limit.
1425 :param bd_id_start: Bridge-domain ID start.
1427 :type node_vxlan_if: str
1428 :type node_vlan_if: str
1430 :type op_node_if: str
1431 :type n_tunnels: int
1432 :type vni_start: int
1433 :type src_ip_start: str
1434 :type dst_ip_start: str
1437 :type bd_id_start: int
1439 # configure IPs, create VXLAN interfaces and VLAN sub-interfaces
1440 vxlan_count = InterfaceUtil.vpp_create_vxlan_and_vlan_interfaces(
1441 node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start,
1442 src_ip_start, dst_ip_start, ip_step, ip_limit)
1444 # update topology with VXLAN interfaces and VLAN sub-interfaces data
1445 # and put interfaces up
1446 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_up(
1447 node, vxlan_count, node_vlan_if)
1449 # configure bridge domains, ARPs and routes
1450 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1451 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1452 ip_step, bd_id_start)
1455 def vpp_create_vxlan_and_vlan_interfaces(
1456 node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start,
1457 src_ip_start, dst_ip_start, ip_step, ip_limit):
1459 Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP
1462 :param node: VPP node.
1463 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1465 :param node_vlan_if: VPP node interface key to create VLAN
1467 :param vxlan_count: Number of tunnel interfaces to create.
1468 :param vni_start: VNI start ID.
1469 :param src_ip_start: VXLAN tunnel source IP address start.
1470 :param dst_ip_start: VXLAN tunnel destination IP address start.
1471 :param ip_step: IP address incremental step.
1472 :param ip_limit: IP address limit.
1474 :type node_vxlan_if: str
1475 :type node_vlan_if: str
1476 :type vxlan_count: int
1477 :type vni_start: int
1478 :type src_ip_start: str
1479 :type dst_ip_start: str
1482 :returns: Number of created VXLAN interfaces.
1487 src_ip_start_int = IPUtil.ip_to_int(src_ip_start)
1488 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1489 ip_limit_int = IPUtil.ip_to_int(ip_limit)
1491 tmp_fn = '/tmp/create_vxlan_interfaces.config'
1492 for i in range(0, vxlan_count):
1493 src_ip_int = src_ip_start_int + i * ip_step
1494 dst_ip_int = dst_ip_start_int + i * ip_step
1495 if src_ip_int > ip_limit_int or dst_ip_int > ip_limit_int:
1496 logger.warn("Can't do more iterations - IPv4 address limit "
1497 "has been reached.")
1500 src_ip = IPUtil.int_to_ip(src_ip_int)
1501 dst_ip = IPUtil.int_to_ip(dst_ip_int)
1503 'sw_interface_add_del_address sw_if_index {sw_idx} {ip}/32\n'
1504 .format(sw_idx=Topology.get_interface_sw_index(
1505 node, node_vxlan_if), ip=src_ip))
1507 'vxlan_add_del_tunnel src {src_ip} dst {dst_ip} vni {vni}\n'
1508 .format(src_ip=src_ip, dst_ip=dst_ip, vni=vni_start+i))
1510 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n'
1511 .format(sw_idx=Topology.get_interface_sw_index(
1512 node, node_vlan_if), vlan=i+1))
1514 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1519 def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
1521 Update topology with VXLAN interfaces and VLAN sub-interfaces data
1522 and put interfaces up.
1524 :param node: VPP node.
1525 :param vxlan_count: Number of tunnel interfaces.
1526 :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
1529 :type vxlan_count: int
1530 :type node_vlan_if: str
1532 with VatTerminal(node) as vat_ter:
1533 if_data = vat_ter.vat_terminal_exec_cmd_from_template(
1534 'interface_dump.vat')[0]
1536 tmp_fn = '/tmp/put_subinterfaces_up.config'
1538 for i in range(0, vxlan_count):
1539 vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
1540 vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
1542 vxlan_subif_idx = None
1543 vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
1544 vlan_subif_name = '{if_name}.{vlan}'.format(
1545 if_name=Topology.get_interface_name(
1546 node, node_vlan_if), vlan=i+1)
1549 for data in if_data:
1550 if_name = data['interface_name']
1551 if not vxlan_found and if_name == vxlan_subif_name:
1552 vxlan_subif_idx = data['sw_if_index']
1554 elif not vlan_found and if_name == vlan_subif_name:
1555 vlan_idx = data['sw_if_index']
1557 if vxlan_found and vlan_found:
1559 Topology.update_interface_sw_if_index(
1560 node, vxlan_subif_key, vxlan_subif_idx)
1561 Topology.update_interface_name(
1562 node, vxlan_subif_key, vxlan_subif_name)
1564 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1565 .format(sw_idx=vxlan_subif_idx))
1566 Topology.update_interface_sw_if_index(
1567 node, vlan_subif_key, vlan_idx)
1568 Topology.update_interface_name(
1569 node, vlan_subif_key, vlan_subif_name)
1571 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1572 .format(sw_idx=vlan_idx))
1574 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1577 def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1578 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1579 ip_step, bd_id_start):
1581 Configure ARPs and routes for VXLAN interfaces and put each pair of
1582 VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
1584 :param node: VPP node.
1585 :param node_vxlan_if: VPP node interface key where VXLAN tunnel
1586 interfaces have been created.
1587 :param vxlan_count: Number of tunnel interfaces.
1588 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1589 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1591 :param dst_ip_start: VXLAN tunnel destination IP address start.
1592 :param ip_step: IP address incremental step.
1593 :param bd_id_start: Bridge-domain ID start.
1595 :type node_vxlan_if: str
1596 :type vxlan_count: int
1599 :type dst_ip_start: str
1601 :type bd_id_start: int
1603 sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
1605 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1607 tmp_fn = '/tmp/configure_routes_and_bridge_domains.config'
1609 for i in range(0, vxlan_count):
1610 dst_ip = IPUtil.int_to_ip(dst_ip_start_int + i * ip_step)
1612 'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} mac {mac}\n'
1613 .format(sw_idx=sw_idx_vxlan, ip=dst_ip,
1614 mac=Topology.get_interface_mac(op_node, op_node_if)))
1616 'ip_add_del_route {ip}/32 via {ip} sw_if_index {sw_idx}'
1617 ' resolve-attempts 10 count 1\n'.format(
1618 ip=dst_ip, sw_idx=sw_idx_vxlan))
1619 bd_id = bd_id_start + i
1622 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1623 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1624 node, 'vxlan_tunnel{nr}'.format(nr=subif_id)), bd_id=bd_id))
1626 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1627 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1628 node, 'vlan_subif{nr}'.format(nr=subif_id)), bd_id=bd_id))
1630 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1633 def vpp_sw_interface_rx_placement_dump(node):
1634 """Dump VPP interface RX placement on node.
1636 :param node: Node to run command on.
1638 :returns: Thread mapping information as a list of dictionaries.
1640 :raises RuntimeError: If failed to run command on host.
1641 :raises PapiError: If no API reply received.
1644 for ifc in node['interfaces'].values():
1645 if ifc['vpp_sw_index'] is not None:
1646 api = dict(api_name='sw_interface_rx_placement_dump')
1647 api_args = dict(sw_if_index=ifc['vpp_sw_index'])
1648 api['api_args'] = api_args
1649 api_data.append(api)
1651 with PapiExecutor(node) as papi_executor:
1652 papi_executor.execute_papi(api_data)
1654 papi_executor.papi_should_have_passed()
1655 api_reply = papi_executor.get_papi_reply()
1656 except AssertionError:
1657 raise RuntimeError('Failed to run {api_name} on host '
1658 '{host}!'.format(host=node['host'], **api))
1661 thr_mapping = [s['sw_interface_rx_placement_details'] \
1662 for r in api_reply for s in r['api_reply']]
1663 return sorted(thr_mapping, key=lambda k: k['sw_if_index'])
1665 raise PapiError('No reply received for {api_name} on host {host}!'.
1666 format(host=node['host'], **api))
1669 def vpp_sw_interface_set_rx_placement(node, sw_if_index, queue_id,
1671 """Set interface RX placement to worker on node.
1673 :param node: Node to run command on.
1674 :param sw_if_index: VPP SW interface index.
1675 :param queue_id: VPP interface queue ID.
1676 :param worker_id: VPP worker ID (indexing from 0).
1678 :type sw_if_index: int
1680 :type worker_id: int
1681 :raises RuntimeError: If failed to run command on host.
1682 :raises PapiError: If no API reply received.
1685 api = dict(api_name='sw_interface_set_rx_placement')
1686 api_args = dict(sw_if_index=sw_if_index, queue_id=queue_id,
1687 worker_id=worker_id)
1688 api['api_args'] = api_args
1689 api_data.append(api)
1691 with PapiExecutor(node) as papi_executor:
1692 papi_executor.execute_papi(api_data)
1694 papi_executor.papi_should_have_passed()
1695 api_reply = papi_executor.get_papi_reply()
1696 except AssertionError:
1697 raise RuntimeError('Failed to run {api_name} on host '
1698 '{host}!'.format(host=node['host'], **api))
1701 raise PapiError('No reply received for {api_name} on host {host}!'.
1702 format(host=node['host'], **api))
1705 def vpp_round_robin_rx_placement(node, prefix):
1706 """Set Round Robin interface RX placement on all worker threads
1709 :param node: Topology nodes.
1710 :param prefix: Interface name prefix.
1715 worker_cnt = len(VPPUtil.vpp_show_threads(node)) - 1
1716 for placement in InterfaceUtil.vpp_sw_interface_rx_placement_dump(node):
1717 for interface in node['interfaces'].values():
1718 if placement['sw_if_index'] == interface['vpp_sw_index'] \
1719 and prefix in interface['name']:
1720 InterfaceUtil.vpp_sw_interface_set_rx_placement(
1721 node, placement['sw_if_index'], placement['queue_id'],
1722 worker_id % worker_cnt)
1726 def vpp_round_robin_rx_placement_on_all_duts(nodes, prefix):
1727 """Set Round Robin interface RX placement on all worker threads
1730 :param nodes: Topology nodes.
1731 :param prefix: Interface name prefix.
1735 for node in nodes.values():
1736 if node['type'] == NodeType.DUT:
1737 InterfaceUtil.vpp_round_robin_rx_placement(node, prefix)