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 ipaddress import ip_address
21 from robot.api import logger
23 from resources.libraries.python.topology import Topology
24 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
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.
50 return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
51 dst_mac.replace(':', ''), src_mac.replace(':', ''),
55 def _build_ip_mask(proto='', src_ip='', dst_ip='', src_port='',
57 """Build IP ACL mask data in hexstring format.
59 :param proto: Protocol number <0-ff>.
60 :param src_ip: Source ip address <0-ffffffff>.
61 :param dst_ip: Destination ip address <0-ffffffff>.
62 :param src_port: Source port number <0-ffff>.
63 :param str dst_port: Destination port number <0-ffff>.
69 :returns: IP mask in hexstring format.
83 return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
84 proto, src_ip, dst_ip, src_port, dst_port))[0:end]
87 def _build_ip6_mask(next_hdr='', src_ip='', dst_ip='', src_port='',
89 """Build IPv6 ACL mask data in hexstring format.
91 :param next_hdr: Next header number <0-ff>.
92 :param src_ip: Source ip address <0-ffffffff>.
93 :param dst_ip: Destination ip address <0-ffffffff>.
94 :param src_port: Source port number <0-ffff>.
95 :param dst_port: Destination port number <0-ffff>.
101 :returns: IPv6 ACL mask in hexstring format.
115 return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
116 next_hdr, src_ip, dst_ip, src_port, dst_port))[0:end]
119 def _build_mac_match(dst_mac='', src_mac='', ether_type=''):
120 """Build MAC ACL match data in hexstring format.
122 :param dst_mac: Source MAC address <x:x:x:x:x:x>.
123 :param src_mac: Destination MAC address <x:x:x:x:x:x>.
124 :param ether_type: Ethernet type <0-ffff>.
127 :type ether_type: str
128 :returns: MAC ACL match data in hexstring format.
138 return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format(
139 dst_mac.replace(':', ''), src_mac.replace(':', ''),
143 def _build_ip_match(proto=0, src_ip='', dst_ip='', src_port=0, dst_port=0):
144 """Build IP ACL match data in hexstring format.
146 :param proto: Protocol number with valid option "x".
147 :param src_ip: Source ip address with format of "x.x.x.x".
148 :param dst_ip: Destination ip address with format of "x.x.x.x".
149 :param src_port: Source port number "x".
150 :param dst_port: Destination port number "x".
156 :returns: IP ACL match data in hexstring format.
160 src_ip = binascii.hexlify(ip_address(unicode(src_ip)).packed)
162 dst_ip = binascii.hexlify(ip_address(unicode(dst_ip)).packed)
174 return ('{!s:0>20}{!s:0>12}{!s:0>8}{!s:0>4}{!s:0>4}'.format(
175 hex(proto)[2:], src_ip, dst_ip, hex(src_port)[2:],
176 hex(dst_port)[2:]))[0:end]
179 def _build_ip6_match(next_hdr=0, src_ip='', dst_ip='', src_port=0,
181 """Build IPv6 ACL match data in hexstring format.
183 :param next_hdr: Next header number with valid option "x".
184 :param src_ip: Source ip6 address with format of "xxxx:xxxx::xxxx".
185 :param dst_ip: Destination ip6 address with format of
187 :param src_port: Source port number "x".
188 :param dst_port: Destination port number "x".
194 :returns: IPv6 ACL match data in hexstring format.
198 src_ip = binascii.hexlify(ip_address(unicode(src_ip)).packed)
200 dst_ip = binascii.hexlify(ip_address(unicode(dst_ip)).packed)
212 return ('{!s:0>14}{!s:0>34}{!s:0>32}{!s:0>4}{!s:0>4}'.format(
213 hex(next_hdr)[2:], src_ip, dst_ip, hex(src_port)[2:],
214 hex(dst_port)[2:]))[0:end]
217 def _classify_add_del_table(node, is_add, mask, match_n_vectors=1,
218 table_index=0xFFFFFFFF, nbuckets=2,
219 memory_size=2097152, skip_n_vectors=0,
220 next_table_index=0xFFFFFFFF,
221 miss_next_index=0xFFFFFFFF, current_data_flag=0,
222 current_data_offset=0):
223 """Add or delete a classify table.
225 :param node: VPP node to create classify table.
226 :param is_add: If 1 the table is added, if 0 the table is deleted.
227 :param mask: ACL mask in hexstring format.
228 :param match_n_vectors: Number of vectors to match (Default value = 1).
229 :param table_index: Index of the classify table.
230 (Default value = 0xFFFFFFFF)
231 :param nbuckets: Number of buckets when adding a table.
233 :param memory_size: Memory size when adding a table.
234 (Default value = 2097152)
235 :param skip_n_vectors: Number of skip vectors (Default value = 0).
236 :param next_table_index: Index of next table.
237 (Default value = 0xFFFFFFFF)
238 :param miss_next_index: Index of miss table.
239 (Default value = 0xFFFFFFFF)
240 :param current_data_flag: Option to use current node's packet payload
241 as the starting point from where packets are classified.
242 This option is only valid for L2/L3 input ACL for now.
243 0: by default, classify data from the buffer's start location
244 1: classify packets from VPP node's current data pointer.
245 :param current_data_offset: A signed value to shift the start location
246 of the packet to be classified.
247 For example, if input IP ACL node is used, L2 header's first byte
248 can be accessible by configuring current_data_offset to -14
249 if there is no vlan tag.
250 This is valid only if current_data_flag is set to 1.
255 :type match_n_vectors: int
256 :type table_index: int
258 :type memory_size: int
259 :type skip_n_vectors: int
260 :type next_table_index: int
261 :type miss_next_index: int
262 :type current_data_flag: int
263 :type current_data_offset: int
264 :returns: (table_index, skip_n, match_n)
265 table_index: Classify table index.
266 skip_n: Number of skip vectors.
267 match_n: Number of match vectors.
268 :rtype: tuple(int, int, int)
270 mask_len = ((len(mask) - 1) / 16 + 1) * 16
271 mask = mask + '\0' * (mask_len - len(mask))
275 table_index=table_index,
277 memory_size=memory_size,
278 skip_n_vectors=skip_n_vectors,
279 match_n_vectors=match_n_vectors,
280 next_table_index=next_table_index,
281 miss_next_index=miss_next_index,
282 current_data_flag=current_data_flag,
283 current_data_offset=current_data_offset,
288 cmd = 'classify_add_del_table'
289 err_msg = "Failed to create a classify table on host {host}".format(
292 with PapiSocketExecutor(node) as papi_exec:
293 reply = papi_exec.add(cmd, **args).get_reply(err_msg)
295 return int(reply["new_table_index"]), int(reply["skip_n_vectors"]),\
296 int(reply["match_n_vectors"])
299 def _classify_add_del_session(node, is_add, table_index, match,
300 opaque_index=0xFFFFFFFF,
301 hit_next_index=0xFFFFFFFF, advance=0,
302 action=0, metadata=0):
303 """Add or delete a classify session.
305 :param node: VPP node to create classify session.
306 :param is_add: If 1 the session is added, if 0 the session is deleted.
307 :param table_index: Index of the table to add/del the session.
308 :param match: For add, match value for session, required, needs to
309 include bytes in front with length of skip_n_vectors of target table
310 times sizeof (u32x4) (values of those bytes will be ignored).
311 :param opaque_index: For add, opaque_index of new session.
312 (Default value = 0xFFFFFFFF)
313 :param hit_next_index: For add, hit_next_index of new session.
314 (Default value = 0xFFFFFFFF)
315 :param advance: For add, advance value for session. (Default value = 0)
316 :param action: 0: No action (by default) metadata is not used.
317 1: Classified IP packets will be looked up from the specified ipv4
318 fib table (configured by metadata as VRF id).
319 Only valid for L3 input ACL node
320 2: Classified IP packets will be looked up from the specified ipv6
321 fib table (configured by metadata as VRF id).
322 Only valid for L3 input ACL node
323 3: Classified packet will be steered to source routig policy of
324 given index (in metadata).
325 This is only valid for IPv6 packets redirected to a source
327 :param metadata: Valid only if action != 0
328 VRF id if action is 1 or 2. SR policy index if action is 3.
332 :type table_index: int
334 :type opaque_index: int
335 :type hit_next_index: int
341 match_len = ((len(match) - 1) / 16 + 1) * 16
342 match = match + '\0' * (match_len - len(match))
345 table_index=table_index,
346 hit_next_index=hit_next_index,
347 opaque_index=opaque_index,
354 cmd = 'classify_add_del_session'
355 err_msg = "Failed to create a classify session on host {host}".format(
358 with PapiSocketExecutor(node) as papi_exec:
359 papi_exec.add(cmd, **args).get_reply(err_msg)
362 def _macip_acl_add(node, rules, tag=""):
365 :param node: VPP node to add MACIP ACL.
366 :param rules: List of rules for given ACL.
372 cmd = "macip_acl_add"
379 err_msg = "Failed to create a classify session on host {host}".format(
382 with PapiSocketExecutor(node) as papi_exec:
383 papi_exec.add(cmd, **args).get_reply(err_msg)
386 def _acl_interface_set_acl_list(node, sw_if_index, acl_type, acls):
387 """Set ACL list for interface.
389 :param node: VPP node to set ACL list for interface.
390 :param sw_if_index: sw_if_index of the used interface.
391 :param acl_type: Type of ACL(s) - input or output.
392 :param acls: List of ACLs.
394 :type sw_if_index: int
398 cmd = "acl_interface_set_acl_list"
399 n_input = len(acls) if acl_type == "input" else 0
401 sw_if_index=sw_if_index,
407 err_msg = "Failed to set acl list for interface {idx} on host {host}".\
408 format(idx=sw_if_index, host=node['host'])
410 with PapiSocketExecutor(node) as papi_exec:
411 papi_exec.add(cmd, **args).get_reply(err_msg)
414 def _acl_add_replace(node, acl_idx, rules, tag=""):
415 """ Add/replace ACLs.
417 :param node: VPP node to add MACIP ACL.
418 :param acl_idx: ACL index.
419 :param rules: List of rules for given ACL.
426 cmd = "acl_add_replace"
428 tag=tag.encode("utf-8"),
429 acl_index=4294967295 if acl_idx is None else acl_idx,
434 err_msg = "Failed to add/replace acls on host {host}".format(
437 with PapiSocketExecutor(node) as papi_exec:
438 papi_exec.add(cmd, **args).get_reply(err_msg)
441 def vpp_creates_classify_table_l3(node, ip_version, direction, ip_addr):
442 """Create classify table for IP address filtering.
444 :param node: VPP node to create classify table.
445 :param ip_version: Version of IP protocol.
446 :param direction: Direction of traffic - src/dst.
447 :param ip_addr: IPv4 or Ipv6 (depending on the parameter 'ip_version')
450 :type ip_version: str
453 :returns: (table_index, skip_n, match_n)
454 table_index: Classify table index.
455 skip_n: Number of skip vectors.
456 match_n: Number of match vectors.
457 :rtype: tuple(int, int, int)
458 :raises ValueError: If the parameters 'ip_version' or 'direction' have
462 ip4=Classify._build_ip_mask,
463 ip6=Classify._build_ip6_mask
465 if ip_version == "ip4" or ip_version == "ip6":
466 ip_addr = binascii.hexlify(ip_address(unicode(ip_addr)).packed)
468 raise ValueError("IP version {ver} is not supported.".
469 format(ver=ip_version))
471 if direction == "src":
472 mask = mask_f[ip_version](src_ip=ip_addr)
473 elif direction == "dst":
474 mask = mask_f[ip_version](dst_ip=ip_addr)
476 raise ValueError("Direction {dir} is not supported.".
477 format(dir=direction))
479 return Classify._classify_add_del_table(
482 mask=binascii.unhexlify(mask),
483 match_n_vectors=(len(mask) - 1) // 32 + 1
487 def vpp_creates_classify_table_l2(node, direction, mac=""):
488 """Create classify table for MAC address filtering.
490 :param node: VPP node to create classify table.
491 :param direction: Direction of traffic - src/dst.
492 :param mac: Source or destination (depending on the parameter
493 'direction') MAC address.
497 :returns: (table_index, skip_n, match_n)
498 table_index: Classify table index.
499 skip_n: Number of skip vectors.
500 match_n: Number of match vectors.
501 :rtype: tuple(int, int, int)
502 :raises ValueError: If the parameter 'direction' has incorrect value.
504 if direction == "src":
505 mask = Classify._build_mac_mask(src_mac=mac)
506 elif direction == "dst":
507 mask = Classify._build_mac_mask(dst_mac=mac)
509 raise ValueError("Direction {dir} is not supported.".
510 format(dir=direction))
512 return Classify._classify_add_del_table(
515 mask=binascii.unhexlify(mask),
516 match_n_vectors=(len(mask) - 1) // 32 + 1
520 def vpp_creates_classify_table_hex(node, hex_mask):
521 """Create classify table with hex mask.
523 :param node: VPP node to create classify table based on hex mask.
524 :param hex_mask: Classify hex mask.
527 :returns: (table_index, skip_n, match_n)
528 table_index: Classify table index.
529 skip_n: Number of skip vectors.
530 match_n: Number of match vectors.
531 :rtype: tuple(int, int, int)
533 return Classify._classify_add_del_table(
536 mask=binascii.unhexlify(hex_mask),
537 match_n_vectors=(len(hex_mask) - 1) // 32 + 1
541 def vpp_configures_classify_session_l3(node, acl_method, table_index,
542 ip_version, direction, address):
543 """Configuration of classify session for IP address filtering.
545 :param node: VPP node to setup classify session.
546 :param acl_method: ACL method - deny/permit.
547 :param table_index: Classify table index.
548 :param ip_version: Version of IP protocol.
549 :param direction: Direction of traffic - src/dst.
550 :param address: IPv4 or IPv6 address.
552 :type acl_method: str
553 :type table_index: int
554 :type ip_version: str
557 :raises ValueError: If the parameter 'direction' has incorrect value.
560 ip4=Classify._build_ip_match,
561 ip6=Classify._build_ip6_match
563 if direction == "src":
564 match = match_f[ip_version](src_ip=address)
565 elif direction == "dst":
566 match = match_f[ip_version](dst_ip=address)
568 raise ValueError("Direction {dir} is not supported.".
569 format(dir=direction))
574 Classify._classify_add_del_session(
577 table_index=table_index,
578 match=binascii.unhexlify(match),
579 action=action[acl_method])
582 def vpp_configures_classify_session_l2(node, acl_method, table_index,
584 """Configuration of classify session for MAC address filtering.
586 :param node: VPP node to setup classify session.
587 :param acl_method: ACL method - deny/permit.
588 :param table_index: Classify table index.
589 :param direction: Direction of traffic - src/dst.
590 :param address: MAC address.
592 :type acl_method: str
593 :type table_index: int
596 :raises ValueError: If the parameter 'direction' has incorrect value.
598 if direction == "src":
599 match = Classify._build_mac_match(src_mac=address)
600 elif direction == "dst":
601 match = Classify._build_mac_match(dst_mac=address)
603 raise ValueError("Direction {dir} is not supported.".
604 format(dir=direction))
609 Classify._classify_add_del_session(
612 table_index=table_index,
613 match=binascii.unhexlify(match),
614 action=action[acl_method])
617 def vpp_configures_classify_session_hex(node, acl_method, table_index,
619 """Configuration of classify session with hex value.
621 :param node: VPP node to setup classify session.
622 :param acl_method: ACL method - deny/permit.
623 :param table_index: Classify table index.
624 :param hex_value: Classify hex value.
626 :type acl_method: str
627 :type table_index: int
634 Classify._classify_add_del_session(
637 table_index=table_index,
638 match=binascii.unhexlify(hex_value),
639 action=action[acl_method])
642 def compute_classify_hex_mask(ip_version, protocol, direction):
643 """Compute classify hex mask for TCP or UDP packet matching.
645 :param ip_version: Version of IP protocol.
646 :param protocol: Type of protocol.
647 :param direction: Traffic direction.
648 :type ip_version: str
651 :returns: Classify hex mask.
653 :raises ValueError: If protocol is not TCP or UDP.
654 :raises ValueError: If direction is not source or destination or
655 source + destination.
657 if protocol in ('TCP', 'UDP'):
658 base_mask = Classify._compute_base_mask(ip_version)
660 if direction == 'source':
661 return base_mask + 'FFFF0000'
662 elif direction == 'destination':
663 return base_mask + '0000FFFF'
664 elif direction == 'source + destination':
665 return base_mask + 'FFFFFFFF'
667 raise ValueError("Invalid direction!")
669 raise ValueError("Invalid protocol!")
672 def compute_classify_hex_value(hex_mask, source_port, destination_port):
673 """Compute classify hex value for TCP or UDP packet matching.
675 :param hex_mask: Classify hex mask.
676 :param source_port: Source TCP/UDP port.
677 :param destination_port: Destination TCP/UDP port.
679 :type source_port: str
680 :type destination_port: str
681 :returns: Classify hex value.
684 source_port_hex = Classify._port_convert(source_port)
685 destination_port_hex = Classify._port_convert(destination_port)
687 return hex_mask[:-8] + source_port_hex + destination_port_hex
690 def _port_convert(port):
691 """Convert port number for classify hex table format.
693 :param port: TCP/UDP port number.
695 :returns: TCP/UDP port number in 4-digit hexadecimal format.
698 return '{0:04x}'.format(int(port))
701 def _compute_base_mask(ip_version):
702 """Compute base classify hex mask based on IP version.
704 :param ip_version: Version of IP protocol.
705 :type ip_version: str
706 :returns: Base hex mask.
709 if ip_version == 'ip4':
711 # base value of classify hex table for IPv4 TCP/UDP ports
712 elif ip_version == 'ip6':
714 # base value of classify hex table for IPv6 TCP/UDP ports
716 raise ValueError("Invalid IP version!")
719 def get_classify_table_data(node, table_index):
720 """Retrieve settings for classify table by ID.
722 :param node: VPP node to retrieve classify data from.
723 :param table_index: Index of a specific classify table.
725 :type table_index: int
726 :returns: Classify table settings.
729 cmd = 'classify_table_info'
730 err_msg = "Failed to get 'classify_table_info' on host {host}".format(
733 table_id=int(table_index)
735 with PapiSocketExecutor(node) as papi_exec:
736 reply = papi_exec.add(cmd, **args).get_reply(err_msg)
740 def get_classify_session_data(node, table_index):
741 """Retrieve settings for all classify sessions in a table.
743 :param node: VPP node to retrieve classify data from.
744 :param table_index: Index of a classify table.
746 :type table_index: int
747 :returns: List of classify session settings.
750 cmd = "classify_session_dump"
752 table_id=int(table_index)
754 with PapiSocketExecutor(node) as papi_exec:
755 details = papi_exec.add(cmd, **args).get_details()
760 def vpp_log_plugin_acl_settings(node):
761 """Retrieve configured settings from the ACL plugin and write to robot
764 :param node: VPP node.
767 PapiSocketExecutor.dump_and_log(node, ["acl_dump", ])
770 def vpp_log_plugin_acl_interface_assignment(node):
771 """Retrieve interface assignment from the ACL plugin and write to robot
774 :param node: VPP node.
777 PapiSocketExecutor.dump_and_log(node, ["acl_interface_list_dump", ])
780 def set_acl_list_for_interface(node, interface, acl_type, acl_idx=None):
781 """Set the list of input or output ACLs applied to the interface. It
782 unapplies any previously applied ACLs.
784 :param node: VPP node to set ACL on.
785 :param interface: Interface name or sw_if_index.
786 :param acl_type: Type of ACL(s) - input or output.
787 :param acl_idx: Index(ies) of ACLs to be applied on the interface.
789 :type interface: str or int
793 if isinstance(interface, basestring):
794 sw_if_index = Topology.get_interface_sw_index(node, interface)
796 sw_if_index = int(interface)
798 acls = acl_idx if isinstance(acl_idx, list) else list()
800 Classify._acl_interface_set_acl_list(node=node,
801 sw_if_index=sw_if_index,
806 def add_replace_acl_multi_entries(node, acl_idx=None, rules=None, tag=""):
807 """Add a new ACL or replace the existing one. To replace an existing
808 ACL, pass the ID of this ACL.
810 :param node: VPP node to set ACL on.
811 :param acl_idx: ID of ACL. (Optional)
812 :param rules: Required rules. (Optional)
813 :param tag: ACL tag (Optional).
819 reg_ex_src_ip = re.compile(r'(src [0-9a-fA-F.:/\d{1,2}]*)')
820 reg_ex_dst_ip = re.compile(r'(dst [0-9a-fA-F.:/\d{1,2}]*)')
821 reg_ex_sport = re.compile(r'(sport \d{1,5})')
822 reg_ex_dport = re.compile(r'(dport \d{1,5})')
823 reg_ex_proto = re.compile(r'(proto \d{1,5})')
826 for rule in rules.split(", "):
828 acl_rule["is_permit"] = 1 if "permit" in rule else 0
829 acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
831 groups = re.search(reg_ex_src_ip, rule)
833 grp = groups.group(1).split(' ')[1].split('/')
834 acl_rule["src_ip_addr"] = ip_address(unicode(grp[0])).packed
835 acl_rule["src_ip_prefix_len"] = int(grp[1])
837 groups = re.search(reg_ex_dst_ip, rule)
839 grp = groups.group(1).split(' ')[1].split('/')
840 acl_rule["dst_ip_addr"] = ip_address(unicode(grp[0])).packed
841 acl_rule["dst_ip_prefix_len"] = int(grp[1])
843 groups = re.search(reg_ex_sport, rule)
845 port = int(groups.group(1).split(' ')[1])
846 acl_rule["srcport_or_icmptype_first"] = port
847 acl_rule["srcport_or_icmptype_last"] = port
849 acl_rule["srcport_or_icmptype_first"] = 0
850 acl_rule["srcport_or_icmptype_last"] = 65535
852 groups = re.search(reg_ex_dport, rule)
854 port = int(groups.group(1).split(' ')[1])
855 acl_rule["dstport_or_icmpcode_first"] = port
856 acl_rule["dstport_or_icmpcode_last"] = port
858 acl_rule["dstport_or_icmpcode_first"] = 0
859 acl_rule["dstport_or_icmpcode_last"] = 65535
861 groups = re.search(reg_ex_proto, rule)
863 proto = int(groups.group(1).split(' ')[1])
864 acl_rule["proto"] = proto
866 acl_rule["proto"] = 0
868 acl_rules.append(acl_rule)
870 Classify._acl_add_replace(
871 node, acl_idx=acl_idx, rules=acl_rules, tag=tag)
874 def add_macip_acl_multi_entries(node, rules=""):
875 """Add a new MACIP ACL.
877 :param node: VPP node to set MACIP ACL on.
878 :param rules: Required MACIP rules.
882 reg_ex_ip = re.compile(r'(ip [0-9a-fA-F.:/\d{1,2}]*)')
883 reg_ex_mac = re.compile(r'(mac \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
884 reg_ex_mask = re.compile(r'(mask \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
887 for rule in rules.split(", "):
889 acl_rule["is_permit"] = 1 if "permit" in rule else 0
890 acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
892 groups = re.search(reg_ex_mac, rule)
894 mac = groups.group(1).split(' ')[1].replace(':', '')
895 acl_rule["src_mac"] = binascii.unhexlify(unicode(mac))
897 groups = re.search(reg_ex_mask, rule)
899 mask = groups.group(1).split(' ')[1].replace(':', '')
900 acl_rule["src_mac_mask"] = binascii.unhexlify(unicode(mask))
902 groups = re.search(reg_ex_ip, rule)
904 grp = groups.group(1).split(' ')[1].split('/')
905 acl_rule["src_ip_addr"] = ip_address(unicode(grp[0])).packed
906 acl_rule["src_ip_prefix_len"] = int(grp[1])
908 acl_rules.append(acl_rule)
910 Classify._macip_acl_add(node=node, rules=acl_rules)
913 def vpp_log_macip_acl_settings(node):
914 """Retrieve configured MACIP settings from the ACL plugin and write to
917 :param node: VPP node.
920 PapiSocketExecutor.dump_and_log(node, ["macip_acl_dump", ])
923 def add_del_macip_acl_interface(node, interface, action, acl_idx):
924 """Apply/un-apply the MACIP ACL to/from a given interface.
926 :param node: VPP node to set MACIP ACL on.
927 :param interface: Interface name or sw_if_index.
928 :param action: Required action - add or del.
929 :param acl_idx: ACL index to be applied on the interface.
931 :type interface: str or int
933 :type acl_idx: str or int
934 :raises RuntimeError: If unable to set MACIP ACL for the interface.
936 if isinstance(interface, basestring):
937 sw_if_index = Topology.get_interface_sw_index(node, interface)
939 sw_if_index = interface
941 is_add = 1 if action == "add" else 0
943 cmd = 'macip_acl_interface_add_del'
944 err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
948 sw_if_index=int(sw_if_index),
949 acl_index=int(acl_idx)
951 with PapiSocketExecutor(node) as papi_exec:
952 papi_exec.add(cmd, **args).get_reply(err_msg)
955 def vpp_log_macip_acl_interface_assignment(node):
956 """Get interface list and associated MACIP ACLs and write to robot log.
958 :param node: VPP node.
961 cmd = 'macip_acl_interface_get'
962 err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
964 with PapiSocketExecutor(node) as papi_exec:
965 reply = papi_exec.add(cmd).get_reply(err_msg)