1 # Copyright (c) 2019 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Classify utilities library."""
19 from socket import AF_INET, AF_INET6, inet_aton, inet_pton
21 from robot.api import logger
23 from resources.libraries.python.topology import Topology
24 from resources.libraries.python.PapiExecutor import PapiExecutor
27 class Classify(object):
28 """Classify utilities."""
31 def _build_mac_mask(dst_mac='', src_mac='', ether_type=''):
32 """Build MAC ACL mask data in hexstring format.
34 :param dst_mac: Source MAC address <0-ffffffffffff>.
35 :param src_mac: Destination MAC address <0-ffffffffffff>.
36 :param ether_type: Ethernet type <0-ffff>.
40 :returns MAC ACL mask in hexstring format.
43 return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
44 dst_mac.replace(':', ''), src_mac.replace(':', ''), ether_type)).\
48 def _build_ip_mask(proto='', src_ip='', dst_ip='', src_port='',
50 """Build IP ACL mask data in hexstring format.
52 :param proto: Protocol number <0-ff>.
53 :param src_ip: Source ip address <0-ffffffff>.
54 :param dst_ip: Destination ip address <0-ffffffff>.
55 :param src_port: Source port number <0-ffff>.
56 :param str dst_port: Destination port number <0-ffff>.
62 :returns: IP mask in hexstring format.
65 return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
66 proto, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
69 def _build_ip6_mask(next_hdr='', src_ip='', dst_ip='', src_port='',
71 """Build IPv6 ACL mask data in hexstring format.
73 :param next_hdr: Next header number <0-ff>.
74 :param src_ip: Source ip address <0-ffffffff>.
75 :param dst_ip: Destination ip address <0-ffffffff>.
76 :param src_port: Source port number <0-ffff>.
77 :param dst_port: Destination port number <0-ffff>.
83 :returns: IPv6 ACL mask in hexstring format.
86 return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
87 next_hdr, src_ip, dst_ip, src_port, dst_port)).rstrip('0')
90 def _build_mac_match(dst_mac='', src_mac='', ether_type=''):
91 """Build MAC ACL match data in hexstring format.
93 :param dst_mac: Source MAC address <x:x:x:x:x:x>.
94 :param src_mac: Destination MAC address <x:x:x:x:x:x>.
95 :param ether_type: Ethernet type <0-ffff>.
99 :returns: MAC ACL match data in hexstring format.
103 dst_mac = dst_mac.replace(':', '')
105 src_mac = src_mac.replace(':', '')
107 return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
108 dst_mac, src_mac, ether_type)).rstrip('0')
111 def _build_ip_match(proto=0, src_ip='', dst_ip='', src_port=0, dst_port=0):
112 """Build IP ACL match data in hexstring format.
114 :param proto: Protocol number with valid option "x".
115 :param src_ip: Source ip address with format of "x.x.x.x".
116 :param dst_ip: Destination ip address with format of "x.x.x.x".
117 :param src_port: Source port number "x".
118 :param dst_port: Destination port number "x".
124 :returns: IP ACL match data in hexstring format.
128 src_ip = binascii.hexlify(inet_aton(src_ip))
130 dst_ip = binascii.hexlify(inet_aton(dst_ip))
132 return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
133 hex(proto)[2:], src_ip, dst_ip, hex(src_port)[2:],
134 hex(dst_port)[2:])).rstrip('0')
137 def _build_ip6_match(next_hdr=0, src_ip='', dst_ip='', src_port=0,
139 """Build IPv6 ACL match data in hexstring format.
141 :param next_hdr: Next header number with valid option "x".
142 :param src_ip: Source ip6 address with format of "xxx:xxxx::xxxx".
143 :param dst_ip: Destination ip6 address with format of
145 :param src_port: Source port number "x".
146 :param dst_port: Destination port number "x".
152 :returns: IPv6 ACL match data in hexstring format.
156 src_ip = binascii.hexlify(inet_pton(AF_INET6, src_ip))
158 dst_ip = binascii.hexlify(inet_pton(AF_INET6, dst_ip))
160 return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
161 hex(next_hdr)[2:], src_ip, dst_ip, hex(src_port)[2:],
162 hex(dst_port)[2:])).rstrip('0')
165 def _classify_add_del_table(node, is_add, mask, match_n_vectors=1,
166 table_index=0xFFFFFFFF, nbuckets=2,
167 memory_size=2097152, skip_n_vectors=0,
168 next_table_index=0xFFFFFFFF,
169 miss_next_index=0xFFFFFFFF, current_data_flag=0,
170 current_data_offset=0):
171 """Add or delete a classify table.
173 :param node: VPP node to create classify table.
174 :param is_add: If 1 the table is added, if 0 the table is deleted.
175 :param mask: ACL mask in hexstring format.
176 :param match_n_vectors: Number of vectors to match (Default value = 1).
177 :param table_index: Index of the classify table.
178 (Default value = 0xFFFFFFFF)
179 :param nbuckets: Number of buckets when adding a table.
181 :param memory_size: Memory size when adding a table.
182 (Default value = 2097152)
183 :param skip_n_vectors: Number of skip vectors (Default value = 0).
184 :param next_table_index: Index of next table.
185 (Default value = 0xFFFFFFFF)
186 :param miss_next_index: Index of miss table.
187 (Default value = 0xFFFFFFFF)
188 :param current_data_flag: Option to use current node's packet payload
189 as the starting point from where packets are classified.
190 This option is only valid for L2/L3 input ACL for now.
191 0: by default, classify data from the buffer's start location
192 1: classify packets from VPP node's current data pointer.
193 :param current_data_offset: A signed value to shift the start location
194 of the packet to be classified.
195 For example, if input IP ACL node is used, L2 header's first byte
196 can be accessible by configuring current_data_offset to -14
197 if there is no vlan tag.
198 This is valid only if current_data_flag is set to 1.
203 :type match_n_vectors: int
204 :type table_index: int
206 :type memory_size: int
207 :type skip_n_vectors: int
208 :type next_table_index: int
209 :type miss_next_index: int
210 :type current_data_flag: int
211 :type current_data_offset: int
212 :returns: (table_index, skip_n, match_n)
213 table_index: Classify table index.
214 skip_n: Number of skip vectors.
215 match_n: Number of match vectors.
216 :rtype: tuple(int, int, int)
218 mask_len = ((len(mask) - 1) / 16 + 1) * 16
219 mask = mask + '\0' * (mask_len - len(mask))
223 table_index=table_index,
225 memory_size=memory_size,
226 skip_n_vectors=skip_n_vectors,
227 match_n_vectors=match_n_vectors,
228 next_table_index=next_table_index,
229 miss_next_index=miss_next_index,
230 current_data_flag=current_data_flag,
231 current_data_offset=current_data_offset,
236 cmd = 'classify_add_del_table'
237 err_msg = "Failed to create a classify table on host {host}".format(
240 with PapiExecutor(node) as papi_exec:
241 data = papi_exec.add(cmd, **args).get_replies(err_msg).\
242 verify_reply(err_msg=err_msg)
244 return int(data["new_table_index"]), int(data["skip_n_vectors"]),\
245 int(data["match_n_vectors"])
248 def _classify_add_del_session(node, is_add, table_index, match,
249 opaque_index=0xFFFFFFFF,
250 hit_next_index=0xFFFFFFFF, advance=0,
251 action=0, metadata=0):
252 """Add or delete a classify session.
254 :param node: VPP node to create classify session.
255 :param is_add: If 1 the session is added, if 0 the session is deleted.
256 :param table_index: Index of the table to add/del the session.
257 :param match: For add, match value for session, required, needs to
258 include bytes in front with length of skip_n_vectors of target table
259 times sizeof (u32x4) (values of those bytes will be ignored).
260 :param opaque_index: For add, opaque_index of new session.
261 (Default value = 0xFFFFFFFF)
262 :param hit_next_index: For add, hit_next_index of new session.
263 (Default value = 0xFFFFFFFF)
264 :param advance: For add, advance value for session. (Default value = 0)
265 :param action: 0: No action (by default) metadata is not used.
266 1: Classified IP packets will be looked up from the specified ipv4
267 fib table (configured by metadata as VRF id).
268 Only valid for L3 input ACL node
269 2: Classified IP packets will be looked up from the specified ipv6
270 fib table (configured by metadata as VRF id).
271 Only valid for L3 input ACL node
272 3: Classified packet will be steered to source routig policy of
273 given index (in metadata).
274 This is only valid for IPv6 packets redirected to a source
276 :param metadata: Valid only if action != 0
277 VRF id if action is 1 or 2. SR policy index if action is 3.
281 :type table_index: int
283 :type opaque_index: int
284 :type hit_next_index: int
290 match_len = ((len(match) - 1) / 16 + 1) * 16
291 match = match + '\0' * (match_len - len(match))
294 table_index=table_index,
295 hit_next_index=hit_next_index,
296 opaque_index=opaque_index,
303 cmd = 'classify_add_del_session'
304 err_msg = "Failed to create a classify session on host {host}".format(
307 with PapiExecutor(node) as papi_exec:
308 papi_exec.add(cmd, **args).get_replies(err_msg). \
309 verify_reply(err_msg=err_msg)
312 def _macip_acl_add(node, rules, tag=""):
315 :param node: VPP node to add MACIP ACL.
316 :param rules: List of rules for given ACL.
322 cmd = "macip_acl_add"
329 err_msg = "Failed to create a classify session on host {host}".format(
332 with PapiExecutor(node) as papi_exec:
333 papi_exec.add(cmd, **args).get_replies(err_msg). \
334 verify_reply(err_msg=err_msg)
337 def _acl_interface_set_acl_list(node, sw_if_index, acl_type, acls):
338 """Set ACL list for interface.
340 :param node: VPP node to set ACL list for interface.
341 :param sw_if_index: sw_if_index of the used interface.
342 :param acl_type: Type of ACL(s) - input or output.
343 :param acls: List of ACLs.
345 :type sw_if_index: int
349 cmd = "acl_interface_set_acl_list"
350 n_input = len(acls) if acl_type == "input" else 0
352 sw_if_index=sw_if_index,
358 err_msg = "Failed to set acl list for interface {idx} on host {host}".\
359 format(idx=sw_if_index, host=node['host'])
361 with PapiExecutor(node) as papi_exec:
362 papi_exec.add(cmd, **args).get_replies(err_msg). \
363 verify_reply(err_msg=err_msg)
366 def _acl_add_replace(node, acl_idx, rules, tag=""):
367 """ Add/replace ACLs.
369 :param node: VPP node to add MACIP ACL.
370 :param acl_idx: ACL index.
371 :param rules: List of rules for given ACL.
378 cmd = "acl_add_replace"
381 acl_index=4294967295 if acl_idx is None else acl_idx,
386 err_msg = "Failed to add/replace acls on host {host}".format(
389 with PapiExecutor(node) as papi_exec:
390 papi_exec.add(cmd, **args).get_replies(err_msg). \
391 verify_reply(err_msg=err_msg)
394 def vpp_creates_classify_table_l3(node, ip_version, direction, ip_addr):
395 """Create classify table for IP address filtering.
397 :param node: VPP node to create classify table.
398 :param ip_version: Version of IP protocol.
399 :param direction: Direction of traffic - src/dst.
400 :param ip_addr: IPv4 or Ipv6 (depending on the parameter 'ip_version')
403 :type ip_version: str
406 :returns: (table_index, skip_n, match_n)
407 table_index: Classify table index.
408 skip_n: Number of skip vectors.
409 match_n: Number of match vectors.
410 :rtype: tuple(int, int, int)
411 :raises ValueError: If the parameters 'ip_version' or 'direction' have
415 ip4=Classify._build_ip_mask,
416 ip6=Classify._build_ip6_mask
418 if ip_version == "ip4":
419 ip_addr = binascii.hexlify(inet_aton(ip_addr))
420 elif ip_version == "ip6":
421 ip_addr = binascii.hexlify(inet_pton(AF_INET6, ip_addr))
423 raise ValueError("IP version {ver} is not supported.".
424 format(ver=ip_version))
426 if direction == "src":
427 mask = mask_f[ip_version](src_ip=ip_addr)
428 elif direction == "dst":
429 mask = mask_f[ip_version](dst_ip=ip_addr)
431 raise ValueError("Direction {dir} is not supported.".
432 format(dir=direction))
434 return Classify._classify_add_del_table(
437 mask=binascii.unhexlify(mask),
438 match_n_vectors=(len(mask) - 1) // 32 + 1
442 def vpp_creates_classify_table_l2(node, direction, mac=""):
443 """Create classify table for MAC address filtering.
445 :param node: VPP node to create classify table.
446 :param direction: Direction of traffic - src/dst.
447 :param mac: Source or destination (depending on the parameter
448 'direction') MAC address.
452 :returns: (table_index, skip_n, match_n)
453 table_index: Classify table index.
454 skip_n: Number of skip vectors.
455 match_n: Number of match vectors.
456 :rtype: tuple(int, int, int)
457 :raises ValueError: If the parameter 'direction' has incorrect value.
459 if direction == "src":
460 mask = Classify._build_mac_mask(src_mac=mac)
461 elif direction == "dst":
462 mask = Classify._build_mac_mask(dst_mac=mac)
464 raise ValueError("Direction {dir} is not supported.".
465 format(dir=direction))
467 return Classify._classify_add_del_table(
470 mask=binascii.unhexlify(mask),
471 match_n_vectors=(len(mask) - 1) // 32 + 1
475 def vpp_creates_classify_table_hex(node, hex_mask):
476 """Create classify table with hex mask.
478 :param node: VPP node to create classify table based on hex mask.
479 :param hex_mask: Classify hex mask.
482 :returns: (table_index, skip_n, match_n)
483 table_index: Classify table index.
484 skip_n: Number of skip vectors.
485 match_n: Number of match vectors.
486 :rtype: tuple(int, int, int)
488 return Classify._classify_add_del_table(
491 mask=binascii.unhexlify(hex_mask),
492 match_n_vectors=(len(hex_mask) - 1) // 32 + 1
496 def vpp_configures_classify_session_l3(node, acl_method, table_index,
497 ip_version, direction, address):
498 """Configuration of classify session for IP address filtering.
500 :param node: VPP node to setup classify session.
501 :param acl_method: ACL method - deny/permit.
502 :param table_index: Classify table index.
503 :param ip_version: Version of IP protocol.
504 :param direction: Direction of traffic - src/dst.
505 :param address: IPv4 or IPv6 address.
507 :type acl_method: str
508 :type table_index: int
509 :type ip_version: str
512 :raises ValueError: If the parameter 'direction' has incorrect value.
515 ip4=Classify._build_ip_match,
516 ip6=Classify._build_ip6_match
518 if direction == "src":
519 match = match_f[ip_version](src_ip=address)
520 elif direction == "dst":
521 match = match_f[ip_version](dst_ip=address)
523 raise ValueError("Direction {dir} is not supported.".
524 format(dir=direction))
529 Classify._classify_add_del_session(
532 table_index=table_index,
533 match=binascii.unhexlify(match),
534 action=action[acl_method])
537 def vpp_configures_classify_session_l2(node, acl_method, table_index,
539 """Configuration of classify session for MAC address filtering.
541 :param node: VPP node to setup classify session.
542 :param acl_method: ACL method - deny/permit.
543 :param table_index: Classify table index.
544 :param direction: Direction of traffic - src/dst.
545 :param address: MAC address.
547 :type acl_method: str
548 :type table_index: int
551 :raises ValueError: If the parameter 'direction' has incorrect value.
553 if direction == "src":
554 match = Classify._build_mac_match(src_mac=address)
555 elif direction == "dst":
556 match = Classify._build_mac_match(dst_mac=address)
558 raise ValueError("Direction {dir} is not supported.".
559 format(dir=direction))
564 Classify._classify_add_del_session(
567 table_index=table_index,
568 match=binascii.unhexlify(match),
569 action=action[acl_method])
572 def vpp_configures_classify_session_hex(node, acl_method, table_index,
574 """Configuration of classify session with hex value.
576 :param node: VPP node to setup classify session.
577 :param acl_method: ACL method - deny/permit.
578 :param table_index: Classify table index.
579 :param hex_value: Classify hex value.
581 :type acl_method: str
582 :type table_index: int
589 Classify._classify_add_del_session(
592 table_index=table_index,
593 match=binascii.unhexlify(hex_value),
594 action=action[acl_method])
597 def compute_classify_hex_mask(ip_version, protocol, direction):
598 """Compute classify hex mask for TCP or UDP packet matching.
600 :param ip_version: Version of IP protocol.
601 :param protocol: Type of protocol.
602 :param direction: Traffic direction.
603 :type ip_version: str
606 :returns: Classify hex mask.
608 :raises ValueError: If protocol is not TCP or UDP.
609 :raises ValueError: If direction is not source or destination or
610 source + destination.
612 if protocol in ('TCP', 'UDP'):
613 base_mask = Classify._compute_base_mask(ip_version)
615 if direction == 'source':
616 return base_mask + 'FFFF0000'
617 elif direction == 'destination':
618 return base_mask + '0000FFFF'
619 elif direction == 'source + destination':
620 return base_mask + 'FFFFFFFF'
622 raise ValueError("Invalid direction!")
624 raise ValueError("Invalid protocol!")
627 def compute_classify_hex_value(hex_mask, source_port, destination_port):
628 """Compute classify hex value for TCP or UDP packet matching.
630 :param hex_mask: Classify hex mask.
631 :param source_port: Source TCP/UDP port.
632 :param destination_port: Destination TCP/UDP port.
634 :type source_port: str
635 :type destination_port: str
636 :returns: Classify hex value.
639 source_port_hex = Classify._port_convert(source_port)
640 destination_port_hex = Classify._port_convert(destination_port)
642 return hex_mask[:-8] + source_port_hex + destination_port_hex
645 def _port_convert(port):
646 """Convert port number for classify hex table format.
648 :param port: TCP/UDP port number.
650 :returns: TCP/UDP port number in 4-digit hexadecimal format.
653 return '{0:04x}'.format(int(port))
656 def _compute_base_mask(ip_version):
657 """Compute base classify hex mask based on IP version.
659 :param ip_version: Version of IP protocol.
660 :type ip_version: str
661 :returns: Base hex mask.
664 if ip_version == 'ip4':
666 # base value of classify hex table for IPv4 TCP/UDP ports
667 elif ip_version == 'ip6':
669 # base value of classify hex table for IPv6 TCP/UDP ports
671 raise ValueError("Invalid IP version!")
674 def get_classify_table_data(node, table_index):
675 """Retrieve settings for classify table by ID.
677 :param node: VPP node to retrieve classify data from.
678 :param table_index: Index of a specific classify table.
680 :type table_index: int
681 :returns: Classify table settings.
684 cmd = 'classify_table_info'
685 err_msg = "Failed to get 'classify_table_info' on host {host}".format(
688 table_id=int(table_index)
690 with PapiExecutor(node) as papi_exec:
691 data = papi_exec.add(cmd, **args).get_replies(err_msg).\
692 verify_reply(err_msg=err_msg)
697 def get_classify_session_data(node, table_index):
698 """Retrieve settings for all classify sessions in a table.
700 :param node: VPP node to retrieve classify data from.
701 :param table_index: Index of a classify table.
703 :type table_index: int
704 :returns: List of classify session settings.
708 table_id=int(table_index)
710 with PapiExecutor(node) as papi_exec:
711 dump = papi_exec.add("classify_session_dump", **args).\
712 get_dump().reply[0]["api_reply"]["classify_session_details"]
717 def vpp_log_plugin_acl_settings(node):
718 """Retrieve configured settings from the ACL plugin and write to robot
721 :param node: VPP node.
724 PapiExecutor.dump_and_log(node, ["acl_dump", ])
727 def vpp_log_plugin_acl_interface_assignment(node):
728 """Retrieve interface assignment from the ACL plugin and write to robot
731 :param node: VPP node.
734 PapiExecutor.dump_and_log(node, ["acl_interface_list_dump", ])
737 def set_acl_list_for_interface(node, interface, acl_type, acl_idx=None):
738 """Set the list of input or output ACLs applied to the interface. It
739 unapplies any previously applied ACLs.
741 :param node: VPP node to set ACL on.
742 :param interface: Interface name or sw_if_index.
743 :param acl_type: Type of ACL(s) - input or output.
744 :param acl_idx: Index(ies) of ACLs to be applied on the interface.
746 :type interface: str or int
750 if isinstance(interface, basestring):
751 sw_if_index = Topology.get_interface_sw_index(node, interface)
753 sw_if_index = int(interface)
755 acls = acl_idx if isinstance(acl_idx, list) else list()
757 Classify._acl_interface_set_acl_list(node=node,
758 sw_if_index=sw_if_index,
763 def add_replace_acl_multi_entries(node, acl_idx=None, rules=None):
764 """Add a new ACL or replace the existing one. To replace an existing
765 ACL, pass the ID of this ACL.
767 :param node: VPP node to set ACL on.
768 :param acl_idx: ID of ACL. (Optional)
769 :param rules: Required rules. (Optional)
774 reg_ex_src_ip = re.compile(r'(src [0-9a-fA-F.:/\d{1,2}]*)')
775 reg_ex_dst_ip = re.compile(r'(dst [0-9a-fA-F.:/\d{1,2}]*)')
776 reg_ex_sport = re.compile(r'(sport \d{1,5})')
777 reg_ex_dport = re.compile(r'(dport \d{1,5})')
780 for rule in rules.split(", "):
782 acl_rule["is_permit"] = 1 if "permit" in rule else 0
783 acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
785 groups = re.search(reg_ex_src_ip, rule)
787 grp = groups.group(1).split(' ')[1].split('/')
788 acl_rule["src_ip_addr"] = str(inet_pton(
789 AF_INET6 if acl_rule["is_ipv6"] else AF_INET, grp[0]))
790 acl_rule["src_ip_prefix_len"] = int(grp[1])
792 groups = re.search(reg_ex_dst_ip, rule)
794 grp = groups.group(1).split(' ')[1].split('/')
795 acl_rule["dst_ip_addr"] = str(inet_pton(
796 AF_INET6 if acl_rule["is_ipv6"] else AF_INET, grp[0]))
797 acl_rule["dst_ip_prefix_len"] = int(grp[1])
799 groups = re.search(reg_ex_sport, rule)
801 port = int(groups.group(1).split(' ')[1])
802 acl_rule["srcport_or_icmptype_first"] = port
803 acl_rule["srcport_or_icmptype_last"] = port
805 groups = re.search(reg_ex_dport, rule)
807 port = int(groups.group(1).split(' ')[1])
808 acl_rule["dstport_or_icmpcode_first"] = port
809 acl_rule["dstport_or_icmpcode_last"] = port
811 acl_rule["proto"] = 0
813 acl_rules.append(acl_rule)
815 Classify._acl_add_replace(node, acl_idx=acl_idx, rules=acl_rules)
818 def add_macip_acl_multi_entries(node, rules=""):
819 """Add a new MACIP ACL.
821 :param node: VPP node to set MACIP ACL on.
822 :param rules: Required MACIP rules.
826 reg_ex_ip = re.compile(r'(ip [0-9a-fA-F.:/\d{1,2}]*)')
827 reg_ex_mac = re.compile(r'(mac \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
828 reg_ex_mask = re.compile(r'(mask \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
831 for rule in rules.split(", "):
833 acl_rule["is_permit"] = 1 if "permit" in rule else 0
834 acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
836 groups = re.search(reg_ex_mac, rule)
838 mac = groups.group(1).split(' ')[1].replace(':', '')
839 acl_rule["src_mac"] = unicode(mac)
841 groups = re.search(reg_ex_mask, rule)
843 mask = groups.group(1).split(' ')[1].replace(':', '')
844 acl_rule["src_mac_mask"] = unicode(mask)
846 groups = re.search(reg_ex_ip, rule)
848 grp = groups.group(1).split(' ')[1].split('/')
849 acl_rule["src_ip_addr"] = str(inet_pton(
850 AF_INET6 if acl_rule["is_ipv6"] else AF_INET, grp[0]))
851 acl_rule["src_ip_prefix_len"] = int(grp[1])
853 acl_rules.append(acl_rule)
855 Classify._macip_acl_add(node=node, rules=acl_rules)
858 def vpp_log_macip_acl_settings(node):
859 """Retrieve configured MACIP settings from the ACL plugin and write to
862 :param node: VPP node.
865 PapiExecutor.dump_and_log(node, ["macip_acl_dump", ])
868 def add_del_macip_acl_interface(node, interface, action, acl_idx):
869 """Apply/un-apply the MACIP ACL to/from a given interface.
871 :param node: VPP node to set MACIP ACL on.
872 :param interface: Interface name or sw_if_index.
873 :param action: Required action - add or del.
874 :param acl_idx: ACL index to be applied on the interface.
876 :type interface: str or int
878 :type acl_idx: str or int
879 :raises RuntimeError: If unable to set MACIP ACL for the interface.
881 if isinstance(interface, basestring):
882 sw_if_index = Topology.get_interface_sw_index(node, interface)
884 sw_if_index = interface
886 is_add = 1 if action == "add" else 0
888 cmd = 'macip_acl_interface_add_del'
889 err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
893 sw_if_index=int(sw_if_index),
894 acl_index=int(acl_idx)
896 with PapiExecutor(node) as papi_exec:
897 papi_exec.add(cmd, **args).get_replies(err_msg).\
898 verify_reply(err_msg=err_msg)
901 def vpp_log_macip_acl_interface_assignment(node):
902 """Get interface list and associated MACIP ACLs and write to robot log.
904 :param node: VPP node.
907 cmd = 'macip_acl_interface_get'
908 err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
910 with PapiExecutor(node) as papi_exec:
911 rpl = papi_exec.add(cmd).get_replies(err_msg).reply[0]["api_reply"]
912 logger.info(rpl["macip_acl_interface_get_reply"])