Merge "Add unit test file for ArithmeticRunner"
[yardstick.git] / yardstick / network_services / helpers / samplevnf_helper.py
index 9d89d41..8e6a3a3 100644 (file)
@@ -19,12 +19,11 @@ import logging
 import os
 import sys
 from collections import OrderedDict, defaultdict
-from itertools import chain
+from itertools import chain, repeat
 
 import six
 from six.moves.configparser import ConfigParser
-
-from yardstick.common.utils import ip_to_hex
+from yardstick.common import utils
 
 LOG = logging.getLogger(__name__)
 
@@ -34,19 +33,6 @@ link {0} config {1} {2}
 link {0} up
 """
 
-ACTION_TEMPLATE = """\
-p action add {0} accept
-p action add {0} fwd {0}
-p action add {0} count
-"""
-
-FW_ACTION_TEMPLATE = """\
-p action add {0} accept
-p action add {0} fwd {0}
-p action add {0} count
-p action add {0} conntrack
-"""
-
 # This sets up a basic passthrough with no rules
 SCRIPT_TPL = """
 {link_config}
@@ -55,13 +41,107 @@ SCRIPT_TPL = """
 
 {arp_config6}
 
-{actions}
+{arp_route_tbl}
+
+{arp_route_tbl6}
 
-{rules}
+{flows}
 
 """
 
 
+class PortPairs(object):
+
+    DOWNLINK = "downlink"
+    UPLINK = "uplink"
+
+    def __init__(self, interfaces):
+        super(PortPairs, self).__init__()
+        self.interfaces = interfaces
+        self._all_ports = None
+        self._uplink_ports = None
+        self._downlink_ports = None
+        self._networks = None
+        self._port_pair_list = None
+        self._valid_networks = None
+
+    @property
+    def networks(self):
+        if self._networks is None:
+            self._networks = {}
+            for intf in self.interfaces:
+                vintf = intf['virtual-interface']
+                try:
+                    vld_id = vintf['vld_id']
+                except KeyError:
+                    # probably unused port?
+                    LOG.warning("intf without vld_id, %s", vintf)
+                else:
+                    self._networks.setdefault(vld_id, []).append(vintf["ifname"])
+        return self._networks
+
+    @classmethod
+    def get_downlink_id(cls, vld_id):
+        # partition returns a tuple
+        parts = list(vld_id.partition(cls.UPLINK))
+        if parts[0]:
+            # 'uplink' was not in or not leftmost in the string
+            return
+        parts[1] = cls.DOWNLINK
+        public_id = ''.join(parts)
+        return public_id
+
+    @property
+    # this only works for vnfs that have both uplink and public visible
+    def valid_networks(self):
+        if self._valid_networks is None:
+            self._valid_networks = []
+            for vld_id in self.networks:
+                downlink_id = self.get_downlink_id(vld_id)
+                if downlink_id in self.networks:
+                    self._valid_networks.append((vld_id, downlink_id))
+        return self._valid_networks
+
+    @property
+    def all_ports(self):
+        if self._all_ports is None:
+            self._all_ports = sorted(set(self.uplink_ports + self.downlink_ports))
+        return self._all_ports
+
+    @property
+    def uplink_ports(self):
+        if self._uplink_ports is None:
+            intfs = chain.from_iterable(
+                intfs for vld_id, intfs in self.networks.items() if
+                vld_id.startswith(self.UPLINK))
+            self._uplink_ports = sorted(set(intfs))
+        return self._uplink_ports
+
+    @property
+    def downlink_ports(self):
+        if self._downlink_ports is None:
+            intfs = chain.from_iterable(
+                intfs for vld_id, intfs in self.networks.items() if
+                vld_id.startswith(self.DOWNLINK))
+            self._downlink_ports = sorted(set(intfs))
+        return self._downlink_ports
+
+    @property
+    def port_pair_list(self):
+        if self._port_pair_list is None:
+            self._port_pair_list = []
+
+            for uplink, downlink in self.valid_networks:
+                for uplink_intf in self.networks[uplink]:
+                    # only VNFs have uplink, public peers
+                    peer_intfs = self.networks.get(downlink, [])
+                    if peer_intfs:
+                        for downlink_intf in peer_intfs:
+                            port_pair = uplink_intf, downlink_intf
+                            self._port_pair_list.append(port_pair)
+        return self._port_pair_list
+
+
 class MultiPortConfig(object):
 
     HW_LB = "HW"
