Refactor IPv4 utils 40/340/1
authorFilip Tehlar <ftehlar@cisco.com>
Wed, 17 Feb 2016 14:59:08 +0000 (06:59 -0800)
committerFilip Tehlar <ftehlar@cisco.com>
Wed, 17 Feb 2016 15:01:28 +0000 (07:01 -0800)
Change-Id: Iae12444efba33e2d37b5d7beb1620e859abd84d7
Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
resources/libraries/python/IPv4NodeAddress.py
resources/libraries/python/IPv4Setup.py [new file with mode: 0644]
resources/libraries/python/IPv4Util.py
resources/libraries/python/InterfaceUtil.py [new file with mode: 0644]
resources/libraries/python/topology.py
resources/libraries/robot/ipv4.robot
resources/libraries/robot/l2_xconnect.robot
resources/traffic_scripts/ipv4_ping_ttl_check.py

index 8db9ffa..49ce41b 100644 (file)
@@ -18,6 +18,8 @@
 """
 from ipaddress import IPv4Network
 
+from resources.libraries.python.topology import Topology
+
 # Default list of IPv4 subnets
 IPV4_NETWORKS = ['20.20.20.0/24',
                  '10.10.10.0/24',
@@ -34,14 +36,14 @@ class IPv4NetworkGenerator(object):
         self._networks = list()
         for network in networks:
             net = IPv4Network(unicode(network))
-            subnet, _ = network.split('/')
-            self._networks.append((net, subnet))
+            self._networks.append(net)
         if len(self._networks) == 0:
             raise Exception('No IPv4 networks')
 
     def next_network(self):
         """
         :return: next network in form (IPv4Network, subnet)
+        :raises: StopIteration if there are no more elements.
         """
         if len(self._networks):
             return self._networks.pop()
@@ -49,56 +51,44 @@ class IPv4NetworkGenerator(object):
             raise StopIteration()
 
 
-def get_variables(networks=IPV4_NETWORKS[:]):
-    """
-    Create dictionary of IPv4 addresses generated from provided subnet list.
-
-    Example of returned dictionary:
-        network = {
-        'NET1': {
-            'subnet': '192.168.1.0',
-            'prefix': 24,
-            'port1': {
-                'addr': '192.168.1.1',
-            },
-            'port2': {
-                'addr': '192.168.1.0',
-            },
-        },
-        'NET2': {
-            'subnet': '192.168.2.0',
-            'prefix': 24,
-            'port1': {
-                'addr': '192.168.2.1',
-            },
-            'port2': {
-                'addr': '192.168.2.2',
-            },
-        },
-    }
-
-    This function is called by RobotFramework automatically.
-
-    :param networks: list of subnets in form a.b.c.d/length
-    :return: Dictionary of IPv4 addresses
+def get_variables(nodes, networks=IPV4_NETWORKS[:]):
+    """Special robot framework method that returns dictionary nodes_ipv4_addr,
+       mapping of node and interface name to IPv4 adddress.
+
+       :param nodes: Nodes of the test topology.
+       :param networks: list of available IPv4 networks
+       :type nodes: dict
+       :type networks: list
+
+       .. note::
+           Robot framework calls it automatically.
     """
