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