@@ -86,29 +166,12 @@ class MultiPortConfig(object):
             return parser.get(section, key)
         return default
 
-    @staticmethod
-    def make_ip_addr(ip, mask):
-        """
-        :param ip: ip adddress
-        :type ip: str
-        :param mask: /24 prefix of 255.255.255.0 netmask
-        :type mask: str
-        :return: interface
-        :rtype: IPv4Interface
-        """
-
-        try:
-            return ipaddress.ip_interface(six.text_type('/'.join([ip, mask])))
-        except (TypeError, ValueError):
-            # None so we can skip later
-            return None
-
     @classmethod
     def validate_ip_and_prefixlen(cls, ip_addr, prefixlen):
-        ip_addr = cls.make_ip_addr(ip_addr, prefixlen)
+        ip_addr = utils.make_ip_addr(ip_addr, prefixlen)
         return ip_addr.ip.exploded, ip_addr.network.prefixlen
 
-    def __init__(self, topology_file, config_tpl, tmp_file, interfaces=None,
+    def __init__(self, topology_file, config_tpl, tmp_file, vnfd_helper,
                  vnf_type='CGNAT', lb_count=2, worker_threads=3,
                  worker_config='1C/1T', lb_config='SW', socket=0):
 
@@ -118,8 +181,7 @@ class MultiPortConfig(object):
         self.worker_threads = self.get_worker_threads(worker_threads)
         self.vnf_type = vnf_type
         self.pipe_line = 0
-        self.interfaces = interfaces if interfaces else {}
-        self.networks = {}
+        self.vnfd_helper = vnfd_helper
         self.write_parser = ConfigParser()
         self.read_parser = ConfigParser()
         self.read_parser.read(config_tpl)
@@ -135,9 +197,11 @@ class MultiPortConfig(object):
         self.tmp_file = os.path.join("/tmp", tmp_file)
         self.pktq_out_os = []
         self.socket = socket
-        self.start_core = ""
+        self.start_core = 1
         self.pipeline_counter = ""
         self.txrx_pipeline = ""
+        self._port_pairs = None
+        self.all_ports = []
         self.port_pair_list = []
         self.lb_to_port_pair_mapping = {}
         self.init_eal()
@@ -145,12 +209,11 @@ class MultiPortConfig(object):
         self.lb_index = None
         self.mul = 0
         self.port_pairs = []
-        self.port_pair_list = []
         self.ports_len = 0
         self.prv_que_handler = None
         self.vnfd = None
-        self.rules = None
-        self.pktq_out = ''
+        self.flows = None
+        self.pktq_out = []
 
     @staticmethod
     def gen_core(core):
@@ -160,24 +223,24 @@ class MultiPortConfig(object):
         return str(core)
 
     def make_port_pairs_iter(self, operand, iterable):
-        return (operand(x[-1], y) for y in iterable for x in chain(*self.port_pairs))
+        return (operand(self.vnfd_helper.port_num(x), y) for y in iterable for x in
+                chain.from_iterable(self.port_pairs))
 
     def make_range_port_pairs_iter(self, operand, start, end):
         return self.make_port_pairs_iter(operand, range(start, end))
 
     def init_eal(self):
-        vpci = [v['virtual-interface']["vpci"] for v in self.interfaces]
+        lines = ['[EAL]\n']
+        vpci = (v['virtual-interface']["vpci"] for v in self.vnfd_helper.interfaces)
+        lines.extend('w = {0}\n'.format(item) for item in vpci)
+        lines.append('\n')
         with open(self.tmp_file, 'w') as fh:
-            fh.write('[EAL]\n')
-            for item in vpci:
-                fh.write('w = {0}\n'.format(item))
-            fh.write('\n')
+            fh.writelines(lines)
 
     def update_timer(self):
         timer_tpl = self.get_config_tpl_data('TIMER')
-        timer_tpl['core'] = self.gen_core(self.start_core)
+        timer_tpl['core'] = self.gen_core(0)
         self.update_write_parser(timer_tpl)
-        self.start_core += 1
 
     def get_config_tpl_data(self, type_value):
         for section in self.read_parser.sections():
@@ -196,7 +259,6 @@ class MultiPortConfig(object):
     def init_write_parser_template(self, type_value='ARPICMP'):
         for section in self.read_parser.sections():
             if type_value == self.parser_get(self.read_parser, section, 'type', object()):
-                self.start_core = self.read_parser.getint(section, 'core')
                 self.pipeline_counter = self.read_parser.getint(section, 'core')
                 self.txrx_pipeline = self.read_parser.getint(section, 'core')
                 return
@@ -226,40 +288,6 @@ class MultiPortConfig(object):
         except ValueError:
             self.start_core = int(self.start_core[:-1]) + 1
 
-    @staticmethod
-    def get_port_pairs(interfaces):
-        port_pair_list = []
-        networks = {}
-        for private_intf in interfaces:
-            vintf = private_intf['virtual-interface']
-            try:
-                vld_id = vintf['vld_id']
-            except KeyError:
-                pass
-            else:
-                networks.setdefault(vld_id, []).append(vintf)
-
-        for name, net in networks.items():
-            # partition returns a tuple
-            parts = list(name.partition('private'))
-            if parts[0]:
-                # 'private' was not in or not leftmost in the string
-                continue
-            parts[1] = 'public'
-            public_id = ''.join(parts)
-            for private_intf in net:
-                try:
-                    public_peer_intfs = networks[public_id]
-                except KeyError:
-                    LOG.warning("private network without peer %s, %s not found", name, public_id)
-                    continue
-
-                for public_intf in public_peer_intfs:
-                    port_pair = private_intf["ifname"], public_intf["ifname"]
-                    port_pair_list.append(port_pair)
-
-        return port_pair_list, networks
-
     def get_lb_count(self):
         self.lb_count = int(min(len(self.port_pair_list), self.lb_count))
 
@@ -267,50 +295,49 @@ class MultiPortConfig(object):
         self.lb_to_port_pair_mapping = defaultdict(int)
         port_pair_count = len(self.port_pair_list)
         lb_pair_count = int(port_pair_count / self.lb_count)
-        for i in range(self.lb_count):
-            self.lb_to_port_pair_mapping[i + 1] = lb_pair_count
-        for i in range(port_pair_count % self.lb_count):
-            self.lb_to_port_pair_mapping[i + 1] += 1
+        extra = port_pair_count % self.lb_count
+        extra_iter = repeat(lb_pair_count + 1, extra)
+        norm_iter = repeat(lb_pair_count, port_pair_count - extra)
+        new_values = {i: v for i, v in enumerate(chain(extra_iter, norm_iter), 1)}
+        self.lb_to_port_pair_mapping.update(new_values)
 
     def set_priv_to_pub_mapping(self):
-        return "".join(str(y) for y in [(int(x[0][-1]), int(x[1][-1])) for x in
-                                        self.port_pair_list])
+        port_nums = [tuple(self.vnfd_helper.port_nums(x)) for x in self.port_pair_list]
+        return "".join(str(y).replace(" ", "") for y in
+                       port_nums)
 
     def set_priv_que_handler(self):
         # iterated twice, can't be generator
-        priv_to_pub_map = [(int(x[0][-1]), int(x[1][-1])) for x in self.port_pairs]
+        priv_to_pub_map = [tuple(self.vnfd_helper.port_nums(x)) for x in self.port_pairs]
         # must be list to use .index()
         port_list = list(chain.from_iterable(priv_to_pub_map))
-        priv_ports = (x[0] for x in priv_to_pub_map)
+        uplink_ports = (x[0] for x in priv_to_pub_map)
         self.prv_que_handler = '({})'.format(
-            ",".join((str(port_list.index(x)) for x in priv_ports)))
+            "".join(("{},".format(port_list.index(x)) for x in uplink_ports)))
 
     def generate_arp_route_tbl(self):