-    net_object = IPv4NetworkGenerator(networks)
-
-    network = {}
-    interface_count_per_node = 2
-
-    for subnet_num in range(len(networks)):
-        net, net_str = net_object.next_network()
-        key = 'NET{}'.format(subnet_num + 1)
-        network[key] = {
-            'subnet': net_str,
-            'prefix': net.prefixlen,
-        }
-        hosts = net.hosts()
-        for port_num in range(interface_count_per_node):
-            port = 'port{}'.format(port_num + 1)
-            network[key][port] = {
-                'addr': str(next(hosts)),
-            }
-
-    return {'DICT__nodes_ipv4_addr': network}
+    topo = Topology()
+    links = topo.get_links(nodes)
+
+    if len(links) > len(networks):
+        raise Exception('Not enough available IPv4 networks for topology.')
+
+    ip4_n = IPv4NetworkGenerator(networks)
+
+    nets = {}
+
+    for link in links:
+        ip4_net = ip4_n.next_network()
+        net_hosts = ip4_net.hosts()
+        port_idx = 0
+        ports = {}
+        for node in nodes.values():
+            if_name = topo.get_interface_by_link_name(node, link)
+            if if_name is not None:
+                port = {'addr': str(next(net_hosts)),
+                        'node': node['host'],
+                        'if': if_name}
+                port_idx += 1
+                port_id = 'port{0}'.format(port_idx)
+                ports.update({port_id: port})
+        nets.update({link: {'net_addr': str(ip4_net.network_address),
+                            'prefix': ip4_net.prefixlen,
+                            'ports': ports}})
+
+    return {'DICT__nodes_ipv4_addr': nets}
diff --git a/resources/libraries/python/IPv4Setup.py b/resources/libraries/python/IPv4Setup.py
new file mode 100644 (file)
index 0000000..ed65518
--- /dev/null
@@ -0,0 +1,309 @@
+# 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"""
+
+from socket import inet_ntoa
+from struct import pack
+from abc import ABCMeta, abstractmethod
+from robot.api.deco import keyword
+
+import resources.libraries.python.ssh as ssh
+from resources.libraries.python.Routing import Routing
+from resources.libraries.python.InterfaceUtil import InterfaceUtil
+from resources.libraries.python.topology import NodeType, Topology
+from resources.libraries.python.VatExecutor import VatExecutor
+
+
+class IPv4Node(object):
+    """Abstract class of a node in a topology."""
+    __metaclass__ = ABCMeta
+
+    def __init__(self, node_info):
+        self.node_info = node_info
+
+    @staticmethod
+    def _get_netmask(prefix_length):
+        bits = 0xffffffff ^ (1 << 32 - prefix_length) - 1
+        return inet_ntoa(pack('>I', bits))
+
+    @abstractmethod
+    def set_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
+
+    @abstractmethod
+    def set_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
+
+    @abstractmethod
+    def unset_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
+
+    @abstractmethod
+    def flush_ip_addresses(self, interface):
+        """Flush all IPv4 addresses from specified interface
+
+        :param interface: interface name
+        :type interface: str
+        :return: nothing
+        """
+        pass
+
+    @abstractmethod
+    def ping(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
+        """
+        pass
+
+
+class Tg(IPv4Node):
+    """Traffic generator node"""
+    def __init__(self, node_info):
+        super(Tg, self).__init__(node_info)
+
+    def _execute(self, cmd):
+        return ssh.exec_cmd_no_error(self.node_info, cmd)
+
+    def _sudo_execute(self, cmd):
+        return ssh.exec_cmd_no_error(self.node_info, cmd, sudo=True)
+
+    def set_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)
+
+    def set_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)
+
+    def unset_route(self, network, prefix_length, gateway, interface):
+        self._sudo_execute('ip route delete {}/{}'.
+                           format(network, prefix_length))
+
+    def arp_ping(self, destination_address, source_interface):
+        self._sudo_execute('arping -c 1 -I {} {}'.format(source_interface,
+                                                         destination_address))
+
+    def ping(self, destination_address, source_interface):
+        self._execute('ping -c 1 -w 5 -I {} {}'.format(source_interface,
+                                                       destination_address))
+
+    def flush_ip_addresses(self, interface):
+        self._sudo_execute('ip addr flush dev {}'.format(interface))
+
+
+class Dut(IPv4Node):
+    """Device under test"""
+    def __init__(self, node_info):
+        super(Dut, self).__init__(node_info)
+
+    def get_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
+        """
+        return Topology().get_interface_sw_index(self.node_info, interface)
+
+    def exec_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 value
+        VatExecutor.cmd_from_template(self.node_info, script, **args)
+
+    def set_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)
+
+    def set_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)
+
+    def set_route(self, network, prefix_length, gateway, interface):
+        Routing.vpp_route_add(self.node_info,
+                      network=network, prefix_len=prefix_length,
+                      gateway=gateway, interface=interface)
+
+    def unset_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))
+
+    def arp_ping(self, destination_address, source_interface):
+        pass
+
+    def flush_ip_addresses(self, interface):
+        self.exec_vat('flush_ip_addresses.vat',
+                      sw_if_index=self.get_sw_if_index(interface))
+
+    def ping(self, destination_address, source_interface):
+        pass
+
+
+def get_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
+    """
+    if node_info['type'] == NodeType.TG:
+        return Tg(node_info)
+    elif node_info['type'] == NodeType.DUT:
+        return Dut(node_info)
+    else:
+        raise NotImplementedError('Node type "{}" unsupported!'.
+                                  format(node_info['type']))
+
+
+class IPv4Setup(object):
+    """IPv4 setup in topology."""
+
+    @staticmethod
+    def vpp_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
+        """
+        for net in nodes_addr.values():
+            for port in net['ports'].values():
+                host = port.get('node')
+                if host is None:
+                    continue
+                topo = Topology()
+                node = topo.get_node_by_hostname(nodes, host)
+                if node is None:
+                    continue
+                if node['type'] != NodeType.DUT:
+                    continue
+                get_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}"')
+    def get_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
+        """
+        for net in nodes_addr.values():
+            for port in net['ports'].values():
+                host = port.get('node')
+                dev = port.get('if')
+                if host == node['host'] and dev == interface:
+                    ip = port.get('addr')
+                    if ip is not None:
+                        return ip
+                    else:
+                        raise Exception(
+                            'Node {n} port {p} IPv4 address is not set'.format(
+                                n=node['host'], p=interface))
+
+        raise Exception('Node {n} port {p} IPv4 address not found.'.format(
+            n=node['host'], p=interface))
+
+    @staticmethod
+    def setup_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
+        """
+        for node in nodes_info.values():
+            if node['type'] == NodeType.TG:
+                continue
+            for interface, interface_data in node['interfaces'].iteritems():
+                if interface == 'mgmt':
+                    continue
+                interface_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)
\ No newline at end of file
index d3a016d..30e185c 100644 (file)
 
 """Implements IPv4 RobotFramework keywords"""
 
-from socket import inet_ntoa
-from struct import pack
-from abc import ABCMeta, abstractmethod
-import copy
-
 from robot.api import logger as log
 from robot.api.deco import keyword
-from robot.utils.asserts import assert_not_equal
 
-import resources.libraries.python.ssh as ssh
 from resources.libraries.python.topology import Topology
 from resources.libraries.python.topology import NodeType
