1 # Copyright (c) 2016-2017 Intel Corporation
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
15 from __future__ import absolute_import
21 from collections import OrderedDict, defaultdict
22 from itertools import chain, repeat
25 from six.moves.configparser import ConfigParser
27 from yardstick.common.utils import ip_to_hex
29 LOG = logging.getLogger(__name__)
31 LINK_CONFIG_TEMPLATE = """\
33 link {0} config {1} {2}
37 ACTION_TEMPLATE = """\
38 p action add {0} accept
39 p action add {0} fwd {0}
40 p action add {0} count
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
50 # This sets up a basic passthrough with no rules
65 class PortPairs(object):
70 def __init__(self, interfaces):
71 super(PortPairs, self).__init__()
72 self.interfaces = interfaces
73 self._all_ports = None
74 self._uplink_ports = None
75 self._downlink_ports = None
77 self._port_pair_list = None
78 self._valid_networks = None
82 if self._networks is None:
84 for intf in self.interfaces:
85 vintf = intf['virtual-interface']
87 vld_id = vintf['vld_id']
89 # probably unused port?
90 LOG.warning("intf without vld_id, %s", vintf)
92 self._networks.setdefault(vld_id, []).append(vintf["ifname"])
96 def get_downlink_id(cls, vld_id):
97 # partition returns a tuple
98 parts = list(vld_id.partition(cls.UPLINK))
100 # 'uplink' was not in or not leftmost in the string
102 parts[1] = cls.DOWNLINK
103 public_id = ''.join(parts)
107 # this only works for vnfs that have both uplink and public visible
108 def valid_networks(self):
109 if self._valid_networks is None:
110 self._valid_networks = []
111 for vld_id in self.networks:
112 downlink_id = self.get_downlink_id(vld_id)
113 if downlink_id in self.networks:
114 self._valid_networks.append((vld_id, downlink_id))
115 return self._valid_networks
119 if self._all_ports is None:
120 self._all_ports = sorted(set(self.uplink_ports + self.downlink_ports))
121 return self._all_ports
124 def uplink_ports(self):
125 if self._uplink_ports is None:
126 intfs = chain.from_iterable(
127 intfs for vld_id, intfs in self.networks.items() if
128 vld_id.startswith(self.UPLINK))
129 self._uplink_ports = sorted(set(intfs))
130 return self._uplink_ports
133 def downlink_ports(self):
134 if self._downlink_ports is None:
135 intfs = chain.from_iterable(
136 intfs for vld_id, intfs in self.networks.items() if
137 vld_id.startswith(self.DOWNLINK))
138 self._downlink_ports = sorted(set(intfs))
139 return self._downlink_ports
142 def port_pair_list(self):
143 if self._port_pair_list is None:
144 self._port_pair_list = []
146 for uplink, downlink in self.valid_networks:
147 for uplink_intf in self.networks[uplink]:
148 # only VNFs have uplink, public peers
149 peer_intfs = self.networks.get(downlink, [])
151 for downlink_intf in peer_intfs:
152 port_pair = uplink_intf, downlink_intf
153 self._port_pair_list.append(port_pair)
154 return self._port_pair_list
157 class MultiPortConfig(object):
162 def float_x_plus_one_tenth_of_y(x, y):
163 return float(x) + float(y) / 10.0
166 def make_str(base, iterator):
167 return ' '.join((base.format(x) for x in iterator))
170 def make_range_str(cls, base, start, stop=0, offset=0):
171 if offset and not stop:
172 stop = start + offset
173 return cls.make_str(base, range(start, stop))
176 def parser_get(parser, section, key, default=None):
177 if parser.has_option(section, key):
178 return parser.get(section, key)
182 def make_ip_addr(ip, mask):
184 :param ip: ip adddress
186 :param mask: /24 prefix of 255.255.255.0 netmask
189 :rtype: IPv4Interface
193 return ipaddress.ip_interface(six.text_type('/'.join([ip, mask])))
194 except (TypeError, ValueError):
195 # None so we can skip later
199 def validate_ip_and_prefixlen(cls, ip_addr, prefixlen):
200 ip_addr = cls.make_ip_addr(ip_addr, prefixlen)
201 return ip_addr.ip.exploded, ip_addr.network.prefixlen
203 def __init__(self, topology_file, config_tpl, tmp_file, vnfd_helper,
204 vnf_type='CGNAT', lb_count=2, worker_threads=3,
205 worker_config='1C/1T', lb_config='SW', socket=0):
207 super(MultiPortConfig, self).__init__()
208 self.topology_file = topology_file
209 self.worker_config = worker_config.split('/')[1].lower()
210 self.worker_threads = self.get_worker_threads(worker_threads)
211 self.vnf_type = vnf_type
213 self.vnfd_helper = vnfd_helper
214 self.write_parser = ConfigParser()
215 self.read_parser = ConfigParser()
216 self.read_parser.read(config_tpl)
217 self.master_core = self.read_parser.get("PIPELINE0", "core")
218 self.master_tpl = self.get_config_tpl_data('MASTER')
219 self.arpicmp_tpl = self.get_config_tpl_data('ARPICMP')
220 self.txrx_tpl = self.get_config_tpl_data('TXRX')
221 self.loadb_tpl = self.get_config_tpl_data('LOADB')
222 self.vnf_tpl = self.get_config_tpl_data(vnf_type)
224 self.lb_count = int(lb_count)
225 self.lb_config = lb_config
226 self.tmp_file = os.path.join("/tmp", tmp_file)
227 self.pktq_out_os = []
230 self.pipeline_counter = ""
231 self.txrx_pipeline = ""
232 self._port_pairs = None
234 self.port_pair_list = []
235 self.lb_to_port_pair_mapping = {}
242 self.prv_que_handler = None
249 # return "s{}c{}".format(self.socket, core)
250 # don't use sockets for VNFs, because we don't want to have to
251 # adjust VM CPU topology. It is virtual anyway
254 def make_port_pairs_iter(self, operand, iterable):
255 return (operand(self.vnfd_helper.port_num(x), y) for y in iterable for x in
256 chain.from_iterable(self.port_pairs))
258 def make_range_port_pairs_iter(self, operand, start, end):
259 return self.make_port_pairs_iter(operand, range(start, end))
263 vpci = (v['virtual-interface']["vpci"] for v in self.vnfd_helper.interfaces)
264 lines.extend('w = {0}\n'.format(item) for item in vpci)
266 with open(self.tmp_file, 'w') as fh:
269 def update_timer(self):
270 timer_tpl = self.get_config_tpl_data('TIMER')
271 timer_tpl['core'] = self.gen_core(self.start_core)
272 self.update_write_parser(timer_tpl)
275 def get_config_tpl_data(self, type_value):
276 for section in self.read_parser.sections():
277 if self.read_parser.has_option(section, 'type'):
278 if type_value == self.read_parser.get(section, 'type'):
279 tpl = OrderedDict(self.read_parser.items(section))
282 def get_txrx_tpl_data(self, value):
283 for section in self.read_parser.sections():
284 if self.read_parser.has_option(section, 'pipeline_txrx_type'):
285 if value == self.read_parser.get(section, 'pipeline_txrx_type'):
286 tpl = OrderedDict(self.read_parser.items(section))
289 def init_write_parser_template(self, type_value='ARPICMP'):
290 for section in self.read_parser.sections():
291 if type_value == self.parser_get(self.read_parser, section, 'type', object()):
292 self.start_core = self.read_parser.getint(section, 'core')
293 self.pipeline_counter = self.read_parser.getint(section, 'core')
294 self.txrx_pipeline = self.read_parser.getint(section, 'core')
296 self.write_parser.add_section(section)
297 for name, value in self.read_parser.items(section):
298 self.write_parser.set(section, name, value)
300 def update_write_parser(self, data):
301 section = "PIPELINE{0}".format(self.pipeline_counter)
302 self.write_parser.add_section(section)
303 for name, value in data.items():
304 self.write_parser.set(section, name, value)
306 def get_worker_threads(self, worker_threads):
307 if self.worker_config == '1t':
308 return worker_threads
310 return worker_threads - worker_threads % 2
312 def generate_next_core_id(self):
313 if self.worker_config == '1t':
318 self.start_core = '{}h'.format(int(self.start_core))
320 self.start_core = int(self.start_core[:-1]) + 1
322 def get_lb_count(self):
323 self.lb_count = int(min(len(self.port_pair_list), self.lb_count))
325 def generate_lb_to_port_pair_mapping(self):
326 self.lb_to_port_pair_mapping = defaultdict(int)
327 port_pair_count = len(self.port_pair_list)
328 lb_pair_count = int(port_pair_count / self.lb_count)
329 extra = port_pair_count % self.lb_count
330 extra_iter = repeat(lb_pair_count + 1, extra)
331 norm_iter = repeat(lb_pair_count, port_pair_count - extra)
332 new_values = {i: v for i, v in enumerate(chain(extra_iter, norm_iter), 1)}
333 self.lb_to_port_pair_mapping.update(new_values)
335 def set_priv_to_pub_mapping(self):
336 port_nums = [tuple(self.vnfd_helper.port_nums(x)) for x in self.port_pair_list]
337 return "".join(str(y).replace(" ", "") for y in
340 def set_priv_que_handler(self):
341 # iterated twice, can't be generator
342 priv_to_pub_map = [tuple(self.vnfd_helper.port_nums(x)) for x in self.port_pairs]
343 # must be list to use .index()
344 port_list = list(chain.from_iterable(priv_to_pub_map))
345 uplink_ports = (x[0] for x in priv_to_pub_map)
346 self.prv_que_handler = '({})'.format(
347 "".join(("{},".format(port_list.index(x)) for x in uplink_ports)))
349 def generate_arp_route_tbl(self):
350 arp_route_tbl_tmpl = "({port0_dst_ip_hex},{port0_netmask_hex},{port_num}," \
353 def build_arp_config(port):
354 dpdk_port_num = self.vnfd_helper.port_num(port)
355 interface = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
356 # We must use the dst because we are on the VNF and we need to
358 dst_port0_ip = ipaddress.ip_interface(six.text_type(
359 "%s/%s" % (interface["dst_ip"], interface["netmask"])))
362 "port0_dst_ip_hex": ip_to_hex(dst_port0_ip.network.network_address.exploded),
363 "port0_netmask_hex": ip_to_hex(dst_port0_ip.network.netmask.exploded),
364 # this is the port num that contains port0 subnet and next_hop_ip_hex
365 # this is LINKID which should be based on DPDK port number
366 "port_num": dpdk_port_num,
367 # next hop is dst in this case
368 # must be within subnet
369 "next_hop_ip_hex": ip_to_hex(dst_port0_ip.ip.exploded),
371 return arp_route_tbl_tmpl.format(**arp_vars)
373 return ' '.join(build_arp_config(port) for port in self.all_ports)
375 def generate_arpicmp_data(self):
376 swq_in_str = self.make_range_str('SWQ{}', self.swq, offset=self.lb_count)
377 self.swq += self.lb_count
378 swq_out_str = self.make_range_str('SWQ{}', self.swq, offset=self.lb_count)
379 self.swq += self.lb_count
380 # ports_mac_list is disabled for some reason
382 # mac_iter = (self.vnfd_helper.find_interface(name=port)['virtual-interface']['local_mac']
383 # for port in self.all_ports)
384 pktq_in_iter = ('RXQ{}.0'.format(self.vnfd_helper.port_num(x[0])) for x in
388 'core': self.gen_core(self.start_core),
389 'pktq_in': swq_in_str,
390 'pktq_out': swq_out_str,
391 # we need to disable ports_mac_list?
392 # it looks like ports_mac_list is no longer required
393 # 'ports_mac_list': ' '.join(mac_iter),
394 'pktq_in_prv': ' '.join(pktq_in_iter),
395 'prv_to_pub_map': self.set_priv_to_pub_mapping(),
396 'arp_route_tbl': self.generate_arp_route_tbl(),
397 # nd_route_tbl must be set or we get segault on random OpenStack IPv6 traffic
398 # 'nd_route_tbl': "(0064:ff9b:0:0:0:0:9810:6414,120,0,0064:ff9b:0:0:0:0:9810:6414)"
399 # safe default? route discard prefix to localhost
400 'nd_route_tbl': "(0100::,64,0,::1)"
402 self.pktq_out_os = swq_out_str.split(' ')
403 # HWLB is a run to complition. So override the pktq_in/pktq_out
404 if self.lb_config == self.HW_LB:
407 self.make_range_str('SWQ{}', self.swq,
408 offset=(self.lb_count * self.worker_threads))
409 arpicmp_data['pktq_in'] = swq_in_str
410 # WA: Since port_pairs will not be populated during arp pipeline
411 self.port_pairs = self.port_pair_list
413 self.make_port_pairs_iter(self.float_x_plus_one_tenth_of_y, [self.mul])
414 pktq_out = self.make_str('TXQ{}', port_iter)
415 arpicmp_data['pktq_out'] = pktq_out
419 def generate_final_txrx_data(self):
420 swq_start = self.swq - self.ports_len * self.worker_threads
423 txq_end = self.worker_threads
425 pktq_out_iter = self.make_range_port_pairs_iter(self.float_x_plus_one_tenth_of_y,
428 swq_str = self.make_range_str('SWQ{}', swq_start, self.swq)
429 txq_str = self.make_str('TXQ{}', pktq_out_iter)
433 'pipeline_txrx_type': 'TXTX',
434 'core': self.gen_core(self.start_core),
436 pktq_in = rxtx_data['pktq_in']
437 pktq_in = '{0} {1}'.format(pktq_in, self.pktq_out_os[self.lb_index - 1])
438 rxtx_data['pktq_in'] = pktq_in
439 self.pipeline_counter += 1
442 def generate_initial_txrx_data(self):
443 pktq_iter = self.make_range_port_pairs_iter(self.float_x_plus_one_tenth_of_y,
444 0, self.worker_threads)
446 rxq_str = self.make_str('RXQ{}', pktq_iter)
447 swq_str = self.make_range_str('SWQ{}', self.swq, offset=self.ports_len)
450 'pktq_out': swq_str + ' SWQ{0}'.format(self.lb_index - 1),
451 'pipeline_txrx_type': 'RXRX',
452 'core': self.gen_core(self.start_core),
454 self.pipeline_counter += 1
457 def generate_lb_data(self):
458 pktq_in = self.make_range_str('SWQ{}', self.swq, offset=self.ports_len)
459 self.swq += self.ports_len
461 offset = self.ports_len * self.worker_threads
462 pktq_out = self.make_range_str('SWQ{}', self.swq, offset=offset)
463 self.pktq_out = pktq_out.split()
465 self.swq += (self.ports_len * self.worker_threads)
467 'prv_que_handler': self.prv_que_handler,
469 'pktq_out': pktq_out,
470 'n_vnf_threads': str(self.worker_threads),
471 'core': self.gen_core(self.start_core),
473 self.pipeline_counter += 1
476 def generate_vnf_data(self):
477 if self.lb_config == self.HW_LB:
478 port_iter = self.make_port_pairs_iter(self.float_x_plus_one_tenth_of_y, [self.mul])
479 pktq_in = self.make_str('RXQ{}', port_iter)
482 port_iter = self.make_port_pairs_iter(self.float_x_plus_one_tenth_of_y, [self.mul])
483 pktq_out = self.make_str('TXQ{}', port_iter)
487 'pktq_out': pktq_out + ' SWQ{0}'.format(self.swq),
488 'prv_que_handler': self.prv_que_handler,
489 'core': self.gen_core(self.start_core),
494 'pktq_in': ' '.join((self.pktq_out.pop(0) for _ in range(self.ports_len))),
495 'pktq_out': self.make_range_str('SWQ{}', self.swq, offset=self.ports_len),
496 'prv_que_handler': self.prv_que_handler,
497 'core': self.gen_core(self.start_core),
499 self.swq += self.ports_len
501 if self.vnf_type in ('ACL', 'VFW'):
502 pipe_line_data.pop('prv_que_handler')
504 if self.vnf_tpl.get('vnf_set'):
505 public_ip_port_range_list = self.vnf_tpl['public_ip_port_range'].split(':')
506 ip_in_hex = '{:x}'.format(int(public_ip_port_range_list[0], 16) + self.lb_index - 1)
507 public_ip_port_range_list[0] = ip_in_hex
508 self.vnf_tpl['public_ip_port_range'] = ':'.join(public_ip_port_range_list)
510 self.pipeline_counter += 1
511 return pipe_line_data
513 def generate_config_data(self):
514 self.init_write_parser_template()
516 # use master core for master, don't use self.start_core
517 self.write_parser.set('PIPELINE0', 'core', self.gen_core(self.master_core))
518 arpicmp_data = self.generate_arpicmp_data()
519 self.arpicmp_tpl.update(arpicmp_data)
520 self.update_write_parser(self.arpicmp_tpl)
523 if self.vnf_type == 'CGNAPT':
524 self.pipeline_counter += 1
527 for lb in self.lb_to_port_pair_mapping:
530 port_pair_count = self.lb_to_port_pair_mapping[lb]
531 if not self.port_pair_list:
534 self.port_pairs = self.port_pair_list[:port_pair_count]
535 self.port_pair_list = self.port_pair_list[port_pair_count:]
536 self.ports_len = port_pair_count * 2
537 self.set_priv_que_handler()
538 if self.lb_config == 'SW':
539 txrx_data = self.generate_initial_txrx_data()
540 self.txrx_tpl.update(txrx_data)
541 self.update_write_parser(self.txrx_tpl)
543 lb_data = self.generate_lb_data()
544 self.loadb_tpl.update(lb_data)
545 self.update_write_parser(self.loadb_tpl)
548 for i in range(self.worker_threads):
549 vnf_data = self.generate_vnf_data()
552 self.vnf_tpl.update(vnf_data)
553 self.update_write_parser(self.vnf_tpl)
555 self.vnf_tpl.pop('vnf_set')
559 self.vnf_tpl.pop('public_ip_port_range')
560 self.generate_next_core_id()
562 if self.lb_config == 'SW':
563 txrx_data = self.generate_final_txrx_data()
564 self.txrx_tpl.update(txrx_data)
565 self.update_write_parser(self.txrx_tpl)
567 self.vnf_tpl = self.get_config_tpl_data(self.vnf_type)
569 def generate_config(self):
570 self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
571 self.port_pair_list = self._port_pairs.port_pair_list
572 self.all_ports = self._port_pairs.all_ports
575 self.generate_lb_to_port_pair_mapping()
576 self.generate_config_data()
577 self.write_parser.write(sys.stdout)
578 with open(self.tmp_file, 'a') as tfh:
579 self.write_parser.write(tfh)
581 def generate_link_config(self):
582 def build_args(port):
583 # lookup interface by name
584 virtual_interface = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
585 local_ip = virtual_interface["local_ip"]
586 netmask = virtual_interface["netmask"]
587 port_num = self.vnfd_helper.port_num(port)
588 port_ip, prefix_len = self.validate_ip_and_prefixlen(local_ip, netmask)
589 return LINK_CONFIG_TEMPLATE.format(port_num, port_ip, prefix_len)
591 return ''.join(build_args(port) for port in self.all_ports)
593 def get_route_data(self, src_key, data_key, port):
594 route_list = self.vnfd['vdu'][0].get(src_key, [])
596 return next((route[data_key] for route in route_list if route['if'] == port), None)
597 except (TypeError, StopIteration, KeyError):
600 def get_ports_gateway(self, port):
601 return self.get_route_data('routing_table', 'gateway', port)
603 def get_ports_gateway6(self, port):
604 return self.get_route_data('nd_route_tbl', 'gateway', port)
606 def get_netmask_gateway(self, port):
607 return self.get_route_data('routing_table', 'netmask', port)
609 def get_netmask_gateway6(self, port):
610 return self.get_route_data('nd_route_tbl', 'netmask', port)
612 def generate_arp_config(self):
614 for port in self.all_ports:
615 # ignore gateway, always use TG IP
616 # gateway = self.get_ports_gateway(port)
617 vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
618 dst_mac = vintf["dst_mac"]
619 dst_ip = vintf["dst_ip"]
621 # (self.vnfd_helper.port_num(port), gateway, dst_mac, self.txrx_pipeline))
622 # so dst_mac is the TG dest mac, so we need TG dest IP.
623 # should be dpdk_port_num
625 (self.vnfd_helper.port_num(port), dst_ip, dst_mac, self.txrx_pipeline))
627 return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config))
629 def generate_arp_config6(self):
631 for port in self.all_ports:
632 # ignore gateway, always use TG IP
633 # gateway6 = self.get_ports_gateway6(port)
634 vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
635 dst_mac6 = vintf["dst_mac"]
636 dst_ip6 = vintf["dst_ip"]
637 # arp_config6.append(
638 # (self.vnfd_helper.port_num(port), gateway6, dst_mac6, self.txrx_pipeline))
640 (self.vnfd_helper.port_num(port), dst_ip6, dst_mac6, self.txrx_pipeline))
642 return '\n'.join(('p {3} arpadd {0} {1} {2}'.format(*values) for values in arp_config6))
644 def generate_action_config(self):
645 port_list = (self.vnfd_helper.port_num(p) for p in self.all_ports)
646 if self.vnf_type == "VFW":
647 template = FW_ACTION_TEMPLATE
649 template = ACTION_TEMPLATE
651 return ''.join((template.format(port) for port in port_list))
653 def get_ip_from_port(self, port):
654 # we can't use gateway because in OpenStack gateways interfer with floating ip routing
655 # return self.make_ip_addr(self.get_ports_gateway(port), self.get_netmask_gateway(port))
656 vintf = self.vnfd_helper.find_interface(name=port)["virtual-interface"]
657 ip = vintf["local_ip"]
658 netmask = vintf["netmask"]
659 return self.make_ip_addr(ip, netmask)
661 def get_network_and_prefixlen_from_ip_of_port(self, port):
662 ip_addr = self.get_ip_from_port(port)
663 # handle cases with no gateway
665 return ip_addr.network.network_address.exploded, ip_addr.network.prefixlen
669 def generate_rule_config(self):
670 cmd = 'acl' if self.vnf_type == "ACL" else "vfw"
671 rules_config = self.rules if self.rules else ''
674 pattern = 'p {0} add {1} {2} {3} {4} {5} 0 65535 0 65535 0 0 {6}'
675 for src_intf, dst_intf in self.port_pair_list:
676 src_port = self.vnfd_helper.port_num(src_intf)
677 dst_port = self.vnfd_helper.port_num(dst_intf)
679 src_net, src_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(src_intf)
680 dst_net, dst_prefix_len = self.get_network_and_prefixlen_from_ip_of_port(dst_intf)
681 # ignore entires with empty values
682 if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
683 new_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
684 dst_net, dst_prefix_len, dst_port))
685 new_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
686 src_net, src_prefix_len, src_port))
688 # src_net = self.get_ports_gateway6(port_pair[0])
689 # src_prefix_len = self.get_netmask_gateway6(port_pair[0])
690 # dst_net = self.get_ports_gateway6(port_pair[1])
691 # dst_prefix_len = self.get_netmask_gateway6(port_pair[0])
692 # # ignore entires with empty values
693 # if all((src_net, src_prefix_len, dst_net, dst_prefix_len)):
694 # new_ipv6_rules.append((cmd, self.txrx_pipeline, src_net, src_prefix_len,
695 # dst_net, dst_prefix_len, dst_port))
696 # new_ipv6_rules.append((cmd, self.txrx_pipeline, dst_net, dst_prefix_len,
697 # src_net, src_prefix_len, src_port))
699 acl_apply = "\np %s applyruleset" % cmd
700 new_rules_config = '\n'.join(pattern.format(*values) for values
701 in chain(new_rules, new_ipv6_rules))
702 return ''.join([rules_config, new_rules_config, acl_apply])
704 def generate_script_data(self):
705 self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
706 self.port_pair_list = self._port_pairs.port_pair_list
709 'link_config': self.generate_link_config(),
710 'arp_config': self.generate_arp_config(),
711 # disable IPv6 for now
712 # 'arp_config6': self.generate_arp_config6(),
718 if self.vnf_type in ('ACL', 'VFW'):
720 'actions': self.generate_action_config(),
721 'rules': self.generate_rule_config(),
726 def generate_script(self, vnfd, rules=None):
729 script_data = self.generate_script_data()
730 script = SCRIPT_TPL.format(**script_data)
731 if self.lb_config == self.HW_LB:
732 script += 'set fwd rxonly'
734 set_sym_hash_ena_per_port {0} enable
735 set_hash_global_config {0} simple_xor ipv4-udp enable
736 set_sym_hash_ena_per_port {1} enable
737 set_hash_global_config {1} simple_xor ipv4-udp enable
738 set_hash_input_set {0} ipv4-udp src-ipv4 udp-src-port add
739 set_hash_input_set {1} ipv4-udp dst-ipv4 udp-dst-port add
740 set_hash_input_set {0} ipv6-udp src-ipv6 udp-src-port add
741 set_hash_input_set {1} ipv6-udp dst-ipv6 udp-dst-port add
743 for port_pair in self.port_pair_list:
744 script += hwlb_tpl.format(*(self.vnfd_helper.port_nums(port_pair)))