-        arp_config = []
-        arp_route_tbl_tmpl = "({port0_dst_ip_hex},{port0_netmask_hex},{port_num}," \
-                             "{next_hop_ip_hex})"
-        for port_pair in self.port_pair_list:
-            for port in port_pair:
-                port_num = int(port[-1])
-                interface = self.interfaces[port_num]
-                # We must use the dst because we are on the VNF and we need to
-                # reach the TG.
-                dst_port0_ip = \
-                    ipaddress.ip_interface(six.text_type(
-                        "%s/%s" % (interface["virtual-interface"]["dst_ip"],
-                                   interface["virtual-interface"]["netmask"])))
-                arp_vars = {
-                    "port0_dst_ip_hex": ip_to_hex(dst_port0_ip.network.network_address.exploded),
-                    "port0_netmask_hex": ip_to_hex(dst_port0_ip.network.netmask.exploded),
-                    # this is the port num that contains port0 subnet and next_hop_ip_hex
-                    "port_num": port_num,
-                    # next hop is dst in this case
-                    # must be within subnet
-                    "next_hop_ip_hex": ip_to_hex(dst_port0_ip.ip.exploded),
-                }
-                arp_config.append(arp_route_tbl_tmpl.format(**arp_vars))
-
-        return ' '.join(arp_config)
+        arp_route_tbl_tmpl = "routeadd net {port_num} {port_dst_ip} 0x{port_netmask_hex}"
+
+        def build_arp_config(port):
+            dpdk_port_num = self.vnfd_helper.port_num(port)
+            interface = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
+            # We must use the dst because we are on the VNF and we need to
+            # reach the TG.
+            dst_port_ip = ipaddress.ip_interface(six.text_type(
+                "%s/%s" % (interface["dst_ip"], interface["netmask"])))
+
+            arp_vars = {
+                "port_netmask_hex": utils.ip_to_hex(dst_port_ip.network.netmask.exploded),
+                # this is the port num that contains port0 subnet and next_hop_ip_hex
+                # this is LINKID which should be based on DPDK port number
+                "port_num": dpdk_port_num,
+                # next hop is dst in this case
+                # must be within subnet
+                "port_dst_ip": str(dst_port_ip.ip),
+            }
+            return arp_route_tbl_tmpl.format(**arp_vars)
+
+        return '\n'.join(build_arp_config(port) for port in self.all_ports)
 
     def generate_arpicmp_data(self):
         swq_in_str = self.make_range_str('SWQ{}', self.swq, offset=self.lb_count)