-from resources.libraries.python.VatExecutor import VatExecutor
 from resources.libraries.python.TrafficScriptExecutor\
     import TrafficScriptExecutor
-
-
-class IPv4Node(object):
-    """Abstract class of a node in a topology."""
-    __metaclass__ = ABCMeta
-
-    def __init__(self, node_info):
-        self.node_info = node_info
-
-    @staticmethod
-    def _get_netmask(prefix_length):
-        bits = 0xffffffff ^ (1 << 32 - prefix_length) - 1
-        return inet_ntoa(pack('>I', bits))
-
-    @abstractmethod
-    def set_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
-
-    @abstractmethod
-    def set_interface_state(self, interface, state):
-        """Set interface state
-
-        :param interface: interface name string
-        :param state: one of following values: "up" or "down"
-        :return: nothing
-        """
-        pass
-
-    @abstractmethod
-    def set_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
-
-    @abstractmethod
-    def unset_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
-
-    @abstractmethod
-    def flush_ip_addresses(self, interface):
-        """Flush all IPv4 addresses from specified interface
-
-        :param interface: interface name
-        :type interface: str
-        :return: nothing
-        """
-        pass
-
-    @abstractmethod
-    def ping(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
-        """
-        pass
-
-
-class Tg(IPv4Node):
-    """Traffic generator node"""
-    def __init__(self, node_info):
-        super(Tg, self).__init__(node_info)
-
-    def _execute(self, cmd):
-        return ssh.exec_cmd_no_error(self.node_info, cmd)
-
-    def _sudo_execute(self, cmd):
-        return ssh.exec_cmd_no_error(self.node_info, cmd, sudo=True)
-
-    def set_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)
-
-    # TODO: not ipv4-specific, move to another class
-    def set_interface_state(self, interface, state):
-        cmd = 'ip link set {} {}'.format(interface, state)
-        self._sudo_execute(cmd)
-
-    def set_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)
-
-    def unset_route(self, network, prefix_length, gateway, interface):
-        self._sudo_execute('ip route delete {}/{}'.
-                           format(network, prefix_length))
-
-    def arp_ping(self, destination_address, source_interface):
-        self._sudo_execute('arping -c 1 -I {} {}'.format(source_interface,
-                                                         destination_address))
-
-    def ping(self, destination_address, source_interface):
-        self._execute('ping -c 1 -w 5 -I {} {}'.format(source_interface,
-                                                       destination_address))
-
-    def flush_ip_addresses(self, interface):
-        self._sudo_execute('ip addr flush dev {}'.format(interface))
-
-
-class Dut(IPv4Node):
-    """Device under test"""
-    def __init__(self, node_info):
-        super(Dut, self).__init__(node_info)
-
-    def get_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
-        """
-        return Topology().get_interface_sw_index(self.node_info, interface)
-
-    def exec_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 value
-        VatExecutor.cmd_from_template(self.node_info, script, **args)
-
-    def set_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)
-
-    def set_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)
-
-    def set_interface_state(self, interface, state):
-        if state == 'up':
-            state = 'admin-up link-up'
-        elif state == 'down':
-            state = 'admin-down link-down'
-        else:
-            raise Exception('Unexpected interface state: {}'.format(state))
-
-        self.exec_vat('set_if_state.vat',
-                      sw_if_index=self.get_sw_if_index(interface), state=state)
-
-    def set_route(self, network, prefix_length, gateway, interface):
-        sw_if_index = self.get_sw_if_index(interface)
-        self.exec_vat('add_route.vat',
-                      network=network, prefix_length=prefix_length,
-                      gateway=gateway, sw_if_index=sw_if_index)
-
-    def unset_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))
-
-    def arp_ping(self, destination_address, source_interface):
-        pass
-
-    def flush_ip_addresses(self, interface):
-        self.exec_vat('flush_ip_addresses.vat',
-                      sw_if_index=self.get_sw_if_index(interface))
-
-    def ping(self, destination_address, source_interface):
-        pass
-
-
-def get_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
-    """
-    if node_info['type'] == NodeType.TG:
-        return Tg(node_info)
-    elif node_info['type'] == NodeType.DUT:
-        return Dut(node_info)
-    else:
-        raise NotImplementedError('Node type "{}" unsupported!'.
-                                  format(node_info['type']))
-
-
-def get_node_hostname(node_info):
-    """Get string identifying specifed node.
-
-    :param node_info: Node in the topology.
-    :type node_info: Dict
-    :return: String identifying node.
-    """
-    return node_info['host']
+from resources.libraries.python.IPv4Setup import get_node
 
 
 class IPv4Util(object):
     """Implements keywords for IPv4 tests."""
 
-    ADDRESSES = {}   # holds configured IPv4 addresses
-    PREFIXES = {}  # holds configured IPv4 addresses' prefixes
-    SUBNETS = {}  # holds configured IPv4 addresses' subnets
-
-    """
-    Helper dictionary used when setting up ipv4 addresses in topology
-
-    Example value:
-    'link1': {  b'port1': {b'addr': b'192.168.3.1'},
-                b'port2': {b'addr': b'192.168.3.2'},
-                b'prefix': 24,
-                b'subnet': b'192.168.3.0'}
-    """
-    topology_helper = None
-
-    @staticmethod
-    def setup_arp_on_all_duts(nodes_info):
-        """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.
-        :type nodes_info: dict
-        """
-        for node in nodes_info.values():
-            if node['type'] == NodeType.TG:
-                continue
-            for interface, interface_data in node['interfaces'].iteritems():
-                if interface == 'mgmt':
-                    continue
-                interface_name = interface_data['name']
-                adj_node, adj_int = Topology.\
-                    get_adjacent_node_and_interface(nodes_info, node,
-                                                    interface_name)
-                ip_address = IPv4Util.get_ip_addr(adj_node, adj_int['name'])
-                mac_address = adj_int['mac_address']
-                get_node(node).set_arp(interface_name, ip_address, mac_address)
-
-    @staticmethod
-    def next_address(subnet):
-        """Get next unused IPv4 address from a subnet
-
-        :param subnet: holds available IPv4 addresses
-        :return: tuple (ipv4_address, prefix_length)
-        """
-        for i in range(1, 4):
-            # build a key and try to get it from address dictionary
-            interface = 'port{}'.format(i)
-            if interface in subnet:
-                addr = subnet[interface]['addr']
-                del subnet[interface]
-                return addr, subnet['prefix']
-        raise Exception('Not enough ipv4 addresses in subnet')
-
-    @staticmethod
-    def next_network(nodes_addr):
-        """Get next unused network from dictionary
-
-        :param nodes_addr: dictionary of available networks
-        :return: dictionary describing an IPv4 subnet with addresses
-        """
-        assert_not_equal(len(nodes_addr), 0, 'Not enough networks')
-        _, subnet = nodes_addr.popitem()
-        return subnet
-
-    @staticmethod
-    def configure_ipv4_addr_on_node(node, nodes_addr):
-        """Configure IPv4 address for all non-management interfaces
-        on a node in topology.
-
-        :param node: dictionary containing information about node
-        :param nodes_addr: dictionary containing IPv4 addresses
-        :return:
-        """
-        for interface, interface_data in node['interfaces'].iteritems():
-            if interface == 'mgmt':
-                continue
-            if interface_data['link'] not in IPv4Util.topology_helper:
-                IPv4Util.topology_helper[interface_data['link']] = \
-                    IPv4Util.next_network(nodes_addr)
-
-            network = IPv4Util.topology_helper[interface_data['link']]
-            address, prefix = IPv4Util.next_address(network)
-
-            if node['type'] != NodeType.TG:
-                get_node(node).set_ip(interface_data['name'], address, prefix)
-                get_node(node).set_interface_state(interface_data['name'], 'up')
-
-            key = (get_node_hostname(node), interface_data['name'])
-            IPv4Util.ADDRESSES[key] = address
-            IPv4Util.PREFIXES[key] = prefix
-            IPv4Util.SUBNETS[key] = network['subnet']
-
-    @staticmethod
-    def dut_nodes_setup_ipv4_addresses(nodes_info, nodes_addr):
-        """Configure IPv4 addresses on all non-management interfaces for each
-        node in nodes_info if node type is not traffic generator
-
-        :param nodes_info: dictionary containing information on all nodes
-        in topology
-        :param nodes_addr: dictionary containing IPv4 addresses
-        :return: nothing
-        """
-        IPv4Util.topology_helper = {}
-        # make a deep copy of nodes_addr because of modifications
-        nodes_addr_copy = copy.deepcopy(nodes_addr)
-        for node in nodes_info.values():
-            IPv4Util.configure_ipv4_addr_on_node(node, nodes_addr_copy)
-
-    @staticmethod
-    def nodes_clear_ipv4_addresses(nodes):
-        """Clear all addresses from all nodes in topology
-
-        :param nodes: dictionary containing information on all nodes
-        :return: nothing
-        """
-        for node in nodes.values():
-            for interface, interface_data in node['interfaces'].iteritems():
-                if interface == 'mgmt':
-                    continue
-                IPv4Util.flush_ip_addresses(interface_data['name'], node)
-
-    # TODO: not ipv4-specific, move to another class
-    @staticmethod
-    @keyword('Node "${node}" interface "${interface}" is in "${state}" state')
-    def set_interface_state(node, interface, state):
-        """See IPv4Node.set_interface_state for more information.
-
-        :param node:
-        :param interface:
-        :param state:
-        :return:
-        """
-        log.debug('Node {} interface {} is in {} state'.format(
-            get_node_hostname(node), interface, state))
-        get_node(node).set_interface_state(interface, state)
-
-    @staticmethod
-    @keyword('Node "${node}" interface "${port}" has IPv4 address '
-             '"${address}" with prefix length "${prefix_length}"')
-    def set_interface_address(node, interface, address, length):
-        """See IPv4Node.set_ip for more information.
-
-        :param node:
-        :param interface:
-        :param address:
-        :param length:
-        :return:
-        """
-        log.debug('Node {} interface {} has IPv4 address {} with prefix '
-                  'length {}'.format(get_node_hostname(node), interface,
-                                     address, length))
-        get_node(node).set_ip(interface, address, int(length))
-        hostname = get_node_hostname(node)
-        IPv4Util.ADDRESSES[hostname, interface] = address
-        IPv4Util.PREFIXES[hostname, interface] = int(length)
-        # TODO: Calculate subnet from ip address and prefix length.
-        # IPv4Util.SUBNETS[hostname, interface] =
-
     @staticmethod
     @keyword('From node "${node}" interface "${port}" ARP-ping '
              'IPv4 address "${ip_address}"')
     def arp_ping(node, interface, ip_address):
         log.debug('From node {} interface {} ARP-ping IPv4 address {}'.
-                  format(get_node_hostname(node), interface, ip_address))
+                  format(Topology.get_node_hostname(node),
+                         interface, ip_address))
         get_node(node).arp_ping(ip_address, interface)
 
     @staticmethod
@@ -454,40 +50,28 @@ class IPv4Util(object):
         :return:
         """
         log.debug('Node {} routes to network {} with prefix length {} '
-                  'via {} interface {}'.format(get_node_hostname(node),
+                  'via {} interface {}'.format(Topology.get_node_hostname(node),
                                                network, prefix_length,
                                                gateway, interface))
         get_node(node).set_route(network, int(prefix_length),
                                  gateway, interface)
 
-    @staticmethod
-    @keyword('Remove IPv4 route from "${node}" to network "${network}" with '
-             'prefix length "${prefix_length}" interface "${interface}" via '
-             '"${gateway}"')
-    def unset_route(node, network, prefix_length, interface, gateway):
-        """See IPv4Node.unset_route for more information.
-
-        :param node:
-        :param network:
-        :param prefix_length:
-        :param interface:
-        :param gateway:
-        :return:
-        """
-        get_node(node).unset_route(network, prefix_length, gateway, interface)
-
     @staticmethod
     @keyword('After ping is sent in topology "${nodes_info}" from node '
-             '"${src_node}" interface "${src_port}" with destination IPv4 '
-             'address of node "${dst_node}" interface "${dst_port}" a ping '
-             'response arrives and TTL is decreased by "${hops}"')
-    def send_ping(nodes_info, src_node, src_port, dst_node, dst_port, hops):
+             '"${src_node}" interface "${src_port}" "${src_ip}" with '
+             'destination IPv4 address "${dst_ip}" of node "${dst_node}" '
+             'interface "${dst_port}" a ping response arrives and TTL is '
+             'decreased by "${hops}"')
+    def send_ping(nodes_info, src_node, src_port, src_ip, dst_ip, dst_node,
+                  dst_port, hops):
         """Send IPv4 ping and wait for response.
 
         :param nodes_info: Dictionary containing information on all nodes
         in topology.
         :param src_node: Source node.
         :param src_port: Source interface.
+        :param src_ip: Source ipv4 address.
+        :param dst_ip: Destination ipv4 address.
         :param dst_node: Destination node.
         :param dst_port: Destination interface.
         :param hops: Number of hops between src_node and dst_node.
@@ -495,61 +79,58 @@ class IPv4Util(object):
         log.debug('After ping is sent from node "{}" interface "{}" '
                   'with destination IPv4 address of node "{}" interface "{}" '
                   'a ping response arrives and TTL is decreased by "${}"'.
-                  format(get_node_hostname(src_node), src_port,
-                         get_node_hostname(dst_node), dst_port, hops))
-        node = src_node
+                  format(Topology.get_node_hostname(src_node), src_port,
+                         Topology.get_node_hostname(dst_node), dst_port, hops))
+        dst_mac = None
         src_mac = Topology.get_interface_mac(src_node, src_port)
         if dst_node['type'] == NodeType.TG:
             dst_mac = Topology.get_interface_mac(src_node, src_port)
         _, adj_int = Topology.\
             get_adjacent_node_and_interface(nodes_info, src_node, src_port)
         first_hop_mac = adj_int['mac_address']
-        src_ip = IPv4Util.get_ip_addr(src_node, src_port)
-        dst_ip = IPv4Util.get_ip_addr(dst_node, dst_port)
         args = '--src_if "{}" --src_mac "{}" --first_hop_mac "{}" ' \
                '--src_ip "{}" --dst_ip "{}" --hops "{}"'\
             .format(src_port, src_mac, first_hop_mac, src_ip, dst_ip, hops)
         if dst_node['type'] == NodeType.TG:
             args += ' --dst_if "{}" --dst_mac "{}"'.format(dst_port, dst_mac)
         TrafficScriptExecutor.run_traffic_script_on_node(
-            "ipv4_ping_ttl_check.py", node, args)
+            "ipv4_ping_ttl_check.py", src_node, args)
 
     @staticmethod
-    @keyword('Get IPv4 address of node "${node}" interface "${port}"')
-    def get_ip_addr(node, port):
-        """Get IPv4 address configured on specified interface
-
-        :param node: node dictionary
-        :param port: interface name
-        :return: IPv4 address of specified interface as a 'str' type
-        """
-        log.debug('Get IPv4 address of node {} interface {}'.
-                  format(get_node_hostname(node), port))
-        return IPv4Util.ADDRESSES[(get_node_hostname(node), port)]
-
-    @staticmethod
-    @keyword('Get IPv4 address prefix of node "${node}" interface "${port}"')
-    def get_ip_addr_prefix(node, port):
+    @keyword('Get IPv4 address prefix of node "${node}" interface "${port}" '
+             'from "${nodes_addr}"')
+    def get_ip_addr_prefix_length(node, port, nodes_addr):
         """ Get IPv4 address prefix for specified interface.
 
         :param node: Node dictionary.
         :param port: Interface name.
