12f6de7af9a01e94b3cd18aae2fd26a55a985073
[csit.git] / resources / libraries / python / IPv6Setup.py
1 # Copyright (c) 2016 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 """Library to set up IPv6 in topology."""
15
16 from robot.api import logger
17 from ipaddress import IPv6Network
18
19 from resources.libraries.python.ssh import SSH
20 from resources.libraries.python.topology import NodeType, Topology
21 from resources.libraries.python.constants import Constants
22 from resources.libraries.python.VatExecutor import VatTerminal, VatExecutor
23
24
25 class IPv6Networks(object):
26     """IPv6 network iterator.
27
28     :param networks: List of the available IPv6 networks.
29     :type networks: list
30     """
31     def __init__(self, networks):
32         self._networks = list()
33         for network in networks:
34             net = IPv6Network(unicode(network))
35             self._networks.append(net)
36         num = len(self._networks)
37         if num == 0:
38             raise Exception('No IPv6 networks')
39
40     def next_network(self):
41         """Get the next element of the iterator.
42
43         :return: IPv6 network.
44         :rtype: IPv6Network object
45         :raises: StopIteration if there is no more elements.
46         """
47         if len(self._networks):
48             return self._networks.pop()
49         else:
50             raise StopIteration()
51
52
53 class IPv6Setup(object):
54     """IPv6 setup in topology."""
55
56     def __init__(self):
57         pass
58
59     def nodes_set_ipv6_addresses(self, nodes, nodes_addr):
60         """Set IPv6 addresses on all VPP nodes in topology.
61
62         :param nodes: Nodes of the test topology.
63         :param nodes_addr: Available nodes IPv6 addresses.
64         :type nodes: dict
65         :type nodes_addr: dict
66         :return: Affected interfaces as list of (node, interface) tuples.
67         :rtype: list
68         """
69         interfaces = []
70
71         for net in nodes_addr.values():
72             for port in net['ports'].values():
73                 host = port.get('node')
74                 if host is None:
75                     continue
76                 topo = Topology()
77                 node = topo.get_node_by_hostname(nodes, host)
78                 if node is None:
79                     continue
80                 if node['type'] == NodeType.DUT:
81                     self.vpp_set_if_ipv6_addr(node, port['if'], port['addr'],
82                                               net['prefix'])
83
84                     interfaces.append((node, port['if']))
85         return interfaces
86
87     def nodes_clear_ipv6_addresses(self, nodes, nodes_addr):
88         """Remove IPv6 addresses from all VPP nodes in topology.
89
90         :param nodes: Nodes of the test topology.
91         :param nodes_addr: Available nodes IPv6 addresses.
92         :type nodes: dict
93         :type nodes_addr: dict
94         """
95         for net in nodes_addr.values():
96             for port in net['ports'].values():
97                 host = port.get('node')
98                 if host is None:
99                     continue
100                 topo = Topology()
101                 node = topo.get_node_by_hostname(nodes, host)
102                 if node is None:
103                     continue
104                 if node['type'] == NodeType.DUT:
105                     self.vpp_del_if_ipv6_addr(node, port['if'], port['addr'],
106                                               net['prefix'])
107
108     @staticmethod
109     def linux_set_if_ipv6_addr(node, interface, addr, prefix):
110         """Set IPv6 address on linux host.
111
112         :param node: Linux node.
113         :param interface: Node interface.
114         :param addr: IPv6 address.
115         :param prefix: IPv6 address prefix.
116         :type node: dict
117         :type interface: str
118         :type addr: str
119         :type prefix: str
120         """
121         ssh = SSH()
122         ssh.connect(node)
123
124         cmd = "ifconfig {dev} inet6 add {ip}/{p} up".format(dev=interface,
125                                                             ip=addr, p=prefix)
126         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
127         if int(ret_code) != 0:
128             raise Exception('TG ifconfig failed')
129
130     @staticmethod
131     def linux_del_if_ipv6_addr(node, interface, addr, prefix):
132         """Delete IPv6 address on linux host.
133
134         :param node: Linux node.
135         :param interface: Node interface.
136         :param addr: IPv6 address.
137         :param prefix: IPv6 address prefix.
138         :type node: dict
139         :type interface: str
140         :type addr: str
141         :type prefix: str
142         """
143         ssh = SSH()
144         ssh.connect(node)
145
146         cmd = "ifconfig {dev} inet6 del {ip}/{p}".format(dev=interface,
147                                                          ip=addr,
148                                                          p=prefix)
149         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
150         if int(ret_code) != 0:
151             raise Exception('TG ifconfig failed')
152
153         cmd = "ifconfig {dev} down".format(dev=interface)
154         (ret_code, _, _) = ssh.exec_command_sudo(cmd)
155         if int(ret_code) != 0:
156             raise Exception('TG ifconfig failed')
157
158     @staticmethod
159     def vpp_set_if_ipv6_addr(node, interface, addr, prefix):
160         """Set IPv6 address on VPP.
161
162         :param node: VPP node.
163         :param interface: Node interface.
164         :param addr: IPv6 address.
165         :param prefix: IPv6 address prefix.
166         :type node: dict
167         :type interface: str
168         :type addr: str
169         :type prefix: str
170         """
171         sw_if_index = Topology.get_interface_sw_index(node, interface)
172         with VatTerminal(node) as vat:
173             vat.vat_terminal_exec_cmd_from_template('add_ip_address.vat',
174                                                     sw_if_index=sw_if_index,
175                                                     address=addr,
176                                                     prefix_length=prefix)
177             vat.vat_terminal_exec_cmd_from_template('set_if_state.vat',
178                                                     sw_if_index=sw_if_index,
179                                                     state='admin-up')
180
181         ssh = SSH()
182         ssh.connect(node)
183         cmd_input = 'exec show int'
184         (ret_code, stdout, stderr) = ssh.exec_command_sudo(
185             Constants.VAT_BIN_NAME, cmd_input)
186         logger.debug('ret: {0}'.format(ret_code))
187         logger.debug('stdout: {0}'.format(stdout))
188         logger.debug('stderr: {0}'.format(stderr))
189
190     @staticmethod
191     def vpp_del_if_ipv6_addr(node, interface, addr, prefix):
192         """Delete IPv6 address on VPP.
193
194         :param node: VPP node.
195         :param interface: Node interface.
196         :param addr: IPv6 address.
197         :param prefix: IPv6 address prefix.
198         :type node: dict
199         :type interface: str
200         :type addr: str
201         :type prefix: str
202         """
203         sw_if_index = Topology.get_interface_sw_index(node, interface)
204         with VatTerminal(node) as vat:
205             vat.vat_terminal_exec_cmd_from_template('del_ip_address.vat',
206                                                     sw_if_index=sw_if_index,
207                                                     address=addr,
208                                                     prefix_length=prefix)
209             vat.vat_terminal_exec_cmd_from_template('set_if_state.vat',
210                                                     sw_if_index=sw_if_index,
211                                                     state='admin-down')
212
213
214     @staticmethod
215     def vpp_set_ipv6_neighbor(node, interface, ipaddr, macaddr):
216         """Set IPv6 neighbor.
217
218            :param node: VPP node.
219            :param interface: Interface name.
220            :param ip_address: IPv6 address.
221            :param mac_address: mac address.
222            :type node: dict
223            :type interface: str
224            :type ip_address: str
225            :type mac_address: str
226         """
227         sw_if_index = Topology.get_interface_sw_index(node, interface)
228         VatExecutor.cmd_from_template(node,
229                                       'add_ip_neighbor.vat',
230                                       sw_if_index=sw_if_index,
231                                       ip_address=ipaddr,
232                                       mac_address=macaddr)
233
234     @staticmethod
235     def vpp_ra_suppress_link_layer(node, interface):
236         """Suppress ICMPv6 router advertisement message for link scope address.
237
238         :param node: VPP node.
239         :param interface: Interface name.
240         :type node: dict
241         :type interface: str
242         """
243         sw_if_index = Topology.get_interface_sw_index(node, interface)
244         VatExecutor.cmd_from_template(node,
245                                       'sw_interface_ip6nd_ra_config.vat',
246                                       sw_if_id=sw_if_index,
247                                       param='surpress')
248
249     @staticmethod
250     def vpp_ra_send_after_interval(node, interface, interval=2):
251         """Setup vpp router advertisement(RA) in such way it sends RA packet
252         after and every interval value.
253
254         :param node: VPP node.
255         :param interface: Interface name.
256         :param interval: Interval for RA resend
257         :type node: dict
258         :type interface: str
259         :type interval: int
260         """
261         sw_if_index = Topology.get_interface_sw_index(node, interface)
262         VatExecutor.cmd_from_template(node,
263                                       'sw_interface_ip6nd_ra_config.vat',
264                                       sw_if_id=sw_if_index,
265                                       param='interval {0}'.format(interval))
266
267     def vpp_all_ra_suppress_link_layer(self, nodes):
268         """Suppress ICMPv6 router advertisement message for link scope address
269         on all VPP nodes in the topology.
270
271         :param nodes: Nodes of the test topology.
272         :type nodes: dict
273         """
274         for node in nodes.values():
275             if node['type'] == NodeType.TG:
276                 continue
277             for port_k, port_v in node['interfaces'].items():
278                 if_name = port_v.get('name')
279                 if if_name is None:
280                     continue
281                 self.vpp_ra_suppress_link_layer(node, if_name)
282
283     @staticmethod
284     def get_link_address(link, nodes_addr):
285         """Get link IPv6 address.
286
287         :param link: Link name.
288         :param nodes_addr: Available nodes IPv6 addresses.
289         :type link: str
290         :type nodes_addr: dict
291         :return: Link IPv6 address.
292         :rtype: str
293         """
294         net = nodes_addr.get(link)
295         if net is None:
296             raise ValueError('Link "{0}" address not found'.format(link))
297         return net.get('net_addr')
298
299     @staticmethod
300     def get_link_prefix(link, nodes_addr):
301         """Get link IPv6 address prefix.
302
303         :param link: Link name.
304         :param nodes_addr: Available nodes IPv6 addresses.
305         :type link: str
306         :type nodes_addr: dict
307         :return: Link IPv6 address prefix.
308         :rtype: int
309         """
310         net = nodes_addr.get(link)
311         if net is None:
312             raise ValueError('Link "{0}" address not found'.format(link))
313         return net.get('prefix')