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