Revert "API cleanup: tap" and bump stable_vpp
[csit.git] / resources / libraries / python / Tap.py
1 # Copyright (c) 2019 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 """Tap utilities library."""
15
16 from ipaddress import ip_address
17 from robot.api import logger
18
19 from resources.libraries.python.Constants import Constants
20 from resources.libraries.python.L2Util import L2Util
21 from resources.libraries.python.InterfaceUtil import InterfaceUtil
22 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
23 from resources.libraries.python.topology import Topology
24
25
26 class Tap(object):
27     """Tap utilities."""
28
29     @staticmethod
30     def add_tap_interface(node, tap_name, mac=None):
31         """Add tap interface with name and optionally with MAC.
32
33         :param node: Node to add tap on.
34         :param tap_name: Tap interface name for linux tap.
35         :param mac: Optional MAC address for VPP tap.
36         :type node: dict
37         :type tap_name: str or unicode
38         :type mac: str
39         :returns: Returns a interface index.
40         :rtype: int
41         """
42         if isinstance(tap_name, unicode):
43             tap_name = str(tap_name)
44         cmd = 'tap_create_v2'
45         args = dict(
46             id=Constants.BITWISE_NON_ZERO,
47             use_random_mac=0 if mac else 1,
48             mac_address=L2Util.mac_to_bin(mac) if mac else 6 * b'\x00',
49             host_namespace=64 * b'\x00',
50             host_mac_addr=6 * b'\x00',
51             host_if_name_set=1,
52             host_if_name=tap_name + (64 - len(tap_name)) * b'\x00',
53             host_bridge=64 * b'\x00',
54             host_ip4_addr=4 * b'\x00',
55             host_ip6_addr=16 * b'\x00',
56             host_ip4_gw=4 * b'\x00',
57             host_ip6_gw=16 * b'\x00'
58         )
59         err_msg = 'Failed to create tap interface {tap} on host {host}'.format(
60             tap=tap_name, host=node['host'])
61
62         with PapiSocketExecutor(node) as papi_exec:
63             sw_if_index = papi_exec.add(cmd, **args).get_sw_if_index(err_msg)
64
65         if_key = Topology.add_new_port(node, 'tap')
66         Topology.update_interface_sw_if_index(node, if_key, sw_if_index)
67         Topology.update_interface_name(node, if_key, tap_name)
68         if mac is None:
69             mac = Tap.vpp_get_tap_interface_mac(node, tap_name)
70         Topology.update_interface_mac_address(node, if_key, mac)
71         tap_dev_name = Tap.vpp_get_tap_dev_name(node, tap_name)
72         Topology.update_interface_tap_dev_name(node, if_key, tap_dev_name)
73
74         return sw_if_index
75
76     @staticmethod
77     def vpp_get_tap_dev_name(node, host_if_name):
78         """Get VPP tap interface name from hardware interfaces dump.
79
80         :param node: DUT node.
81         :param host_if_name: Tap host interface name.
82         :type node: dict
83         :type host_if_name: str
84         :returns: VPP tap interface dev_name.
85         :rtype: str
86         """
87         return Tap.tap_dump(node, host_if_name).get('dev_name')
88
89     @staticmethod
90     def vpp_get_tap_interface_mac(node, interface_name):
91         """Get tap interface MAC address from interfaces dump.
92
93         :param node: DUT node.
94         :param interface_name: Tap interface name.
95         :type node: dict
96         :type interface_name: str
97         :returns: Tap interface MAC address.
98         :rtype: str
99         """
100         return InterfaceUtil.vpp_get_interface_mac(node, interface_name)
101
102     @staticmethod
103     def tap_dump(node, name=None):
104         """Get all TAP interface data from the given node, or data about
105         a specific TAP interface.
106
107         :param node: VPP node to get data from.
108         :param name: Optional name of a specific TAP interface.
109         :type node: dict
110         :type name: str
111         :returns: Dictionary of information about a specific TAP interface, or
112             a List of dictionaries containing all TAP data for the given node.
113         :rtype: dict or list
114         """
115         def process_tap_dump(tap_dump):
116             """Process tap dump.
117
118             :param tap_dump: Tap interface dump.
119             :type tap_dump: dict
120             :returns: Processed tap interface dump.
121             :rtype: dict
122             """
123             tap_dump['dev_name'] = tap_dump['dev_name'].rstrip('\x00')
124             tap_dump['host_if_name'] = tap_dump['host_if_name'].rstrip('\x00')
125             tap_dump['host_namespace'] = \
126                 tap_dump['host_namespace'].rstrip('\x00')
127             tap_dump['host_mac_addr'] = \
128                 L2Util.bin_to_mac(tap_dump['host_mac_addr'])
129             tap_dump['host_ip4_addr'] = ip_address(tap_dump['host_ip4_addr'])
130             tap_dump['host_ip6_addr'] = ip_address(tap_dump['host_ip6_addr'])
131             return tap_dump
132
133         cmd = 'sw_interface_tap_v2_dump'
134         err_msg = 'Failed to get TAP dump on host {host}'.format(
135             host=node['host'])
136         with PapiSocketExecutor(node) as papi_exec:
137             details = papi_exec.add(cmd).get_details(err_msg)
138
139         data = list() if name is None else dict()
140         for dump in details:
141             if name is None:
142                 data.append(process_tap_dump(dump))
143             elif dump.get('host_if_name').rstrip('\x00') == name:
144                 data = process_tap_dump(dump)
145                 break
146
147         logger.debug('TAP data:\n{tap_data}'.format(tap_data=data))
148         return data