+        :return: IPv4 prefix length
         """
-        log.debug('Get IPv4 address prefix of node {} interface {}'.
-                  format(get_node_hostname(node), port))
-        return IPv4Util.PREFIXES[(get_node_hostname(node), port)]
+        for net in nodes_addr.values():
+            for p in net['ports'].values():
+                if p['node'] == node['host'] and p['if'] == port:
+                    return net['prefix']
+
+        raise Exception('Subnet not found for node {n} port {p}'.
+                        format(n=node['host'], p=port))
 
     @staticmethod
-    @keyword('Get IPv4 subnet of node "${node}" interface "${port}"')
-    def get_ip_addr_subnet(node, port):
+    @keyword('Get IPv4 subnet of node "${node}" interface "${port}" from '
+             '"${nodes_addr}"')
+    def get_ip_addr_subnet(node, port, nodes_addr):
         """ Get IPv4 subnet of specified interface.
 
         :param node: Node dictionary.
         :param port: Interface name.
+        :return: IPv4 subnet of 'str' type
         """
-        log.debug('Get IPv4 subnet of node {} interface {}'.
-                  format(get_node_hostname(node), port))
-        return IPv4Util.SUBNETS[(get_node_hostname(node), port)]
+        for net in nodes_addr.values():
+            for p in net['ports'].values():
+                if p['node'] == node['host'] and p['if'] == port:
+                    return net['net_addr']
+
+        raise Exception('Subnet not found for node {n} port {p}'.
+                        format(n=node['host'], p=port))
 
     @staticmethod
     @keyword('Flush IPv4 addresses "${port}" "${node}"')
@@ -560,8 +141,4 @@ class IPv4Util(object):
         :param node:
         :return:
         """
