8e1892392dcc200d907d091055c73ec2a3c3851a
[csit.git] / resources / libraries / python / InterfaceUtil.py
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:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
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.
13
14 """Interface util library."""
15
16 from time import time, sleep
17
18 from robot.api import logger
19
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
32
33
34 class InterfaceUtil(object):
35     """General utilities for managing interfaces"""
36
37     __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
38
39     @staticmethod
40     def set_interface_state(node, interface, state, if_type="key"):
41         """Set interface state on a node.
42
43         Function can be used for DUTs as well as for TGs.
44
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
49         :type node: dict
50         :type interface: str or int
51         :type state: str
52         :type if_type: str
53         :returns: Nothing.
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.
57         """
58
59         if if_type == "key":
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)
63             else:
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
70         else:
71             raise ValueError("if_type unknown: {}".format(if_type))
72
73         if node['type'] == NodeType.DUT:
74             if state == 'up':
75                 state = 'admin-up link-up'
76             elif state == 'down':
77                 state = 'admin-down link-down'
78             else:
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)
85         else:
86             raise ValueError('Node {} has unknown NodeType: "{}"'
87                              .format(node['host'], node['type']))
88
89     @staticmethod
90     def set_interface_ethernet_mtu(node, iface_key, mtu):
91         """Set Ethernet MTU for specified interface.
92
93         Function can be used only for TGs.
94
95         :param node: Node where the interface is.
96         :param iface_key: Interface key from topology file.
97         :param mtu: MTU to set.
98         :type node: dict
99         :type iface_key: str
100         :type mtu: int
101         :returns: Nothing.
102         :raises ValueError: If the node type is "DUT".
103         :raises ValueError: If the node has an unknown node type.
104         """
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)
112         else:
113             raise ValueError('Node {} has unknown NodeType: "{}"'
114                              .format(node['host'], node['type']))
115
116     @staticmethod
117     def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
118         """Set default Ethernet MTU on all interfaces on node.
119
120         Function can be used only for TGs.
121
122         :param node: Node where to set default MTU.
123         :type node: dict
124         :returns: Nothing.
125         """
126         for ifc in node['interfaces']:
127             InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500)
128
129     @staticmethod
130     def vpp_set_interface_mtu(node, interface, mtu=9200):
131         """Set Ethernet MTU on interface.
132
133         :param node: VPP node.
134         :param interface: Interface to setup MTU. Default: 9200.
135         :param mtu: Ethernet MTU size in Bytes.
136         :type node: dict
137         :type interface: str or int
138         :type mtu: int
139         """
140         if isinstance(interface, basestring):
141             sw_if_index = Topology.get_interface_sw_index(node, interface)
142         else:
143             sw_if_index = interface
144
145         if sw_if_index:
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,
149                     mtu=mtu)
150
151     @staticmethod
152     def vpp_set_interfaces_mtu_on_node(node, mtu=9200):
153         """Set Ethernet MTU on all interfaces.
154
155         :param node: VPP node.
156         :param mtu: Ethernet MTU size in Bytes. Default: 9200.
157         :type node: dict
158         :type mtu: int
159         """
160         for interface in node['interfaces']:
161             InterfaceUtil.vpp_set_interface_mtu(node, interface, mtu)
162
163     @staticmethod
164     def vpp_set_interfaces_mtu_on_all_duts(nodes, mtu=9200):
165         """Set Ethernet MTU on all interfaces on all DUTs.
166
167         :param nodes: VPP nodes.
168         :param mtu: Ethernet MTU size in Bytes. Default: 9200.
169         :type nodes: dict
170         :type mtu: int
171         """
172         for node in nodes.values():
173             if node['type'] == NodeType.DUT:
174                 InterfaceUtil.vpp_set_interfaces_mtu_on_node(node, mtu)
175
176     @staticmethod
177     def vpp_node_interfaces_ready_wait(node, timeout=30):
178         """Wait until all interfaces with admin-up are in link-up state.
179
180         :param node: Node to wait on.
181         :param timeout: Waiting timeout in seconds (optional, default 10s).
182         :type node: dict
183         :type timeout: int
184         :returns: Nothing.
185         :raises RuntimeError: If the timeout period value has elapsed.
186         """
187         if_ready = False
188         not_ready = []
189         start = time()
190         while not if_ready:
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))
199             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'))
204             if not not_ready:
205                 if_ready = True
206             else:
207                 logger.debug('Interfaces still in link-down state: {0}, '
208                              'waiting...'.format(not_ready))
209                 sleep(1)
210
211     @staticmethod
212     def vpp_nodes_interfaces_ready_wait(nodes, timeout=30):
213         """Wait until all interfaces with admin-up are in link-up state for
214         listed nodes.
215
216         :param nodes: List of nodes to wait on.
217         :param timeout: Seconds to wait per node for all interfaces to come up.
218         :type nodes: list
219         :type timeout: int
220         :returns: Nothing.
221         """
222         for node in nodes:
223             InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
224
225     @staticmethod
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.
229
230         :param nodes: Nodes in the topology.
231         :param timeout: Seconds to wait per node for all interfaces to come up.
232         :type nodes: dict
233         :type timeout: int
234         :returns: Nothing.
235         """
236         for node in nodes.values():
237             if node['type'] == NodeType.DUT:
238                 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
239
240     @staticmethod
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
244         interface.
245
246         :param node: VPP node to get interface data from.
247         :param interface: Numeric index or name string of a specific interface.
248         :type node: dict
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.
252         :rtype: list or dict
253         :raises TypeError: if the data type of interface is neither basestring
254             nor int.
255         """
256         with VatTerminal(node) as vat:
257             response = vat.vat_terminal_exec_cmd_from_template(
258                 "interface_dump.vat")
259
260         data = response[0]
261
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"
267             else:
268                 raise TypeError
269             for data_if in data:
270                 if data_if[param] == interface:
271                     return data_if
272             return dict()
273         return data
274
275     @staticmethod
276     def vpp_get_interface_name(node, sw_if_index):
277         """Get interface name for the given SW interface index from actual
278         interface dump.
279
280         :param node: VPP node to get interface data from.
281         :param sw_if_index: SW interface index of the specific interface.
282         :type node: dict
283         :type sw_if_index: int
284         :returns: Name of the given interface.
285         :rtype: str
286         """
287
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'])
292         try:
293             if_name = if_data["interface_name"]
294         except KeyError:
295             if_name = None
296         return if_name
297
298     @staticmethod
299     def vpp_get_interface_mac(node, interface=None):
300         """Get MAC address for the given interface from actual interface dump.
301
302         :param node: VPP node to get interface data from.
303         :param interface: Numeric index or name string of a specific interface.
304         :type node: dict
305         :type interface: int or str
306         :returns: MAC address.
307         :rtype: str
308         """
309
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]]
315         mac_data_nice = []
316         for item in mac_data:
317             if len(item) == 1:
318                 item = '0' + item
319             mac_data_nice.append(item)
320         mac = ":".join(mac_data_nice)
321         return mac
322
323     @staticmethod
324     def vpp_get_interface_ip_addresses(node, interface, ip_version):
325         """Get list of IP addresses from an interface on a VPP node.
326
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).
330          :type node: dict
331          :type interface: str
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.
336          :rtype: list
337         """
338
339         try:
340             sw_if_index = Topology.convert_interface_reference(
341                 node, interface, "sw_if_index")
342         except RuntimeError:
343             if isinstance(interface, basestring):
344                 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
345             else:
346                 raise
347
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)
352
353         data = response[0]
354
355         if ip_version == "ipv4":
356             for item in data:
357                 item["netmask"] = convert_ipv4_netmask_prefix(
358                     item["prefix_length"])
359         return data
360
361     @staticmethod
362     def tg_set_interface_driver(node, pci_addr, driver):
363         """Set interface driver on the TG node.
364
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.
368         :type node: dict
369         :type pci_addr: str
370         :type driver: str
371         :raises RuntimeError: If unbinding from the current driver fails.
372         :raises RuntimeError: If binding to the new driver fails.
373         """
374         old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
375         if old_driver == driver:
376             return
377
378         ssh = SSH()
379         ssh.connect(node)
380
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']))
389
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']))
397
398     @staticmethod
399     def tg_get_interface_driver(node, pci_addr):
400         """Get interface driver from the TG node.
401
402         :param node: Node to get interface driver on (must be TG node).
403         :param pci_addr: PCI address of the interface.
404         :type node: dict
405         :type pci_addr: str
406         :returns: Interface driver or None if not found.
407         :rtype: str
408         :raises RuntimeError: If PCI rescan or lspci command execution failed.
409         """
410         return DUTSetup.get_pci_dev_driver(node, pci_addr)
411
412     @staticmethod
413     def tg_set_interfaces_udev_rules(node):
414         """Set udev rules for interfaces.
415
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.
421         udev rule example
422         SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f",
423         NAME="eth1"
424
425         :param node: Node to set udev rules on (must be TG node).
426         :type node: dict
427         :raises RuntimeError: If setting of udev rules fails.
428         """
429         ssh = SSH()
430         ssh.connect(node)
431
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']))
437
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']))
448
449         cmd = '/etc/init.d/udev restart'
450         ssh.exec_command_sudo(cmd)
451
452     @staticmethod
453     def tg_set_interfaces_default_driver(node):
454         """Set interfaces default driver specified in topology yaml file.
455
456         :param node: Node to setup interfaces driver on (must be TG node).
457         :type node: dict
458         """
459         for interface in node['interfaces'].values():
460             InterfaceUtil.tg_set_interface_driver(node,
461                                                   interface['pci_address'],
462                                                   interface['driver'])
463
464     @staticmethod
465     def update_vpp_interface_data_on_node(node):
466         """Update vpp generated interface data for a given node in DICT__nodes.
467
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.
473
474         :param node: Node selected from DICT__nodes.
475         :type node: dict
476         """
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,
481                                                         interface_dump_json)
482
483     @staticmethod
484     def update_nic_interface_names(node):
485         """Update interface names based on nic type and PCI address.
486
487         This method updates interface names in the same format as VPP does.
488
489         :param node: Node dictionary.
490         :type node: dict
491         """
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)
508             else:
509                 ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc)
510
511     @staticmethod
512     def update_nic_interface_names_on_all_duts(nodes):
513         """Update interface names based on nic type and PCI address on all DUTs.
514
515         This method updates interface names in the same format as VPP does.
516
517         :param nodes: Topology nodes.
518         :type nodes: dict
519         """
520         for node in nodes.values():
521             if node['type'] == NodeType.DUT:
522                 InterfaceUtil.update_nic_interface_names(node)
523
524     @staticmethod
525     def update_tg_interface_data_on_node(node, skip_tg_udev=False):
526         """Update interface name for TG/linux node in DICT__nodes.
527
528         .. note::
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"
535
536         :param node: Node selected from DICT__nodes.
537         :param skip_tg_udev: Skip udev rename on TG node.
538         :type node: dict
539         :type skip_tg_udev: bool
540         :raises RuntimeError: If getting of interface name and MAC fails.
541         """
542         # First setup interface driver specified in yaml file
543         InterfaceUtil.tg_set_interfaces_default_driver(node)
544
545         # Get interface names
546         ssh = SSH()
547         ssh.connect(node)
548
549         cmd = ('for dev in `ls /sys/class/net/`; do echo "\\"`cat '
550                '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;')
551
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'])
559             if name is None:
560                 continue
561             interface['name'] = name
562
563         # Set udev rules for interfaces
564         if not skip_tg_udev:
565             InterfaceUtil.tg_set_interfaces_udev_rules(node)
566
567     @staticmethod
568     def iface_update_numa_node(node):
569         """For all interfaces from topology file update numa node based on
570            information from the node.
571
572         :param node: Node from topology.
573         :type node: dict
574         :returns: Nothing.
575         :raises ValueError: If numa node ia less than 0.
576         :raises RuntimeError: If update of numa node failes.
577         """
578         ssh = SSH()
579         for if_key in Topology.get_node_interfaces(node):
580             if_pci = Topology.get_interface_pci_addr(node, if_key)
581             ssh.connect(node)
582             cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
583             for _ in range(3):
584                 (ret, out, _) = ssh.exec_command(cmd)
585                 if ret == 0:
586                     try:
587                         numa_node = int(out)
588                         if numa_node < 0:
589                             if CpuUtils.cpu_node_count(node) == 1:
590                                 numa_node = 0
591                             else:
592                                 raise ValueError
593                     except ValueError:
594                         logger.trace('Reading numa location failed for: {0}'
595                                      .format(if_pci))
596                     else:
597                         Topology.set_interface_numa_node(node, if_key,
598                                                          numa_node)
599                         break
600             else:
601                 raise RuntimeError('Update numa node failed for: {0}'
602                                    .format(if_pci))
603
604     @staticmethod
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.
608
609         :param nodes: Nodes in the topology.
610         :param skip_tg: Skip TG node
611         :type nodes: dict
612         :type skip_tg: bool
613         :returns: Nothing.
614         """
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)
620
621     @staticmethod
622     def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
623                                                skip_tg_udev=False,
624                                                numa_node=False):
625         """Update interface names on all nodes in DICT__nodes.
626
627         This method updates the topology dictionary by querying interface lists
628         of all nodes mentioned in the topology dictionary.
629
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.
634         :type nodes: dict
635         :type skip_tg: bool
636         :type skip_tg_udev: bool
637         :type numa_node: bool
638         """
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)
645
646             if numa_node:
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)
651
652     @staticmethod
653     def create_vlan_subinterface(node, interface, vlan):
654         """Create VLAN subinterface on node.
655
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.
659         :type node: dict
660         :type interface: str
661         :type vlan: int
662         :returns: Name and index of created subinterface.
663         :rtype: tuple
664         :raises RuntimeError: if it is unable to create VLAN subinterface on the
665             node.
666         """
667         iface_key = Topology.get_interface_by_name(node, interface)
668         sw_if_index = Topology.get_interface_sw_index(node, iface_key)
669
670         output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
671                                                sw_if_index=sw_if_index,
672                                                vlan=vlan)
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,
677                                                      vlan, node['host']))
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)
682         else:
683             raise RuntimeError('Unable to create VLAN subinterface on node {}'
684                                .format(node['host']))
685
686         with VatTerminal(node, False) as vat:
687             vat.vat_terminal_exec_cmd('exec show interfaces')
688
689         return '{}.{}'.format(interface, vlan), sw_vlan_idx
690
691     @staticmethod
692     def create_vxlan_interface(node, vni, source_ip, destination_ip):
693         """Create VXLAN interface and return sw if index of created interface.
694
695         Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT
696         command on the node.
697
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.
702         :type node: dict
703         :type vni: int
704         :type source_ip: str
705         :type destination_ip: str
706         :returns: SW IF INDEX of created interface.
707         :rtype: int
708         :raises RuntimeError: if it is unable to create VxLAN interface on the
709             node.
710         """
711         output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
712                                                src=source_ip,
713                                                dst=destination_ip,
714                                                vni=vni)
715         output = output[0]
716
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)
723             return sw_if_idx
724         else:
725             raise RuntimeError("Unable to create VXLAN interface on node {0}"
726                                .format(node))
727
728     @staticmethod
729     def vxlan_dump(node, interface=None):
730         """Get VxLAN data for the given interface.
731
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.
735         :type node: dict
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.
739         :rtype: dict or list
740         :raises TypeError: if the data type of interface is neither basestring
741             nor int.
742         """
743         param = "sw_if_index"
744         if interface is None:
745             param = ''
746             sw_if_index = ''
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
751         else:
752             raise TypeError("Wrong interface format {0}".format(interface))
753
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)
757
758         if sw_if_index:
759             for vxlan in response[0]:
760                 if vxlan["sw_if_index"] == sw_if_index:
761                     return vxlan
762             return {}
763         return response[0]
764
765     @staticmethod
766     def vhost_user_dump(node):
767         """Get vhost-user data for the given node.
768
769         :param node: VPP node to get interface data from.
770         :type node: dict
771         :returns: List of dictionaries with all vhost-user interfaces.
772         :rtype: list
773         """
774         with VatTerminal(node) as vat:
775             response = vat.vat_terminal_exec_cmd_from_template(
776                 "vhost_user_dump.vat")
777
778         return response[0]
779
780     @staticmethod
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.
784
785         :param node: VPP node to get data from.
786         :param name: Optional name of a specific TAP interface.
787         :type node: dict
788         :type name: str
789         :returns: Dictionary of information about a specific TAP interface, or
790             a List of dictionaries containing all TAP data for the given node.
791         :rtype: dict or list
792         """
793         with VatTerminal(node) as vat:
794             response = vat.vat_terminal_exec_cmd_from_template(
795                 "tap_dump.vat")
796         if name is None:
797             return response[0]
798         for item in response[0]:
799             if name == item['dev_name']:
800                 return item
801         return {}
802
803     @staticmethod
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).
808
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]
816             [default_sub]
817         :type node: dict
818         :type interface: str or int
819         :type sub_id: 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.
824         :rtype: tuple
825         :raises RuntimeError: If it is not possible to create sub-interface.
826         """
827
828         outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
829             if outer_vlan_id else ''
830
831         inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
832             if inner_vlan_id else ''
833
834         if type_subif is None:
835             type_subif = ''
836
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)
840         else:
841             sw_if_index = interface
842
843         output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
844                                                sw_if_index=sw_if_index,
845                                                sub_id=sub_id,
846                                                outer_vlan_id=outer_vlan_id,
847                                                inner_vlan_id=inner_vlan_id,
848                                                type_subif=type_subif)
849
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)
858         else:
859             raise RuntimeError('Unable to create sub-interface on node {}'
860                                .format(node['host']))
861
862         with VatTerminal(node, json_param=False) as vat:
863             vat.vat_terminal_exec_cmd('exec show interfaces')
864
865         name = '{}.{}'.format(interface, sub_id)
866         return name, sw_vlan_idx
867
868     @staticmethod
869     def create_gre_tunnel_interface(node, source_ip, destination_ip):
870         """Create GRE tunnel interface on node.
871
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.
875         :type node: dict
876         :type source_ip: str
877         :type destination_ip: str
878         :returns: Name and index of created GRE tunnel interface.
879         :rtype: tuple
880         :raises RuntimeError: If unable to create GRE tunnel interface.
881         """
882         output = VatExecutor.cmd_from_template(node, "create_gre.vat",
883                                                src=source_ip,
884                                                dst=destination_ip)
885         output = output[0]
886
887         if output["retval"] == 0:
888             sw_if_idx = output["sw_if_index"]
889
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)
895
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)
899
900             return name, sw_if_idx
901         else:
902             raise RuntimeError('Unable to create GRE tunnel on node {}.'
903                                .format(node))
904
905     @staticmethod
906     def vpp_create_loopback(node):
907         """Create loopback interface on VPP node.
908
909         :param node: Node to create loopback interface on.
910         :type node: dict
911         :returns: SW interface index.
912         :rtype: int
913         :raises RuntimeError: If it is not possible to create loopback on the
914             node.
915         """
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)
923             return sw_if_idx
924         else:
925             raise RuntimeError('Create loopback failed on node "{}"'
926                                .format(node['host']))
927
928     @staticmethod
929     def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
930         """Create bond interface on VPP node.
931
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).
937         :type node: dict
938         :type mode: str
939         :type load_balance: str
940         :type mac: str
941         :returns: Interface key (name) in topology.
942         :rtype: str
943         :raises RuntimeError: If it is not possible to create bond interface on
944             the node.
945         """
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)
949
950         output = VatExecutor.cmd_from_template(
951             node, 'create_bond_interface.vat', mode=mode, lb=ldb, mac=hw_addr)
952
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,
956                                             ifc_pfx='eth_bond')
957             if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
958             return if_key
959         else:
960             raise RuntimeError('Create bond interface failed on "{host}"'.
961                                format(host=node['host']))
962
963     @staticmethod
964     def add_eth_interface(node, ifc_name=None, sw_if_idx=None, ifc_pfx=None):
965         """Add ethernet interface to current topology.
966
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.
971         :type node: dict
972         :type ifc_name: str
973         :type sw_if_idx: int
974         :type ifc_pfx: str
975         """
976         if_key = Topology.add_new_port(node, ifc_pfx)
977
978         vat_executor = VatExecutor()
979         vat_executor.execute_script_json_out("dump_interfaces.vat", node)
980         interface_dump_json = vat_executor.get_script_stdout()
981
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)
992
993     @staticmethod
994     def vpp_create_avf_interface(node, vf_pci_addr):
995         """Create AVF interface on VPP node.
996
997         :param node: DUT node from topology.
998         :param vf_pci_addr: Virtual Function PCI address.
999         :type node: dict
1000         :type vf_pci_addr: str
1001         :returns: Interface key (name) in topology.
1002         :rtype: str
1003         :raises RuntimeError: If it is not possible to create AVF interface on
1004             the node.
1005         """
1006         with VatTerminal(node, json_param=False) as vat:
1007             vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat',
1008                                                     vf_pci_addr=vf_pci_addr)
1009             output = vat.vat_stdout
1010
1011         if output is not None:
1012             sw_if_idx = int(output.split()[4])
1013             InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
1014                                             ifc_pfx='eth_avf')
1015             if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
1016             return if_key
1017         else:
1018             raise RuntimeError('Create AVF interface failed on {host}'.
1019                                format(host=node['host']))
1020
1021     @staticmethod
1022     def vpp_enslave_physical_interface(node, interface, bond_interface):
1023         """Enslave physical interface to bond interface on VPP node.
1024
1025         :param node: DUT node from topology.
1026         :param interface: Physical interface key from topology file.
1027         :param bond_interface: Load balance
1028         :type node: dict
1029         :type interface: str
1030         :type bond_interface: str
1031         :raises RuntimeError: If it is not possible to enslave physical
1032             interface to bond interface on the node.
1033         """
1034         ifc = Topology.get_interface_sw_index(node, interface)
1035         bond_ifc = Topology.get_interface_sw_index(node, bond_interface)
1036
1037         output = VatExecutor.cmd_from_template(
1038             node, 'enslave_physical_interface.vat', p_int=ifc, b_int=bond_ifc)
1039
1040         retval = output[0].get('retval', None)
1041         if retval is None or int(retval) != 0:
1042             raise RuntimeError('Enslave physical interface {ifc} to bond '
1043                                'interface {bond} failed on node "{n}"'
1044                                .format(ifc=interface, bond=bond_interface,
1045                                        n=node['host']))
1046
1047     @staticmethod
1048     def vpp_show_bond_data_on_node(node, details=False):
1049         """Show (detailed) bond information on VPP node.
1050
1051         :param node: DUT node from topology.
1052         :param details: If detailed information is required or not.
1053         :type node: dict
1054         :type details: bool
1055         """
1056         cmd = 'exec show bond details' if details else 'exec show bond'
1057         with VatTerminal(node, json_param=False) as vat:
1058             vat.vat_terminal_exec_cmd(cmd)
1059
1060     @staticmethod
1061     def vpp_show_bond_data_on_all_nodes(nodes, details=False):
1062         """Show (detailed) bond information on all VPP nodes in DICT__nodes.
1063
1064         :param nodes: Nodes in the topology.
1065         :param details: If detailed information is required or not.
1066         :type nodes: dict
1067         :type details: bool
1068         """
1069         for node_data in nodes.values():
1070             if node_data['type'] == NodeType.DUT:
1071                 InterfaceUtil.vpp_show_bond_data_on_node(node_data, details)
1072
1073     @staticmethod
1074     def vpp_enable_input_acl_interface(node, interface, ip_version,
1075                                        table_index):
1076         """Enable input acl on interface.
1077
1078         :param node: VPP node to setup interface for input acl.
1079         :param interface: Interface to setup input acl.
1080         :param ip_version: Version of IP protocol.
1081         :param table_index: Classify table index.
1082         :type node: dict
1083         :type interface: str or int
1084         :type ip_version: str
1085         :type table_index: int
1086         """
1087         if isinstance(interface, basestring):
1088             sw_if_index = Topology.get_interface_sw_index(node, interface)
1089         else:
1090             sw_if_index = interface
1091
1092         with VatTerminal(node) as vat:
1093             vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
1094                                                     sw_if_index=sw_if_index,
1095                                                     ip_version=ip_version,
1096                                                     table_index=table_index)
1097
1098     @staticmethod
1099     def get_interface_classify_table(node, interface):
1100         """Get name of classify table for the given interface.
1101
1102         :param node: VPP node to get data from.
1103         :param interface: Name or sw_if_index of a specific interface.
1104         :type node: dict
1105         :type interface: str or int
1106         :returns: Classify table name.
1107         :rtype: str
1108         """
1109         if isinstance(interface, basestring):
1110             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1111         else:
1112             sw_if_index = interface
1113
1114         with VatTerminal(node) as vat:
1115             data = vat.vat_terminal_exec_cmd_from_template(
1116                 "classify_interface_table.vat",
1117                 sw_if_index=sw_if_index)
1118         return data[0]
1119
1120     @staticmethod
1121     def get_interface_vrf_table(node, interface):
1122         """Get vrf ID for the given interface.
1123
1124         :param node: VPP node.
1125         :param interface: Name or sw_if_index of a specific interface.
1126         :type node: dict
1127         :type interface: str or int
1128         :returns: vrf ID of the specified interface.
1129         :rtype: int
1130         """
1131
1132         if isinstance(interface, basestring):
1133             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1134         else:
1135             sw_if_index = interface
1136
1137         with VatTerminal(node) as vat:
1138             data = vat.vat_terminal_exec_cmd_from_template(
1139                 "interface_vrf_dump.vat",
1140                 sw_if_index=sw_if_index)
1141         return data[0]["vrf_id"]
1142
1143     @staticmethod
1144     def get_sw_if_index(node, interface_name):
1145         """Get sw_if_index for the given interface from actual interface dump.
1146
1147         :param node: VPP node to get interface data from.
1148         :param interface_name: Name of the specific interface.
1149         :type node: dict
1150         :type interface_name: str
1151         :returns: sw_if_index of the given interface.
1152         :rtype: str
1153         """
1154
1155         with VatTerminal(node) as vat:
1156             if_data = vat.vat_terminal_exec_cmd_from_template(
1157                 "interface_dump.vat")
1158         for interface in if_data[0]:
1159             if interface["interface_name"] == interface_name:
1160                 return interface["sw_if_index"]
1161
1162         return None
1163
1164     @staticmethod
1165     def vxlan_gpe_dump(node, interface_name=None):
1166         """Get VxLAN GPE data for the given interface.
1167
1168         :param node: VPP node to get interface data from.
1169         :param interface_name: Name of the specific interface. If None,
1170             information about all VxLAN GPE interfaces is returned.
1171         :type node: dict
1172         :type interface_name: str
1173         :returns: Dictionary containing data for the given VxLAN GPE interface
1174             or if interface=None, the list of dictionaries with all VxLAN GPE
1175             interfaces.
1176         :rtype: dict or list
1177         """
1178
1179         with VatTerminal(node) as vat:
1180             vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
1181                 "vxlan_gpe_dump.vat")
1182
1183         if interface_name:
1184             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
1185             if sw_if_index:
1186                 for vxlan_gpe in vxlan_gpe_data[0]:
1187                     if vxlan_gpe["sw_if_index"] == sw_if_index:
1188                         return vxlan_gpe
1189             return {}
1190
1191         return vxlan_gpe_data[0]
1192
1193     @staticmethod
1194     def vpp_proxy_arp_interface_enable(node, interface):
1195         """Enable proxy ARP on interface.
1196
1197         :param node: VPP node to enable proxy ARP on interface.
1198         :param interface: Interface to enable proxy ARP.
1199         :type node: dict
1200         :type interface: str or int
1201         """
1202         if isinstance(interface, basestring):
1203             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1204         else:
1205             sw_if_index = interface
1206
1207         with VatTerminal(node) as vat:
1208             vat.vat_terminal_exec_cmd_from_template(
1209                 "proxy_arp_intfc_enable.vat",
1210                 sw_if_index=sw_if_index)
1211
1212     @staticmethod
1213     def vpp_ip_source_check_setup(node, interface):
1214         """Setup Reverse Path Forwarding source check on interface.
1215
1216         :param node: Node to setup RPF source check.
1217         :param interface: Interface name to setup RPF source check.
1218         :type node: dict
1219         :type interface: str
1220         """
1221         with VatTerminal(node) as vat:
1222             vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
1223                                                     interface_name=interface)
1224
1225     @staticmethod
1226     def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
1227         """Assign VPP interface to specific VRF/FIB table.
1228
1229         :param node: VPP node where the FIB and interface are located.
1230         :param interface: Interface to be assigned to FIB.
1231         :param table_id: VRF table ID.
1232         :param ipv6: Assign to IPv6 table. Default False.
1233         :type node: dict
1234         :type interface: str or int
1235         :type table_id: int
1236         :type ipv6: bool
1237         """
1238         if isinstance(interface, basestring):
1239             sw_if_index = Topology.get_interface_sw_index(node, interface)
1240         else:
1241             sw_if_index = interface
1242
1243         ipv6 = 'ipv6' if ipv6 else ''
1244
1245         with VatTerminal(node) as vat:
1246             ret = vat.vat_terminal_exec_cmd_from_template(
1247                 "set_fib_to_interface.vat",
1248                 sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
1249
1250         if ret[0]["retval"] != 0:
1251             raise RuntimeError('Unable to assign interface to FIB node {}.'
1252                                .format(node))
1253
1254     @staticmethod
1255     def set_linux_interface_mac(node, interface, mac, namespace=None,
1256                                 vf_id=None):
1257         """Set MAC address for interface in linux.
1258
1259         :param node: Node where to execute command.
1260         :param interface: Interface in namespace.
1261         :param mac: MAC to be assigned to interface.
1262         :param namespace: Execute command in namespace. Optional
1263         :param vf_id: Virtual Function id. Optional
1264         :type node: dict
1265         :type interface: str
1266         :type mac: str
1267         :type namespace: str
1268         :type vf_id: int
1269         """
1270         mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \
1271             if vf_id is not None else 'address {mac}'.format(mac=mac)
1272         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1273
1274         cmd = ('{ns} ip link set {interface} {mac}'.
1275                format(ns=ns_str, interface=interface, mac=mac_str))
1276         exec_cmd_no_error(node, cmd, sudo=True)
1277
1278     @staticmethod
1279     def set_linux_interface_trust_on(node, interface, namespace=None,
1280                                      vf_id=None):
1281         """Set trust on (promisc) for interface in linux.
1282
1283         :param node: Node where to execute command.
1284         :param interface: Interface in namespace.
1285         :param namespace: Execute command in namespace. Optional
1286         :param vf_id: Virtual Function id. Optional
1287         :type node: dict
1288         :type interface: str
1289         :type namespace: str
1290         :type vf_id: int
1291         """
1292         trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \
1293             if vf_id is not None else 'trust on'
1294         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1295
1296         cmd = ('{ns} ip link set dev {interface} {trust}'.
1297                format(ns=ns_str, interface=interface, trust=trust_str))
1298         exec_cmd_no_error(node, cmd, sudo=True)
1299
1300     @staticmethod
1301     def set_linux_interface_spoof_off(node, interface, namespace=None,
1302                                       vf_id=None):
1303         """Set spoof off for interface in linux.
1304
1305         :param node: Node where to execute command.
1306         :param interface: Interface in namespace.
1307         :param namespace: Execute command in namespace. Optional
1308         :param vf_id: Virtual Function id. Optional
1309         :type node: dict
1310         :type interface: str
1311         :type namespace: str
1312         :type vf_id: int
1313         """
1314         spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \
1315             if vf_id is not None else 'spoof off'
1316         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1317
1318         cmd = ('{ns} ip link set dev {interface} {spoof}'.
1319                format(ns=ns_str, interface=interface, spoof=spoof_str))
1320         exec_cmd_no_error(node, cmd, sudo=True)
1321
1322     @staticmethod
1323     def init_avf_interface(node, ifc_key, numvfs=1, topology_type='L2'):
1324         """Init PCI device by creating VFs and bind them to vfio-pci for AVF
1325         driver testing on DUT.
1326
1327         :param node: DUT node.
1328         :param ifc_key: Interface key from topology file.
1329         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
1330         :param topology_type: Topology type.
1331         :type node: dict
1332         :type ifc_key: str
1333         :type numvfs: int
1334         :type topology_type: str
1335         :returns: Virtual Function topology interface keys.
1336         :rtype: list
1337         """
1338         ssh = SSH()
1339         ssh.connect(node)
1340
1341         # Read PCI address and driver.
1342         pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key)
1343         pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":")
1344         uio_driver = Topology.get_uio_driver(node)
1345         kernel_driver = Topology.get_interface_driver(node, ifc_key)
1346         current_driver = DUTSetup.get_pci_dev_driver(
1347             node, pf_pci_addr.replace(':', r'\:'))
1348
1349         VPPUtil.stop_vpp_service(node)
1350         if current_driver != kernel_driver:
1351             # PCI device must be re-bound to kernel driver before creating VFs.
1352             DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True)
1353             # Stop VPP to prevent deadlock.
1354             # Unbind from current driver.
1355             DUTSetup.pci_driver_unbind(node, pf_pci_addr)
1356             # Bind to kernel driver.
1357             DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver)
1358
1359         # Initialize PCI VFs
1360         DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs)
1361
1362         vf_ifc_keys = []
1363         # Set MAC address and bind each virtual function to uio driver.
1364         for vf_id in range(numvfs):
1365             vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2],
1366                                     pf_mac_addr[3], pf_mac_addr[4],
1367                                     pf_mac_addr[5], "{:02x}".format(vf_id)])
1368
1369             pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\
1370                 format(pci=pf_pci_addr)
1371             InterfaceUtil.set_linux_interface_trust_on(node, pf_dev,
1372                                                        vf_id=vf_id)
1373             if topology_type == 'L2':
1374                 InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev,
1375                                                             vf_id=vf_id)
1376             InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr,
1377                                                   vf_id=vf_id)
1378
1379             DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id)
1380             DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver)
1381
1382             # Add newly created ports into topology file
1383             vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key)
1384             vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
1385             vf_ifc_key = Topology.add_new_port(node, vf_ifc_name)
1386             Topology.update_interface_name(node, vf_ifc_key,
1387                                            vf_ifc_name+str(vf_id+1))
1388             Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr)
1389             Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr)
1390             vf_ifc_keys.append(vf_ifc_key)
1391
1392         return vf_ifc_keys
1393
1394     @staticmethod
1395     def vpp_create_multiple_vxlan_ipv4_tunnels(
1396             node, node_vxlan_if, node_vlan_if, op_node, op_node_if,
1397             n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, ip_limit,
1398             bd_id_start):
1399         """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on
1400         VPP node.
1401
1402         Put each pair of VXLAN tunnel interface and VLAN sub-interface to
1403         separate bridge-domain.
1404
1405         :param node: VPP node to create VXLAN tunnel interfaces.
1406         :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1407             interfaces.
1408         :param node_vlan_if: VPP node interface key to create VLAN
1409             sub-interface.
1410         :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1411         :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1412             interfaces.
1413         :param n_tunnels: Number of tunnel interfaces to create.
1414         :param vni_start: VNI start ID.
1415         :param src_ip_start: VXLAN tunnel source IP address start.
1416         :param dst_ip_start: VXLAN tunnel destination IP address start.
1417         :param ip_step: IP address incremental step.
1418         :param ip_limit: IP address limit.
1419         :param bd_id_start: Bridge-domain ID start.
1420         :type node: dict
1421         :type node_vxlan_if: str
1422         :type node_vlan_if: str
1423         :type op_node: dict
1424         :type op_node_if: str
1425         :type n_tunnels: int
1426         :type vni_start: int
1427         :type src_ip_start: str
1428         :type dst_ip_start: str
1429         :type ip_step: int
1430         :type ip_limit: str
1431         :type bd_id_start: int
1432         """
1433         # configure IPs, create VXLAN interfaces and VLAN sub-interfaces
1434         vxlan_count = InterfaceUtil.vpp_create_vxlan_and_vlan_interfaces(
1435             node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start,
1436             src_ip_start, dst_ip_start, ip_step, ip_limit)
1437
1438         # update topology with VXLAN interfaces and VLAN sub-interfaces data
1439         # and put interfaces up
1440         InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_up(
1441             node, vxlan_count, node_vlan_if)
1442
1443         # configure bridge domains, ARPs and routes
1444         InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1445             node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1446             ip_step, bd_id_start)
1447
1448     @staticmethod
1449     def vpp_create_vxlan_and_vlan_interfaces(
1450             node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start,
1451             src_ip_start, dst_ip_start, ip_step, ip_limit):
1452         """
1453         Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP
1454         node.
1455
1456         :param node: VPP node.
1457         :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1458             interfaces.
1459         :param node_vlan_if: VPP node interface key to create VLAN
1460             sub-interface.
1461         :param vxlan_count: Number of tunnel interfaces to create.
1462         :param vni_start: VNI start ID.
1463         :param src_ip_start: VXLAN tunnel source IP address start.
1464         :param dst_ip_start: VXLAN tunnel destination IP address start.
1465         :param ip_step: IP address incremental step.
1466         :param ip_limit: IP address limit.
1467         :type node: dict
1468         :type node_vxlan_if: str
1469         :type node_vlan_if: str
1470         :type vxlan_count: int
1471         :type vni_start: int
1472         :type src_ip_start: str
1473         :type dst_ip_start: str
1474         :type ip_step: int
1475         :type ip_limit: str
1476         :returns: Number of created VXLAN interfaces.
1477         :rtype: int
1478         """
1479         commands = list()
1480
1481         src_ip_start_int = IPUtil.ip_to_int(src_ip_start)
1482         dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1483         ip_limit_int = IPUtil.ip_to_int(ip_limit)
1484
1485         tmp_fn = '/tmp/create_vxlan_interfaces.config'
1486         for i in range(0, vxlan_count):
1487             src_ip_int = src_ip_start_int + i * ip_step
1488             dst_ip_int = dst_ip_start_int + i * ip_step
1489             if src_ip_int > ip_limit_int or dst_ip_int > ip_limit_int:
1490                 logger.warn("Can't do more iterations - IPv4 address limit "
1491                             "has been reached.")
1492                 vxlan_count = i
1493                 break
1494             src_ip = IPUtil.int_to_ip(src_ip_int)
1495             dst_ip = IPUtil.int_to_ip(dst_ip_int)
1496             commands.append(
1497                 'sw_interface_add_del_address sw_if_index {sw_idx} {ip}/32\n'
1498                 .format(sw_idx=Topology.get_interface_sw_index(
1499                     node, node_vxlan_if), ip=src_ip))
1500             commands.append(
1501                 'vxlan_add_del_tunnel src {src_ip} dst {dst_ip} vni {vni}\n'
1502                 .format(src_ip=src_ip, dst_ip=dst_ip, vni=vni_start+i))
1503             commands.append(
1504                 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n'
1505                 .format(sw_idx=Topology.get_interface_sw_index(
1506                     node, node_vlan_if), vlan=i+1))
1507
1508         VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1509
1510         return vxlan_count
1511
1512     @staticmethod
1513     def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
1514         """
1515         Update topology with VXLAN interfaces and VLAN sub-interfaces data
1516         and put interfaces up.
1517
1518         :param node: VPP node.
1519         :param vxlan_count: Number of tunnel interfaces.
1520         :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
1521             have been created.
1522         :type node: dict
1523         :type vxlan_count: int
1524         :type node_vlan_if: str
1525         """
1526         with VatTerminal(node) as vat_ter:
1527             if_data = vat_ter.vat_terminal_exec_cmd_from_template(
1528                 'interface_dump.vat')[0]
1529
1530         tmp_fn = '/tmp/put_subinterfaces_up.config'
1531         commands = list()
1532         for i in range(0, vxlan_count):
1533             vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
1534             vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
1535             vxlan_found = False
1536             vxlan_subif_idx = None
1537             vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
1538             vlan_subif_name = '{if_name}.{vlan}'.format(
1539                 if_name=Topology.get_interface_name(
1540                     node, node_vlan_if), vlan=i+1)
1541             vlan_found = False
1542             vlan_idx = None
1543             for data in if_data:
1544                 if_name = data['interface_name']
1545                 if not vxlan_found and if_name == vxlan_subif_name:
1546                     vxlan_subif_idx = data['sw_if_index']
1547                     vxlan_found = True
1548                 elif not vlan_found and if_name == vlan_subif_name:
1549                     vlan_idx = data['sw_if_index']
1550                     vlan_found = True
1551                 if vxlan_found and vlan_found:
1552                     break
1553             Topology.update_interface_sw_if_index(
1554                 node, vxlan_subif_key, vxlan_subif_idx)
1555             Topology.update_interface_name(
1556                 node, vxlan_subif_key, vxlan_subif_name)
1557             commands.append(
1558                 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1559                 .format(sw_idx=vxlan_subif_idx))
1560             Topology.update_interface_sw_if_index(
1561                 node, vlan_subif_key, vlan_idx)
1562             Topology.update_interface_name(
1563                 node, vlan_subif_key, vlan_subif_name)
1564             commands.append(
1565                 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1566                 .format(sw_idx=vlan_idx))
1567
1568         VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1569
1570     @staticmethod
1571     def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1572             node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1573             ip_step, bd_id_start):
1574         """
1575         Configure ARPs and routes for VXLAN interfaces and put each pair of
1576         VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
1577
1578         :param node: VPP node.
1579         :param node_vxlan_if: VPP node interface key where VXLAN tunnel
1580             interfaces have been created.
1581         :param vxlan_count: Number of tunnel interfaces.
1582         :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1583         :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1584             interfaces.
1585         :param dst_ip_start: VXLAN tunnel destination IP address start.
1586         :param ip_step: IP address incremental step.
1587         :param bd_id_start: Bridge-domain ID start.
1588         :type node: dict
1589         :type node_vxlan_if: str
1590         :type vxlan_count: int
1591         :type op_node: dict
1592         :type op_node_if:
1593         :type dst_ip_start: str
1594         :type ip_step: int
1595         :type bd_id_start: int
1596         """
1597         sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
1598
1599         dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1600
1601         tmp_fn = '/tmp/configure_routes_and_bridge_domains.config'
1602         commands = list()
1603         for i in range(0, vxlan_count):
1604             dst_ip = IPUtil.int_to_ip(dst_ip_start_int + i * ip_step)
1605             commands.append(
1606                 'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} mac {mac}\n'
1607                 .format(sw_idx=sw_idx_vxlan, ip=dst_ip,
1608                         mac=Topology.get_interface_mac(op_node, op_node_if)))
1609             commands.append(
1610                 'ip_add_del_route {ip}/32 via {ip} sw_if_index {sw_idx}'
1611                 ' resolve-attempts 10 count 1\n'.format(
1612                     ip=dst_ip, sw_idx=sw_idx_vxlan))
1613             bd_id = bd_id_start + i
1614             subif_id = i + 1
1615             commands.append(
1616                 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1617                 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1618                     node, 'vxlan_tunnel{nr}'.format(nr=subif_id)), bd_id=bd_id))
1619             commands.append(
1620                 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1621                 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1622                     node, 'vlan_subif{nr}'.format(nr=subif_id)), bd_id=bd_id))
1623
1624         VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1625
1626     @staticmethod
1627     def vpp_sw_interface_rx_placement_dump(node):
1628         """Dump VPP interface RX placement on node.
1629
1630         :param node: Node to run command on.
1631         :type node: dict
1632         :returns: Thread mapping information as a list of dictionaries.
1633         :rtype: list
1634         :raises RuntimeError: If failed to run command on host.
1635         :raises PapiError: If no API reply received.
1636         """
1637         api_data = list()
1638         for ifc in node['interfaces'].values():
1639             if ifc['vpp_sw_index'] is not None:
1640                 api = dict(api_name='sw_interface_rx_placement_dump')
1641                 api_args = dict(sw_if_index=ifc['vpp_sw_index'])
1642                 api['api_args'] = api_args
1643                 api_data.append(api)
1644
1645         with PapiExecutor(node) as papi_executor:
1646             papi_executor.execute_papi(api_data)
1647             try:
1648                 papi_executor.papi_should_have_passed()
1649                 api_reply = papi_executor.get_papi_reply()
1650             except AssertionError:
1651                 raise RuntimeError('Failed to run {api_name} on host '
1652                                    '{host}!'.format(host=node['host'], **api))
1653
1654         if api_reply:
1655             thr_mapping = [s['sw_interface_rx_placement_details'] \
1656                 for r in api_reply for s in r['api_reply']]
1657             return sorted(thr_mapping, key=lambda k: k['sw_if_index'])
1658         else:
1659             raise PapiError('No reply received for {api_name} on host {host}!'.
1660                             format(host=node['host'], **api))
1661
1662     @staticmethod
1663     def vpp_sw_interface_set_rx_placement(node, sw_if_index, queue_id,
1664                                           worker_id):
1665         """Set interface RX placement to worker on node.
1666
1667         :param node: Node to run command on.
1668         :param sw_if_index: VPP SW interface index.
1669         :param queue_id: VPP interface queue ID.
1670         :param worker_id: VPP worker ID (indexing from 0).
1671         :type node: dict
1672         :type sw_if_index: int
1673         :type queue_id: int
1674         :type worker_id: int
1675         :raises RuntimeError: If failed to run command on host.
1676         :raises PapiError: If no API reply received.
1677         """
1678         api_data = list()
1679         api = dict(api_name='sw_interface_set_rx_placement')
1680         api_args = dict(sw_if_index=sw_if_index, queue_id=queue_id,
1681                         worker_id=worker_id)
1682         api['api_args'] = api_args
1683         api_data.append(api)
1684
1685         with PapiExecutor(node) as papi_executor:
1686             papi_executor.execute_papi(api_data)
1687             try:
1688                 papi_executor.papi_should_have_passed()
1689                 api_reply = papi_executor.get_papi_reply()
1690             except AssertionError:
1691                 raise RuntimeError('Failed to run {api_name} on host '
1692                                    '{host}!'.format(host=node['host'], **api))
1693
1694         if not api_reply:
1695             raise PapiError('No reply received for {api_name} on host {host}!'.
1696                             format(host=node['host'], **api))
1697
1698     @staticmethod
1699     def vpp_round_robin_rx_placement(node, prefix):
1700         """Set Round Robin interface RX placement on all worker threads
1701         on node.
1702
1703         :param node: Topology nodes.
1704         :param prefix: Interface name prefix.
1705         :type node: dict
1706         :type prefix: str
1707         """
1708         worker_id = 0
1709         worker_cnt = len(VPPUtil.vpp_show_threads(node)) - 1
1710         for placement in InterfaceUtil.vpp_sw_interface_rx_placement_dump(node):
1711             for interface in node['interfaces'].values():
1712                 if placement['sw_if_index'] == interface['vpp_sw_index'] \
1713                     and prefix in interface['name']:
1714                     InterfaceUtil.vpp_sw_interface_set_rx_placement(
1715                         node, placement['sw_if_index'], placement['queue_id'],
1716                         worker_id % worker_cnt)
1717                     worker_id += 1
1718
1719     @staticmethod
1720     def vpp_round_robin_rx_placement_on_all_duts(nodes, prefix):
1721         """Set Round Robin interface RX placement on all worker threads
1722         on all DUTs.
1723
1724         :param nodes: Topology nodes.
1725         :param prefix: Interface name prefix.
1726         :type nodes: dict
1727         :type prefix: str
1728         """
1729         for node in nodes.values():
1730             if node['type'] == NodeType.DUT:
1731                 InterfaceUtil.vpp_round_robin_rx_placement(node, prefix)