cff2c9f695d1e0f58ad3291b5f7761c9f9e8e4ce
[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.IPUtil import convert_ipv4_netmask_prefix
23 from resources.libraries.python.IPUtil import IPUtil
24 from resources.libraries.python.parsers.JsonParser import JsonParser
25 from resources.libraries.python.ssh import SSH, exec_cmd_no_error
26 from resources.libraries.python.topology import NodeType, Topology
27 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
28 from resources.libraries.python.VatJsonUtil import VatJsonUtil
29 from resources.libraries.python.VPPUtil import VPPUtil
30
31
32 class InterfaceUtil(object):
33     """General utilities for managing interfaces"""
34
35     __UDEV_IF_RULES_FILE = '/etc/udev/rules.d/10-network.rules'
36
37     @staticmethod
38     def set_interface_state(node, interface, state, if_type="key"):
39         """Set interface state on a node.
40
41         Function can be used for DUTs as well as for TGs.
42
43         :param node: Node where the interface is.
44         :param interface: Interface key or sw_if_index or name.
45         :param state: One of 'up' or 'down'.
46         :param if_type: Interface type
47         :type node: dict
48         :type interface: str or int
49         :type state: str
50         :type if_type: str
51         :returns: Nothing.
52         :raises ValueError: If the interface type is unknown.
53         :raises ValueError: If the state of interface is unexpected.
54         :raises ValueError: If the node has an unknown node type.
55         """
56
57         if if_type == "key":
58             if isinstance(interface, basestring):
59                 sw_if_index = Topology.get_interface_sw_index(node, interface)
60                 iface_name = Topology.get_interface_name(node, interface)
61             else:
62                 sw_if_index = interface
63         elif if_type == "name":
64             iface_key = Topology.get_interface_by_name(node, interface)
65             if iface_key is not None:
66                 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
67             iface_name = interface
68         else:
69             raise ValueError("if_type unknown: {}".format(if_type))
70
71         if node['type'] == NodeType.DUT:
72             if state == 'up':
73                 state = 'admin-up link-up'
74             elif state == 'down':
75                 state = 'admin-down link-down'
76             else:
77                 raise ValueError('Unexpected interface state: {}'.format(state))
78             VatExecutor.cmd_from_template(node, 'set_if_state.vat',
79                                           sw_if_index=sw_if_index, state=state)
80         elif node['type'] == NodeType.TG or node['type'] == NodeType.VM:
81             cmd = 'ip link set {} {}'.format(iface_name, state)
82             exec_cmd_no_error(node, cmd, sudo=True)
83         else:
84             raise ValueError('Node {} has unknown NodeType: "{}"'
85                              .format(node['host'], node['type']))
86
87     @staticmethod
88     def set_interface_ethernet_mtu(node, iface_key, mtu):
89         """Set Ethernet MTU for specified interface.
90
91         Function can be used only for TGs.
92
93         :param node: Node where the interface is.
94         :param iface_key: Interface key from topology file.
95         :param mtu: MTU to set.
96         :type node: dict
97         :type iface_key: str
98         :type mtu: int
99         :returns: Nothing.
100         :raises ValueError: If the node type is "DUT".
101         :raises ValueError: If the node has an unknown node type.
102         """
103         if node['type'] == NodeType.DUT:
104             raise ValueError('Node {}: Setting Ethernet MTU for interface '
105                              'on DUT nodes not supported', node['host'])
106         elif node['type'] == NodeType.TG:
107             iface_name = Topology.get_interface_name(node, iface_key)
108             cmd = 'ip link set {} mtu {}'.format(iface_name, mtu)
109             exec_cmd_no_error(node, cmd, sudo=True)
110         else:
111             raise ValueError('Node {} has unknown NodeType: "{}"'
112                              .format(node['host'], node['type']))
113
114     @staticmethod
115     def set_default_ethernet_mtu_on_all_interfaces_on_node(node):
116         """Set default Ethernet MTU on all interfaces on node.
117
118         Function can be used only for TGs.
119
120         :param node: Node where to set default MTU.
121         :type node: dict
122         :returns: Nothing.
123         """
124         for ifc in node['interfaces']:
125             InterfaceUtil.set_interface_ethernet_mtu(node, ifc, 1500)
126
127     @staticmethod
128     def vpp_set_interface_mtu(node, interface, mtu=9200):
129         """Set Ethernet MTU on interface.
130
131         :param node: VPP node.
132         :param interface: Interface to setup MTU. Default: 9200.
133         :param mtu: Ethernet MTU size in Bytes.
134         :type node: dict
135         :type interface: str or int
136         :type mtu: int
137         """
138         if isinstance(interface, basestring):
139             sw_if_index = Topology.get_interface_sw_index(node, interface)
140         else:
141             sw_if_index = interface
142
143         if sw_if_index:
144             with VatTerminal(node, json_param=False) as vat:
145                 vat.vat_terminal_exec_cmd_from_template(
146                     "hw_interface_set_mtu.vat", sw_if_index=sw_if_index,
147                     mtu=mtu)
148
149     @staticmethod
150     def vpp_set_interfaces_mtu_on_node(node, mtu=9200):
151         """Set Ethernet MTU on all interfaces.
152
153         :param node: VPP node.
154         :param mtu: Ethernet MTU size in Bytes. Default: 9200.
155         :type node: dict
156         :type mtu: int
157         """
158         for interface in node['interfaces']:
159             InterfaceUtil.vpp_set_interface_mtu(node, interface, mtu)
160
161     @staticmethod
162     def vpp_set_interfaces_mtu_on_all_duts(nodes, mtu=9200):
163         """Set Ethernet MTU on all interfaces on all DUTs.
164
165         :param nodes: VPP nodes.
166         :param mtu: Ethernet MTU size in Bytes. Default: 9200.
167         :type nodes: dict
168         :type mtu: int
169         """
170         for node in nodes.values():
171             if node['type'] == NodeType.DUT:
172                 InterfaceUtil.vpp_set_interfaces_mtu_on_node(node, mtu)
173
174     @staticmethod
175     def vpp_node_interfaces_ready_wait(node, timeout=30):
176         """Wait until all interfaces with admin-up are in link-up state.
177
178         :param node: Node to wait on.
179         :param timeout: Waiting timeout in seconds (optional, default 10s).
180         :type node: dict
181         :type timeout: int
182         :returns: Nothing.
183         :raises RuntimeError: If the timeout period value has elapsed.
184         """
185         if_ready = False
186         not_ready = []
187         start = time()
188         while not if_ready:
189             out = InterfaceUtil.vpp_get_interface_data(node)
190             if time() - start > timeout:
191                 for interface in out:
192                     if interface.get('admin_up_down') == 1:
193                         if interface.get('link_up_down') != 1:
194                             logger.debug('{0} link-down'.format(
195                                 interface.get('interface_name')))
196                 raise RuntimeError('timeout, not up {0}'.format(not_ready))
197             not_ready = []
198             for interface in out:
199                 if interface.get('admin_up_down') == 1:
200                     if interface.get('link_up_down') != 1:
201                         not_ready.append(interface.get('interface_name'))
202             if not not_ready:
203                 if_ready = True
204             else:
205                 logger.debug('Interfaces still in link-down state: {0}, '
206                              'waiting...'.format(not_ready))
207                 sleep(1)
208
209     @staticmethod
210     def vpp_nodes_interfaces_ready_wait(nodes, timeout=30):
211         """Wait until all interfaces with admin-up are in link-up state for
212         listed nodes.
213
214         :param nodes: List of nodes to wait on.
215         :param timeout: Seconds to wait per node for all interfaces to come up.
216         :type nodes: list
217         :type timeout: int
218         :returns: Nothing.
219         """
220         for node in nodes:
221             InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
222
223     @staticmethod
224     def all_vpp_interfaces_ready_wait(nodes, timeout=30):
225         """Wait until all interfaces with admin-up are in link-up state for all
226         nodes in the topology.
227
228         :param nodes: Nodes in the topology.
229         :param timeout: Seconds to wait per node for all interfaces to come up.
230         :type nodes: dict
231         :type timeout: int
232         :returns: Nothing.
233         """
234         for node in nodes.values():
235             if node['type'] == NodeType.DUT:
236                 InterfaceUtil.vpp_node_interfaces_ready_wait(node, timeout)
237
238     @staticmethod
239     def vpp_get_interface_data(node, interface=None):
240         """Get all interface data from a VPP node. If a name or
241         sw_interface_index is provided, return only data for the matching
242         interface.
243
244         :param node: VPP node to get interface data from.
245         :param interface: Numeric index or name string of a specific interface.
246         :type node: dict
247         :type interface: int or str
248         :returns: List of dictionaries containing data for each interface, or a
249             single dictionary for the specified interface.
250         :rtype: list or dict
251         :raises TypeError: if the data type of interface is neither basestring
252             nor int.
253         """
254         with VatTerminal(node) as vat:
255             response = vat.vat_terminal_exec_cmd_from_template(
256                 "interface_dump.vat")
257
258         data = response[0]
259
260         if interface is not None:
261             if isinstance(interface, basestring):
262                 param = "interface_name"
263             elif isinstance(interface, int):
264                 param = "sw_if_index"
265             else:
266                 raise TypeError
267             for data_if in data:
268                 if data_if[param] == interface:
269                     return data_if
270             return dict()
271         return data
272
273     @staticmethod
274     def vpp_get_interface_name(node, sw_if_index):
275         """Get interface name for the given SW interface index from actual
276         interface dump.
277
278         :param node: VPP node to get interface data from.
279         :param sw_if_index: SW interface index of the specific interface.
280         :type node: dict
281         :type sw_if_index: int
282         :returns: Name of the given interface.
283         :rtype: str
284         """
285
286         if_data = InterfaceUtil.vpp_get_interface_data(node, sw_if_index)
287         if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
288             if_data = InterfaceUtil.vpp_get_interface_data(
289                 node, if_data['sup_sw_if_index'])
290         try:
291             if_name = if_data["interface_name"]
292         except KeyError:
293             if_name = None
294         return if_name
295
296     @staticmethod
297     def vpp_get_interface_mac(node, interface=None):
298         """Get MAC address for the given interface from actual interface dump.
299
300         :param node: VPP node to get interface data from.
301         :param interface: Numeric index or name string of a specific interface.
302         :type node: dict
303         :type interface: int or str
304         :returns: MAC address.
305         :rtype: str
306         """
307
308         if_data = InterfaceUtil.vpp_get_interface_data(node, interface)
309         if if_data['sup_sw_if_index'] != if_data['sw_if_index']:
310             if_data = InterfaceUtil.vpp_get_interface_data(
311                 node, if_data['sup_sw_if_index'])
312         mac_data = [str(hex(item))[2:] for item in if_data['l2_address'][:6]]
313         mac_data_nice = []
314         for item in mac_data:
315             if len(item) == 1:
316                 item = '0' + item
317             mac_data_nice.append(item)
318         mac = ":".join(mac_data_nice)
319         return mac
320
321     @staticmethod
322     def vpp_get_interface_ip_addresses(node, interface, ip_version):
323         """Get list of IP addresses from an interface on a VPP node.
324
325          :param node: VPP node to get data from.
326          :param interface: Name of an interface on the VPP node.
327          :param ip_version: IP protocol version (ipv4 or ipv6).
328          :type node: dict
329          :type interface: str
330          :type ip_version: str
331          :returns: List of dictionaries, each containing IP address, subnet
332             prefix length and also the subnet mask for ipv4 addresses.
333             Note: A single interface may have multiple IP addresses assigned.
334          :rtype: list
335         """
336
337         try:
338             sw_if_index = Topology.convert_interface_reference(
339                 node, interface, "sw_if_index")
340         except RuntimeError:
341             if isinstance(interface, basestring):
342                 sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
343             else:
344                 raise
345
346         with VatTerminal(node) as vat:
347             response = vat.vat_terminal_exec_cmd_from_template(
348                 "ip_address_dump.vat", ip_version=ip_version,
349                 sw_if_index=sw_if_index)
350
351         data = response[0]
352
353         if ip_version == "ipv4":
354             for item in data:
355                 item["netmask"] = convert_ipv4_netmask_prefix(
356                     item["prefix_length"])
357         return data
358
359     @staticmethod
360     def tg_set_interface_driver(node, pci_addr, driver):
361         """Set interface driver on the TG node.
362
363         :param node: Node to set interface driver on (must be TG node).
364         :param pci_addr: PCI address of the interface.
365         :param driver: Driver name.
366         :type node: dict
367         :type pci_addr: str
368         :type driver: str
369         :raises RuntimeError: If unbinding from the current driver fails.
370         :raises RuntimeError: If binding to the new driver fails.
371         """
372         old_driver = InterfaceUtil.tg_get_interface_driver(node, pci_addr)
373         if old_driver == driver:
374             return
375
376         ssh = SSH()
377         ssh.connect(node)
378
379         # Unbind from current driver
380         if old_driver is not None:
381             cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/unbind"'\
382                 .format(pci_addr, old_driver)
383             (ret_code, _, _) = ssh.exec_command_sudo(cmd)
384             if int(ret_code) != 0:
385                 raise RuntimeError("'{0}' failed on '{1}'"
386                                    .format(cmd, node['host']))
387
388         # Bind to the new driver
389         cmd = 'sh -c "echo {0} > /sys/bus/pci/drivers/{1}/bind"'\
390             .format(pci_addr, driver)
391         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
392         if int(ret_code) != 0:
393             raise RuntimeError("'{0}' failed on '{1}'"
394                                .format(cmd, node['host']))
395
396     @staticmethod
397     def tg_get_interface_driver(node, pci_addr):
398         """Get interface driver from the TG node.
399
400         :param node: Node to get interface driver on (must be TG node).
401         :param pci_addr: PCI address of the interface.
402         :type node: dict
403         :type pci_addr: str
404         :returns: Interface driver or None if not found.
405         :rtype: str
406         :raises RuntimeError: If PCI rescan or lspci command execution failed.
407         """
408         return DUTSetup.get_pci_dev_driver(node, pci_addr)
409
410     @staticmethod
411     def tg_set_interfaces_udev_rules(node):
412         """Set udev rules for interfaces.
413
414         Create udev rules file in /etc/udev/rules.d where are rules for each
415         interface used by TG node, based on MAC interface has specific name.
416         So after unbind and bind again to kernel driver interface has same
417         name as before. This must be called after TG has set name for each
418         port in topology dictionary.
419         udev rule example
420         SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="52:54:00:e1:8a:0f",
421         NAME="eth1"
422
423         :param node: Node to set udev rules on (must be TG node).
424         :type node: dict
425         :raises RuntimeError: If setting of udev rules fails.
426         """
427         ssh = SSH()
428         ssh.connect(node)
429
430         cmd = 'rm -f {0}'.format(InterfaceUtil.__UDEV_IF_RULES_FILE)
431         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
432         if int(ret_code) != 0:
433             raise RuntimeError("'{0}' failed on '{1}'"
434                                .format(cmd, node['host']))
435
436         for interface in node['interfaces'].values():
437             rule = 'SUBSYSTEM==\\"net\\", ACTION==\\"add\\", ATTR{address}' + \
438                    '==\\"' + interface['mac_address'] + '\\", NAME=\\"' + \
439                    interface['name'] + '\\"'
440             cmd = 'sh -c "echo \'{0}\' >> {1}"'.format(
441                 rule, InterfaceUtil.__UDEV_IF_RULES_FILE)
442             (ret_code, _, _) = ssh.exec_command_sudo(cmd)
443             if int(ret_code) != 0:
444                 raise RuntimeError("'{0}' failed on '{1}'"
445                                    .format(cmd, node['host']))
446
447         cmd = '/etc/init.d/udev restart'
448         ssh.exec_command_sudo(cmd)
449
450     @staticmethod
451     def tg_set_interfaces_default_driver(node):
452         """Set interfaces default driver specified in topology yaml file.
453
454         :param node: Node to setup interfaces driver on (must be TG node).
455         :type node: dict
456         """
457         for interface in node['interfaces'].values():
458             InterfaceUtil.tg_set_interface_driver(node,
459                                                   interface['pci_address'],
460                                                   interface['driver'])
461
462     @staticmethod
463     def update_vpp_interface_data_on_node(node):
464         """Update vpp generated interface data for a given node in DICT__nodes.
465
466         Updates interface names, software if index numbers and any other details
467         generated specifically by vpp that are unknown before testcase run.
468         It does this by dumping interface list to JSON output from all
469         devices using vpp_api_test, and pairing known information from topology
470         (mac address/pci address of interface) to state from VPP.
471
472         :param node: Node selected from DICT__nodes.
473         :type node: dict
474         """
475         vat_executor = VatExecutor()
476         vat_executor.execute_script_json_out("dump_interfaces.vat", node)
477         interface_dump_json = vat_executor.get_script_stdout()
478         VatJsonUtil.update_vpp_interface_data_from_json(node,
479                                                         interface_dump_json)
480
481     @staticmethod
482     def update_nic_interface_names(node):
483         """Update interface names based on nic type and PCI address.
484
485         This method updates interface names in the same format as VPP does.
486
487         :param node: Node dictionary.
488         :type node: dict
489         """
490         for ifc in node['interfaces'].values():
491             if_pci = ifc['pci_address'].replace('.', ':').split(':')
492             bus = '{:x}'.format(int(if_pci[1], 16))
493             dev = '{:x}'.format(int(if_pci[2], 16))
494             fun = '{:x}'.format(int(if_pci[3], 16))
495             loc = '{bus}/{dev}/{fun}'.format(bus=bus, dev=dev, fun=fun)
496             if ifc['model'] == 'Intel-XL710':
497                 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
498             elif ifc['model'] == 'Intel-X710':
499                 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
500             elif ifc['model'] == 'Intel-X520-DA2':
501                 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
502             elif ifc['model'] == 'Cisco-VIC-1385':
503                 ifc['name'] = 'FortyGigabitEthernet{loc}'.format(loc=loc)
504             elif ifc['model'] == 'Cisco-VIC-1227':
505                 ifc['name'] = 'TenGigabitEthernet{loc}'.format(loc=loc)
506             else:
507                 ifc['name'] = 'UnknownEthernet{loc}'.format(loc=loc)
508
509     @staticmethod
510     def update_nic_interface_names_on_all_duts(nodes):
511         """Update interface names based on nic type and PCI address on all DUTs.
512
513         This method updates interface names in the same format as VPP does.
514
515         :param nodes: Topology nodes.
516         :type nodes: dict
517         """
518         for node in nodes.values():
519             if node['type'] == NodeType.DUT:
520                 InterfaceUtil.update_nic_interface_names(node)
521
522     @staticmethod
523     def update_tg_interface_data_on_node(node, skip_tg_udev=False):
524         """Update interface name for TG/linux node in DICT__nodes.
525
526         .. note::
527             # for dev in `ls /sys/class/net/`;
528             > do echo "\"`cat /sys/class/net/$dev/address`\": \"$dev\""; done
529             "52:54:00:9f:82:63": "eth0"
530             "52:54:00:77:ae:a9": "eth1"
531             "52:54:00:e1:8a:0f": "eth2"
532             "00:00:00:00:00:00": "lo"
533
534         :param node: Node selected from DICT__nodes.
535         :param skip_tg_udev: Skip udev rename on TG node.
536         :type node: dict
537         :type skip_tg_udev: bool
538         :raises RuntimeError: If getting of interface name and MAC fails.
539         """
540         # First setup interface driver specified in yaml file
541         InterfaceUtil.tg_set_interfaces_default_driver(node)
542
543         # Get interface names
544         ssh = SSH()
545         ssh.connect(node)
546
547         cmd = ('for dev in `ls /sys/class/net/`; do echo "\\"`cat '
548                '/sys/class/net/$dev/address`\\": \\"$dev\\""; done;')
549
550         (ret_code, stdout, _) = ssh.exec_command(cmd)
551         if int(ret_code) != 0:
552             raise RuntimeError('Get interface name and MAC failed')
553         tmp = "{" + stdout.rstrip().replace('\n', ',') + "}"
554         interfaces = JsonParser().parse_data(tmp)
555         for interface in node['interfaces'].values():
556             name = interfaces.get(interface['mac_address'])
557             if name is None:
558                 continue
559             interface['name'] = name
560
561         # Set udev rules for interfaces
562         if not skip_tg_udev:
563             InterfaceUtil.tg_set_interfaces_udev_rules(node)
564
565     @staticmethod
566     def iface_update_numa_node(node):
567         """For all interfaces from topology file update numa node based on
568            information from the node.
569
570         :param node: Node from topology.
571         :type node: dict
572         :returns: Nothing.
573         :raises ValueError: If numa node ia less than 0.
574         :raises RuntimeError: If update of numa node failes.
575         """
576         ssh = SSH()
577         for if_key in Topology.get_node_interfaces(node):
578             if_pci = Topology.get_interface_pci_addr(node, if_key)
579             ssh.connect(node)
580             cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
581             for _ in range(3):
582                 (ret, out, _) = ssh.exec_command(cmd)
583                 if ret == 0:
584                     try:
585                         numa_node = int(out)
586                         if numa_node < 0:
587                             if CpuUtils.cpu_node_count(node) == 1:
588                                 numa_node = 0
589                             else:
590                                 raise ValueError
591                     except ValueError:
592                         logger.trace('Reading numa location failed for: {0}'
593                                      .format(if_pci))
594                     else:
595                         Topology.set_interface_numa_node(node, if_key,
596                                                          numa_node)
597                         break
598             else:
599                 raise RuntimeError('Update numa node failed for: {0}'
600                                    .format(if_pci))
601
602     @staticmethod
603     def update_all_numa_nodes(nodes, skip_tg=False):
604         """For all nodes and all their interfaces from topology file update numa
605         node information based on information from the node.
606
607         :param nodes: Nodes in the topology.
608         :param skip_tg: Skip TG node
609         :type nodes: dict
610         :type skip_tg: bool
611         :returns: Nothing.
612         """
613         for node in nodes.values():
614             if node['type'] == NodeType.DUT:
615                 InterfaceUtil.iface_update_numa_node(node)
616             elif node['type'] == NodeType.TG and not skip_tg:
617                 InterfaceUtil.iface_update_numa_node(node)
618
619     @staticmethod
620     def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
621                                                skip_tg_udev=False,
622                                                numa_node=False):
623         """Update interface names on all nodes in DICT__nodes.
624
625         This method updates the topology dictionary by querying interface lists
626         of all nodes mentioned in the topology dictionary.
627
628         :param nodes: Nodes in the topology.
629         :param skip_tg: Skip TG node.
630         :param skip_tg_udev: Skip udev rename on TG node.
631         :param numa_node: Retrieve numa_node location.
632         :type nodes: dict
633         :type skip_tg: bool
634         :type skip_tg_udev: bool
635         :type numa_node: bool
636         """
637         for node_data in nodes.values():
638             if node_data['type'] == NodeType.DUT:
639                 InterfaceUtil.update_vpp_interface_data_on_node(node_data)
640             elif node_data['type'] == NodeType.TG and not skip_tg:
641                 InterfaceUtil.update_tg_interface_data_on_node(
642                     node_data, skip_tg_udev)
643
644             if numa_node:
645                 if node_data['type'] == NodeType.DUT:
646                     InterfaceUtil.iface_update_numa_node(node_data)
647                 elif node_data['type'] == NodeType.TG and not skip_tg:
648                     InterfaceUtil.iface_update_numa_node(node_data)
649
650     @staticmethod
651     def create_vlan_subinterface(node, interface, vlan):
652         """Create VLAN subinterface on node.
653
654         :param node: Node to add VLAN subinterface on.
655         :param interface: Interface name on which create VLAN subinterface.
656         :param vlan: VLAN ID of the subinterface to be created.
657         :type node: dict
658         :type interface: str
659         :type vlan: int
660         :returns: Name and index of created subinterface.
661         :rtype: tuple
662         :raises RuntimeError: if it is unable to create VLAN subinterface on the
663             node.
664         """
665         iface_key = Topology.get_interface_by_name(node, interface)
666         sw_if_index = Topology.get_interface_sw_index(node, iface_key)
667
668         output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
669                                                sw_if_index=sw_if_index,
670                                                vlan=vlan)
671         if output[0]["retval"] == 0:
672             sw_vlan_idx = output[0]["sw_if_index"]
673             logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
674                          'created on node {}'.format(sw_vlan_idx,
675                                                      vlan, node['host']))
676             if_key = Topology.add_new_port(node, "vlan_subif")
677             Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
678             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
679             Topology.update_interface_name(node, if_key, ifc_name)
680         else:
681             raise RuntimeError('Unable to create VLAN subinterface on node {}'
682                                .format(node['host']))
683
684         with VatTerminal(node, False) as vat:
685             vat.vat_terminal_exec_cmd('exec show interfaces')
686
687         return '{}.{}'.format(interface, vlan), sw_vlan_idx
688
689     @staticmethod
690     def create_vxlan_interface(node, vni, source_ip, destination_ip):
691         """Create VXLAN interface and return sw if index of created interface.
692
693         Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT
694         command on the node.
695
696         :param node: Node where to create VXLAN interface.
697         :param vni: VXLAN Network Identifier.
698         :param source_ip: Source IP of a VXLAN Tunnel End Point.
699         :param destination_ip: Destination IP of a VXLAN Tunnel End Point.
700         :type node: dict
701         :type vni: int
702         :type source_ip: str
703         :type destination_ip: str
704         :returns: SW IF INDEX of created interface.
705         :rtype: int
706         :raises RuntimeError: if it is unable to create VxLAN interface on the
707             node.
708         """
709         output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
710                                                src=source_ip,
711                                                dst=destination_ip,
712                                                vni=vni)
713         output = output[0]
714
715         if output["retval"] == 0:
716             sw_if_idx = output["sw_if_index"]
717             if_key = Topology.add_new_port(node, "vxlan_tunnel")
718             Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
719             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
720             Topology.update_interface_name(node, if_key, ifc_name)
721             return sw_if_idx
722         else:
723             raise RuntimeError("Unable to create VXLAN interface on node {0}"
724                                .format(node))
725
726     @staticmethod
727     def vxlan_dump(node, interface=None):
728         """Get VxLAN data for the given interface.
729
730         :param node: VPP node to get interface data from.
731         :param interface: Numeric index or name string of a specific interface.
732             If None, information about all VxLAN interfaces is returned.
733         :type node: dict
734         :type interface: int or str
735         :returns: Dictionary containing data for the given VxLAN interface or if
736             interface=None, the list of dictionaries with all VxLAN interfaces.
737         :rtype: dict or list
738         :raises TypeError: if the data type of interface is neither basestring
739             nor int.
740         """
741         param = "sw_if_index"
742         if interface is None:
743             param = ''
744             sw_if_index = ''
745         elif isinstance(interface, basestring):
746             sw_if_index = Topology.get_interface_sw_index(node, interface)
747         elif isinstance(interface, int):
748             sw_if_index = interface
749         else:
750             raise TypeError("Wrong interface format {0}".format(interface))
751
752         with VatTerminal(node) as vat:
753             response = vat.vat_terminal_exec_cmd_from_template(
754                 "vxlan_dump.vat", param=param, sw_if_index=sw_if_index)
755
756         if sw_if_index:
757             for vxlan in response[0]:
758                 if vxlan["sw_if_index"] == sw_if_index:
759                     return vxlan
760             return {}
761         return response[0]
762
763     @staticmethod
764     def vhost_user_dump(node):
765         """Get vhost-user data for the given node.
766
767         :param node: VPP node to get interface data from.
768         :type node: dict
769         :returns: List of dictionaries with all vhost-user interfaces.
770         :rtype: list
771         """
772         with VatTerminal(node) as vat:
773             response = vat.vat_terminal_exec_cmd_from_template(
774                 "vhost_user_dump.vat")
775
776         return response[0]
777
778     @staticmethod
779     def tap_dump(node, name=None):
780         """Get all TAP interface data from the given node, or data about
781         a specific TAP interface.
782
783         :param node: VPP node to get data from.
784         :param name: Optional name of a specific TAP interface.
785         :type node: dict
786         :type name: str
787         :returns: Dictionary of information about a specific TAP interface, or
788             a List of dictionaries containing all TAP data for the given node.
789         :rtype: dict or list
790         """
791         with VatTerminal(node) as vat:
792             response = vat.vat_terminal_exec_cmd_from_template(
793                 "tap_dump.vat")
794         if name is None:
795             return response[0]
796         for item in response[0]:
797             if name == item['dev_name']:
798                 return item
799         return {}
800
801     @staticmethod
802     def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
803                             inner_vlan_id=None, type_subif=None):
804         """Create sub-interface on node. It is possible to set required
805         sub-interface type and VLAN tag(s).
806
807         :param node: Node to add sub-interface.
808         :param interface: Interface name on which create sub-interface.
809         :param sub_id: ID of the sub-interface to be created.
810         :param outer_vlan_id: Optional outer VLAN ID.
811         :param inner_vlan_id: Optional inner VLAN ID.
812         :param type_subif: Optional type of sub-interface. Values supported by
813             VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match]
814             [default_sub]
815         :type node: dict
816         :type interface: str or int
817         :type sub_id: int
818         :type outer_vlan_id: int
819         :type inner_vlan_id: int
820         :type type_subif: str
821         :returns: Name and index of created sub-interface.
822         :rtype: tuple
823         :raises RuntimeError: If it is not possible to create sub-interface.
824         """
825
826         outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
827             if outer_vlan_id else ''
828
829         inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
830             if inner_vlan_id else ''
831
832         if type_subif is None:
833             type_subif = ''
834
835         if isinstance(interface, basestring):
836             iface_key = Topology.get_interface_by_name(node, interface)
837             sw_if_index = Topology.get_interface_sw_index(node, iface_key)
838         else:
839             sw_if_index = interface
840
841         output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
842                                                sw_if_index=sw_if_index,
843                                                sub_id=sub_id,
844                                                outer_vlan_id=outer_vlan_id,
845                                                inner_vlan_id=inner_vlan_id,
846                                                type_subif=type_subif)
847
848         if output[0]["retval"] == 0:
849             sw_vlan_idx = output[0]["sw_if_index"]
850             logger.trace('Created subinterface with index {}'
851                          .format(sw_vlan_idx))
852             if_key = Topology.add_new_port(node, "subinterface")
853             Topology.update_interface_sw_if_index(node, if_key, sw_vlan_idx)
854             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_vlan_idx)
855             Topology.update_interface_name(node, if_key, ifc_name)
856         else:
857             raise RuntimeError('Unable to create sub-interface on node {}'
858                                .format(node['host']))
859
860         with VatTerminal(node, json_param=False) as vat:
861             vat.vat_terminal_exec_cmd('exec show interfaces')
862
863         name = '{}.{}'.format(interface, sub_id)
864         return name, sw_vlan_idx
865
866     @staticmethod
867     def create_gre_tunnel_interface(node, source_ip, destination_ip):
868         """Create GRE tunnel interface on node.
869
870         :param node: VPP node to add tunnel interface.
871         :param source_ip: Source of the GRE tunnel.
872         :param destination_ip: Destination of the GRE tunnel.
873         :type node: dict
874         :type source_ip: str
875         :type destination_ip: str
876         :returns: Name and index of created GRE tunnel interface.
877         :rtype: tuple
878         :raises RuntimeError: If unable to create GRE tunnel interface.
879         """
880         output = VatExecutor.cmd_from_template(node, "create_gre.vat",
881                                                src=source_ip,
882                                                dst=destination_ip)
883         output = output[0]
884
885         if output["retval"] == 0:
886             sw_if_idx = output["sw_if_index"]
887
888             vat_executor = VatExecutor()
889             vat_executor.execute_script_json_out("dump_interfaces.vat", node)
890             interface_dump_json = vat_executor.get_script_stdout()
891             name = VatJsonUtil.get_interface_name_from_json(
892                 interface_dump_json, sw_if_idx)
893
894             if_key = Topology.add_new_port(node, "gre_tunnel")
895             Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
896             Topology.update_interface_name(node, if_key, name)
897
898             return name, sw_if_idx
899         else:
900             raise RuntimeError('Unable to create GRE tunnel on node {}.'
901                                .format(node))
902
903     @staticmethod
904     def vpp_create_loopback(node):
905         """Create loopback interface on VPP node.
906
907         :param node: Node to create loopback interface on.
908         :type node: dict
909         :returns: SW interface index.
910         :rtype: int
911         :raises RuntimeError: If it is not possible to create loopback on the
912             node.
913         """
914         out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
915         if out[0].get('retval') == 0:
916             sw_if_idx = out[0].get('sw_if_index')
917             if_key = Topology.add_new_port(node, "loopback")
918             Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
919             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
920             Topology.update_interface_name(node, if_key, ifc_name)
921             return sw_if_idx
922         else:
923             raise RuntimeError('Create loopback failed on node "{}"'
924                                .format(node['host']))
925
926     @staticmethod
927     def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
928         """Create bond interface on VPP node.
929
930         :param node: DUT node from topology.
931         :param mode: Link bonding mode.
932         :param load_balance: Load balance (optional, valid for xor and lacp
933             modes, otherwise ignored).
934         :param mac: MAC address to assign to the bond interface (optional).
935         :type node: dict
936         :type mode: str
937         :type load_balance: str
938         :type mac: str
939         :returns: Interface key (name) in topology.
940         :rtype: str
941         :raises RuntimeError: If it is not possible to create bond interface on
942             the node.
943         """
944         hw_addr = '' if mac is None else 'hw-addr {mac}'.format(mac=mac)
945         ldb = '' if load_balance is None \
946             else 'lb {ldb}'.format(ldb=load_balance)
947
948         output = VatExecutor.cmd_from_template(
949             node, 'create_bond_interface.vat', mode=mode, lb=ldb, mac=hw_addr)
950
951         if output[0].get('retval') == 0:
952             sw_if_idx = output[0].get('sw_if_index')
953             InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
954                                             ifc_pfx='eth_bond')
955             if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
956             return if_key
957         else:
958             raise RuntimeError('Create bond interface failed on "{host}"'.
959                                format(host=node['host']))
960
961     @staticmethod
962     def add_eth_interface(node, ifc_name=None, sw_if_idx=None, ifc_pfx=None):
963         """Add ethernet interface to current topology.
964
965         :param node: DUT node from topology.
966         :param ifc_name: Name of the interface.
967         :param sw_if_idx: SW interface index.
968         :param ifc_pfx: Interface key prefix.
969         :type node: dict
970         :type ifc_name: str
971         :type sw_if_idx: int
972         :type ifc_pfx: str
973         """
974         if_key = Topology.add_new_port(node, ifc_pfx)
975
976         vat_executor = VatExecutor()
977         vat_executor.execute_script_json_out("dump_interfaces.vat", node)
978         interface_dump_json = vat_executor.get_script_stdout()
979
980         if ifc_name and sw_if_idx is None:
981             sw_if_idx = VatJsonUtil.get_interface_sw_index_from_json(
982                 interface_dump_json, ifc_name)
983         Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
984         if sw_if_idx and ifc_name is None:
985             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
986         Topology.update_interface_name(node, if_key, ifc_name)
987         ifc_mac = VatJsonUtil.get_interface_mac_from_json(
988             interface_dump_json, sw_if_idx)
989         Topology.update_interface_mac_address(node, if_key, ifc_mac)
990
991     @staticmethod
992     def vpp_create_avf_interface(node, vf_pci_addr):
993         """Create AVF interface on VPP node.
994
995         :param node: DUT node from topology.
996         :param vf_pci_addr: Virtual Function PCI address.
997         :type node: dict
998         :type vf_pci_addr: str
999         :returns: Interface key (name) in topology.
1000         :rtype: str
1001         :raises RuntimeError: If it is not possible to create AVF interface on
1002             the node.
1003         """
1004         with VatTerminal(node, json_param=False) as vat:
1005             vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat',
1006                                                     vf_pci_addr=vf_pci_addr)
1007             output = vat.vat_stdout
1008
1009         if output is not None:
1010             sw_if_idx = int(output.split()[4])
1011             InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
1012                                             ifc_pfx='eth_avf')
1013             if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
1014             return if_key
1015         else:
1016             raise RuntimeError('Create AVF interface failed on {host}'.
1017                                format(host=node['host']))
1018
1019     @staticmethod
1020     def vpp_enslave_physical_interface(node, interface, bond_interface):
1021         """Enslave physical interface to bond interface on VPP node.
1022
1023         :param node: DUT node from topology.
1024         :param interface: Physical interface key from topology file.
1025         :param bond_interface: Load balance
1026         :type node: dict
1027         :type interface: str
1028         :type bond_interface: str
1029         :raises RuntimeError: If it is not possible to enslave physical
1030             interface to bond interface on the node.
1031         """
1032         ifc = Topology.get_interface_sw_index(node, interface)
1033         bond_ifc = Topology.get_interface_sw_index(node, bond_interface)
1034
1035         output = VatExecutor.cmd_from_template(
1036             node, 'enslave_physical_interface.vat', p_int=ifc, b_int=bond_ifc)
1037
1038         retval = output[0].get('retval', None)
1039         if retval is None or int(retval) != 0:
1040             raise RuntimeError('Enslave physical interface {ifc} to bond '
1041                                'interface {bond} failed on node "{n}"'
1042                                .format(ifc=interface, bond=bond_interface,
1043                                        n=node['host']))
1044
1045     @staticmethod
1046     def vpp_show_bond_data_on_node(node, details=False):
1047         """Show (detailed) bond information on VPP node.
1048
1049         :param node: DUT node from topology.
1050         :param details: If detailed information is required or not.
1051         :type node: dict
1052         :type details: bool
1053         """
1054         cmd = 'exec show bond details' if details else 'exec show bond'
1055         with VatTerminal(node, json_param=False) as vat:
1056             vat.vat_terminal_exec_cmd(cmd)
1057
1058     @staticmethod
1059     def vpp_show_bond_data_on_all_nodes(nodes, details=False):
1060         """Show (detailed) bond information on all VPP nodes in DICT__nodes.
1061
1062         :param nodes: Nodes in the topology.
1063         :param details: If detailed information is required or not.
1064         :type nodes: dict
1065         :type details: bool
1066         """
1067         for node_data in nodes.values():
1068             if node_data['type'] == NodeType.DUT:
1069                 InterfaceUtil.vpp_show_bond_data_on_node(node_data, details)
1070
1071     @staticmethod
1072     def vpp_enable_input_acl_interface(node, interface, ip_version,
1073                                        table_index):
1074         """Enable input acl on interface.
1075
1076         :param node: VPP node to setup interface for input acl.
1077         :param interface: Interface to setup input acl.
1078         :param ip_version: Version of IP protocol.
1079         :param table_index: Classify table index.
1080         :type node: dict
1081         :type interface: str or int
1082         :type ip_version: str
1083         :type table_index: int
1084         """
1085         if isinstance(interface, basestring):
1086             sw_if_index = Topology.get_interface_sw_index(node, interface)
1087         else:
1088             sw_if_index = interface
1089
1090         with VatTerminal(node) as vat:
1091             vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
1092                                                     sw_if_index=sw_if_index,
1093                                                     ip_version=ip_version,
1094                                                     table_index=table_index)
1095
1096     @staticmethod
1097     def get_interface_classify_table(node, interface):
1098         """Get name of classify table for the given interface.
1099
1100         :param node: VPP node to get data from.
1101         :param interface: Name or sw_if_index of a specific interface.
1102         :type node: dict
1103         :type interface: str or int
1104         :returns: Classify table name.
1105         :rtype: str
1106         """
1107         if isinstance(interface, basestring):
1108             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1109         else:
1110             sw_if_index = interface
1111
1112         with VatTerminal(node) as vat:
1113             data = vat.vat_terminal_exec_cmd_from_template(
1114                 "classify_interface_table.vat",
1115                 sw_if_index=sw_if_index)
1116         return data[0]
1117
1118     @staticmethod
1119     def get_interface_vrf_table(node, interface):
1120         """Get vrf ID for the given interface.
1121
1122         :param node: VPP node.
1123         :param interface: Name or sw_if_index of a specific interface.
1124         :type node: dict
1125         :type interface: str or int
1126         :returns: vrf ID of the specified interface.
1127         :rtype: int
1128         """
1129
1130         if isinstance(interface, basestring):
1131             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1132         else:
1133             sw_if_index = interface
1134
1135         with VatTerminal(node) as vat:
1136             data = vat.vat_terminal_exec_cmd_from_template(
1137                 "interface_vrf_dump.vat",
1138                 sw_if_index=sw_if_index)
1139         return data[0]["vrf_id"]
1140
1141     @staticmethod
1142     def get_sw_if_index(node, interface_name):
1143         """Get sw_if_index for the given interface from actual interface dump.
1144
1145         :param node: VPP node to get interface data from.
1146         :param interface_name: Name of the specific interface.
1147         :type node: dict
1148         :type interface_name: str
1149         :returns: sw_if_index of the given interface.
1150         :rtype: str
1151         """
1152
1153         with VatTerminal(node) as vat:
1154             if_data = vat.vat_terminal_exec_cmd_from_template(
1155                 "interface_dump.vat")
1156         for interface in if_data[0]:
1157             if interface["interface_name"] == interface_name:
1158                 return interface["sw_if_index"]
1159
1160         return None
1161
1162     @staticmethod
1163     def vxlan_gpe_dump(node, interface_name=None):
1164         """Get VxLAN GPE data for the given interface.
1165
1166         :param node: VPP node to get interface data from.
1167         :param interface_name: Name of the specific interface. If None,
1168             information about all VxLAN GPE interfaces is returned.
1169         :type node: dict
1170         :type interface_name: str
1171         :returns: Dictionary containing data for the given VxLAN GPE interface
1172             or if interface=None, the list of dictionaries with all VxLAN GPE
1173             interfaces.
1174         :rtype: dict or list
1175         """
1176
1177         with VatTerminal(node) as vat:
1178             vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
1179                 "vxlan_gpe_dump.vat")
1180
1181         if interface_name:
1182             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
1183             if sw_if_index:
1184                 for vxlan_gpe in vxlan_gpe_data[0]:
1185                     if vxlan_gpe["sw_if_index"] == sw_if_index:
1186                         return vxlan_gpe
1187             return {}
1188
1189         return vxlan_gpe_data[0]
1190
1191     @staticmethod
1192     def vpp_proxy_arp_interface_enable(node, interface):
1193         """Enable proxy ARP on interface.
1194
1195         :param node: VPP node to enable proxy ARP on interface.
1196         :param interface: Interface to enable proxy ARP.
1197         :type node: dict
1198         :type interface: str or int
1199         """
1200         if isinstance(interface, basestring):
1201             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1202         else:
1203             sw_if_index = interface
1204
1205         with VatTerminal(node) as vat:
1206             vat.vat_terminal_exec_cmd_from_template(
1207                 "proxy_arp_intfc_enable.vat",
1208                 sw_if_index=sw_if_index)
1209
1210     @staticmethod
1211     def vpp_ip_source_check_setup(node, interface):
1212         """Setup Reverse Path Forwarding source check on interface.
1213
1214         :param node: Node to setup RPF source check.
1215         :param interface: Interface name to setup RPF source check.
1216         :type node: dict
1217         :type interface: str
1218         """
1219         with VatTerminal(node) as vat:
1220             vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
1221                                                     interface_name=interface)
1222
1223     @staticmethod
1224     def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
1225         """Assign VPP interface to specific VRF/FIB table.
1226
1227         :param node: VPP node where the FIB and interface are located.
1228         :param interface: Interface to be assigned to FIB.
1229         :param table_id: VRF table ID.
1230         :param ipv6: Assign to IPv6 table. Default False.
1231         :type node: dict
1232         :type interface: str or int
1233         :type table_id: int
1234         :type ipv6: bool
1235         """
1236         if isinstance(interface, basestring):
1237             sw_if_index = Topology.get_interface_sw_index(node, interface)
1238         else:
1239             sw_if_index = interface
1240
1241         ipv6 = 'ipv6' if ipv6 else ''
1242
1243         with VatTerminal(node) as vat:
1244             ret = vat.vat_terminal_exec_cmd_from_template(
1245                 "set_fib_to_interface.vat",
1246                 sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
1247
1248         if ret[0]["retval"] != 0:
1249             raise RuntimeError('Unable to assign interface to FIB node {}.'
1250                                .format(node))
1251
1252     @staticmethod
1253     def set_linux_interface_mac(node, interface, mac, namespace=None,
1254                                 vf_id=None):
1255         """Set MAC address for interface in linux.
1256
1257         :param node: Node where to execute command.
1258         :param interface: Interface in namespace.
1259         :param mac: MAC to be assigned to interface.
1260         :param namespace: Execute command in namespace. Optional
1261         :param vf_id: Virtual Function id. Optional
1262         :type node: dict
1263         :type interface: str
1264         :type mac: str
1265         :type namespace: str
1266         :type vf_id: int
1267         """
1268         mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \
1269             if vf_id is not None else 'address {mac}'.format(mac=mac)
1270         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1271
1272         cmd = ('{ns} ip link set {interface} {mac}'.
1273                format(ns=ns_str, interface=interface, mac=mac_str))
1274         exec_cmd_no_error(node, cmd, sudo=True)
1275
1276     @staticmethod
1277     def set_linux_interface_trust_on(node, interface, namespace=None,
1278                                      vf_id=None):
1279         """Set trust on (promisc) for interface in linux.
1280
1281         :param node: Node where to execute command.
1282         :param interface: Interface in namespace.
1283         :param namespace: Execute command in namespace. Optional
1284         :param vf_id: Virtual Function id. Optional
1285         :type node: dict
1286         :type interface: str
1287         :type namespace: str
1288         :type vf_id: int
1289         """
1290         trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \
1291             if vf_id is not None else 'trust on'
1292         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1293
1294         cmd = ('{ns} ip link set dev {interface} {trust}'.
1295                format(ns=ns_str, interface=interface, trust=trust_str))
1296         exec_cmd_no_error(node, cmd, sudo=True)
1297
1298     @staticmethod
1299     def set_linux_interface_spoof_off(node, interface, namespace=None,
1300                                       vf_id=None):
1301         """Set spoof off for interface in linux.
1302
1303         :param node: Node where to execute command.
1304         :param interface: Interface in namespace.
1305         :param namespace: Execute command in namespace. Optional
1306         :param vf_id: Virtual Function id. Optional
1307         :type node: dict
1308         :type interface: str
1309         :type namespace: str
1310         :type vf_id: int
1311         """
1312         spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \
1313             if vf_id is not None else 'spoof off'
1314         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1315
1316         cmd = ('{ns} ip link set dev {interface} {spoof}'.
1317                format(ns=ns_str, interface=interface, spoof=spoof_str))
1318         exec_cmd_no_error(node, cmd, sudo=True)
1319
1320     @staticmethod
1321     def init_avf_interface(node, ifc_key, numvfs=1, topology_type='L2'):
1322         """Init PCI device by creating VFs and bind them to vfio-pci for AVF
1323         driver testing on DUT.
1324
1325         :param node: DUT node.
1326         :param ifc_key: Interface key from topology file.
1327         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
1328         :param topology_type: Topology type.
1329         :type node: dict
1330         :type ifc_key: str
1331         :type numvfs: int
1332         :type topology_type: str
1333         :returns: Virtual Function topology interface keys.
1334         :rtype: list
1335         """
1336         ssh = SSH()
1337         ssh.connect(node)
1338
1339         # Read PCI address and driver.
1340         pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key)
1341         pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":")
1342         uio_driver = Topology.get_uio_driver(node)
1343         kernel_driver = Topology.get_interface_driver(node, ifc_key)
1344         current_driver = DUTSetup.get_pci_dev_driver(
1345             node, pf_pci_addr.replace(':', r'\:'))
1346
1347         VPPUtil.stop_vpp_service(node)
1348         if current_driver != kernel_driver:
1349             # PCI device must be re-bound to kernel driver before creating VFs.
1350             DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True)
1351             # Stop VPP to prevent deadlock.
1352             # Unbind from current driver.
1353             DUTSetup.pci_driver_unbind(node, pf_pci_addr)
1354             # Bind to kernel driver.
1355             DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver)
1356
1357         # Initialize PCI VFs
1358         DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs)
1359
1360         vf_ifc_keys = []
1361         # Set MAC address and bind each virtual function to uio driver.
1362         for vf_id in range(numvfs):
1363             vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2],
1364                                     pf_mac_addr[3], pf_mac_addr[4],
1365                                     pf_mac_addr[5], "{:02x}".format(vf_id)])
1366
1367             pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\
1368                 format(pci=pf_pci_addr)
1369             InterfaceUtil.set_linux_interface_trust_on(node, pf_dev,
1370                                                        vf_id=vf_id)
1371             if topology_type == 'L2':
1372                 InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev,
1373                                                             vf_id=vf_id)
1374             InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr,
1375                                                   vf_id=vf_id)
1376
1377             DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id)
1378             DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver)
1379
1380             # Add newly created ports into topology file
1381             vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key)
1382             vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
1383             vf_ifc_key = Topology.add_new_port(node, vf_ifc_name)
1384             Topology.update_interface_name(node, vf_ifc_key,
1385                                            vf_ifc_name+str(vf_id+1))
1386             Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr)
1387             Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr)
1388             vf_ifc_keys.append(vf_ifc_key)
1389
1390         return vf_ifc_keys
1391
1392     @staticmethod
1393     def vpp_create_multiple_vxlan_ipv4_tunnels(
1394             node, node_vxlan_if, node_vlan_if, op_node, op_node_if,
1395             n_tunnels, vni_start, src_ip_start, dst_ip_start, ip_step, ip_limit,
1396             bd_id_start):
1397         """Create multiple VXLAN tunnel interfaces and VLAN sub-interfaces on
1398         VPP node.
1399
1400         Put each pair of VXLAN tunnel interface and VLAN sub-interface to
1401         separate bridge-domain.
1402
1403         :param node: VPP node to create VXLAN tunnel interfaces.
1404         :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1405             interfaces.
1406         :param node_vlan_if: VPP node interface key to create VLAN
1407             sub-interface.
1408         :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1409         :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1410             interfaces.
1411         :param n_tunnels: Number of tunnel interfaces to create.
1412         :param vni_start: VNI start ID.
1413         :param src_ip_start: VXLAN tunnel source IP address start.
1414         :param dst_ip_start: VXLAN tunnel destination IP address start.
1415         :param ip_step: IP address incremental step.
1416         :param ip_limit: IP address limit.
1417         :param bd_id_start: Bridge-domain ID start.
1418         :type node: dict
1419         :type node_vxlan_if: str
1420         :type node_vlan_if: str
1421         :type op_node: dict
1422         :type op_node_if: str
1423         :type n_tunnels: int
1424         :type vni_start: int
1425         :type src_ip_start: str
1426         :type dst_ip_start: str
1427         :type ip_step: int
1428         :type ip_limit: str
1429         :type bd_id_start: int
1430         """
1431         # configure IPs, create VXLAN interfaces and VLAN sub-interfaces
1432         vxlan_count = InterfaceUtil.vpp_create_vxlan_and_vlan_interfaces(
1433             node, node_vxlan_if, node_vlan_if, n_tunnels, vni_start,
1434             src_ip_start, dst_ip_start, ip_step, ip_limit)
1435
1436         # update topology with VXLAN interfaces and VLAN sub-interfaces data
1437         # and put interfaces up
1438         InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_up(
1439             node, vxlan_count, node_vlan_if)
1440
1441         # configure bridge domains, ARPs and routes
1442         InterfaceUtil.vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1443             node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1444             ip_step, bd_id_start)
1445
1446     @staticmethod
1447     def vpp_create_vxlan_and_vlan_interfaces(
1448             node, node_vxlan_if, node_vlan_if, vxlan_count, vni_start,
1449             src_ip_start, dst_ip_start, ip_step, ip_limit):
1450         """
1451         Configure IPs, create VXLAN interfaces and VLAN sub-interfaces on VPP
1452         node.
1453
1454         :param node: VPP node.
1455         :param node_vxlan_if: VPP node interface key to create VXLAN tunnel
1456             interfaces.
1457         :param node_vlan_if: VPP node interface key to create VLAN
1458             sub-interface.
1459         :param vxlan_count: Number of tunnel interfaces to create.
1460         :param vni_start: VNI start ID.
1461         :param src_ip_start: VXLAN tunnel source IP address start.
1462         :param dst_ip_start: VXLAN tunnel destination IP address start.
1463         :param ip_step: IP address incremental step.
1464         :param ip_limit: IP address limit.
1465         :type node: dict
1466         :type node_vxlan_if: str
1467         :type node_vlan_if: str
1468         :type vxlan_count: int
1469         :type vni_start: int
1470         :type src_ip_start: str
1471         :type dst_ip_start: str
1472         :type ip_step: int
1473         :type ip_limit: str
1474         :returns: Number of created VXLAN interfaces.
1475         :rtype: int
1476         """
1477         commands = list()
1478
1479         src_ip_start_int = IPUtil.ip_to_int(src_ip_start)
1480         dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1481         ip_limit_int = IPUtil.ip_to_int(ip_limit)
1482
1483         tmp_fn = '/tmp/create_vxlan_interfaces.config'
1484         for i in range(0, vxlan_count):
1485             src_ip_int = src_ip_start_int + i * ip_step
1486             dst_ip_int = dst_ip_start_int + i * ip_step
1487             if src_ip_int > ip_limit_int or dst_ip_int > ip_limit_int:
1488                 logger.warn("Can't do more iterations - IPv4 address limit "
1489                             "has been reached.")
1490                 vxlan_count = i
1491                 break
1492             src_ip = IPUtil.int_to_ip(src_ip_int)
1493             dst_ip = IPUtil.int_to_ip(dst_ip_int)
1494             commands.append(
1495                 'sw_interface_add_del_address sw_if_index {sw_idx} {ip}/32\n'
1496                 .format(sw_idx=Topology.get_interface_sw_index(
1497                     node, node_vxlan_if), ip=src_ip))
1498             commands.append(
1499                 'vxlan_add_del_tunnel src {src_ip} dst {dst_ip} vni {vni}\n'
1500                 .format(src_ip=src_ip, dst_ip=dst_ip, vni=vni_start+i))
1501             commands.append(
1502                 'create_vlan_subif sw_if_index {sw_idx} vlan {vlan}\n'
1503                 .format(sw_idx=Topology.get_interface_sw_index(
1504                     node, node_vlan_if), vlan=i+1))
1505
1506         VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1507
1508         return vxlan_count
1509
1510     @staticmethod
1511     def vpp_put_vxlan_and_vlan_interfaces_up(node, vxlan_count, node_vlan_if):
1512         """
1513         Update topology with VXLAN interfaces and VLAN sub-interfaces data
1514         and put interfaces up.
1515
1516         :param node: VPP node.
1517         :param vxlan_count: Number of tunnel interfaces.
1518         :param node_vlan_if: VPP node interface key where VLAN sub-interfaces
1519             have been created.
1520         :type node: dict
1521         :type vxlan_count: int
1522         :type node_vlan_if: str
1523         """
1524         with VatTerminal(node) as vat_ter:
1525             if_data = vat_ter.vat_terminal_exec_cmd_from_template(
1526                 'interface_dump.vat')[0]
1527
1528         tmp_fn = '/tmp/put_subinterfaces_up.config'
1529         commands = list()
1530         for i in range(0, vxlan_count):
1531             vxlan_subif_key = Topology.add_new_port(node, 'vxlan_tunnel')
1532             vxlan_subif_name = 'vxlan_tunnel{nr}'.format(nr=i)
1533             vxlan_found = False
1534             vxlan_subif_idx = None
1535             vlan_subif_key = Topology.add_new_port(node, 'vlan_subif')
1536             vlan_subif_name = '{if_name}.{vlan}'.format(
1537                 if_name=Topology.get_interface_name(
1538                     node, node_vlan_if), vlan=i+1)
1539             vlan_found = False
1540             vlan_idx = None
1541             for data in if_data:
1542                 if_name = data['interface_name']
1543                 if not vxlan_found and if_name == vxlan_subif_name:
1544                     vxlan_subif_idx = data['sw_if_index']
1545                     vxlan_found = True
1546                 elif not vlan_found and if_name == vlan_subif_name:
1547                     vlan_idx = data['sw_if_index']
1548                     vlan_found = True
1549                 if vxlan_found and vlan_found:
1550                     break
1551             Topology.update_interface_sw_if_index(
1552                 node, vxlan_subif_key, vxlan_subif_idx)
1553             Topology.update_interface_name(
1554                 node, vxlan_subif_key, vxlan_subif_name)
1555             commands.append(
1556                 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1557                 .format(sw_idx=vxlan_subif_idx))
1558             Topology.update_interface_sw_if_index(
1559                 node, vlan_subif_key, vlan_idx)
1560             Topology.update_interface_name(
1561                 node, vlan_subif_key, vlan_subif_name)
1562             commands.append(
1563                 'sw_interface_set_flags sw_if_index {sw_idx} admin-up link-up\n'
1564                 .format(sw_idx=vlan_idx))
1565
1566         VatExecutor().write_and_execute_script(node, tmp_fn, commands)
1567
1568     @staticmethod
1569     def vpp_put_vxlan_and_vlan_interfaces_to_bridge_domain(
1570             node, node_vxlan_if, vxlan_count, op_node, op_node_if, dst_ip_start,
1571             ip_step, bd_id_start):
1572         """
1573         Configure ARPs and routes for VXLAN interfaces and put each pair of
1574         VXLAN tunnel interface and VLAN sub-interface to separate bridge-domain.
1575
1576         :param node: VPP node.
1577         :param node_vxlan_if: VPP node interface key where VXLAN tunnel
1578             interfaces have been created.
1579         :param vxlan_count: Number of tunnel interfaces.
1580         :param op_node: Opposite VPP node for VXLAN tunnel interfaces.
1581         :param op_node_if: Opposite VPP node interface key for VXLAN tunnel
1582             interfaces.
1583         :param dst_ip_start: VXLAN tunnel destination IP address start.
1584         :param ip_step: IP address incremental step.
1585         :param bd_id_start: Bridge-domain ID start.
1586         :type node: dict
1587         :type node_vxlan_if: str
1588         :type vxlan_count: int
1589         :type op_node: dict
1590         :type op_node_if:
1591         :type dst_ip_start: str
1592         :type ip_step: int
1593         :type bd_id_start: int
1594         """
1595         sw_idx_vxlan = Topology.get_interface_sw_index(node, node_vxlan_if)
1596
1597         dst_ip_start_int = IPUtil.ip_to_int(dst_ip_start)
1598
1599         tmp_fn = '/tmp/configure_routes_and_bridge_domains.config'
1600         commands = list()
1601         for i in range(0, vxlan_count):
1602             dst_ip = IPUtil.int_to_ip(dst_ip_start_int + i * ip_step)
1603             commands.append(
1604                 'ip_neighbor_add_del sw_if_index {sw_idx} dst {ip} mac {mac}\n'
1605                 .format(sw_idx=sw_idx_vxlan, ip=dst_ip,
1606                         mac=Topology.get_interface_mac(op_node, op_node_if)))
1607             commands.append(
1608                 'ip_add_del_route {ip}/32 via {ip} sw_if_index {sw_idx}'
1609                 ' resolve-attempts 10 count 1\n'.format(
1610                     ip=dst_ip, sw_idx=sw_idx_vxlan))
1611             bd_id = bd_id_start + i
1612             subif_id = i + 1
1613             commands.append(
1614                 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1615                 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1616                     node, 'vxlan_tunnel{nr}'.format(nr=subif_id)), bd_id=bd_id))
1617             commands.append(
1618                 'sw_interface_set_l2_bridge sw_if_index {sw_idx} bd_id {bd_id} '
1619                 'shg 0 enable\n'.format(sw_idx=Topology.get_interface_sw_index(
1620                     node, 'vlan_subif{nr}'.format(nr=subif_id)), bd_id=bd_id))
1621
1622         VatExecutor().write_and_execute_script(node, tmp_fn, commands)