-        key = (get_node_hostname(node), port)
-        del IPv4Util.ADDRESSES[key]
-        del IPv4Util.PREFIXES[key]
-        del IPv4Util.SUBNETS[key]
         get_node(node).flush_ip_addresses(port)
diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py
new file mode 100644 (file)
index 0000000..bc8bf94
--- /dev/null
@@ -0,0 +1,54 @@
+# 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.
+
+"""Interface util library"""
+
+from resources.libraries.python.ssh import exec_cmd_no_error
+from resources.libraries.python.topology import NodeType, Topology
+from resources.libraries.python.VatExecutor import VatExecutor
+
+
+class InterfaceUtil(object):
+    """General utilities for managing interfaces"""
+
+    @staticmethod
+    def set_interface_state(node, interface, state):
+        """Set interface state on a node.
+
+        Function can be used for DUTs as well as for TGs.
+
+        :param node: node where the interface is
+        :param interface: interface name
+        :param state: one of 'up' or 'down'
+        :type node: dict
+        :type interface: str
+        :type state: str
+        :return: nothing
+        """
+        if node['type'] == NodeType.DUT:
+            if state == 'up':
+                state = 'admin-up link-up'
+            elif state == 'down':
+                state = 'admin-down link-down'
+            else:
+                raise Exception('Unexpected interface state: {}'.format(state))
+
+            sw_if_index = Topology.get_interface_sw_index(node, interface)
+            VatExecutor.cmd_from_template(node, 'set_if_state.vat',
+                                          sw_if_index=sw_if_index, state=state)
+
+        elif node['type'] == NodeType.TG:
+            cmd = 'ip link set {} {}'.format(interface, state)
+            exec_cmd_no_error(node, cmd, sudo=True)
+        else:
+            raise Exception('Unknown NodeType: "{}"'.format(node['type']))
index 6a7ea79..8b6905d 100644 (file)
@@ -647,3 +647,20 @@ class Topology(object):
                           'DUT1_BD_LINKS': dut1_bd_links,
                           'DUT2_BD_LINKS': dut2_bd_links}
         return topology_links
