CSIT-1205 Create AVF driver test
[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
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                             raise ValueError
586                     except ValueError:
587                         logger.trace('Reading numa location failed for: {0}'\
588                             .format(if_pci))
589                     else:
590                         Topology.set_interface_numa_node(node, if_key,
591                                                          numa_node)
592                         break
593             else:
594                 raise RuntimeError('Update numa node failed for: {0}'\
595                     .format(if_pci))
596
597     @staticmethod
598     def update_all_numa_nodes(nodes, skip_tg=False):
599         """For all nodes and all their interfaces from topology file update numa
600         node information based on information from the node.
601
602         :param nodes: Nodes in the topology.
603         :param skip_tg: Skip TG node
604         :type nodes: dict
605         :type skip_tg: bool
606         :returns: Nothing.
607         """
608         for node in nodes.values():
609             if node['type'] == NodeType.DUT:
610                 InterfaceUtil.iface_update_numa_node(node)
611             elif node['type'] == NodeType.TG and not skip_tg:
612                 InterfaceUtil.iface_update_numa_node(node)
613
614     @staticmethod
615     def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
616                                                numa_node=False):
617         """Update interface names on all nodes in DICT__nodes.
618
619         This method updates the topology dictionary by querying interface lists
620         of all nodes mentioned in the topology dictionary.
621
622         :param nodes: Nodes in the topology.
623         :param skip_tg: Skip TG node
624         :param numa_node: Retrieve numa_node location.
625         :type nodes: dict
626         :type skip_tg: bool
627         :type numa_node: bool
628         """
629         for node_data in nodes.values():
630             if node_data['type'] == NodeType.DUT:
631                 InterfaceUtil.update_vpp_interface_data_on_node(node_data)
632             elif node_data['type'] == NodeType.TG and not skip_tg:
633                 InterfaceUtil.update_tg_interface_data_on_node(node_data)
634
635             if numa_node:
636                 if node_data['type'] == NodeType.DUT:
637                     InterfaceUtil.iface_update_numa_node(node_data)
638                 elif node_data['type'] == NodeType.TG and not skip_tg:
639                     InterfaceUtil.iface_update_numa_node(node_data)
640
641     @staticmethod
642     def create_vlan_subinterface(node, interface, vlan):
643         """Create VLAN subinterface on node.
644
645         :param node: Node to add VLAN subinterface on.
646         :param interface: Interface name on which create VLAN subinterface.
647         :param vlan: VLAN ID of the subinterface to be created.
648         :type node: dict
649         :type interface: str
650         :type vlan: int
651         :returns: Name and index of created subinterface.
652         :rtype: tuple
653         :raises RuntimeError: if it is unable to create VLAN subinterface on the
654             node.
655         """
656         iface_key = Topology.get_interface_by_name(node, interface)
657         sw_if_index = Topology.get_interface_sw_index(node, iface_key)
658
659         output = VatExecutor.cmd_from_template(node, "create_vlan_subif.vat",
660                                                sw_if_index=sw_if_index,
661                                                vlan=vlan)
662         if output[0]["retval"] == 0:
663             sw_subif_idx = output[0]["sw_if_index"]
664             logger.trace('VLAN subinterface with sw_if_index {} and VLAN ID {} '
665                          'created on node {}'.format(sw_subif_idx,
666                                                      vlan, node['host']))
667             if_key = Topology.add_new_port(node, "vlan_subif")
668             Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx)
669             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx)
670             Topology.update_interface_name(node, if_key, ifc_name)
671         else:
672             raise RuntimeError('Unable to create VLAN subinterface on node {}'
673                                .format(node['host']))
674
675         with VatTerminal(node, False) as vat:
676             vat.vat_terminal_exec_cmd('exec show interfaces')
677
678         return '{}.{}'.format(interface, vlan), sw_subif_idx
679
680     @staticmethod
681     def create_vxlan_interface(node, vni, source_ip, destination_ip):
682         """Create VXLAN interface and return sw if index of created interface.
683
684         Executes "vxlan_add_del_tunnel src {src} dst {dst} vni {vni}" VAT
685         command on the node.
686
687         :param node: Node where to create VXLAN interface.
688         :param vni: VXLAN Network Identifier.
689         :param source_ip: Source IP of a VXLAN Tunnel End Point.
690         :param destination_ip: Destination IP of a VXLAN Tunnel End Point.
691         :type node: dict
692         :type vni: int
693         :type source_ip: str
694         :type destination_ip: str
695         :returns: SW IF INDEX of created interface.
696         :rtype: int
697         :raises RuntimeError: if it is unable to create VxLAN interface on the
698             node.
699         """
700         output = VatExecutor.cmd_from_template(node, "vxlan_create.vat",
701                                                src=source_ip,
702                                                dst=destination_ip,
703                                                vni=vni)
704         output = output[0]
705
706         if output["retval"] == 0:
707             sw_if_idx = output["sw_if_index"]
708             if_key = Topology.add_new_port(node, "vxlan_tunnel")
709             Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
710             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
711             Topology.update_interface_name(node, if_key, ifc_name)
712             return sw_if_idx
713         else:
714             raise RuntimeError("Unable to create VXLAN interface on node {0}"
715                                .format(node))
716
717     @staticmethod
718     def vxlan_dump(node, interface=None):
719         """Get VxLAN data for the given interface.
720
721         :param node: VPP node to get interface data from.
722         :param interface: Numeric index or name string of a specific interface.
723             If None, information about all VxLAN interfaces is returned.
724         :type node: dict
725         :type interface: int or str
726         :returns: Dictionary containing data for the given VxLAN interface or if
727             interface=None, the list of dictionaries with all VxLAN interfaces.
728         :rtype: dict or list
729         :raises TypeError: if the data type of interface is neither basestring
730             nor int.
731         """
732         param = "sw_if_index"
733         if interface is None:
734             param = ''
735             sw_if_index = ''
736         elif isinstance(interface, basestring):
737             sw_if_index = Topology.get_interface_sw_index(node, interface)
738         elif isinstance(interface, int):
739             sw_if_index = interface
740         else:
741             raise TypeError("Wrong interface format {0}".format(interface))
742
743         with VatTerminal(node) as vat:
744             response = vat.vat_terminal_exec_cmd_from_template(
745                 "vxlan_dump.vat", param=param, sw_if_index=sw_if_index)
746
747         if sw_if_index:
748             for vxlan in response[0]:
749                 if vxlan["sw_if_index"] == sw_if_index:
750                     return vxlan
751             return {}
752         return response[0]
753
754     @staticmethod
755     def vhost_user_dump(node):
756         """Get vhost-user data for the given node.
757
758         :param node: VPP node to get interface data from.
759         :type node: dict
760         :returns: List of dictionaries with all vhost-user interfaces.
761         :rtype: list
762         """
763         with VatTerminal(node) as vat:
764             response = vat.vat_terminal_exec_cmd_from_template(
765                 "vhost_user_dump.vat")
766
767         return response[0]
768
769     @staticmethod
770     def tap_dump(node, name=None):
771         """Get all TAP interface data from the given node, or data about
772         a specific TAP interface.
773
774         :param node: VPP node to get data from.
775         :param name: Optional name of a specific TAP interface.
776         :type node: dict
777         :type name: str
778         :returns: Dictionary of information about a specific TAP interface, or
779             a List of dictionaries containing all TAP data for the given node.
780         :rtype: dict or list
781         """
782         with VatTerminal(node) as vat:
783             response = vat.vat_terminal_exec_cmd_from_template(
784                 "tap_dump.vat")
785         if name is None:
786             return response[0]
787         for item in response[0]:
788             if name == item['dev_name']:
789                 return item
790         return {}
791
792     @staticmethod
793     def create_subinterface(node, interface, sub_id, outer_vlan_id=None,
794                             inner_vlan_id=None, type_subif=None):
795         """Create sub-interface on node. It is possible to set required
796         sub-interface type and VLAN tag(s).
797
798         :param node: Node to add sub-interface.
799         :param interface: Interface name on which create sub-interface.
800         :param sub_id: ID of the sub-interface to be created.
801         :param outer_vlan_id: Optional outer VLAN ID.
802         :param inner_vlan_id: Optional inner VLAN ID.
803         :param type_subif: Optional type of sub-interface. Values supported by
804             VPP: [no_tags] [one_tag] [two_tags] [dot1ad] [exact_match]
805             [default_sub]
806         :type node: dict
807         :type interface: str or int
808         :type sub_id: int
809         :type outer_vlan_id: int
810         :type inner_vlan_id: int
811         :type type_subif: str
812         :returns: Name and index of created sub-interface.
813         :rtype: tuple
814         :raises RuntimeError: If it is not possible to create sub-interface.
815         """
816
817         outer_vlan_id = 'outer_vlan_id {0}'.format(outer_vlan_id)\
818             if outer_vlan_id else ''
819
820         inner_vlan_id = 'inner_vlan_id {0}'.format(inner_vlan_id)\
821             if inner_vlan_id else ''
822
823         if type_subif is None:
824             type_subif = ''
825
826         if isinstance(interface, basestring):
827             iface_key = Topology.get_interface_by_name(node, interface)
828             sw_if_index = Topology.get_interface_sw_index(node, iface_key)
829         else:
830             sw_if_index = interface
831
832         output = VatExecutor.cmd_from_template(node, "create_sub_interface.vat",
833                                                sw_if_index=sw_if_index,
834                                                sub_id=sub_id,
835                                                outer_vlan_id=outer_vlan_id,
836                                                inner_vlan_id=inner_vlan_id,
837                                                type_subif=type_subif)
838
839         if output[0]["retval"] == 0:
840             sw_subif_idx = output[0]["sw_if_index"]
841             logger.trace('Created subinterface with index {}'
842                          .format(sw_subif_idx))
843             if_key = Topology.add_new_port(node, "subinterface")
844             Topology.update_interface_sw_if_index(node, if_key, sw_subif_idx)
845             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_subif_idx)
846             Topology.update_interface_name(node, if_key, ifc_name)
847         else:
848             raise RuntimeError('Unable to create sub-interface on node {}'
849                                .format(node['host']))
850
851         with VatTerminal(node, json_param=False) as vat:
852             vat.vat_terminal_exec_cmd('exec show interfaces')
853
854         name = '{}.{}'.format(interface, sub_id)
855         return name, sw_subif_idx
856
857     @staticmethod
858     def create_gre_tunnel_interface(node, source_ip, destination_ip):
859         """Create GRE tunnel interface on node.
860
861         :param node: VPP node to add tunnel interface.
862         :param source_ip: Source of the GRE tunnel.
863         :param destination_ip: Destination of the GRE tunnel.
864         :type node: dict
865         :type source_ip: str
866         :type destination_ip: str
867         :returns: Name and index of created GRE tunnel interface.
868         :rtype: tuple
869         :raises RuntimeError: If unable to create GRE tunnel interface.
870         """
871         output = VatExecutor.cmd_from_template(node, "create_gre.vat",
872                                                src=source_ip,
873                                                dst=destination_ip)
874         output = output[0]
875
876         if output["retval"] == 0:
877             sw_if_idx = output["sw_if_index"]
878
879             vat_executor = VatExecutor()
880             vat_executor.execute_script_json_out("dump_interfaces.vat", node)
881             interface_dump_json = vat_executor.get_script_stdout()
882             name = VatJsonUtil.get_interface_name_from_json(
883                 interface_dump_json, sw_if_idx)
884
885             if_key = Topology.add_new_port(node, "gre_tunnel")
886             Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
887             Topology.update_interface_name(node, if_key, name)
888
889             return name, sw_if_idx
890         else:
891             raise RuntimeError('Unable to create GRE tunnel on node {}.'
892                                .format(node))
893
894     @staticmethod
895     def vpp_create_loopback(node):
896         """Create loopback interface on VPP node.
897
898         :param node: Node to create loopback interface on.
899         :type node: dict
900         :returns: SW interface index.
901         :rtype: int
902         :raises RuntimeError: If it is not possible to create loopback on the
903             node.
904         """
905         out = VatExecutor.cmd_from_template(node, "create_loopback.vat")
906         if out[0].get('retval') == 0:
907             sw_if_idx = out[0].get('sw_if_index')
908             if_key = Topology.add_new_port(node, "loopback")
909             Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
910             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
911             Topology.update_interface_name(node, if_key, ifc_name)
912             return sw_if_idx
913         else:
914             raise RuntimeError('Create loopback failed on node "{}"'
915                                .format(node['host']))
916
917     @staticmethod
918     def vpp_create_bond_interface(node, mode, load_balance=None, mac=None):
919         """Create bond interface on VPP node.
920
921         :param node: DUT node from topology.
922         :param mode: Link bonding mode.
923         :param load_balance: Load balance (optional, valid for xor and lacp
924             modes, otherwise ignored).
925         :param mac: MAC address to assign to the bond interface (optional).
926         :type node: dict
927         :type mode: str
928         :type load_balance: str
929         :type mac: str
930         :returns: Interface key (name) in topology.
931         :rtype: str
932         :raises RuntimeError: If it is not possible to create bond interface on
933             the node.
934         """
935         hw_addr = '' if mac is None else 'hw-addr {mac}'.format(mac=mac)
936         ldb = '' if load_balance is None \
937             else 'lb {ldb}'.format(ldb=load_balance)
938
939         output = VatExecutor.cmd_from_template(
940             node, 'create_bond_interface.vat', mode=mode, lb=ldb, mac=hw_addr)
941
942         if output[0].get('retval') == 0:
943             sw_if_idx = output[0].get('sw_if_index')
944             InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
945                                             ifc_pfx='eth_bond')
946             if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
947             return if_key
948         else:
949             raise RuntimeError('Create bond interface failed on "{host}"'.
950                                format(host=node['host']))
951
952     @staticmethod
953     def add_eth_interface(node, ifc_name=None, sw_if_idx=None, ifc_pfx=None):
954         """Add ethernet interface to current topology.
955
956         :param node: DUT node from topology.
957         :param ifc_name: Name of the interface.
958         :param sw_if_idx: SW interface index.
959         :param ifc_pfx: Interface key prefix.
960         :type node: dict
961         :type ifc_name: str
962         :type sw_if_idx: int
963         :type ifc_pfx: str
964         """
965         if_key = Topology.add_new_port(node, ifc_pfx)
966
967         vat_executor = VatExecutor()
968         vat_executor.execute_script_json_out("dump_interfaces.vat", node)
969         interface_dump_json = vat_executor.get_script_stdout()
970
971         if ifc_name and sw_if_idx is None:
972             sw_if_idx = VatJsonUtil.get_interface_sw_index_from_json(
973                 interface_dump_json, ifc_name)
974         Topology.update_interface_sw_if_index(node, if_key, sw_if_idx)
975         if sw_if_idx and ifc_name is None:
976             ifc_name = InterfaceUtil.vpp_get_interface_name(node, sw_if_idx)
977         Topology.update_interface_name(node, if_key, ifc_name)
978         ifc_mac = VatJsonUtil.get_interface_mac_from_json(
979             interface_dump_json, sw_if_idx)
980         Topology.update_interface_mac_address(node, if_key, ifc_mac)
981
982     @staticmethod
983     def vpp_create_avf_interface(node, vf_pci_addr):
984         """Create AVF interface on VPP node.
985
986         :param node: DUT node from topology.
987         :param vf_pci_addr: Virtual Function PCI address.
988         :type node: dict
989         :type vf_pci_addr: str
990         :returns: Interface key (name) in topology.
991         :rtype: str
992         :raises RuntimeError: If it is not possible to create AVF interface on
993             the node.
994         """
995         with VatTerminal(node, json_param=False) as vat:
996             vat.vat_terminal_exec_cmd_from_template('create_avf_interface.vat',
997                                                     vf_pci_addr=vf_pci_addr)
998             output = vat.vat_stdout
999
1000         if output is not None:
1001             sw_if_idx = int(output.split()[4])
1002             InterfaceUtil.add_eth_interface(node, sw_if_idx=sw_if_idx,
1003                                             ifc_pfx='eth_avf')
1004             if_key = Topology.get_interface_by_sw_index(node, sw_if_idx)
1005             return if_key
1006         else:
1007             raise RuntimeError('Create AVF interface failed on {host}'.
1008                                format(host=node['host']))
1009
1010     @staticmethod
1011     def vpp_enslave_physical_interface(node, interface, bond_interface):
1012         """Enslave physical interface to bond interface on VPP node.
1013
1014         :param node: DUT node from topology.
1015         :param interface: Physical interface key from topology file.
1016         :param bond_interface: Load balance
1017         :type node: dict
1018         :type interface: str
1019         :type bond_interface: str
1020         :raises RuntimeError: If it is not possible to enslave physical
1021             interface to bond interface on the node.
1022         """
1023         ifc = Topology.get_interface_sw_index(node, interface)
1024         bond_ifc = Topology.get_interface_sw_index(node, bond_interface)
1025
1026         output = VatExecutor.cmd_from_template(
1027             node, 'enslave_physical_interface.vat', p_int=ifc, b_int=bond_ifc)
1028
1029         retval = output[0].get('retval', None)
1030         if retval is None or int(retval) != 0:
1031             raise RuntimeError('Enslave physical interface {ifc} to bond '
1032                                'interface {bond} failed on node "{n}"'
1033                                .format(ifc=interface, bond=bond_interface,
1034                                        n=node['host']))
1035
1036     @staticmethod
1037     def vpp_show_bond_data_on_node(node, details=False):
1038         """Show (detailed) bond information on VPP node.
1039
1040         :param node: DUT node from topology.
1041         :param details: If detailed information is required or not.
1042         :type node: dict
1043         :type details: bool
1044         """
1045         cmd = 'exec show bond details' if details else 'exec show bond'
1046         with VatTerminal(node, json_param=False) as vat:
1047             vat.vat_terminal_exec_cmd(cmd)
1048
1049     @staticmethod
1050     def vpp_show_bond_data_on_all_nodes(nodes, details=False):
1051         """Show (detailed) bond information on all VPP nodes in DICT__nodes.
1052
1053         :param nodes: Nodes in the topology.
1054         :param details: If detailed information is required or not.
1055         :type nodes: dict
1056         :type details: bool
1057         """
1058         for node_data in nodes.values():
1059             if node_data['type'] == NodeType.DUT:
1060                 InterfaceUtil.vpp_show_bond_data_on_node(node_data, details)
1061
1062     @staticmethod
1063     def vpp_enable_input_acl_interface(node, interface, ip_version,
1064                                        table_index):
1065         """Enable input acl on interface.
1066
1067         :param node: VPP node to setup interface for input acl.
1068         :param interface: Interface to setup input acl.
1069         :param ip_version: Version of IP protocol.
1070         :param table_index: Classify table index.
1071         :type node: dict
1072         :type interface: str or int
1073         :type ip_version: str
1074         :type table_index: int
1075         """
1076         if isinstance(interface, basestring):
1077             sw_if_index = Topology.get_interface_sw_index(node, interface)
1078         else:
1079             sw_if_index = interface
1080
1081         with VatTerminal(node) as vat:
1082             vat.vat_terminal_exec_cmd_from_template("input_acl_int.vat",
1083                                                     sw_if_index=sw_if_index,
1084                                                     ip_version=ip_version,
1085                                                     table_index=table_index)
1086
1087     @staticmethod
1088     def get_interface_classify_table(node, interface):
1089         """Get name of classify table for the given interface.
1090
1091         :param node: VPP node to get data from.
1092         :param interface: Name or sw_if_index of a specific interface.
1093         :type node: dict
1094         :type interface: str or int
1095         :returns: Classify table name.
1096         :rtype: str
1097         """
1098         if isinstance(interface, basestring):
1099             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1100         else:
1101             sw_if_index = interface
1102
1103         with VatTerminal(node) as vat:
1104             data = vat.vat_terminal_exec_cmd_from_template(
1105                 "classify_interface_table.vat",
1106                 sw_if_index=sw_if_index)
1107         return data[0]
1108
1109     @staticmethod
1110     def get_interface_vrf_table(node, interface):
1111         """Get vrf ID for the given interface.
1112
1113         :param node: VPP node.
1114         :param interface: Name or sw_if_index of a specific interface.
1115         :type node: dict
1116         :type interface: str or int
1117         :returns: vrf ID of the specified interface.
1118         :rtype: int
1119         """
1120
1121         if isinstance(interface, basestring):
1122             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1123         else:
1124             sw_if_index = interface
1125
1126         with VatTerminal(node) as vat:
1127             data = vat.vat_terminal_exec_cmd_from_template(
1128                 "interface_vrf_dump.vat",
1129                 sw_if_index=sw_if_index)
1130         return data[0]["vrf_id"]
1131
1132     @staticmethod
1133     def get_sw_if_index(node, interface_name):
1134         """Get sw_if_index for the given interface from actual interface dump.
1135
1136         :param node: VPP node to get interface data from.
1137         :param interface_name: Name of the specific interface.
1138         :type node: dict
1139         :type interface_name: str
1140         :returns: sw_if_index of the given interface.
1141         :rtype: str
1142         """
1143
1144         with VatTerminal(node) as vat:
1145             if_data = vat.vat_terminal_exec_cmd_from_template(
1146                 "interface_dump.vat")
1147         for interface in if_data[0]:
1148             if interface["interface_name"] == interface_name:
1149                 return interface["sw_if_index"]
1150
1151         return None
1152
1153     @staticmethod
1154     def vxlan_gpe_dump(node, interface_name=None):
1155         """Get VxLAN GPE data for the given interface.
1156
1157         :param node: VPP node to get interface data from.
1158         :param interface_name: Name of the specific interface. If None,
1159             information about all VxLAN GPE interfaces is returned.
1160         :type node: dict
1161         :type interface_name: str
1162         :returns: Dictionary containing data for the given VxLAN GPE interface
1163             or if interface=None, the list of dictionaries with all VxLAN GPE
1164             interfaces.
1165         :rtype: dict or list
1166         """
1167
1168         with VatTerminal(node) as vat:
1169             vxlan_gpe_data = vat.vat_terminal_exec_cmd_from_template(
1170                 "vxlan_gpe_dump.vat")
1171
1172         if interface_name:
1173             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface_name)
1174             if sw_if_index:
1175                 for vxlan_gpe in vxlan_gpe_data[0]:
1176                     if vxlan_gpe["sw_if_index"] == sw_if_index:
1177                         return vxlan_gpe
1178             return {}
1179
1180         return vxlan_gpe_data[0]
1181
1182     @staticmethod
1183     def vpp_proxy_arp_interface_enable(node, interface):
1184         """Enable proxy ARP on interface.
1185
1186         :param node: VPP node to enable proxy ARP on interface.
1187         :param interface: Interface to enable proxy ARP.
1188         :type node: dict
1189         :type interface: str or int
1190         """
1191         if isinstance(interface, basestring):
1192             sw_if_index = InterfaceUtil.get_sw_if_index(node, interface)
1193         else:
1194             sw_if_index = interface
1195
1196         with VatTerminal(node) as vat:
1197             vat.vat_terminal_exec_cmd_from_template(
1198                 "proxy_arp_intfc_enable.vat",
1199                 sw_if_index=sw_if_index)
1200
1201     @staticmethod
1202     def vpp_ip_source_check_setup(node, interface):
1203         """Setup Reverse Path Forwarding source check on interface.
1204
1205         :param node: Node to setup RPF source check.
1206         :param interface: Interface name to setup RPF source check.
1207         :type node: dict
1208         :type interface: str
1209         """
1210         with VatTerminal(node) as vat:
1211             vat.vat_terminal_exec_cmd_from_template("ip_source_check.vat",
1212                                                     interface_name=interface)
1213
1214     @staticmethod
1215     def assign_interface_to_fib_table(node, interface, table_id, ipv6=False):
1216         """Assign VPP interface to specific VRF/FIB table.
1217
1218         :param node: VPP node where the FIB and interface are located.
1219         :param interface: Interface to be assigned to FIB.
1220         :param table_id: VRF table ID.
1221         :param ipv6: Assign to IPv6 table. Default False.
1222         :type node: dict
1223         :type interface: str or int
1224         :type table_id: int
1225         :type ipv6: bool
1226         """
1227         if isinstance(interface, basestring):
1228             sw_if_index = Topology.get_interface_sw_index(node, interface)
1229         else:
1230             sw_if_index = interface
1231
1232         ipv6 = 'ipv6' if ipv6 else ''
1233
1234         with VatTerminal(node) as vat:
1235             ret = vat.vat_terminal_exec_cmd_from_template(
1236                 "set_fib_to_interface.vat",
1237                 sw_index=sw_if_index, vrf=table_id, ipv6=ipv6)
1238
1239         if ret[0]["retval"] != 0:
1240             raise RuntimeError('Unable to assign interface to FIB node {}.'
1241                                .format(node))
1242
1243     @staticmethod
1244     def set_linux_interface_mac(node, interface, mac, namespace=None,
1245                                 vf_id=None):
1246         """Set MAC address for interface in linux.
1247
1248         :param node: Node where to execute command.
1249         :param interface: Interface in namespace.
1250         :param mac: MAC to be assigned to interface.
1251         :param namespace: Execute command in namespace. Optional
1252         :param vf_id: Virtual Function id. Optional
1253         :type node: dict
1254         :type interface: str
1255         :type mac: str
1256         :type namespace: str
1257         :type vf_id: int
1258         """
1259         mac_str = 'vf {vf_id} mac {mac}'.format(vf_id=vf_id, mac=mac) \
1260             if vf_id is not None else 'address {mac}'.format(mac=mac)
1261         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1262
1263         cmd = ('{ns} ip link set {interface} {mac}'.
1264                format(ns=ns_str, interface=interface, mac=mac_str))
1265         exec_cmd_no_error(node, cmd, sudo=True)
1266
1267     @staticmethod
1268     def set_linux_interface_trust_on(node, interface, namespace=None,
1269                                      vf_id=None):
1270         """Set trust on (promisc) for interface in linux.
1271
1272         :param node: Node where to execute command.
1273         :param interface: Interface in namespace.
1274         :param namespace: Execute command in namespace. Optional
1275         :param vf_id: Virtual Function id. Optional
1276         :type node: dict
1277         :type interface: str
1278         :type namespace: str
1279         :type vf_id: int
1280         """
1281         trust_str = 'vf {vf_id} trust on'.format(vf_id=vf_id) \
1282             if vf_id is not None else 'trust on'
1283         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1284
1285         cmd = ('{ns} ip link set dev {interface} {trust}'.
1286                format(ns=ns_str, interface=interface, trust=trust_str))
1287         exec_cmd_no_error(node, cmd, sudo=True)
1288
1289     @staticmethod
1290     def set_linux_interface_spoof_off(node, interface, namespace=None,
1291                                       vf_id=None):
1292         """Set spoof off for interface in linux.
1293
1294         :param node: Node where to execute command.
1295         :param interface: Interface in namespace.
1296         :param namespace: Execute command in namespace. Optional
1297         :param vf_id: Virtual Function id. Optional
1298         :type node: dict
1299         :type interface: str
1300         :type namespace: str
1301         :type vf_id: int
1302         """
1303         spoof_str = 'vf {vf_id} spoof off'.format(vf_id=vf_id) \
1304             if vf_id is not None else 'spoof off'
1305         ns_str = 'ip netns exec {ns}'.format(ns=namespace) if namespace else ''
1306
1307         cmd = ('{ns} ip link set dev {interface} {spoof}'.
1308                format(ns=ns_str, interface=interface, spoof=spoof_str))
1309         exec_cmd_no_error(node, cmd, sudo=True)
1310
1311     @staticmethod
1312     def init_avf_interface(node, ifc_key, numvfs=1, topology_type='L2'):
1313         """Init PCI device by creating VFs and bind them to vfio-pci for AVF
1314         driver testing on DUT.
1315
1316         :param node: DUT node.
1317         :param iface_key: Interface key from topology file.
1318         :param numvfs: Number of VFs to initialize, 0 - disable the VFs.
1319         :param topology_type: Topology type.
1320         :type node: dict
1321         :iface_key: str
1322         :type numvfs: int
1323         :typ topology_type: str
1324         :returns: Virtual Function topology interface keys.
1325         :rtype: list
1326         """
1327         ssh = SSH()
1328         ssh.connect(node)
1329
1330         # Read PCI address and driver.
1331         pf_pci_addr = Topology.get_interface_pci_addr(node, ifc_key)
1332         pf_mac_addr = Topology.get_interface_mac(node, ifc_key).split(":")
1333         uio_driver = Topology.get_uio_driver(node)
1334         kernel_driver = Topology.get_interface_driver(node, ifc_key)
1335         current_driver = DUTSetup.get_pci_dev_driver(node,\
1336             pf_pci_addr.replace(':', r'\:'))
1337
1338         if current_driver != kernel_driver:
1339             # PCI device must be re-bound to kernel driver before creating VFs.
1340             DUTSetup.verify_kernel_module(node, kernel_driver, force_load=True)
1341             # Stop VPP to prevent deadlock.
1342             VPPUtil.stop_vpp_service(node)
1343             # Unbind from current driver.
1344             DUTSetup.pci_driver_unbind(node, pf_pci_addr)
1345             # Bind to kernel driver.
1346             DUTSetup.pci_driver_bind(node, pf_pci_addr, kernel_driver)
1347
1348         # Initialize PCI VFs
1349         DUTSetup.set_sriov_numvfs(node, pf_pci_addr, numvfs)
1350
1351         vf_ifc_keys = []
1352         # Set MAC address and bind each virtual function to uio driver.
1353         for vf_id in range(numvfs):
1354             vf_mac_addr = ":".join([pf_mac_addr[0], pf_mac_addr[2],
1355                                     pf_mac_addr[3], pf_mac_addr[4],
1356                                     pf_mac_addr[5], "{:02x}".format(vf_id)])
1357
1358             pf_dev = '`basename /sys/bus/pci/devices/{pci}/net/*`'.\
1359                 format(pci=pf_pci_addr)
1360             InterfaceUtil.set_linux_interface_trust_on(node, pf_dev,
1361                                                        vf_id=vf_id)
1362             if topology_type == 'L2':
1363                 InterfaceUtil.set_linux_interface_spoof_off(node, pf_dev,
1364                                                             vf_id=vf_id)
1365             InterfaceUtil.set_linux_interface_mac(node, pf_dev, vf_mac_addr,
1366                                                   vf_id=vf_id)
1367
1368             DUTSetup.pci_vf_driver_unbind(node, pf_pci_addr, vf_id)
1369             DUTSetup.pci_vf_driver_bind(node, pf_pci_addr, vf_id, uio_driver)
1370
1371             # Add newly created ports into topology file
1372             vf_ifc_name = '{pf_if_key}_vf'.format(pf_if_key=ifc_key)
1373             vf_pci_addr = DUTSetup.get_virtfn_pci_addr(node, pf_pci_addr, vf_id)
1374             vf_ifc_key = Topology.add_new_port(node, vf_ifc_name)
1375             Topology.update_interface_name(node, vf_ifc_key,
1376                                            vf_ifc_name+str(vf_id+1))
1377             Topology.update_interface_mac_address(node, vf_ifc_key, vf_mac_addr)
1378             Topology.update_interface_pci_address(node, vf_ifc_key, vf_pci_addr)
1379             vf_ifc_keys.append(vf_ifc_key)
1380
1381         return vf_ifc_keys