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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """IPv4 setup library"""
16 from socket import inet_ntoa
17 from struct import pack
18 from abc import ABCMeta, abstractmethod
19 from robot.api.deco import keyword
21 import resources.libraries.python.ssh as ssh
22 from resources.libraries.python.Routing import Routing
23 from resources.libraries.python.InterfaceUtil import InterfaceUtil
24 from resources.libraries.python.topology import NodeType, Topology
25 from resources.libraries.python.VatExecutor import VatExecutor
28 class IPv4Node(object):
29 """Abstract class of a node in a topology."""
30 __metaclass__ = ABCMeta
32 def __init__(self, node_info):
33 self.node_info = node_info
36 def _get_netmask(prefix_length):
37 bits = 0xffffffff ^ (1 << 32 - prefix_length) - 1
38 return inet_ntoa(pack('>I', bits))
41 def set_ip(self, interface, address, prefix_length):
42 """Configure IPv4 address on interface
44 :param interface: interface name
49 :type prefix_length: int
55 def set_route(self, network, prefix_length, gateway, interface):
56 """Configure IPv4 route
58 :param network: network IPv4 address
59 :param prefix_length: mask length
60 :param gateway: IPv4 address of the gateway
61 :param interface: interface name
63 :type prefix_length: int
71 def unset_route(self, network, prefix_length, gateway, interface):
72 """Remove specified IPv4 route
74 :param network: network IPv4 address
75 :param prefix_length: mask length
76 :param gateway: IPv4 address of the gateway
77 :param interface: interface name
79 :type prefix_length: int
87 def flush_ip_addresses(self, interface):
88 """Flush all IPv4 addresses from specified interface
90 :param interface: interface name
97 def ping(self, destination_address, source_interface):
98 """Send an ICMP request to destination node
100 :param destination_address: address to send the ICMP request
101 :param source_interface:
102 :type destination_address: str
103 :type source_interface: str
110 """Traffic generator node"""
111 def __init__(self, node_info):
112 super(Tg, self).__init__(node_info)
114 def _execute(self, cmd):
115 return ssh.exec_cmd_no_error(self.node_info, cmd)
117 def _sudo_execute(self, cmd):
118 return ssh.exec_cmd_no_error(self.node_info, cmd, sudo=True)
120 def set_ip(self, interface, address, prefix_length):
121 cmd = 'ip -4 addr flush dev {}'.format(interface)
122 self._sudo_execute(cmd)
123 cmd = 'ip addr add {}/{} dev {}'.format(address, prefix_length,
125 self._sudo_execute(cmd)
127 def set_route(self, network, prefix_length, gateway, interface):
128 netmask = self._get_netmask(prefix_length)
129 cmd = 'route add -net {} netmask {} gw {}'.\
130 format(network, netmask, gateway)
131 self._sudo_execute(cmd)
133 def unset_route(self, network, prefix_length, gateway, interface):
134 self._sudo_execute('ip route delete {}/{}'.
135 format(network, prefix_length))
137 def arp_ping(self, destination_address, source_interface):
138 self._sudo_execute('arping -c 1 -I {} {}'.format(source_interface,
139 destination_address))
141 def ping(self, destination_address, source_interface):
142 self._execute('ping -c 1 -w 5 -I {} {}'.format(source_interface,
143 destination_address))
145 def flush_ip_addresses(self, interface):
146 self._sudo_execute('ip addr flush dev {}'.format(interface))
150 """Device under test"""
151 def __init__(self, node_info):
152 super(Dut, self).__init__(node_info)
154 def get_sw_if_index(self, interface):
155 """Get sw_if_index of specified interface from current node
157 :param interface: interface name
159 :return: sw_if_index of 'int' type
161 return Topology().get_interface_sw_index(self.node_info, interface)
163 def exec_vat(self, script, **args):
164 """Wrapper for VAT executor.
166 :param script: script to execute
167 :param args: parameters to the script
172 # TODO: check return value
173 VatExecutor.cmd_from_template(self.node_info, script, **args)
175 def set_arp(self, interface, ip_address, mac_address):
176 """Set entry in ARP cache.
178 :param interface: Interface name.
179 :param ip_address: IP address.
180 :param mac_address: MAC address.
182 :type ip_address: str
183 :type mac_address: str
185 self.exec_vat('add_ip_neighbor.vat',
186 sw_if_index=self.get_sw_if_index(interface),
187 ip_address=ip_address, mac_address=mac_address)
189 def set_ip(self, interface, address, prefix_length):
190 self.exec_vat('add_ip_address.vat',
191 sw_if_index=self.get_sw_if_index(interface),
192 address=address, prefix_length=prefix_length)
194 def set_route(self, network, prefix_length, gateway, interface):
195 Routing.vpp_route_add(self.node_info,
196 network=network, prefix_len=prefix_length,
197 gateway=gateway, interface=interface)
199 def unset_route(self, network, prefix_length, gateway, interface):
200 self.exec_vat('del_route.vat', network=network,
201 prefix_length=prefix_length, gateway=gateway,
202 sw_if_index=self.get_sw_if_index(interface))
204 def arp_ping(self, destination_address, source_interface):
207 def flush_ip_addresses(self, interface):
208 self.exec_vat('flush_ip_addresses.vat',
209 sw_if_index=self.get_sw_if_index(interface))
211 def ping(self, destination_address, source_interface):
215 def get_node(node_info):
216 """Creates a class instance derived from Node based on type.
218 :param node_info: dictionary containing information on nodes in topology
219 :return: Class instance that is derived from Node
221 if node_info['type'] == NodeType.TG:
223 elif node_info['type'] == NodeType.DUT:
224 return Dut(node_info)
226 raise NotImplementedError('Node type "{}" unsupported!'.
227 format(node_info['type']))
230 class IPv4Setup(object):
231 """IPv4 setup in topology."""
234 def vpp_nodes_set_ipv4_addresses(nodes, nodes_addr):
235 """Set IPv4 addresses on all VPP nodes in topology.
237 :param nodes: Nodes of the test topology.
238 :param nodes_addr: Available nodes IPv4 adresses.
240 :type nodes_addr: dict
241 :return: affected interfaces as list of (node, interface) tuples
246 for net in nodes_addr.values():
247 for port in net['ports'].values():
248 host = port.get('node')
252 node = topo.get_node_by_hostname(nodes, host)
255 if node['type'] != NodeType.DUT:
257 get_node(node).set_ip(port['if'], port['addr'], net['prefix'])
258 interfaces.append((node, port['if']))
263 @keyword('Get IPv4 address of node "${node}" interface "${port}" '
264 'from "${nodes_addr}"')
265 def get_ip_addr(node, interface, nodes_addr):
266 """Return IPv4 address of the node port.
267 :param node: Node in the topology.
268 :param interface: Interface name of the node.
269 :param nodes_addr: Nodes IPv4 adresses.
272 :type nodes_addr: dict
273 :return: IPv4 address string
275 for net in nodes_addr.values():
276 for port in net['ports'].values():
277 host = port.get('node')
279 if host == node['host'] and dev == interface:
280 ip = port.get('addr')
285 'Node {n} port {p} IPv4 address is not set'.format(
286 n=node['host'], p=interface))
288 raise Exception('Node {n} port {p} IPv4 address not found.'.format(
289 n=node['host'], p=interface))
292 def setup_arp_on_all_duts(nodes_info, nodes_addr):
293 """For all DUT nodes extract MAC and IP addresses of adjacent
294 interfaces from topology and use them to setup ARP entries.
296 :param nodes_info: Dictionary containing information on all nodes
298 :param nodes_addr: Nodes IPv4 adresses.
299 :type nodes_info: dict
300 :type nodes_addr: dict
302 for node in nodes_info.values():
303 if node['type'] == NodeType.TG:
305 for interface, interface_data in node['interfaces'].iteritems():
306 if interface == 'mgmt':
308 interface_name = interface_data['name']
309 adj_node, adj_int = Topology.\
310 get_adjacent_node_and_interface(nodes_info, node,
312 ip_address = IPv4Setup.get_ip_addr(adj_node, adj_int['name'],
314 mac_address = adj_int['mac_address']
315 get_node(node).set_arp(interface_name, ip_address, mac_address)