+
+    @staticmethod
+    def is_tg_node(node):
+        """Find out whether the node is TG
+
+        :param node: node to examine
+        :return: True if node is type of TG; False otherwise
+        """
+        return node['type'] == NodeType.TG
+
+    @staticmethod
+    def get_node_hostname(node):
+        """
+        :param node: node dictionary
+        :return: host name as 'str' type
+        """
+        return node['host']
\ No newline at end of file
index b5f313d..a5745a8 100644 (file)
 *** Settings ***
 | Resource | resources/libraries/robot/default.robot
 | Resource | resources/libraries/robot/counters.robot
-| Library | resources.libraries.python.IPv4Util
+| Library | resources.libraries.python.IPv4Util.IPv4Util
+| Library | resources.libraries.python.IPv4Setup.IPv4Setup
 | Library | resources.libraries.python.TrafficScriptExecutor
-| Variables | resources/libraries/python/IPv4NodeAddress.py
+| Variables | resources/libraries/python/IPv4NodeAddress.py | ${nodes}
 
 *** Keywords ***
 
 | Setup IPv4 adresses on all DUT nodes in topology
 | | [Documentation] | Setup IPv4 address on all DUTs in topology
 | | [Arguments] | ${nodes} | ${nodes_addr}
-| | DUT Nodes setup IPv4 addresses | ${nodes} | ${nodes_addr}
-
-| Interfaces needed for IPv4 testing are in "${state}" state
-| | Node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port1']['name']}" is in "${state}" state
-| | Node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port3']['name']}" is in "${state}" state
-| | Node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port1']['name']}" is in "${state}" state
-| | Node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port3']['name']}" is in "${state}" state
+| | VPP nodes setup ipv4 addresses | ${nodes} | ${nodes_addr}
 
 | Routes are set up for IPv4 testing
