ae5451020b2394452585f3213dcc05d0b7691c97
[yardstick.git] / yardstick / network_services / helpers / samplevnf_helper.py
1 # Copyright (c) 2016-2017 Intel Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 from __future__ import absolute_import
16
17 import ipaddress
18 import logging
19 import os
20 import sys
21 from collections import OrderedDict, defaultdict
22 from itertools import chain
23
24 import six
25 from six.moves.configparser import ConfigParser
26
27 from yardstick.common.utils import ip_to_hex
28
29 LOG = logging.getLogger(__name__)
30
31 LINK_CONFIG_TEMPLATE = """\
32 link {0} down
33 link {0} config {1} {2}
34 link {0} up
35 """
36
37 ACTION_TEMPLATE = """\
38 p action add {0} accept
39 p action add {0} fwd {0}
40 p action add {0} count
41 """
42
43 FW_ACTION_TEMPLATE = """\
44 p action add {0} accept
45 p action add {0} fwd {0}
46 p action add {0} count
47 p action add {0} conntrack
48 """
49
50 # This sets up a basic passthrough with no rules
51 SCRIPT_TPL = """
52 {link_config}
53
54 {arp_config}
55
56 {arp_config6}
57
58 {actions}
59
60 {rules}
61
62 """
63
64
65 class MultiPortConfig(object):
66
67     HW_LB = "HW"
68
69     @staticmethod
70     def float_x_plus_one_tenth_of_y(x, y):
71         return float(x) + float(y) / 10.0
72
73     @staticmethod
74     def make_str(base, iterator):
75         return ' '.join((base.format(x) for x in iterator))
76
77     @classmethod
78     def make_range_str(cls, base, start, stop=0, offset=0):
79         if offset and not stop:
80             stop = start + offset
81         return cls.make_str(base, range(start, stop))
82
83     @staticmethod
84     def parser_get(parser, section, key, default=None):
85         if parser.has_option(section, key):
86             return parser.get(section, key)
87         return default
88
89     @staticmethod
90     def make_ip_addr(ip, mask):
91         """
92         :param ip: ip adddress
93         :type ip: str
94         :param mask: /24 prefix of 255.255.255.0 netmask
95         :type mask: str
96         :return: interface
97         :rtype: IPv4Interface
98         """
99
100         try:
101             return ipaddress.ip_interface(six.text_type('/'.join([ip, mask])))
102         except (TypeError, ValueError):
103             # None so we can skip later
104             return None
105
106     @classmethod
107     def validate_ip_and_prefixlen(cls, ip_addr, prefixlen):
108         ip_addr = cls.make_ip_addr(ip_addr, prefixlen)
109         return ip_addr.ip.exploded, ip_addr.network.prefixlen
110
111     def __init__(self, topology_file, config_tpl, tmp_file, interfaces=None,
112                  vnf_type='CGNAT', lb_count=2, worker_threads=3,
113                  worker_config='1C/1T', lb_config='SW', socket=0):
114
115         super(MultiPortConfig, self).__init__()
116         self.topology_file = topology_file
117         self.worker_config = worker_config.split('/')[1].lower()
118         self.worker_threads = self.get_worker_threads(worker_threads)
119         self.vnf_type = vnf_type
120         self.pipe_line = 0
121         self.interfaces = interfaces if interfaces else {}
122         self.networks = {}
123         self.write_parser = ConfigParser()
124         self.read_parser = ConfigParser()
125         self.read_parser.read(config_tpl)
126         self.master_core = self.read_parser.get("PIPELINE0", "core")
127         self.master_tpl = self.get_config_tpl_data('MASTER')
128         self.arpicmp_tpl = self.get_config_tpl_data('ARPICMP')
129         self.txrx_tpl = self.get_config_tpl_data('TXRX')
130         self.loadb_tpl = self.get_config_tpl_data('LOADB')
131         self.vnf_tpl = self.get_config_tpl_data(vnf_type)
132         self.swq = 0
133         self.lb_count = int(lb_count)
134         self.lb_config = lb_config
135         self.tmp_file = os.path.join("/tmp", tmp_file)
136         self.pktq_out_os = []
137         self.socket = socket
138         self.start_core = ""
139         self.pipeline_counter = ""
140         self.txrx_pipeline = ""
141         self.port_pair_list = []
142         self.lb_to_port_pair_mapping = {}
143         self.init_eal()
144
145         self.lb_index = None
146         self.mul = 0
147         self.port_pairs = []
148         self.port_pair_list = []
149         self.ports_len = 0
150         self.prv_que_handler = None
151         self.vnfd = None
152         self.rules = None
153         self.pktq_out = ''
154
155     @staticmethod
156     def gen_core(core):
157         # return "s{}c{}".format(self.socket, core)
158         # don't use sockets for VNFs, because we don't want to have to
159         # adjust VM CPU topology.  It is virtual anyway
160         return str(core)
161
162     def make_port_pairs_iter(self, operand, iterable):
163         return (operand(x[-1], y) for y in iterable for x in chain(*self.port_pairs))
164
165     def make_range_port_pairs_iter(self, operand, start, end):
166         return self.make_port_pairs_iter(operand, range(start, end))
167
168     def init_eal(self):
169         vpci = [v['virtual-interface']["vpci"] for v in self.interfaces]
170         with open(self.tmp_file, 'w') as fh:
171             fh.write('[EAL]\n')
172             for item in vpci:
173                 fh.write('w = {0}\n'.format(item))
174             fh.write('\n')
175
176     def update_timer(self):
177         timer_tpl = self.get_config_tpl_data('TIMER')
178         timer_tpl['core'] = self.gen_core(self.start_core)
179         self.update_write_parser(timer_tpl)
180         self.start_core += 1
181
182     def get_config_tpl_data(self, type_value):
183         for section in self.read_parser.sections():
184             if self.read_parser.has_option(section, 'type'):
185                 if type_value == self.read_parser.get(section, 'type'):
186                     tpl = OrderedDict(self.read_parser.items(section))
187                     return tpl
188
189     def get_txrx_tpl_data(self, value):
190         for section in self.read_parser.sections():
191             if self.read_parser.has_option(section, 'pipeline_txrx_type'):
192                 if value == self.read_parser.get(section, 'pipeline_txrx_type'):
193                     tpl = OrderedDict(self.read_parser.items(section))
194                     return tpl
195
196     def init_write_parser_template(self, type_value='ARPICMP'):
197         for section in self.read_parser.sections():
198             if type_value == self.parser_get(self.read_parser, section, 'type', object()):
199                 self.start_core = self.read_parser.getint(section, 'core')
200                 self.pipeline_counter = self.read_parser.getint(section, 'core')
201                 self.txrx_pipeline = self.read_parser.getint(section, 'core')
202                 return
203             self.write_parser.add_section(section)
204             for name, value in self.read_parser.items(section):
205                 self.write_parser.set(section, name, value)
206
207     def update_write_parser(self, data):
208         section = "PIPELINE{0}".format(self.pipeline_counter)
209         self.write_parser.add_section(section)
210         for name, value in data.items():
211             self.write_parser.set(section, name, value)
212
213     def get_worker_threads(self, worker_threads):
214         if self.worker_config == '1t':
215             return worker_threads
216         else:
217             return worker_threads - worker_threads % 2
218
219     def generate_next_core_id(self):
220         if self.worker_config == '1t':
221             self.start_core += 1
222             return
223
224         try:
225             self.start_core = '{}h'.format(int(self.start_core))
226         except ValueError:
227             self.start_core = int(self.start_core[:-1]) + 1
228
229     @staticmethod
230     def get_port_pairs(interfaces):
231         port_pair_list = []
232         networks = defaultdict(list)
233         for private_intf in interfaces:
234             vintf = private_intf['virtual-interface']
235             networks[vintf['vld_id']].append(vintf)
236
237         for name, net in networks.items():
238             # partition returns a tuple
239             parts = list(name.partition('private'))
240             if parts[0]:
241                 # 'private' was not in or not leftmost in the string
242                 continue
243             parts[1] = 'public'
244             public_id = ''.join(parts)
245             for private_intf in net:
246                 try:
247                     public_peer_intfs = networks[public_id]
248                 except KeyError:
249                     LOG.warning("private network without peer %s, %s not found", name, public_id)
250                     continue
251
252                 for public_intf in public_peer_intfs:
253                     port_pair = private_intf["ifname"], public_intf["ifname"]
254                     port_pair_list.append(port_pair)
255
256         return port_pair_list, networks
257
258     def get_lb_count(self):
259         self.lb_count = int(min(len(self.port_pair_list), self.lb_count))
260
261     def generate_lb_to_port_pair_mapping(self):
262         self.lb_to_port_pair_mapping = defaultdict(int)
263         port_pair_count = len(self.port_pair_list)
264         lb_pair_count = int(port_pair_count / self.lb_count)
265         for i in range(self.lb_count):
266             self.lb_to_port_pair_mapping[i + 1] = lb_pair_count
267         for i in range(port_pair_count % self.lb_count):
268             self.lb_to_port_pair_mapping[i + 1] += 1
269
270     def set_priv_to_pub_mapping(self):
271         return "".join(str(y) for y in [(int(x[0][-1]), int(x[1][-1])) for x in
272                                         self.port_pair_list])
273
274     def set_priv_que_handler(self):
275         # iterated twice, can't be generator
276         priv_to_pub_map = [(int(x[0][-1]), int(x[1][-1])) for x in self.port_pairs]
277         # must be list to use .index()
278         port_list = list(chain.from_iterable(priv_to_pub_map))
279         priv_ports = (x[0] for x in priv_to_pub_map)
280         self.prv_que_handler = '({})'.format(
281             ",".join((str(port_list.index(x)) for x in priv_ports)))
282
283     def generate_arp_route_tbl(self):
284         arp_config = []
285         arp_route_tbl_tmpl = "({port0_dst_ip_hex},{port0_netmask_hex},{port_num}," \
286                              "{next_hop_ip_hex})"
287         for port_pair in self.port_pair_list:
288             for port in port_pair:
289                 port_num = int(port[-1])
290                 interface = self.interfaces[port_num]
291                 # We must use the dst because we are on the VNF and we need to
292                 # reach the TG.
293                 dst_port0_ip = \
294                     ipaddress.ip_interface(six.text_type(
295                         "%s/%s" % (interface["virtual-interface"]["dst_ip"],
296                                    interface["virtual-interface"]["netmask"])))
297                 arp_vars = {
298                     "port0_dst_ip_hex": ip_to_hex(dst_port0_ip.network.network_address.exploded),
299                     "port0_netmask_hex": ip_to_hex(dst_port0_ip.network.netmask.exploded),
300                     # this is the port num that contains port0 subnet and next_hop_ip_hex
301                     "port_num": port_num,
302                     # next hop is dst in this case
303                     # must be within subnet
304                     "next_hop_ip_hex": ip_to_hex(dst_port0_ip.ip.exploded),
305                 }
306                 arp_config.append(arp_route_tbl_tmpl.format(**arp_vars))
307
308         return ' '.join(arp_config)
309
310     def generate_arpicmp_data(self):
311         swq_in_str = self.make_range_str('SWQ{}', self.swq, offset=self.lb_count)
312         self.swq += self.lb_count
313         swq_out_str = self.make_range_str('SWQ{}', self.swq, offset=self.lb_count)
314         self.swq += self.lb_count
315         # ports_mac_list is disabled for some reason
316         # mac_iter = (self.interfaces[int(x[-1])]['virtual-interface']['local_mac']
317         #             for port_pair in self.port_pair_list for x in port_pair)
318         pktq_in_iter = ('RXQ{}'.format(float(x[0][-1])) for x in self.port_pair_list)
319
320         arpicmp_data = {
321             'core': self.gen_core(self.start_core),
322             'pktq_in': swq_in_str,
323             'pktq_out': swq_out_str,
324             # we need to disable ports_mac_list?
325             # it looks like ports_mac_list is no longer required
326             # 'ports_mac_list': ' '.join(mac_iter),
327             'pktq_in_prv': ' '.join(pktq_in_iter),
328             'prv_to_pub_map': self.set_priv_to_pub_mapping(),
329             'arp_route_tbl': self.generate_arp_route_tbl(),
330             # nd_route_tbl must be set or we get segault on random OpenStack IPv6 traffic
331             # 'nd_route_tbl': "(0064:ff9b:0:0:0:0:9810:6414,120,0,0064:ff9b:0:0:0:0:9810:6414)"
332             # safe default?  route discard prefix to localhost
333             'nd_route_tbl': "(0100::,64,0,::1)"
334         }
335         self.pktq_out_os = swq_out_str.split(' ')
336         # why?
337         if self.lb_config == self.HW_LB:
338             arpicmp_data['pktq_in'] = swq_in_str
339             self.swq = 0
340         return arpicmp_data
341
342     def generate_final_txrx_data(self):
343         swq_start = self.swq - self.ports_len * self.worker_threads
344
345         txq_start = 0
346         txq_end = self.worker_threads
347
348         pktq_out_iter = self.make_range_port_pairs_iter(self.float_x_plus_one_tenth_of_y,
349                                                         txq_start, txq_end)
350
351         swq_str = self.make_range_str('SWQ{}', swq_start, self.swq)
352         txq_str = self.make_str('TXQ{}', pktq_out_iter)
353         rxtx_data = {
354             'pktq_in': swq_str,
355             'pktq_out': txq_str,
356             'pipeline_txrx_type': 'TXTX',
357             'core': self.gen_core(self.start_core),
358         }
359         pktq_in = rxtx_data['pktq_in']
360         pktq_in = '{0} {1}'.format(pktq_in, self.pktq_out_os[self.lb_index - 1])
361         rxtx_data['pktq_in'] = pktq_in
362         self.pipeline_counter += 1
363         return rxtx_data
364
365     def generate_initial_txrx_data(self):
366         pktq_iter = self.make_range_port_pairs_iter(self.float_x_plus_one_tenth_of_y,
367                                                     0, self.worker_threads)
368
369         rxq_str = self.make_str('RXQ{}', pktq_iter)
370         swq_str = self.make_range_str('SWQ{}', self.swq, offset=self.ports_len)
371         txrx_data = {
372             'pktq_in': rxq_str,
373             'pktq_out': swq_str + ' SWQ{0}'.format(self.lb_index - 1),
374             'pipeline_txrx_type': 'RXRX',
375             'core': self.gen_core(self.start_core),
376         }
377         self.pipeline_counter += 1
378         return txrx_data
379
380     def generate_lb_data(self):
381         pktq_in = self.make_range_str('SWQ{}', self.swq, offset=self.ports_len)
382         self.swq += self.ports_len
383
384         offset = self.ports_len * self.worker_threads
385         pktq_out = self.make_range_str('SWQ{}', self.swq, offset=offset)
386         self.pktq_out = pktq_out.split()
387
388         self.swq += (self.ports_len * self.worker_threads)
389         lb_data = {
390             'prv_que_handler': self.prv_que_handler,
391             'pktq_in': pktq_in,
392             'pktq_out': pktq_out,
393             'n_vnf_threads': str(self.worker_threads),
394             'core': self.gen_core(self.start_core),
395         }
396         self.pipeline_counter += 1
397         return lb_data
398
399     def generate_vnf_data(self):
400         if self.lb_config == self.HW_LB:
401             port_iter = self.make_port_pairs_iter(self.float_x_plus_one_tenth_of_y, [self.mul])
402             pktq_in = self.make_str('RXQ{}', port_iter)
403
404             self.mul += 1
405             port_iter = self.make_port_pairs_iter(self.float_x_plus_one_tenth_of_y, [self.mul])
406             pktq_out = self.make_str('TXQ{}', port_iter)
407
408             pipe_line_data = {
409                 'pktq_in': pktq_in,
410                 'pktq_out': pktq_out + ' SWQ{0}'.format(self.swq),
411                 'prv_que_handler': self.prv_que_handler,
412                 'core': self.gen_core(self.start_core),
413             }
414             self.swq += 1
415         else:
416             pipe_line_data = {
417                 'pktq_in': ' '.join((self.pktq_out.pop(0) for _ in range(self.ports_len))),
418                 'pktq_out': self.make_range_str('SWQ{}', self.swq, offset=self.ports_len),
419                 'prv_que_handler': self.prv_que_handler,
420                 'core': self.gen_core(self.start_core),
421             }
422             self.swq += self.ports_len
423
424         if self.vnf_type in ('ACL', 'VFW'):
425             pipe_line_data.pop('prv_que_handler')
426
427         if self.vnf_tpl.get('vnf_set'):
428             public_ip_port_range_list = self.vnf_tpl['public_ip_port_range'].split(':')
429             ip_in_hex = '{:x}'.format(int(public_ip_port_range_list[0], 16) + self.lb_index - 1)
430             public_ip_port_range_list[0] = ip_in_hex
431             self.vnf_tpl['public_ip_port_range'] = ':'.join(public_ip_port_range_list)
432
433         self.pipeline_counter += 1
434         return pipe_line_data
435
436     def generate_config_data(self):
437         self.init_write_parser_template()
438
439         # use master core for master, don't use self.start_core
440         self.write_parser.set('PIPELINE0', 'core', self.gen_core(self.master_core))
441         arpicmp_data = self.generate_arpicmp_data()
442         self.arpicmp_tpl.update(arpicmp_data)
443         self.update_write_parser(self.arpicmp_tpl)
444
445         self.start_core += 1
446         if self.vnf_type == 'CGNAPT':
447             self.pipeline_counter += 1
448             self.update_timer()
449
450         for lb in self.lb_to_port_pair_mapping:
451             self.lb_index = lb
452             self.mul = 0
453             port_pair_count = self.lb_to_port_pair_mapping[lb]
454             if not self.port_pair_list:
455                 continue
456
457             self.port_pairs = self.port_pair_list[:port_pair_count]
458             self.port_pair_list = self.port_pair_list[port_pair_count:]
459             self.ports_len = port_pair_count * 2
460             self.set_priv_que_handler()
461             if self.lb_config == 'SW':
462                 txrx_data = self.generate_initial_txrx_data()
463                 self.txrx_tpl.update(txrx_data)
464                 self.update_write_parser(self.txrx_tpl)
465                 self.start_core += 1
466                 lb_data = self.generate_lb_data()
467                 self.loadb_tpl.update(lb_data)
468                 self.update_write_parser(self.loadb_tpl)
469                 self.start_core += 1
470
471             for i in range(self.worker_threads):
472                 vnf_data = self.generate_vnf_data()
473                 if not self.vnf_tpl:
474                     self.vnf_tpl = {}
475                 self.vnf_tpl.update(vnf_data)
476                 self.update_write_parser(self.vnf_tpl)
477                 try:
478                     self.vnf_tpl.pop('vnf_set')
479                 except KeyError:
480                     pass
481                 else:
482                     self.vnf_tpl.pop('public_ip_port_range')
483                 self.generate_next_core_id()
484
485             if self.lb_config == 'SW':
486                 txrx_data = self.generate_final_txrx_data()
487                 self.txrx_tpl.update(txrx_data)
488                 self.update_write_parser(self.txrx_tpl)
489                 self.start_core += 1
490             self.vnf_tpl = self.get_config_tpl_data(self.vnf_type)
491
492     def generate_config(self):
493         self.port_pair_list, self.networks = self.get_port_pairs(self.interfaces)
494         self.get_lb_count()
495         self.generate_lb_to_port_pair_mapping()
496         self.generate_config_data()
497         self.write_parser.write(sys.stdout)
498         with open(self.tmp_file, 'a') as tfh:
499             self.write_parser.write(tfh)
500
501     def generate_link_config(self):
502
503         link_configs = []
504         for port_pair in self.port_pair_list:
505             for port in port_pair:
506                 port = port[-1]
507                 virtual_interface = self.interfaces[int(port)]["virtual-interface"]
508                 local_ip = virtual_interface["local_ip"]
509                 netmask = virtual_interface["netmask"]
510                 port_ip, prefix_len = self.validate_ip_and_prefixlen(local_ip, netmask)
511                 link_configs.append(LINK_CONFIG_TEMPLATE.format(port, port_ip, prefix_len))
512
513         return ''.join(link_configs)
514
515     def get_route_data(self, src_key, data_key, port):
516         route_list = self.vnfd['vdu'][0].get(src_key, [])
517         try:
518             return next((route[data_key] for route in route_list if route['if'] == port), None)
519         except (TypeError, StopIteration, KeyError):
520             return None
521
522     def get_ports_gateway(self, port):
523         return self.get_route_data('routing_table', 'gateway', port)
524
525     def get_ports_gateway6(self, port):
526         return self.get_route_data('nd_route_tbl', 'gateway', port)
527
528     def get_netmask_gateway(self, port):
529         return self.get_route_data('routing_table', 'netmask', port)
530
531     def get_netmask_gateway6(self, port):
532         return self.get_route_data('nd_route_tbl', 'netmask', port)
533
534     def generate_arp_config(self):
535         arp_config = []
536         for port_pair in self.port_pair_list:
537             for port in port_pair:
538                 # ignore gateway, always use TG IP
539                 # gateway = self.get_ports_gateway(port)
540                 dst_mac = self.interfaces[int(port[-1])]["virtual-interface"]["dst_mac"]
541                 dst_ip = self.interfaces[int(port[-1])]["virtual-interface"]["dst_ip"]
542                 # arp_config.append((port[-1], gateway, dst_mac, self.txrx_pipeline))
543                 # so dst_mac is the TG dest mac, so we need TG dest IP.
544                 arp_config.append((port[-1], dst_ip, dst_mac, self.txrx_pipeline))
545
546         return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config))
547
548     def generate_arp_config6(self):
549         arp_config6 = []
550         for port_pair in self.port_pair_list:
551             for port in port_pair:
552                 # ignore gateway, always use TG IP
553                 # gateway6 = self.get_ports_gateway6(port)
554                 dst_mac6 = self.interfaces[int(port[-1])]["virtual-interface"]["dst_mac"]
555                 dst_ip6 = self.interfaces[int(port[-1])]["virtual-interface"]["dst_ip"]
556                 # arp_config6.append((port[-1], gateway6, dst_mac6, self.txrx_pipeline))
557                 arp_config6.append((port[-1], dst_ip6, dst_mac6, self.txrx_pipeline))
558
559         return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config6))
560
561     def generate_action_config(self):
562         port_list = []
563         for port_pair in self.port_pair_list:
564             for port in port_pair:
565                 port_list.append(port[-1])
566
567         if self.vnf_type == "VFW":
568             template = FW_ACTION_TEMPLATE
569         else:
570             template = ACTION_TEMPLATE
571
572         return ''.join((template.format(port) for port in port_list))
573
574     def get_ip_from_port(self, port):
575         # we can't use gateway because in OpenStack gateways interfer with floating ip routing
576         # return self.make_ip_addr(self.get_ports_gateway(port), self.get_netmask_gateway(port))
577         ip = self.interfaces[port]["virtual-interface"]["local_ip"]
578         netmask = self.interfaces[port]["virtual-interface"]["netmask"]
579         return self.make_ip_addr(ip, netmask)
580
581     def get_network_and_prefixlen_from_ip_of_port(self, port):
582         ip_addr = self.get_ip_from_port(port)
583         # handle cases with no gateway
584         if ip_addr:
585             return ip_addr.network.network_address.exploded, ip_addr.network.prefixlen
586         else:
587             return None, None
588
589     def generate_rule_config(self):
590         cmd = 'acl' if self.vnf_type == "ACL" else "vfw"
591         rules_config = self.rules if self.rules else ''
592         new_rules = []
593         new_ipv6_rules = []
594         pattern = 'p {0} add {1} {2} {3} {4} {5} 0 65535 0 65535 0 0 {6}'
595         for port_pair in self.port_pair_list:
596             src_port = int(port_pair[0][-1])
597             dst_port = int(port_pair[1][-1])
598
599             src_net, src_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(src_port)
600             dst_net, dst_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(dst_port)
601             # ignore entires with empty values
602             if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
603                 new_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
604                                   dst_net, dst_prefix_len, dst_port))
605                 new_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
606                                   src_net, src_prefix_len, src_port))
607
608             # src_net = self.get_ports_gateway6(port_pair[0])
609             # src_prefix_len = self.get_netmask_gateway6(port_pair[0])
610             # dst_net = self.get_ports_gateway6(port_pair[1])
611             # dst_prefix_len = self.get_netmask_gateway6(port_pair[0])
612             # # ignore entires with empty values
613             # if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
614             #     new_ipv6_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
615             #                            dst_net, dst_prefix_len, dst_port))
616             #     new_ipv6_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
617             #                            src_net, src_prefix_len, src_port))
618
619         acl_apply = "\np %s applyruleset" % cmd
620         new_rules_config = '\n'.join(pattern.format(*values) for values
621                                      in chain(new_rules, new_ipv6_rules))
622         return ''.join([rules_config, new_rules_config, acl_apply])
623
624     def generate_script_data(self):
625         self.port_pair_list, self.networks = self.get_port_pairs(self.interfaces)
626         self.get_lb_count()
627         script_data = {
628             'link_config': self.generate_link_config(),
629             'arp_config': self.generate_arp_config(),
630             # disable IPv6 for now
631             # 'arp_config6': self.generate_arp_config6(),
632             'arp_config6': "",
633             'actions': '',
634             'rules': '',
635         }
636
637         if self.vnf_type in ('ACL', 'VFW'):
638             script_data.update({
639                 'actions': self.generate_action_config(),
640                 'rules': self.generate_rule_config(),
641             })
642
643         return script_data
644
645     def generate_script(self, vnfd, rules=None):
646         self.vnfd = vnfd
647         self.rules = rules
648         script_data = self.generate_script_data()
649         script = SCRIPT_TPL.format(**script_data)
650         if self.lb_config == self.HW_LB:
651             script += 'set fwd rxonly'
652             hwlb_tpl = """
653 set_sym_hash_ena_per_port {0} enable
654 set_hash_global_config {0} simple_xor ipv4-udp enable
655 set_sym_hash_ena_per_port {1} enable
656 set_hash_global_config {1} simple_xor ipv4-udp enable
657 set_hash_input_set {0} ipv4-udp src-ipv4 udp-src-port add
658 set_hash_input_set {1} ipv4-udp dst-ipv4 udp-dst-port add
659 set_hash_input_set {0} ipv6-udp src-ipv6 udp-src-port add
660 set_hash_input_set {1} ipv6-udp dst-ipv6 udp-dst-port add
661 """
662             for port_pair in self.port_pair_list:
663                 script += hwlb_tpl.format(port_pair[0][-1], port_pair[1][-1])
664         return script