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 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.IPUtil import convert_ipv4_netmask_prefix
24 from resources.libraries.python.IPUtil import IPUtil
25 from resources.libraries.python.parsers.JsonParser import JsonParser
26 from resources.libraries.python.ssh import SSH, exec_cmd_no_error
27 from resources.libraries.python.topology import NodeType, Topology
28 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
29 from resources.libraries.python.VatJsonUtil import VatJsonUtil
30 from resources.libraries.python.VPPUtil import VPPUtil
33 class InterfaceUtil(object):
34 """General utilities for managing interfaces"""
36 __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
39 def set_interface_state(node, interface, state, if_type="key"):
40 """Set interface state on a node.
42 Function can be used for DUTs as well as for TGs.
44 :param node: Node where the interface is.
45 :param interface: Interface key or sw_if_index or name.
46 :param state: One of 'up' or 'down'.
47 :param if_type: Interface type
49 :type interface: str or int
53 :raises ValueError: If the interface type is unknown.
54 :raises ValueError: If the state of interface is unexpected.
55 :raises ValueError: If the node has an unknown node type.
59 if isinstance(interface, basestring):
60 sw_if_index = Topology.get_interface_sw_index(node, interface)
61 iface_name = Topology.get_interface_name(node, interface)
63 sw_if_index = interface
64 elif if_type == "name":
65 iface_key = Topology.get_interface_by_name(node, interface)
66 if iface_key is not None:
67 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
68 iface_name = interface
70 raise ValueError("if_type unknown: {}".format(if_type))
72 if node['type'] == NodeType.DUT:
74 state = 'admin-up link-up'
76 state = 'admin-down link-down'
78 raise ValueError('Unexpected interface state: {}'.format(state))
79 VatExecutor.cmd_from_template(node, 'set_if_state.vat',
80 sw_if_index=sw_if_index, state=state)
81 elif node['type'] == NodeType.TG or node['type'] == NodeType.VM:
82 cmd = 'ip link set {} {}'.format(iface_name, state)
83 exec_cmd_no_error(node, cmd, sudo=True)
85 raise ValueError('Node {} has unknown NodeType: "{}"'
86 .format(node['host'], node['type']))
89 def set_interface_ethernet_mtu(node, iface_key, mtu):
90 """Set Ethernet MTU for specified interface.
92 Function can be used only for TGs.
94 :param node: Node where the interface is.
95 :param iface_key: Interface key from topology file.
96 :param mtu: MTU to set.
101 :raises ValueError: If the node type is "DUT".
102 :raises ValueError: If the node has an unknown node type.
104 if node['type'] == NodeType.DUT:
105 raise ValueError('Node {}: Setting Ethernet MTU for interface '
106 'on DUT nodes not supported', node['host'])
107 elif node['type'] == NodeType.TG:
108 iface_name = Topology.get_interface_name(node, iface_key)
109 cmd = 'ip link set {} mtu {}'.format(iface_name, mtu)
110 exec_cmd_no_error(node, cmd, sudo=True)
112 raise ValueError('Node {} has unknown NodeType: "{}"'
113 .format(node['host'], node['type']))
116 def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
117 """Set default Ethernet MTU on all interfaces on node.
119 Function can be used only for TGs.
121 :param node: Node where to set default MTU.
125 for ifc in node['interfaces']:
126 InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500)
129 def vpp_set_interface_mtu(node, interface, mtu=9200):
130 """Set Ethernet MTU on interface.
132 :param node: VPP node.
133 :param interface: Interface to setup MTU. Default: 9200.
134 :param mtu: Ethernet MTU size in Bytes.
136 :type interface: str or int
139 if isinstance(interface, basestring):
140 sw_if_index = Topology.get_interface_sw_index(node, interface)
142 sw_if_index = interface
145 with VatTerminal(node, json_param=False) as vat:
146 vat.vat_terminal_exec_cmd_from_template(
147 "hw_interface_set_mtu.vat", sw_if_index=sw_if_index,
151 def vpp_set_interfaces_mtu_on_node(node, mtu=9200):
152 """Set Ethernet MTU on all interfaces.
154 :param node: VPP node.
155 :param mtu: Ethernet MTU size in Bytes. Default: 9200.
159 for interface in node['interfaces']:
160 InterfaceUtil.vpp_set_interface_mtu(node, interface, mtu)
163 def vpp_set_interfaces_mtu_on_all_duts(nodes, mtu=9200):
164 """Set Ethernet MTU on all interfaces on all DUTs.
166 :param nodes: VPP nodes.
167 :param mtu: Ethernet MTU size in Bytes. Default: 9200.
171 for node in nodes.values():
172 if node['type'] == NodeType.DUT:
173 InterfaceUtil.vpp_set_interfaces_mtu_on_node(node, mtu)
176 def vpp_node_interfaces_ready_wait(node, timeout=30):
177 """Wait until all interfaces with admin-up are in link-up state.
179 :param node: Node to wait on.
180 :param timeout: Waiting timeout in seconds (optional, default 10s).
184 :raises RuntimeError: If the timeout period value has elapsed.
190 out = InterfaceUtil.vpp_get_interface_data(node)
191 if time() - start > timeout:
192 for interface in out:
193 if interface.get('admin_up_down') == 1:
194 if interface.get('link_up_down') != 1:
195 logger.debug('{0} link-down'.format(
196 interface.get('interface_name')))
197 raise RuntimeError('timeout, not up {0}'.format(not_ready))
199 for interface in out:
200 if interface.get('admin_up_down') == 1:
201 if interface.get('link_up_down') != 1:
202 not_ready.append(interface.get('interface_name'))
206 logger.debug('Interfaces still in link-down state: {0}, '
207 'waiting...'.format(not_ready))
211 def vpp_nodes_interfaces_ready_wait(nodes, timeout=30):
212 """Wait until all interfaces with admin-up are in link-up state for
215 :param nodes: List of nodes to wait on.
216 :param timeout: Seconds to wait per node for all interfaces to come up.
222 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
225 def all_vpp_interfaces_ready_wait(nodes, timeout=30):
226 """Wait until all interfaces with admin-up are in link-up state for all
227 nodes in the topology.
229 :param nodes: Nodes in the topology.
230 :param timeout: Seconds to wait per node for all interfaces to come up.
235 for node in nodes.values():
236 if node['type'] == NodeType.DUT:
237 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
240 def vpp_get_interface_data(node, interface=None):
241 """Get all interface data from a VPP node. If a name or
242 sw_interface_index is provided, return only data for the matching
245 :param node: VPP node to get interface data from.
246 :param interface: Numeric index or name string of a specific interface.
248 :type interface: int or str
249 :returns: List of dictionaries containing data for each interface, or a
250 single dictionary for the specified interface.
252 :raises TypeError: if the data type of interface is neither basestring
255 with VatTerminal(node) as vat:
256 response = vat.vat_terminal_exec_cmd_from_template(
257 "interface_dump.vat")
261 if interface is not None:
262 if isinstance(interface, basestring):
263 param = "interface_name"
264 elif isinstance(interface, int):
265 param = "sw_if_index"
269 if data_if[param] == interface:
275 def vpp_get_interface_name(node, sw_if_index):
276 """Get interface name for the given SW interface index from actual
279 :param node: VPP node to get interface data from.
280 :param sw_if_index: SW interface index of the specific interface.
282 :type sw_if_index: int
283 :returns: Name of the given interface.
287 if_data = InterfaceUtil.vpp_get_interface_data(node, sw_if_index)
288 if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
289 if_data = InterfaceUtil.vpp_get_interface_data(
290 node, if_data['sup_sw_if_index'])
292 if_name = if_data["interface_name"]
298 def vpp_get_interface_mac(node, interface=None):
299 """Get MAC address for the given interface from actual interface dump.
301 :param node: VPP node to get interface data from.
302 :param interface: Numeric index or name string of a specific interface.
304 :type interface: int or str
305 :returns: MAC address.
309 if_data = InterfaceUtil.vpp_get_interface_data(node, interface)
310 if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
311 if_data = InterfaceUtil.vpp_get_interface_data(
312 node, if_data['sup_sw_if_index'])
313 mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]]
315 for item in mac_data:
318 mac_data_nice.append(item)
319 mac = ":".join(mac_data_nice)
323 def vpp_get_interface_ip_addresses(node, interface, ip_version):
324 """Get list of IP addresses from an interface on a VPP node.
326 :param node: VPP node to get data from.
327 :param interface: Name of an interface on the VPP node.
328 :param ip_version: IP protocol version (ipv4 or ipv6).
331 :type ip_version: str
332 :returns: List of dictionaries, each containing IP address, subnet
333 prefix length and also the subnet mask for ipv4 addresses.
334 Note: A single interface may have multiple IP addresses assigned.
339 sw_if_index = Topology.convert_interface_reference(
340 node, interface, "sw_if_index")
342 if isinstance(interface, basestring):
343 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
347 with VatTerminal(node) as vat:
348 response = vat.vat_terminal_exec_cmd_from_template(
349 "ip_address_dump.vat", ip_version=ip_version,
350 sw_if_index=sw_if_index)
354 if ip_version == "ipv4":
356 item["netmask"] = convert_ipv4_netmask_prefix(
357 item["prefix_length"])
361 def tg_set_interface_driver(node, pci_addr, driver):
362 """Set interface driver on the TG node.
364 :param node: Node to set interface driver on (must be TG node).
365 :param pci_addr: PCI address of the interface.
366 :param driver: Driver name.
370 :raises RuntimeError: If unbinding from the current driver fails.
371 :raises RuntimeError: If binding to the new driver fails.
373 old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
374 if old_driver == driver:
380 # Unbind from current driver
381 if old_driver is not None:
382 cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'\
383 .format(pci_addr, old_driver)
384 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
385 if int(ret_code) != 0:
386 raise RuntimeError("'{0}' failed on '{1}'"
387 .format(cmd, node['host']))
389 # Bind to the new driver
390 cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'\
391 .format(pci_addr, driver)
392 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
393 if int(ret_code) != 0:
394 raise RuntimeError("'{0}' failed on '{1}'"
395 .format(cmd, node['host']))
398 def tg_get_interface_driver(node, pci_addr):
399 """Get interface driver from the TG node.
401 :param node: Node to get interface driver on (must be TG node).
402 :param pci_addr: PCI address of the interface.
405 :returns: Interface driver or None if not found.
407 :raises RuntimeError: If PCI rescan or lspci command execution failed.
409 return DUTSetup.get_pci_dev_driver(node, pci_addr)
412 def tg_set_interfaces_udev_rules(node):
413 """Set udev rules for interfaces.
415 Create udev rules file in /etc/udev/rules.d where are rules for each
416 interface used by TG node, based on MAC interface has specific name.
417 So after unbind and bind again to kernel driver interface has same
418 name as before. This must be called after TG has set name for each
419 port in topology dictionary.
421 SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f",
424 :param node: Node to set udev rules on (must be TG node).
426 :raises RuntimeError: If setting of udev rules fails.
431 cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE)
432 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
433 if int(ret_code) != 0:
434 raise RuntimeError("'{0}' failed on '{1}'"
435 .format(cmd, node['host']))
437 for interface in node['interfaces'].values():
438 rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
439 '==\\"' + interface['mac_address'] + '\\", NAME=\\"' + \
440 interface['name'] + '\\"'
441 cmd = 'sh -c "echo \'{0}\' >> {1}"'.format(
442 rule, InterfaceUtil.__UDEV_IF_RULES_FILE)
443 (ret_code, _, _) = ssh.exec_command_sudo(cmd)
444 if int(ret_code) != 0:
445 raise RuntimeError("'{0}' failed on '{1}'"
446 .format(cmd, node['host']))
448 cmd = '/etc/init.d/udev restart'
449 ssh.exec_command_sudo(cmd)
452 def tg_set_interfaces_default_driver(node):
453 """Set interfaces default driver specified in topology yaml file.
455 :param node: Node to setup interfaces driver on (must be TG node).
458 for interface in node['interfaces'].values():
459 InterfaceUtil.tg_set_interface_driver(node,
460 interface['pci_address'],
464 def update_vpp_interface_data_on_node(node):
465 """Update vpp generated interface data for a given node in DICT__nodes.
467 Updates interface names, software if index numbers and any other details
468 generated specifically by vpp that are unknown before testcase run.
469 It does this by dumping interface list to JSON output from all
470 devices using vpp_api_test, and pairing known information from topology
471 (mac address/pci address of interface) to state from VPP.
473 :param node: Node selected from DICT__nodes.
476 vat_executor = VatExecutor()
477 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
478 interface_dump_json = vat_executor.get_script_stdout()
479 VatJsonUtil.update_vpp_interface_data_from_json(node,
483 def update_nic_interface_names(node):
484 """Update interface names based on nic type and PCI address.
486 This method updates interface names in the same format as VPP does.
488 :param node: Node dictionary.
491 for ifc in node['interfaces'].values():
492 if_pci = ifc['pci_address'].replace('.', ':').split(':')
493 bus = '{:x}'.format(int(if_pci[1], 16))
494 dev = '{:x}'.format(int(if_pci[2], 16))
495 fun = '{:x}'.format(int(if_pci[3], 16))
496 loc = '{bus}/{dev}/{fun}'.format(bus=bus, dev=dev, fun=fun)
497 if ifc['model'] == 'Intel-XL710':
498 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
499 elif ifc['model'] == 'Intel-X710':
500 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
501 elif ifc['model'] == 'Intel-X520-DA2':
502 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
503 elif ifc['model'] == 'Cisco-VIC-1385':
504 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
505 elif ifc['model'] == 'Cisco-VIC-1227':
506 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
508 ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc)
511 def update_nic_interface_names_on_all_duts(nodes):
512 """Update interface names based on nic type and PCI address on all DUTs.
514 This method updates interface names in the same format as VPP does.
516 :param nodes: Topology nodes.
519 for node in nodes.values():
520 if node['type'] == NodeType.DUT:
521 InterfaceUtil.update_nic_interface_names(node)
524 def update_tg_interface_data_on_node(node, skip_tg_udev=False):
525 """Update interface name for TG/linux node in DICT__nodes.
528 # for dev in `ls /sys/class/net/`;
529 > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done
530 "52:54:00:9f:82:63": "eth0"
531 "52:54:00:77:ae:a9": "eth1"
532 "52:54:00:e1:8a:0f": "eth2"
533 "00:00:00:00:00:00": "lo"
535 :param node: Node selected from DICT__nodes.
536 :param skip_tg_udev: Skip udev rename on TG node.
538 :type skip_tg_udev: bool
539 :raises RuntimeError: If getting of interface name and MAC fails.
541 # First setup interface driver specified in yaml file
542 InterfaceUtil.tg_set_interfaces_default_driver(node)
544 # Get interface names
548 cmd = ('for dev in `ls /sys/class/net/`; do echo "\\"`cat '
549 '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;')
551 (ret_code, stdout, _) = ssh.exec_command(cmd)
552 if int(ret_code) != 0:
553 raise RuntimeError('Get interface name and MAC failed')
554 tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
555 interfaces = JsonParser().parse_data(tmp)
556 for interface in node['interfaces'].values():
557 name = interfaces.get(interface['mac_address'])
560 interface['name'] = name
562 # Set udev rules for interfaces
564 InterfaceUtil.tg_set_interfaces_udev_rules(node)
567 def iface_update_numa_node(node):
568 """For all interfaces from topology file update numa node based on
569 information from the node.
571 :param node: Node from topology.
574 :raises ValueError: If numa node ia less than 0.
575 :raises RuntimeError: If update of numa node failes.
578 for if_key in Topology.get_node_interfaces(node):
579 if_pci = Topology.get_interface_pci_addr(node, if_key)
581 cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
583 (ret, out, _) = ssh.exec_command(cmd)
588 if CpuUtils.cpu_node_count(node) == 1:
593 logger.trace('Reading numa location failed for: {0}'
596 Topology.set_interface_numa_node(node, if_key,
600 raise RuntimeError('Update numa node failed for: {0}'
604 def update_all_numa_nodes(nodes, skip_tg=False):
605 """For all nodes and all their interfaces from topology file update numa
606 node information based on information from the node.
608 :param nodes: Nodes in the topology.
609 :param skip_tg: Skip TG node
614 for node in nodes.values():
615 if node['type'] == NodeType.DUT:
616 InterfaceUtil.iface_update_numa_node(node)
617 elif node['type'] == NodeType.TG and not skip_tg:
618 InterfaceUtil.iface_update_numa_node(node)
621 def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
624 """Update interface names on all nodes in DICT__nodes.
626 This method updates the topology dictionary by querying interface lists
627 of all nodes mentioned in the topology dictionary.
629 :param nodes: Nodes in the topology.
630 :param skip_tg: Skip TG node.
631 :param skip_tg_udev: Skip udev rename on TG node.
632 :param numa_node: Retrieve numa_node location.
635 :type skip_tg_udev: bool
636 :type numa_node: bool
638 for node_data in nodes.values():
639 if node_data['type'] == NodeType.DUT:
640 InterfaceUtil.update_vpp_interface_data_on_node(node_data)
641 elif node_data['type'] == NodeType.TG and not skip_tg:
642 InterfaceUtil.update_tg_interface_data_on_node(
643 node_data, skip_tg_udev)
646 if node_data['type'] == NodeType.DUT:
647 InterfaceUtil.iface_update_numa_node(node_data)
648 elif node_data['type'] == NodeType.TG and not skip_tg:
649 InterfaceUtil.iface_update_numa_node(node_data)
652 def create_vlan_subinterface(node, interface, vlan):
653 """Create VLAN subinterface on node.
655 :param node: Node to add VLAN subinterface on.
656 :param interface: Interface name on which create VLAN subinterface.
657 :param vlan: VLAN ID of the subinterface to be created.
661 :returns: Name and index of created subinterface.
663 :raises RuntimeError: if it is unable to create VLAN subinterface on the
666 iface_key = Topology.get_interface_by_name(node, interface)
667 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
669 output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
670 sw_if_index=sw_if_index,
672 if output[0]["retval"] == 0:
673 sw_vlan_idx = output[0]["sw_if_index"]
674 logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
675 'created on node {}'.format(sw_vlan_idx,
677 if_key = Topology.add_new_port(node, "vlan_subif")
678 Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
679 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
680 Topology.update_interface_name(node, if_key, ifc_name)
682 raise RuntimeError('Unable to create VLAN subinterface on node {}'
683 .format(node['host']))
685 with VatTerminal(node, False) as vat:
686 vat.vat_terminal_exec_cmd('exec show interfaces')
688 return '{}.{}'.format(interface, vlan), sw_vlan_idx
691 def create_vxlan_interface(node, vni, source_ip, destination_ip):
692 """Create VXLAN interface and return sw if index of created interface.
694 Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT
697 :param node: Node where to create VXLAN interface.
698 :param vni: VXLAN Network Identifier.
699 :param source_ip: Source IP of a VXLAN Tunnel End Point.
700 :param destination_ip: Destination IP of a VXLAN Tunnel End Point.
704 :type destination_ip: str
705 :returns: SW IF INDEX of created interface.
707 :raises RuntimeError: if it is unable to create VxLAN interface on the
710 output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
716 if output["retval"] == 0:
717 sw_if_idx = output["sw_if_index"]
718 if_key = Topology.add_new_port(node, "vxlan_tunnel")
719 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
720 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
721 Topology.update_interface_name(node, if_key, ifc_name)
724 raise RuntimeError("Unable to create VXLAN interface on node {0}"
728 def vxlan_dump(node, interface=None):
729 """Get VxLAN data for the given interface.
731 :param node: VPP node to get interface data from.
732 :param interface: Numeric index or name string of a specific interface.
733 If None, information about all VxLAN interfaces is returned.
735 :type interface: int or str
736 :returns: Dictionary containing data for the given VxLAN interface or if
737 interface=None, the list of dictionaries with all VxLAN interfaces.
739 :raises TypeError: if the data type of interface is neither basestring
742 param = "sw_if_index"
743 if interface is None:
746 elif isinstance(interface, basestring):
747 sw_if_index = Topology.get_interface_sw_index(node, interface)
748 elif isinstance(interface, int):
749 sw_if_index = interface
751 raise TypeError("Wrong interface format {0}".format(interface))
753 with VatTerminal(node) as vat:
754 response = vat.vat_terminal_exec_cmd_from_template(
755 "vxlan_dump.vat", param=param, sw_if_index=sw_if_index)
758 for vxlan in response[0]:
759 if vxlan["sw_if_index"] == sw_if_index:
765 def vhost_user_dump(node):
766 """Get vhost-user data for the given node.
768 :param node: VPP node to get interface data from.
770 :returns: List of dictionaries with all vhost-user interfaces.
773 with VatTerminal(node) as vat:
774 response = vat.vat_terminal_exec_cmd_from_template(
775 "vhost_user_dump.vat")
780 def tap_dump(node, name=None):
781 """Get all TAP interface data from the given node, or data about
782 a specific TAP interface.
784 :param node: VPP node to get data from.
785 :param name: Optional name of a specific TAP interface.
788 :returns: Dictionary of information about a specific TAP interface, or
789 a List of dictionaries containing all TAP data for the given node.
792 with VatTerminal(node) as vat:
793 response = vat.vat_terminal_exec_cmd_from_template(
797 for item in response[0]:
798 if name == item['dev_name']:
803 def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
804 inner_vlan_id=None, type_subif=None):
805 """Create sub-interface on node. It is possible to set required
806 sub-interface type and VLAN tag(s).
808 :param node: Node to add sub-interface.
809 :param interface: Interface name on which create sub-interface.
810 :param sub_id: ID of the sub-interface to be created.
811 :param outer_vlan_id: Optional outer VLAN ID.
812 :param inner_vlan_id: Optional inner VLAN ID.
813 :param type_subif: Optional type of sub-interface. Values supported by
814 VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match]
817 :type interface: str or int
819 :type outer_vlan_id: int
820 :type inner_vlan_id: int
821 :type type_subif: str
822 :returns: Name and index of created sub-interface.
824 :raises RuntimeError: If it is not possible to create sub-interface.
827 outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
828 if outer_vlan_id else ''
830 inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
831 if inner_vlan_id else ''
833 if type_subif is None:
836 if isinstance(interface, basestring):
837 iface_key = Topology.get_interface_by_name(node, interface)
838 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
840 sw_if_index = interface
842 output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
843 sw_if_index=sw_if_index,
845 outer_vlan_id=outer_vlan_id,
846 inner_vlan_id=inner_vlan_id,
847 type_subif=type_subif)
849 if output[0]["retval"] == 0:
850 sw_vlan_idx = output[0]["sw_if_index"]
851 logger.trace('Created subinterface with index {}'
852 .format(sw_vlan_idx))
853 if_key = Topology.add_new_port(node, "subinterface")
854 Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
855 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
856 Topology.update_interface_name(node, if_key, ifc_name)
858 raise RuntimeError('Unable to create sub-interface on node {}'
859 .format(node['host']))
861 with VatTerminal(node, json_param=False) as vat:
862 vat.vat_terminal_exec_cmd('exec show interfaces')
864 name = '{}.{}'.format(interface, sub_id)
865 return name, sw_vlan_idx
868 def create_gre_tunnel_interface(node, source_ip, destination_ip):
869 """Create GRE tunnel interface on node.
871 :param node: VPP node to add tunnel interface.
872 :param source_ip: Source of the GRE tunnel.
873 :param destination_ip: Destination of the GRE tunnel.
876 :type destination_ip: str
877 :returns: Name and index of created GRE tunnel interface.
879 :raises RuntimeError: If unable to create GRE tunnel interface.
881 output = VatExecutor.cmd_from_template(node, "create_gre.vat",
886 if output["retval"] == 0:
887 sw_if_idx = output["sw_if_index"]
889 vat_executor = VatExecutor()
890 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
891 interface_dump_json = vat_executor.get_script_stdout()
892 name = VatJsonUtil.get_interface_name_from_json(
893 interface_dump_json, sw_if_idx)
895 if_key = Topology.add_new_port(node, "gre_tunnel")
896 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
897 Topology.update_interface_name(node, if_key, name)
899 return name, sw_if_idx
901 raise RuntimeError('Unable to create GRE tunnel on node {}.'
905 def vpp_create_loopback(node):
906 """Create loopback interface on VPP node.
908 :param node: Node to create loopback interface on.
910 :returns: SW interface index.
912 :raises RuntimeError: If it is not possible to create loopback on the
915 out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
916 if out[0].get('retval') == 0:
917 sw_if_idx = out[0].get('sw_if_index')
918 if_key = Topology.add_new_port(node, "loopback")
919 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
920 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
921 Topology.update_interface_name(node, if_key, ifc_name)
924 raise RuntimeError('Create loopback failed on node "{}"'
925 .format(node['host']))
928 def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
929 """Create bond interface on VPP node.
931 :param node: DUT node from topology.
932 :param mode: Link bonding mode.
933 :param load_balance: Load balance (optional, valid for xor and lacp
934 modes, otherwise ignored).
935 :param mac: MAC address to assign to the bond interface (optional).
938 :type load_balance: str
940 :returns: Interface key (name) in topology.
942 :raises RuntimeError: If it is not possible to create bond interface on
945 hw_addr = '' if mac is None else 'hw-addr {mac}'.format(mac=mac)
946 ldb = '' if load_balance is None \
947 else 'lb {ldb}'.format(ldb=load_balance)
949 output = VatExecutor.cmd_from_template(
950 node, 'create_bond_interface.vat', mode=mode, lb=ldb, mac=hw_addr)
952 if output[0].get('retval') == 0:
953 sw_if_idx = output[0].get('sw_if_index')
954 InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
956 if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
959 raise RuntimeError('Create bond interface failed on "{host}"'.
960 format(host=node['host']))
963 def add_eth_interface(node, ifc_name=None, sw_if_idx=None, ifc_pfx=None):
964 """Add ethernet interface to current topology.
966 :param node: DUT node from topology.
967 :param ifc_name: Name of the interface.
968 :param sw_if_idx: SW interface index.
969 :param ifc_pfx: Interface key prefix.
975 if_key = Topology.add_new_port(node, ifc_pfx)
977 vat_executor = VatExecutor()
978 vat_executor.execute_script_json_out("dump_interfaces.vat", node)
979 interface_dump_json = vat_executor.get_script_stdout()
981 if ifc_name and sw_if_idx is None:
982 sw_if_idx = VatJsonUtil.get_interface_sw_index_from_json(
983 interface_dump_json, ifc_name)
984 Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
985 if sw_if_idx and ifc_name is None:
986 ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
987 Topology.update_interface_name(node, if_key, ifc_name)
988 ifc_mac = VatJsonUtil.get_interface_mac_from_json(
989 interface_dump_json, sw_if_idx)
990 Topology.update_interface_mac_address(node, if_key, ifc_mac)
993 def vpp_create_avf_interface(node, vf_pci_addr, num_rx_queues=None):
994 """Create AVF interface on VPP node.
996 :param node: DUT node from topology.
997 :param vf_pci_addr: Virtual Function PCI address.
998 :param num_rx_queues: Number of RX queues.
1000 :type vf_pci_addr: str
1001 :type num_rx_queues: int
1002 :returns: Interface key (name) in topology.
1004 :raises RuntimeError: If it is not possible to create AVF interface on
1007 num_rx_queues = 'num-rx-queues {num_rx_queues}'\
1008 .format(num_rx_queues=num_rx_queues) if num_rx_queues else ''
1010 with VatTerminal(node, json_param=False) as vat:
1011 vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat',
1012 vf_pci_addr=vf_pci_addr,
1013 num_rx_queues=num_rx_queues)
1014 output = vat.vat_stdout
1016 if output is not None:
1017 sw_if_idx = int(output.split()[4])
1018 InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
1020 if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
1023 raise RuntimeError('Create AVF interface failed on {host}'.
1024 format(host=node['host']))
1027 def vpp_enslave_physical_interface(node, interface, bond_interface):
1028 """Enslave physical interface to bond interface on VPP node.
1030 :param node: DUT node from topology.
1031 :param interface: Physical interface key from topology file.
1032 :param bond_interface: Load balance
1034 :type interface: str
1035 :type bond_interface: str
1036 :raises RuntimeError: If it is not possible to enslave physical
1037 interface to bond interface on the node.
1039 ifc = Topology.get_interface_sw_index(node, interface)
1040 bond_ifc = Topology.get_interface_sw_index(node, bond_interface)
1042 output = VatExecutor.cmd_from_template(
1043 node, 'enslave_physical_interface.vat', p_int=ifc, b_int=bond_ifc)
1045 retval = output[0].get('retval', None)
1046 if retval is None or int(retval) != 0:
1047 raise RuntimeError('Enslave physical interface {ifc} to bond '
1048 'interface {bond} failed on node "{n}"'
1049 .format(ifc=interface, bond=bond_interface,
1053 def vpp_show_bond_data_on_node(node, details=False):
1054 """Show (detailed) bond information on VPP node.
1056 :param node: DUT node from topology.
1057 :param details: If detailed information is required or not.
1061 cmd = 'exec show bond details' if details else 'exec show bond'
1062 with VatTerminal(node, json_param=False) as vat:
1063 vat.vat_terminal_exec_cmd(cmd)
1066 def vpp_show_bond_data_on_all_nodes(nodes, details=False):
1067 """Show (detailed) bond information on all VPP nodes in DICT__nodes.
1069 :param nodes: Nodes in the topology.
1070 :param details: If detailed information is required or not.
1074 for node_data in nodes.values():
1075 if node_data['type'] == NodeType.DUT:
1076 InterfaceUtil.vpp_show_bond_data_on_node(node_data, details)
1079 def vpp_enable_input_acl_interface(node, interface, ip_version,
1081 """Enable input acl on interface.
1083 :param node: VPP node to setup interface for input acl.
1084 :param interface: Interface to setup input acl.
1085 :param ip_version: Version of IP protocol.
1086 :param table_index: Classify table index.
1088 :type interface: str or int
1089 :type ip_version: str
1090 :type table_index: int
1092 if isinstance(interface, basestring):
1093 sw_if_index = Topology.get_interface_sw_index(node, interface)
1095 sw_if_index = interface
1097 with VatTerminal(node) as vat:
1098 vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
1099 sw_if_index=sw_if_index,
1100 ip_version=ip_version,
1101 table_index=table_index)
1104 def get_interface_classify_table(node, interface):
1105 """Get name of classify table for the given interface.
1107 :param node: VPP node to get data from.
1108 :param interface: Name or sw_if_index of a specific interface.
1110 :type interface: str or int
1111 :returns: Classify table name.
1114 if isinstance(interface, basestring):
1115 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1117 sw_if_index = interface
1119 with VatTerminal(node) as vat:
1120 data = vat.vat_terminal_exec_cmd_from_template(
1121 "classify_interface_table.vat",
1122 sw_if_index=sw_if_index)
1126 def get_interface_vrf_table(node, interface):
1127 """Get vrf ID for the given interface.
1129 :param node: VPP node.
1130 :param interface: Name or sw_if_index of a specific interface.
1132 :type interface: str or int
1133 :returns: vrf ID of the specified interface.
1137 if isinstance(interface, basestring):
1138 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1140 sw_if_index = interface
1142 with VatTerminal(node) as vat:
1143 data = vat.vat_terminal_exec_cmd_from_template(
1144 "interface_vrf_dump.vat",
1145 sw_if_index=sw_if_index)
1146 return data[0]["vrf_id"]
1149 def get_sw_if_index(node, interface_name):
1150 """Get sw_if_index for the given interface from actual interface dump.
1152 :param node: VPP node to get interface data from.
1153 :param interface_name: Name of the specific interface.
1155 :type interface_name: str
1156 :returns: sw_if_index of the given interface.
1160 with VatTerminal(node) as vat:
1161 if_data = vat.vat_terminal_exec_cmd_from_template(
1162 "interface_dump.vat")
1163 for interface in if_data[0]:
1164 if interface["interface_name"] == interface_name:
1165 return interface["sw_if_index"]
1170 def vxlan_gpe_dump(node, interface_name=None):
1171 """Get VxLAN GPE data for the given interface.
1173 :param node: VPP node to get interface data from.
1174 :param interface_name: Name of the specific interface. If None,
1175 information about all VxLAN GPE interfaces is returned.
1177 :type interface_name: str
1178 :returns: Dictionary containing data for the given VxLAN GPE interface
1179 or if interface=None, the list of dictionaries with all VxLAN GPE
1181 :rtype: dict or list
1184 with VatTerminal(node) as vat:
1185 vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
1186 "vxlan_gpe_dump.vat")
1189 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
1191 for vxlan_gpe in vxlan_gpe_data[0]:
1192 if vxlan_gpe["sw_if_index"] == sw_if_index:
1196 return vxlan_gpe_data[0]
1199 def vpp_proxy_arp_interface_enable(node, interface):
1200 """Enable proxy ARP on interface.
1202 :param node: VPP node to enable proxy ARP on interface.
1203 :param interface: Interface to enable proxy ARP.
1205 :type interface: str or int
1207 if isinstance(interface, basestring):
1208 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1210 sw_if_index = interface
1212 with VatTerminal(node) as vat:
1213 vat.vat_terminal_exec_cmd_from_template(
1214 "proxy_arp_intfc_enable.vat",
1215 sw_if_index=sw_if_index)
1218 def vpp_ip_source_check_setup(node, interface):
1219 """Setup Reverse Path Forwarding source check on interface.
1221 :param node: Node to setup RPF source check.
1222 :param interface: Interface name to setup RPF source check.
1224 :type interface: str
1226 with VatTerminal(node) as vat:
1227 vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
1228 interface_name=interface)
1231 def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
1232 """Assign VPP interface to specific VRF/FIB table.
1234 :param node: VPP node where the FIB and interface are located.
1235 :param interface: Interface to be assigned to FIB.
1236 :param table_id: VRF table ID.
1237 :param ipv6: Assign to IPv6 table. Default False.
1239 :type interface: str or int
1243 if isinstance(interface, basestring):
1244 sw_if_index = Topology.get_interface_sw_index(node, interface)
1246 sw_if_index = interface
1248 ipv6 = 'ipv6' if ipv6 else ''
1250 with VatTerminal(node) as vat:
1251 ret = vat.vat_terminal_exec_cmd_from_template(
1252 "set_fib_to_interface.vat",
1253 sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
1255 if ret[0]["retval"] != 0:
1256 raise RuntimeError('Unable to assign interface to FIB node {}.'
1260 def set_linux_interface_mac(node, interface, mac, namespace=None,
1262 """Set MAC address for interface in linux.
1264 :param node: Node where to execute command.
1265 :param interface: Interface in namespace.
1266 :param mac: MAC to be assigned to interface.
1267 :param namespace: Execute command in namespace. Optional
1268 :param vf_id: Virtual Function id. Optional
1270 :type interface: str
1272 :type namespace: str
1275 mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \
1276 if vf_id is not None else 'address {mac}'.format(mac=mac)
1277 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1279 cmd = ('{ns} ip link set {interface} {mac}'.
1280 format(ns=ns_str, interface=interface, mac=mac_str))
1281 exec_cmd_no_error(node, cmd, sudo=True)
1284 def set_linux_interface_trust_on(node, interface, namespace=None,
1286 """Set trust on (promisc) for interface in linux.
1288 :param node: Node where to execute command.
1289 :param interface: Interface in namespace.
1290 :param namespace: Execute command in namespace. Optional
1291 :param vf_id: Virtual Function id. Optional
1293 :type interface: str
1294 :type namespace: str
1297 trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \
1298 if vf_id is not None else 'trust on'
1299 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1301 cmd = ('{ns} ip link set dev {interface} {trust}'.
1302 format(ns=ns_str, interface=interface, trust=trust_str))
1303 exec_cmd_no_error(node, cmd, sudo=True)
1306 def set_linux_interface_spoof_off(node, interface, namespace=None,
1308 """Set spoof off for interface in linux.
1310 :param node: Node where to execute command.
1311 :param interface: Interface in namespace.
1312 :param namespace: Execute command in namespace. Optional
1313 :param vf_id: Virtual Function id. Optional
1315 :type interface: str
1316 :type namespace: str
1319 spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \
1320 if vf_id is not None else 'spoof off'
1321 ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1323 cmd = ('{ns} ip link set dev {interface} {spoof}'.
1324 format(ns=ns_str, interface=interface, spoof=spoof_str))
1325 exec_cmd_no_error(node, cmd, sudo=True)
1328 def init_avf_interface(node, ifc_key, numvfs=1, traffic_type='L2'):
1329 """Init PCI device by creating VFs and bind them to vfio-pci for AVF
1330 driver testing on DUT.
1332 :param node: DUT node.
1333 :param ifc_key: Interface key from topology file.
1334 :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
1335 :param traffic_type: Expected type of traffic, affects spoofing.
1336 Default value "L2" sets linux interface spoof off.
1337 Other values do not do that.
1341 :type traffic_type: str
1342 :returns: Virtual Function topology interface keys.
1348 # Read PCI address and driver.
1349 pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key)
1350 pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":")
1351 uio_driver = Topology.get_uio_driver(node)
1352 kernel_driver = Topology.get_interface_driver(node, ifc_key)
1353 current_driver = DUTSetup.get_pci_dev_driver(
1354 node, pf_pci_addr.replace(':', r'\:'))
1356 VPPUtil.stop_vpp_service(node)
1357 if current_driver != kernel_driver:
1358 # PCI device must be re-bound to kernel driver before creating VFs.
1359 DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True)
1360 # Stop VPP to prevent deadlock.
1361 # Unbind from current driver.
1362 DUTSetup.pci_driver_unbind(node, pf_pci_addr)
1363 # Bind to kernel driver.
1364 DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver)
1366 # Initialize PCI VFs
1367 DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs)
1370 # Set MAC address and bind each virtual function to uio driver.
1371 for vf_id in range(numvfs):
1372 vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2],
1373 pf_mac_addr[3], pf_mac_addr[4],
1374 pf_mac_addr[5], "{:02x}".format(vf_id)])
1376 pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\
1377 format(pci=pf_pci_addr)
1378 InterfaceUtil.set_linux_interface_trust_on(node, pf_dev,
1380 if traffic_type == 'L2':
1381 InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev,
1383 InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr,
1386 DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id)
1387 DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver)
1389 # Add newly created ports into topology file
1390 vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key)
1391 vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
1392 vf_ifc_key = Topology.add_new_port(node, vf_ifc_name)
1393 Topology.update_interface_name(node, vf_ifc_key,
1394 vf_ifc_name+str(vf_id+1))
1395 Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr)
1396 Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr)
1397 vf_ifc_keys.append(vf_ifc_key)
1402 def vpp_create_multiple_vxlan_ipv4_tunnels(
1403 node, node_vxlan_if, node_vlan_if, op_node, op_node_if,
1404 n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, ip_limit,
1406 """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on
1409 Put each pair of VXLAN tunnel interface and VLAN sub-interface to
1410 separate bridge-domain.
1412 :param node: VPP node to create VXLAN tunnel interfaces.
1413 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1415 :param node_vlan_if: VPP node interface key to create VLAN
1417 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1418 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1420 :param n_tunnels: Number of tunnel interfaces to create.
1421 :param vni_start: VNI start ID.
1422 :param src_ip_start: VXLAN tunnel source IP address start.
1423 :param dst_ip_start: VXLAN tunnel destination IP address start.
1424 :param ip_step: IP address incremental step.
1425 :param ip_limit: IP address limit.
1426 :param bd_id_start: Bridge-domain ID start.
1428 :type node_vxlan_if: str
1429 :type node_vlan_if: str
1431 :type op_node_if: str
1432 :type n_tunnels: int
1433 :type vni_start: int
1434 :type src_ip_start: str
1435 :type dst_ip_start: str
1438 :type bd_id_start: int
1440 # configure IPs, create VXLAN interfaces and VLAN sub-interfaces
1441 vxlan_count = InterfaceUtil.vpp_create_vxlan_and_vlan_interfaces(
1442 node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start,
1443 src_ip_start, dst_ip_start, ip_step, ip_limit)
1445 # update topology with VXLAN interfaces and VLAN sub-interfaces data
1446 # and put interfaces up
1447 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_up(
1448 node, vxlan_count, node_vlan_if)
1450 # configure bridge domains, ARPs and routes
1451 InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1452 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1453 ip_step, bd_id_start)
1456 def vpp_create_vxlan_and_vlan_interfaces(
1457 node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start,
1458 src_ip_start, dst_ip_start, ip_step, ip_limit):
1460 Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP
1463 :param node: VPP node.
1464 :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1466 :param node_vlan_if: VPP node interface key to create VLAN
1468 :param vxlan_count: Number of tunnel interfaces to create.
1469 :param vni_start: VNI start ID.
1470 :param src_ip_start: VXLAN tunnel source IP address start.
1471 :param dst_ip_start: VXLAN tunnel destination IP address start.
1472 :param ip_step: IP address incremental step.
1473 :param ip_limit: IP address limit.
1475 :type node_vxlan_if: str
1476 :type node_vlan_if: str
1477 :type vxlan_count: int
1478 :type vni_start: int
1479 :type src_ip_start: str
1480 :type dst_ip_start: str
1483 :returns: Number of created VXLAN interfaces.
1488 src_ip_start_int = IPUtil.ip_to_int(src_ip_start)
1489 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1490 ip_limit_int = IPUtil.ip_to_int(ip_limit)
1492 tmp_fn = '/tmp/create_vxlan_interfaces.config'
1493 for i in range(0, vxlan_count):
1494 src_ip_int = src_ip_start_int + i * ip_step
1495 dst_ip_int = dst_ip_start_int + i * ip_step
1496 if src_ip_int > ip_limit_int or dst_ip_int > ip_limit_int:
1497 logger.warn("Can't do more iterations - IPv4 address limit "
1498 "has been reached.")
1501 src_ip = IPUtil.int_to_ip(src_ip_int)
1502 dst_ip = IPUtil.int_to_ip(dst_ip_int)
1504 'sw_interface_add_del_address sw_if_index {sw_idx} {ip}/32\n'
1505 .format(sw_idx=Topology.get_interface_sw_index(
1506 node, node_vxlan_if), ip=src_ip))
1508 'vxlan_add_del_tunnel src {src_ip} dst {dst_ip} vni {vni}\n'
1509 .format(src_ip=src_ip, dst_ip=dst_ip, vni=vni_start+i))
1511 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n'
1512 .format(sw_idx=Topology.get_interface_sw_index(
1513 node, node_vlan_if), vlan=i+1))
1515 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1520 def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
1522 Update topology with VXLAN interfaces and VLAN sub-interfaces data
1523 and put interfaces up.
1525 :param node: VPP node.
1526 :param vxlan_count: Number of tunnel interfaces.
1527 :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
1530 :type vxlan_count: int
1531 :type node_vlan_if: str
1533 with VatTerminal(node) as vat_ter:
1534 if_data = vat_ter.vat_terminal_exec_cmd_from_template(
1535 'interface_dump.vat')[0]
1537 tmp_fn = '/tmp/put_subinterfaces_up.config'
1539 for i in range(0, vxlan_count):
1540 vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
1541 vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
1543 vxlan_subif_idx = None
1544 vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
1545 vlan_subif_name = '{if_name}.{vlan}'.format(
1546 if_name=Topology.get_interface_name(
1547 node, node_vlan_if), vlan=i+1)
1550 for data in if_data:
1551 if_name = data['interface_name']
1552 if not vxlan_found and if_name == vxlan_subif_name:
1553 vxlan_subif_idx = data['sw_if_index']
1555 elif not vlan_found and if_name == vlan_subif_name:
1556 vlan_idx = data['sw_if_index']
1558 if vxlan_found and vlan_found:
1560 Topology.update_interface_sw_if_index(
1561 node, vxlan_subif_key, vxlan_subif_idx)
1562 Topology.update_interface_name(
1563 node, vxlan_subif_key, vxlan_subif_name)
1565 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1566 .format(sw_idx=vxlan_subif_idx))
1567 Topology.update_interface_sw_if_index(
1568 node, vlan_subif_key, vlan_idx)
1569 Topology.update_interface_name(
1570 node, vlan_subif_key, vlan_subif_name)
1572 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1573 .format(sw_idx=vlan_idx))
1575 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1578 def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1579 node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1580 ip_step, bd_id_start):
1582 Configure ARPs and routes for VXLAN interfaces and put each pair of
1583 VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
1585 :param node: VPP node.
1586 :param node_vxlan_if: VPP node interface key where VXLAN tunnel
1587 interfaces have been created.
1588 :param vxlan_count: Number of tunnel interfaces.
1589 :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1590 :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1592 :param dst_ip_start: VXLAN tunnel destination IP address start.
1593 :param ip_step: IP address incremental step.
1594 :param bd_id_start: Bridge-domain ID start.
1596 :type node_vxlan_if: str
1597 :type vxlan_count: int
1600 :type dst_ip_start: str
1602 :type bd_id_start: int
1604 sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
1606 dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1608 tmp_fn = '/tmp/configure_routes_and_bridge_domains.config'
1610 for i in range(0, vxlan_count):
1611 dst_ip = IPUtil.int_to_ip(dst_ip_start_int + i * ip_step)
1613 'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} mac {mac}\n'
1614 .format(sw_idx=sw_idx_vxlan, ip=dst_ip,
1615 mac=Topology.get_interface_mac(op_node, op_node_if)))
1617 'ip_add_del_route {ip}/32 via {ip} sw_if_index {sw_idx}'
1618 ' resolve-attempts 10 count 1\n'.format(
1619 ip=dst_ip, sw_idx=sw_idx_vxlan))
1620 bd_id = bd_id_start + i
1623 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1624 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1625 node, 'vxlan_tunnel{nr}'.format(nr=subif_id)), bd_id=bd_id))
1627 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1628 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1629 node, 'vlan_subif{nr}'.format(nr=subif_id)), bd_id=bd_id))
1631 VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1634 def vpp_sw_interface_rx_placement_dump(node):
1635 """Dump VPP interface RX placement on node.
1637 :param node: Node to run command on.
1639 :returns: Thread mapping information as a list of dictionaries.
1643 cmd = 'sw_interface_rx_placement_dump'
1644 cmd_reply = 'sw_interface_rx_placement_details'
1645 err_msg = "Failed to run '{cmd}' PAPI command on host {host}!".format(
1646 cmd=cmd, host=node['host'])
1647 with PapiExecutor(node) as papi_exec:
1648 for ifc in node['interfaces'].values():
1649 if ifc['vpp_sw_index'] is not None:
1650 papi_exec.add(cmd, sw_if_index=ifc['vpp_sw_index'])
1651 papi_resp = papi_exec.get_dump(err_msg)
1652 thr_mapping = [s[cmd_reply] for r in papi_resp.reply
1653 for s in r['api_reply']]
1654 return sorted(thr_mapping, key=lambda k: k['sw_if_index'])
1657 def vpp_sw_interface_set_rx_placement(node, sw_if_index, queue_id,
1659 """Set interface RX placement to worker on node.
1661 :param node: Node to run command on.
1662 :param sw_if_index: VPP SW interface index.
1663 :param queue_id: VPP interface queue ID.
1664 :param worker_id: VPP worker ID (indexing from 0).
1666 :type sw_if_index: int
1668 :type worker_id: int
1669 :raises RuntimeError: If failed to run command on host or if no API
1673 cmd = 'sw_interface_set_rx_placement'
1674 cmd_reply = 'sw_interface_set_rx_placement_reply'
1675 err_msg = "Failed to run '{cmd}' PAPI command on host {host}!".format(
1676 host=node['host'], cmd=cmd)
1677 args = dict(sw_if_index=sw_if_index, queue_id=queue_id,
1678 worker_id=worker_id)
1679 with PapiExecutor(node) as papi_exec:
1680 papi_resp = papi_exec.add(cmd, **args).execute_should_pass(err_msg)
1681 data = papi_resp.reply[0]['api_reply'][cmd_reply]
1682 if data['retval'] != 0:
1683 raise RuntimeError("Failed to set interface RX placement "
1684 "to worker on host {host}".
1685 format(host=node['host']))
1688 def vpp_round_robin_rx_placement(node, prefix):
1689 """Set Round Robin interface RX placement on all worker threads
1692 :param node: Topology nodes.
1693 :param prefix: Interface name prefix.
1698 worker_cnt = len(VPPUtil.vpp_show_threads(node)) - 1
1699 for placement in InterfaceUtil.vpp_sw_interface_rx_placement_dump(node):
1700 for interface in node['interfaces'].values():
1701 if placement['sw_if_index'] == interface['vpp_sw_index'] \
1702 and prefix in interface['name']:
1703 InterfaceUtil.vpp_sw_interface_set_rx_placement(
1704 node, placement['sw_if_index'], placement['queue_id'],
1705 worker_id % worker_cnt)
1709 def vpp_round_robin_rx_placement_on_all_duts(nodes, prefix):
1710 """Set Round Robin interface RX placement on all worker threads
1713 :param nodes: Topology nodes.
1714 :param prefix: Interface name prefix.
1718 for node in nodes.values():
1719 if node['type'] == NodeType.DUT:
1720 InterfaceUtil.vpp_round_robin_rx_placement(node, prefix)