-| | ${gateway} = | Get IPv4 address of node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port3']['name']}"
-| | ${subnet} = | Get IPv4 subnet of node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port1']['name']}"
-| | ${prefix_length} = | Get IPv4 address prefix of node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port1']['name']}"
+| | ${gateway}= | Get IPv4 address of node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port3']['name']}" from "${nodes_ipv4_addr}"
+| | ${subnet} = | Get IPv4 subnet of node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port1']['name']}" from "${nodes_ipv4_addr}"
+| | ${prefix_length} = | Get IPv4 address prefix of node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port1']['name']}" from "${nodes_ipv4_addr}"
 | | Node "${nodes['DUT1']}" routes to IPv4 network "${subnet}" with prefix length "${prefix_length}" using interface "${nodes['DUT1']['interfaces']['port3']['name']}" via "${gateway}"
-| | ${gateway} = | Get IPv4 address of node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port3']['name']}"
-| | ${subnet} = | Get IPv4 subnet of node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port1']['name']}"
-| | ${prefix_length} = | Get IPv4 address prefix of node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port1']['name']}"
+| | ${gateway} = | Get IPv4 address of node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port3']['name']}" from "${nodes_ipv4_addr}"
+| | ${subnet} = | Get IPv4 subnet of node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port1']['name']}" from "${nodes_ipv4_addr}"
+| | ${prefix_length} = | Get IPv4 address prefix of node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port1']['name']}" from "${nodes_ipv4_addr}"
 | | Node "${nodes['DUT2']}" routes to IPv4 network "${subnet}" with prefix length "${prefix_length}" using interface "${nodes['DUT2']['interfaces']['port3']['name']}" via "${gateway}"
 
 | Setup DUT nodes for IPv4 testing
 | | Routes are set up for IPv4 testing
 
 | Setup nodes for IPv4 testing
-| | Interfaces needed for IPv4 testing are in "up" state
 | | Setup IPv4 adresses on all DUT nodes in topology | ${nodes} | ${nodes_ipv4_addr}
-| | Setup ARP on all DUTs | ${nodes}
+| | Setup ARP on all DUTs | ${nodes} | ${nodes_ipv4_addr}
 | | Routes are set up for IPv4 testing
 
 | TG interface "${tg_port}" can route to node "${node}" interface "${port}" "${hops}" hops away using IPv4
 | | Node "${nodes['TG']}" interface "${tg_port}" can route to node "${node}" interface "${port}" "${hops}" hops away using IPv4
 
 | Node "${from_node}" interface "${from_port}" can route to node "${to_node}" interface "${to_port}" "${hops}" hops away using IPv4
-| | After ping is sent in topology "${nodes}" from node "${from_node}" interface "${from_port}" with destination IPv4 address of node "${to_node}" interface "${to_port}" a ping response arrives and TTL is decreased by "${hops}"
+| | ${src_ip}= | Get IPv4 address of node "${from_node}" interface "${from_port}" from "${nodes_ipv4_addr}"
+| | ${dst_ip}= | Get IPv4 address of node "${to_node}" interface "${to_port}" from "${nodes_ipv4_addr}"
+| | ${src_mac}= | Get interface mac | ${from_node} | ${from_port}
+| | ${dst_mac}= | Get interface mac | ${to_node} | ${to_port}
+| | ${is_dst_tg}= | Is TG node | ${to_node}
+| | ${adj_node} | ${adj_int}= | Get adjacent node and interface | ${nodes} | ${from_node} | ${from_port}
+| | ${args}= | Traffic Script Gen Arg | ${to_port} | ${from_port} | ${src_mac}
+| |          | ...                    | ${dst_mac} | ${src_ip} | ${dst_ip}
+| | ${args}= | Catenate | ${args} | --hops ${hops} | --first_hop_mac ${adj_int['mac_address']}
+| |          | ...      | --is_dst_defined ${is_dst_tg}
+| | Run Traffic Script On Node | ipv4_ping_ttl_check.py | ${from_node} | ${args}
 
 | Ipv4 icmp echo sweep
 | | [Documentation] | Type of the src_node must be TG and dst_node must be DUT
 | | [Arguments] | ${src_node} | ${dst_node} | ${src_port} | ${dst_port}
-| | ${src_ip}= | Get IPv4 address of node "${src_node}" interface "${src_port}"
-| | ${dst_ip}= | Get IPv4 address of node "${dst_node}" interface "${dst_port}"
+| | ${src_ip}= | Get IPv4 address of node "${src_node}" interface "${src_port}" from "${nodes_ipv4_addr}"
+| | ${dst_ip}= | Get IPv4 address of node "${dst_node}" interface "${dst_port}" from "${nodes_ipv4_addr}"
 | | ${src_mac}= | Get Interface Mac | ${src_node} | ${src_port}
 | | ${dst_mac}= | Get Interface Mac | ${dst_node} | ${dst_port}
 | | ${args}= | Traffic Script Gen Arg | ${src_port} | ${src_port} | ${src_mac}