@@ -318,12 +345,14 @@ class MultiPortConfig(object):
         swq_out_str = self.make_range_str('SWQ{}', self.swq, offset=self.lb_count)
         self.swq += self.lb_count
         # ports_mac_list is disabled for some reason
-        # mac_iter = (self.interfaces[int(x[-1])]['virtual-interface']['local_mac']
-        #             for port_pair in self.port_pair_list for x in port_pair)
-        pktq_in_iter = ('RXQ{}'.format(float(x[0][-1])) for x in self.port_pair_list)
+
+        # mac_iter = (self.vnfd_helper.find_interface(name=port)['virtual-interface']['local_mac']
+        #             for port in self.all_ports)
+        pktq_in_iter = ('RXQ{}.0'.format(self.vnfd_helper.port_num(x[0])) for x in
+                        self.port_pair_list)
 
         arpicmp_data = {
-            'core': self.gen_core(self.start_core),
+            'core': self.gen_core(0),
             'pktq_in': swq_in_str,
             'pktq_out': swq_out_str,
             # we need to disable ports_mac_list?
@@ -331,11 +360,6 @@ class MultiPortConfig(object):
             # 'ports_mac_list': ' '.join(mac_iter),
             'pktq_in_prv': ' '.join(pktq_in_iter),
             'prv_to_pub_map': self.set_priv_to_pub_mapping(),
-            'arp_route_tbl': self.generate_arp_route_tbl(),
-            # nd_route_tbl must be set or we get segault on random OpenStack IPv6 traffic
-            # 'nd_route_tbl': "(0064:ff9b:0:0:0:0:9810:6414,120,0,0064:ff9b:0:0:0:0:9810:6414)"
-            # safe default?  route discard prefix to localhost
-            'nd_route_tbl': "(0100::,64,0,::1)"
         }
         self.pktq_out_os = swq_out_str.split(' ')
         # HWLB is a run to complition. So override the pktq_in/pktq_out
