# Copyright (c) 2016 Cisco and/or its affiliates.# Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at:## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License."""IPv4 setup library"""fromsocketimportinet_ntoafromstructimportpackfromabcimportABCMeta,abstractmethodfromrobot.api.decoimportkeywordimportresources.libraries.python.sshassshfromresources.libraries.python.RoutingimportRoutingfromresources.libraries.python.InterfaceUtilimportInterfaceUtilfromresources.libraries.python.topologyimportNodeType,Topologyfromresources.libraries.python.VatExecutorimportVatExecutorclassIPv4Node(object):"""Abstract class of a node in a topology."""__metaclass__=ABCMetadef__init__(self,node_info):self.node_info=node_info@staticmethoddef_get_netmask(prefix_length):bits=0xffffffff^(1<<32-prefix_length)-1returninet_ntoa(pack('>I',bits))@abstractmethoddefset_ip(self,interface,address,prefix_length):"""Configure IPv4 address on interface :param interface: interface name :param address: :param prefix_length: :type interface: str :type address: str :type prefix_length: int :return: nothing """pass@abstractmethoddefset_route(self,network,prefix_length,gateway,interface):"""Configure IPv4 route :param network: network IPv4 address :param prefix_length: mask length :param gateway: IPv4 address of the gateway :param interface: interface name :type network: str :type prefix_length: int :type gateway: str :type interface: str :return: nothing """pass@abstractmethoddefunset_route(self,network,prefix_length,gateway,interface):"""Remove specified IPv4 route :param network: network IPv4 address :param prefix_length: mask length :param gateway: IPv4 address of the gateway :param interface: interface name :type network: str :type prefix_length: int :type gateway: str :type interface: str :return: nothing """pass@abstractmethoddefflush_ip_addresses(self,interface):"""Flush all IPv4 addresses from specified interface :param interface: interface name :type interface: str :return: nothing """pass@abstractmethoddefping(self,destination_address,source_interface):"""Send an ICMP request to destination node :param destination_address: address to send the ICMP request :param source_interface: :type destination_address: str :type source_interface: str :return: nothing """passclassTg(IPv4Node):"""Traffic generator node"""def__init__(self,node_info):super(Tg,self).__init__(node_info)def_execute(self,cmd):returnssh.exec_cmd_no_error(self.node_info,cmd)def_sudo_execute(self,cmd):returnssh.exec_cmd_no_error(self.node_info,cmd,sudo=True)defset_ip(self,interface,address,prefix_length):cmd='ip -4 addr flush dev {}'.format(interface)self._sudo_execute(cmd)cmd='ip addr add {}/{} dev {}'.format(address,prefix_length,interface)self._sudo_execute(cmd)defset_route(self,network,prefix_length,gateway,interface):netmask=self._get_netmask(prefix_length)cmd='route add -net {} netmask {} gw {}'.\
format(network,netmask,gateway)self._sudo_execute(cmd)defunset_route(self,network,prefix_length,gateway,interface):self._sudo_execute('ip route delete {}/{}'.format(network,prefix_length))defarp_ping(self,destination_address,source_interface):self._sudo_execute('arping -c 1 -I {} {}'.format(source_interface,destination_address))defping(self,destination_address,source_interface):self._execute('ping -c 1 -w 5 -I {} {}'.format(source_interface,destination_address))defflush_ip_addresses(self,interface):self._sudo_execute('ip addr flush dev {}'.format(interface))classDut(IPv4Node):"""Device under test"""def__init__(self,node_info):super(Dut,self).__init__(node_info)defget_sw_if_index(self,interface):"""Get sw_if_index of specified interface from current node :param interface: interface name :type interface: str :return: sw_if_index of 'int' type """returnTopology().get_interface_sw_index(self.node_info,interface)defexec_vat(self,script,**args):"""Wrapper for VAT executor. :param script: script to execute :param args: parameters to the script :type script: str :type args: dict :return: nothing """# TODO: check return valueVatExecutor.cmd_from_template(self.node_info,script,**args)defset_arp(self,interface,ip_address,mac_address):"""Set entry in ARP cache. :param interface: Interface name. :param ip_address: IP address. :param mac_address: MAC address. :type interface: str :type ip_address: str :type mac_address: str """self.exec_vat('add_ip_neighbor.vat',sw_if_index=self.get_sw_if_index(interface),ip_address=ip_address,mac_address=mac_address)defset_ip(self,interface,address,prefix_length):self.exec_vat('add_ip_address.vat',sw_if_index=self.get_sw_if_index(interface),address=address,prefix_length=prefix_length)defset_route(self,network,prefix_length,gateway,interface):Routing.vpp_route_add(self.node_info,network=network,prefix_len=prefix_length,gateway=gateway,interface=interface)defunset_route(self,network,prefix_length,gateway,interface):self.exec_vat('del_route.vat',network=network,prefix_length=prefix_length,gateway=gateway,sw_if_index=self.get_sw_if_index(interface))defarp_ping(self,destination_address,source_interface):passdefflush_ip_addresses(self,interface):self.exec_vat('flush_ip_addresses.vat',sw_if_index=self.get_sw_if_index(interface))defping(self,destination_address,source_interface):passdefget_node(node_info):"""Creates a class instance derived from Node based on type. :param node_info: dictionary containing information on nodes in topology :return: Class instance that is derived from Node """ifnode_info['type']==NodeType.TG:returnTg(node_info)elifnode_info['type']==NodeType.DUT:returnDut(node_info)else:raiseNotImplementedError('Node type "{}" unsupported!'.format(node_info['type']))classIPv4Setup(object):"""IPv4 setup in topology."""@staticmethoddefvpp_nodes_setup_ipv4_addresses(nodes,nodes_addr):"""Setup IPv4 addresses on all VPP nodes in topology. :param nodes: Nodes of the test topology. :param nodes_addr: Available nodes IPv4 adresses. :type nodes: dict :type nodes_addr: dict """fornetinnodes_addr.values():forportinnet['ports'].values():host=port.get('node')ifhostisNone:continuetopo=Topology()node=topo.get_node_by_hostname(nodes,host)ifnodeisNone:continueifnode['type']!=NodeType.DUT:continueget_node(node).set_ip(port['if'],port['addr'],net['prefix'])InterfaceUtil.set_interface_state(node,port['if'],'up')@staticmethod@keyword('Get IPv4 address of node "${node}" interface "${port}" ''from "${nodes_addr}"')defget_ip_addr(node,interface,nodes_addr):"""Return IPv4 address of the node port. :param node: Node in the topology. :param interface: Interface name of the node. :param nodes_addr: Nodes IPv4 adresses. :type node: dict :type interface: str :type nodes_addr: dict :return: IPv4 address string """fornetinnodes_addr.values():forportinnet['ports'].values():host=port.get('node')dev=port.get('if')ifhost==node['host']anddev==interface:ip=port.get('addr')ifipisnotNone:returnipelse:raiseException('Node {n} port {p} IPv4 address is not set'.format(n=node['host'],p=interface))raiseException('Node {n} port {p} IPv4 address not found.'.format(n=node['host'],p=interface))@staticmethoddefsetup_arp_on_all_duts(nodes_info,nodes_addr):"""For all DUT nodes extract MAC and IP addresses of adjacent interfaces from topology and use them to setup ARP entries. :param nodes_info: Dictionary containing information on all nodes in topology. :param nodes_addr: Nodes IPv4 adresses. :type nodes_info: dict :type nodes_addr: dict """fornodeinnodes_info.values():ifnode['type']==NodeType.TG:continueforinterface,interface_datainnode['interfaces'].iteritems():ifinterface=='mgmt':continueinterface_name=interface_data['name']adj_node,adj_int=Topology.\
get_adjacent_node_and_interface(nodes_info,node,interface_name)ip_address=IPv4Setup.get_ip_addr(adj_node,adj_int['name'],nodes_addr)mac_address=adj_int['mac_address']get_node(node).set_arp(interface_name,ip_address,mac_address)