@@ -78,8 +82,8 @@
 | | ${link_name}= | Get first active connecting link between node "${tg_node}" and "${vpp_node}"
 | | ${src_if}= | Get interface by link name | ${tg_node} | ${link_name}
 | | ${dst_if}= | Get interface by link name | ${vpp_node} | ${link_name}
-| | ${src_ip}= | Get IPv4 address of node "${tg_node}" interface "${src_if}"
-| | ${dst_ip}= | Get IPv4 address of node "${vpp_node}" interface "${dst_if}"
+| | ${src_ip}= | Get IPv4 address of node "${tg_node}" interface "${src_if}" from "${nodes_ipv4_addr}"
+| | ${dst_ip}= | Get IPv4 address of node "${vpp_node}" interface "${dst_if}" from "${nodes_ipv4_addr}"
 | | ${src_mac}= | Get node link mac | ${tg_node} | ${link_name}
 | | ${dst_mac}= | Get node link mac | ${vpp_node} | ${link_name}
 | | ${args}= | Traffic Script Gen Arg | ${src_if} | ${src_if} | ${src_mac}
index 2603863..f42c748 100644 (file)
@@ -17,7 +17,7 @@
 | Library | resources.libraries.python.CrossConnectSetup
 | Library | resources.libraries.python.topology.Topology
 | Library | resources.libraries.python.TrafficScriptExecutor
-| Library | resources.libraries.python.IPv4Util
+| Library | resources.libraries.python.InterfaceUtil.InterfaceUtil
 | Variables | resources/libraries/python/constants.py
 
 *** Keywords ***
@@ -52,8 +52,7 @@
 
 
 | Interfaces on all DUTs are in "${state}" state
-| | Node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port1']['name']}" is in "${state}" state
-| | Node "${nodes['DUT1']}" interface "${nodes['DUT1']['interfaces']['port3']['name']}" is in "${state}" state
-| | Node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port1']['name']}" is in "${state}" state
-| | Node "${nodes['DUT2']}" interface "${nodes['DUT2']['interfaces']['port3']['name']}" is in "${state}" state
-
+| | Set interface state | ${nodes['DUT1']} | ${nodes['DUT1']['interfaces']['port1']['name']} | ${state}
+| | Set interface state | ${nodes['DUT1']} | ${nodes['DUT1']['interfaces']['port3']['name']} | ${state}
+| | Set interface state | ${nodes['DUT2']} | ${nodes['DUT2']['interfaces']['port1']['name']} | ${state}
+| | Set interface state | ${nodes['DUT2']} | ${nodes['DUT2']['interfaces']['port3']['name']} | ${state}
index 1286b46..2fd9d55 100755 (executable)
@@ -16,7 +16,7 @@
 from scapy.all import Ether, IP, ICMP
 from resources.libraries.python.PacketVerifier \
     import Interface, create_gratuitous_arp_request, auto_pad
-from optparse import OptionParser
+from resources.libraries.python.TrafficScriptArg import TrafficScriptArg
 
 
 def check_ttl(ttl_begin, ttl_end, ttl_diff):
@@ -45,28 +45,19 @@ def ckeck_packets_equal(pkt_send, pkt_recv):
         raise Exception("Sent packet doesn't match received packet")
 
 
-parser = OptionParser()
-parser.add_option("--src_if", dest="src_if")
-parser.add_option("--dst_if", dest="dst_if")  # optional
-parser.add_option("--src_mac", dest="src_mac")
-parser.add_option("--first_hop_mac", dest="first_hop_mac")
-parser.add_option("--dst_mac", dest="dst_mac")  # optional
-parser.add_option("--src_ip", dest="src_ip")
-parser.add_option("--dst_ip", dest="dst_ip")
-parser.add_option("--hops", dest="hops")  # optional
-# If one of 'dst_if', 'dst_mac' and 'hops' is specified all must be specified.
-(opts, args) = parser.parse_args()
-src_if_name = opts.src_if
-dst_if_name = opts.dst_if
-dst_if_defined = True
-if dst_if_name is None:
-    dst_if_defined = False
-src_mac = opts.src_mac
-first_hop_mac = opts.first_hop_mac
-dst_mac = opts.dst_mac
-src_ip = opts.src_ip
-dst_ip = opts.dst_ip
-hops = int(opts.hops)
+args = TrafficScriptArg(['src_mac', 'dst_mac', 'src_ip', 'dst_ip',
+                         'hops', 'first_hop_mac', 'is_dst_defined'])
+
+src_if_name = args.get_arg('tx_if')
+dst_if_name = args.get_arg('rx_if')
+dst_if_defined = True if args.get_arg('is_dst_defined') == 'True' else False
+
+src_mac = args.get_arg('src_mac')
+first_hop_mac = args.get_arg('first_hop_mac')
+dst_mac = args.get_arg('dst_mac')
+src_ip = args.get_arg('src_ip')
+dst_ip = args.get_arg('dst_ip')
+hops = int(args.get_arg('hops'))
 
 if dst_if_defined and (src_if_name == dst_if_name):
     raise Exception("Source interface name equals destination interface name")