@@ -354,7 +378,7 @@ class MultiPortConfig(object):
 
         return arpicmp_data
 
-    def generate_final_txrx_data(self):
+    def generate_final_txrx_data(self, core=0):
         swq_start = self.swq - self.ports_len * self.worker_threads
 
         txq_start = 0
@@ -369,7 +393,7 @@ class MultiPortConfig(object):
             'pktq_in': swq_str,
             'pktq_out': txq_str,
             'pipeline_txrx_type': 'TXTX',
-            'core': self.gen_core(self.start_core),
+            'core': self.gen_core(core),
         }
         pktq_in = rxtx_data['pktq_in']
         pktq_in = '{0} {1}'.format(pktq_in, self.pktq_out_os[self.lb_index - 1])
@@ -390,7 +414,7 @@ class MultiPortConfig(object):
             'core': self.gen_core(self.start_core),
         }
         self.pipeline_counter += 1
-        return txrx_data
+        return self.start_core, txrx_data
 
     def generate_lb_data(self):
         pktq_in = self.make_range_str('SWQ{}', self.swq, offset=self.ports_len)
@@ -457,11 +481,13 @@ class MultiPortConfig(object):
         self.arpicmp_tpl.update(arpicmp_data)
         self.update_write_parser(self.arpicmp_tpl)
 
-        self.start_core += 1
         if self.vnf_type == 'CGNAPT':
             self.pipeline_counter += 1
             self.update_timer()
 
+        if self.lb_config == 'HW':
+            self.start_core = 1
+
         for lb in self.lb_to_port_pair_mapping:
             self.lb_index = lb
             self.mul = 0
@@ -474,7 +500,7 @@ class MultiPortConfig(object):
             self.ports_len = port_pair_count * 2
             self.set_priv_que_handler()
             if self.lb_config == 'SW':
-                txrx_data = self.generate_initial_txrx_data()
+                core, txrx_data = self.generate_initial_txrx_data()
                 self.txrx_tpl.update(txrx_data)
                 self.update_write_parser(self.txrx_tpl)
                 self.start_core += 1
@@ -483,7 +509,7 @@ class MultiPortConfig(object):
                 self.update_write_parser(self.loadb_tpl)
                 self.start_core += 1
 
-            for i in range(self.worker_threads):
+            for _ in range(self.worker_threads):
                 vnf_data = self.generate_vnf_data()
                 if not self.vnf_tpl:
                     self.vnf_tpl = {}
@@ -498,14 +524,16 @@ class MultiPortConfig(object):
                 self.generate_next_core_id()
 
             if self.lb_config == 'SW':
-                txrx_data = self.generate_final_txrx_data()
+                txrx_data = self.generate_final_txrx_data(core)
                 self.txrx_tpl.update(txrx_data)
                 self.update_write_parser(self.txrx_tpl)
-                self.start_core += 1
             self.vnf_tpl = self.get_config_tpl_data(self.vnf_type)
 
     def generate_config(self):
-        self.port_pair_list, self.networks = self.get_port_pairs(self.interfaces)
+        self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
+        self.port_pair_list = self._port_pairs.port_pair_list
+        self.all_ports = self._port_pairs.all_ports
+
         self.get_lb_count()
         self.generate_lb_to_port_pair_mapping()
         self.generate_config_data()
@@ -514,18 +542,16 @@ class MultiPortConfig(object):
             self.write_parser.write(tfh)
 
     def generate_link_config(self):
