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

©2016 FD.io a Linux Foundation Collaborative Project. All Rights Reserved.
Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered trademark of Linus Torvalds.
Please see our privacy policy and terms of use.