+        def build_args(port):
+            # lookup interface by name
+            virtual_interface = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
+            local_ip = virtual_interface["local_ip"]
+            netmask = virtual_interface["netmask"]
+            port_num = self.vnfd_helper.port_num(port)
+            port_ip, prefix_len = self.validate_ip_and_prefixlen(local_ip, netmask)
+            return LINK_CONFIG_TEMPLATE.format(port_num, port_ip, prefix_len)
 
-        link_configs = []
-        for port_pair in self.port_pair_list:
-            for port in port_pair:
-                port = port[-1]
-                virtual_interface = self.interfaces[int(port)]["virtual-interface"]
-                local_ip = virtual_interface["local_ip"]
-                netmask = virtual_interface["netmask"]
-                port_ip, prefix_len = self.validate_ip_and_prefixlen(local_ip, netmask)
-                link_configs.append(LINK_CONFIG_TEMPLATE.format(port, port_ip, prefix_len))
-
-        return ''.join(link_configs)
+        return ''.join(build_args(port) for port in self.all_ports)
 
     def get_route_data(self, src_key, data_key, port):
         route_list = self.vnfd['vdu'][0].get(src_key, [])
@@ -548,96 +574,42 @@ class MultiPortConfig(object):
 
     def generate_arp_config(self):
         arp_config = []
-        for port_pair in self.port_pair_list:
-            for port in port_pair:
-                # ignore gateway, always use TG IP
-                # gateway = self.get_ports_gateway(port)
-                dst_mac = self.interfaces[int(port[-1])]["virtual-interface"]["dst_mac"]
-                dst_ip = self.interfaces[int(port[-1])]["virtual-interface"]["dst_ip"]
-                # arp_config.append((port[-1], gateway, dst_mac, self.txrx_pipeline))
-                # so dst_mac is the TG dest mac, so we need TG dest IP.
-                arp_config.append((port[-1], dst_ip, dst_mac, self.txrx_pipeline))
+        for port in self.all_ports:
+            # ignore gateway, always use TG IP
+            # gateway = self.get_ports_gateway(port)
+            vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
+            dst_mac = vintf["dst_mac"]
+            dst_ip = vintf["dst_ip"]
+            # arp_config.append(
+            #     (self.vnfd_helper.port_num(port), gateway, dst_mac, self.txrx_pipeline))
+            # so dst_mac is the TG dest mac, so we need TG dest IP.
+            # should be dpdk_port_num
+            arp_config.append(
+                (self.vnfd_helper.port_num(port), dst_ip, dst_mac, self.txrx_pipeline))
 
         return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config))
 
     def generate_arp_config6(self):
         arp_config6 = []
-        for port_pair in self.port_pair_list:
-            for port in port_pair:
-                # ignore gateway, always use TG IP
-                # gateway6 = self.get_ports_gateway6(port)
-                dst_mac6 = self.interfaces[int(port[-1])]["virtual-interface"]["dst_mac"]
-                dst_ip6 = self.interfaces[int(port[-1])]["virtual-interface"]["dst_ip"]
-                # arp_config6.append((port[-1], gateway6, dst_mac6, self.txrx_pipeline))
-                arp_config6.append((port[-1], dst_ip6, dst_mac6, self.txrx_pipeline))
+        for port in self.all_ports:
+            # ignore gateway, always use TG IP
+            # gateway6 = self.get_ports_gateway6(port)
+            vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
+            dst_mac6 = vintf["dst_mac"]
+            dst_ip6 = vintf["dst_ip"]
+            # arp_config6.append(
+            #     (self.vnfd_helper.port_num(port), gateway6, dst_mac6, self.txrx_pipeline))
+            arp_config6.append(
+                (self.vnfd_helper.port_num(port), dst_ip6, dst_mac6, self.txrx_pipeline))
 
         return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config6))
 
-    def generate_action_config(self):
-        port_list = []
-        for port_pair in self.port_pair_list:
-            for port in port_pair:
-                port_list.append(port[-1])
-
-        if self.vnf_type == "VFW":
-            template = FW_ACTION_TEMPLATE
-        else:
-            template = ACTION_TEMPLATE
-
-        return ''.join((template.format(port) for port in port_list))
-
-    def get_ip_from_port(self, port):
-        # we can't use gateway because in OpenStack gateways interfer with floating ip routing
-        # return self.make_ip_addr(self.get_ports_gateway(port), self.get_netmask_gateway(port))
-        ip = self.interfaces[port]["virtual-interface"]["local_ip"]
-        netmask = self.interfaces[port]["virtual-interface"]["netmask"]
-        return self.make_ip_addr(ip, netmask)
-
-    def get_network_and_prefixlen_from_ip_of_port(self, port):
-        ip_addr = self.get_ip_from_port(port)
-        # handle cases with no gateway
-        if ip_addr:
-            return ip_addr.network.network_address.exploded, ip_addr.network.prefixlen
-        else:
-            return None, None
-
-    def generate_rule_config(self):
-        cmd = 'acl' if self.vnf_type == "ACL" else "vfw"
-        rules_config = self.rules if self.rules else ''
-        new_rules = []
-        new_ipv6_rules = []
-        pattern = 'p {0} add {1} {2} {3} {4} {5} 0 65535 0 65535 0 0 {6}'
-        for port_pair in self.port_pair_list:
-            src_port = int(port_pair[0][-1])
-            dst_port = int(port_pair[1][-1])
-
-            src_net, src_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(src_port)
-            dst_net, dst_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(dst_port)
-            # ignore entires with empty values
-            if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
-                new_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
-                                  dst_net, dst_prefix_len, dst_port))
-                new_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
-                                  src_net, src_prefix_len, src_port))
-
-            # src_net = self.get_ports_gateway6(port_pair[0])
-            # src_prefix_len = self.get_netmask_gateway6(port_pair[0])
-            # dst_net = self.get_ports_gateway6(port_pair[1])
-            # dst_prefix_len = self.get_netmask_gateway6(port_pair[0])
-            # # ignore entires with empty values
-            # if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
-            #     new_ipv6_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
-            #                            dst_net, dst_prefix_len, dst_port))
-            #     new_ipv6_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
-            #                            src_net, src_prefix_len, src_port))
-
-        acl_apply = "\np %s applyruleset" % cmd
-        new_rules_config = '\n'.join(pattern.format(*values) for values
-                                     in chain(new_rules, new_ipv6_rules))
-        return ''.join([rules_config, new_rules_config, acl_apply])
+    def get_flows_config(self):
+        return self.flows if self.flows else ''
 
     def generate_script_data(self):
-        self.port_pair_list, self.networks = self.get_port_pairs(self.interfaces)
+        self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
+        self.port_pair_list = self._port_pairs.port_pair_list
         self.get_lb_count()
         script_data = {
             'link_config': self.generate_link_config(),
@@ -645,21 +617,15 @@ class MultiPortConfig(object):
             # disable IPv6 for now
             # 'arp_config6': self.generate_arp_config6(),
             'arp_config6': "",
-            'actions': '',
-            'rules': '',
+            'arp_route_tbl': self.generate_arp_route_tbl(),
+            'arp_route_tbl6': "",
+            'flows': self.get_flows_config()
         }
-
-        if self.vnf_type in ('ACL', 'VFW'):
-            script_data.update({
-                'actions': self.generate_action_config(),
-                'rules': self.generate_rule_config(),
-            })
-
         return script_data
 
-    def generate_script(self, vnfd, rules=None):
+    def generate_script(self, vnfd, flows=None):
         self.vnfd = vnfd
-        self.rules = rules
+        self.flows = flows
         script_data = self.generate_script_data()
         script = SCRIPT_TPL.format(**script_data)
         if self.lb_config == self.HW_LB:
@@ -675,5 +641,5 @@ set_hash_input_set {0} ipv6-udp src-ipv6 udp-src-port add
 set_hash_input_set {1} ipv6-udp dst-ipv6 udp-dst-port add
 """
             for port_pair in self.port_pair_list:
-                script += hwlb_tpl.format(port_pair[0][-1], port_pair[1][-1])
+                script += hwlb_tpl.format(*(self.vnfd_helper.port_nums(port_pair)))
         return script