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 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.
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 PapiExecutor(node) as papi_exec:
293 data = papi_exec.add(cmd, **args).get_replies(err_msg).\
294 verify_reply(err_msg=err_msg)
296 return int(data["new_table_index"]), int(data["skip_n_vectors"]),\
297 int(data["match_n_vectors"])
300 def _classify_add_del_session(node, is_add, table_index, match,
301 opaque_index=0xFFFFFFFF,
302 hit_next_index=0xFFFFFFFF, advance=0,
303 action=0, metadata=0):
304 """Add or delete a classify session.
306 :param node: VPP node to create classify session.
307 :param is_add: If 1 the session is added, if 0 the session is deleted.
308 :param table_index: Index of the table to add/del the session.
309 :param match: For add, match value for session, required, needs to
310 include bytes in front with length of skip_n_vectors of target table
311 times sizeof (u32x4) (values of those bytes will be ignored).
312 :param opaque_index: For add, opaque_index of new session.
313 (Default value = 0xFFFFFFFF)
314 :param hit_next_index: For add, hit_next_index of new session.
315 (Default value = 0xFFFFFFFF)
316 :param advance: For add, advance value for session. (Default value = 0)
317 :param action: 0: No action (by default) metadata is not used.
318 1: Classified IP packets will be looked up from the specified ipv4
319 fib table (configured by metadata as VRF id).
320 Only valid for L3 input ACL node
321 2: Classified IP packets will be looked up from the specified ipv6
322 fib table (configured by metadata as VRF id).
323 Only valid for L3 input ACL node
324 3: Classified packet will be steered to source routig policy of
325 given index (in metadata).
326 This is only valid for IPv6 packets redirected to a source
328 :param metadata: Valid only if action != 0
329 VRF id if action is 1 or 2. SR policy index if action is 3.
333 :type table_index: int
335 :type opaque_index: int
336 :type hit_next_index: int
342 match_len = ((len(match) - 1) / 16 + 1) * 16
343 match = match + '\0' * (match_len - len(match))
346 table_index=table_index,
347 hit_next_index=hit_next_index,
348 opaque_index=opaque_index,
355 cmd = 'classify_add_del_session'
356 err_msg = "Failed to create a classify session on host {host}".format(
359 with PapiExecutor(node) as papi_exec:
360 papi_exec.add(cmd, **args).get_replies(err_msg). \
361 verify_reply(err_msg=err_msg)
364 def _macip_acl_add(node, rules, tag=""):
367 :param node: VPP node to add MACIP ACL.
368 :param rules: List of rules for given ACL.
374 cmd = "macip_acl_add"
381 err_msg = "Failed to create a classify session on host {host}".format(
384 with PapiExecutor(node) as papi_exec:
385 papi_exec.add(cmd, **args).get_replies(err_msg). \
386 verify_reply(err_msg=err_msg)
389 def _acl_interface_set_acl_list(node, sw_if_index, acl_type, acls):
390 """Set ACL list for interface.
392 :param node: VPP node to set ACL list for interface.
393 :param sw_if_index: sw_if_index of the used interface.
394 :param acl_type: Type of ACL(s) - input or output.
395 :param acls: List of ACLs.
397 :type sw_if_index: int
401 cmd = "acl_interface_set_acl_list"
402 n_input = len(acls) if acl_type == "input" else 0
404 sw_if_index=sw_if_index,
410 err_msg = "Failed to set acl list for interface {idx} on host {host}".\
411 format(idx=sw_if_index, host=node['host'])
413 with PapiExecutor(node) as papi_exec:
414 papi_exec.add(cmd, **args).get_replies(err_msg). \
415 verify_reply(err_msg=err_msg)
418 def _acl_add_replace(node, acl_idx, rules, tag=""):
419 """ Add/replace ACLs.
421 :param node: VPP node to add MACIP ACL.
422 :param acl_idx: ACL index.
423 :param rules: List of rules for given ACL.
430 cmd = "acl_add_replace"
433 acl_index=4294967295 if acl_idx is None else acl_idx,
438 err_msg = "Failed to add/replace acls on host {host}".format(
441 with PapiExecutor(node) as papi_exec:
442 papi_exec.add(cmd, **args).get_replies(err_msg). \
443 verify_reply(err_msg=err_msg)
446 def vpp_creates_classify_table_l3(node, ip_version, direction, ip_addr):
447 """Create classify table for IP address filtering.
449 :param node: VPP node to create classify table.
450 :param ip_version: Version of IP protocol.
451 :param direction: Direction of traffic - src/dst.
452 :param ip_addr: IPv4 or Ipv6 (depending on the parameter 'ip_version')
455 :type ip_version: str
458 :returns: (table_index, skip_n, match_n)
459 table_index: Classify table index.
460 skip_n: Number of skip vectors.
461 match_n: Number of match vectors.
462 :rtype: tuple(int, int, int)
463 :raises ValueError: If the parameters 'ip_version' or 'direction' have
467 ip4=Classify._build_ip_mask,
468 ip6=Classify._build_ip6_mask
470 if ip_version == "ip4" or ip_version == "ip6":
471 ip_addr = binascii.hexlify(ip_address(unicode(ip_addr)).packed)
473 raise ValueError("IP version {ver} is not supported.".
474 format(ver=ip_version))
476 if direction == "src":
477 mask = mask_f[ip_version](src_ip=ip_addr)
478 elif direction == "dst":
479 mask = mask_f[ip_version](dst_ip=ip_addr)
481 raise ValueError("Direction {dir} is not supported.".
482 format(dir=direction))
484 return Classify._classify_add_del_table(
487 mask=binascii.unhexlify(mask),
488 match_n_vectors=(len(mask) - 1) // 32 + 1
492 def vpp_creates_classify_table_l2(node, direction, mac=""):
493 """Create classify table for MAC address filtering.
495 :param node: VPP node to create classify table.
496 :param direction: Direction of traffic - src/dst.
497 :param mac: Source or destination (depending on the parameter
498 'direction') MAC address.
502 :returns: (table_index, skip_n, match_n)
503 table_index: Classify table index.
504 skip_n: Number of skip vectors.
505 match_n: Number of match vectors.
506 :rtype: tuple(int, int, int)
507 :raises ValueError: If the parameter 'direction' has incorrect value.
509 if direction == "src":
510 mask = Classify._build_mac_mask(src_mac=mac)
511 elif direction == "dst":
512 mask = Classify._build_mac_mask(dst_mac=mac)
514 raise ValueError("Direction {dir} is not supported.".
515 format(dir=direction))
517 return Classify._classify_add_del_table(
520 mask=binascii.unhexlify(mask),
521 match_n_vectors=(len(mask) - 1) // 32 + 1
525 def vpp_creates_classify_table_hex(node, hex_mask):
526 """Create classify table with hex mask.
528 :param node: VPP node to create classify table based on hex mask.
529 :param hex_mask: Classify hex mask.
532 :returns: (table_index, skip_n, match_n)
533 table_index: Classify table index.
534 skip_n: Number of skip vectors.
535 match_n: Number of match vectors.
536 :rtype: tuple(int, int, int)
538 return Classify._classify_add_del_table(
541 mask=binascii.unhexlify(hex_mask),
542 match_n_vectors=(len(hex_mask) - 1) // 32 + 1
546 def vpp_configures_classify_session_l3(node, acl_method, table_index,
547 ip_version, direction, address):
548 """Configuration of classify session for IP address filtering.
550 :param node: VPP node to setup classify session.
551 :param acl_method: ACL method - deny/permit.
552 :param table_index: Classify table index.
553 :param ip_version: Version of IP protocol.
554 :param direction: Direction of traffic - src/dst.
555 :param address: IPv4 or IPv6 address.
557 :type acl_method: str
558 :type table_index: int
559 :type ip_version: str
562 :raises ValueError: If the parameter 'direction' has incorrect value.
565 ip4=Classify._build_ip_match,
566 ip6=Classify._build_ip6_match
568 if direction == "src":
569 match = match_f[ip_version](src_ip=address)
570 elif direction == "dst":
571 match = match_f[ip_version](dst_ip=address)
573 raise ValueError("Direction {dir} is not supported.".
574 format(dir=direction))
579 Classify._classify_add_del_session(
582 table_index=table_index,
583 match=binascii.unhexlify(match),
584 action=action[acl_method])
587 def vpp_configures_classify_session_l2(node, acl_method, table_index,
589 """Configuration of classify session for MAC address filtering.
591 :param node: VPP node to setup classify session.
592 :param acl_method: ACL method - deny/permit.
593 :param table_index: Classify table index.
594 :param direction: Direction of traffic - src/dst.
595 :param address: MAC address.
597 :type acl_method: str
598 :type table_index: int
601 :raises ValueError: If the parameter 'direction' has incorrect value.
603 if direction == "src":
604 match = Classify._build_mac_match(src_mac=address)
605 elif direction == "dst":
606 match = Classify._build_mac_match(dst_mac=address)
608 raise ValueError("Direction {dir} is not supported.".
609 format(dir=direction))
614 Classify._classify_add_del_session(
617 table_index=table_index,
618 match=binascii.unhexlify(match),
619 action=action[acl_method])
622 def vpp_configures_classify_session_hex(node, acl_method, table_index,
624 """Configuration of classify session with hex value.
626 :param node: VPP node to setup classify session.
627 :param acl_method: ACL method - deny/permit.
628 :param table_index: Classify table index.
629 :param hex_value: Classify hex value.
631 :type acl_method: str
632 :type table_index: int
639 Classify._classify_add_del_session(
642 table_index=table_index,
643 match=binascii.unhexlify(hex_value),
644 action=action[acl_method])
647 def compute_classify_hex_mask(ip_version, protocol, direction):
648 """Compute classify hex mask for TCP or UDP packet matching.
650 :param ip_version: Version of IP protocol.
651 :param protocol: Type of protocol.
652 :param direction: Traffic direction.
653 :type ip_version: str
656 :returns: Classify hex mask.
658 :raises ValueError: If protocol is not TCP or UDP.
659 :raises ValueError: If direction is not source or destination or
660 source + destination.
662 if protocol in ('TCP', 'UDP'):
663 base_mask = Classify._compute_base_mask(ip_version)
665 if direction == 'source':
666 return base_mask + 'FFFF0000'
667 elif direction == 'destination':
668 return base_mask + '0000FFFF'
669 elif direction == 'source + destination':
670 return base_mask + 'FFFFFFFF'
672 raise ValueError("Invalid direction!")
674 raise ValueError("Invalid protocol!")
677 def compute_classify_hex_value(hex_mask, source_port, destination_port):
678 """Compute classify hex value for TCP or UDP packet matching.
680 :param hex_mask: Classify hex mask.
681 :param source_port: Source TCP/UDP port.
682 :param destination_port: Destination TCP/UDP port.
684 :type source_port: str
685 :type destination_port: str
686 :returns: Classify hex value.
689 source_port_hex = Classify._port_convert(source_port)
690 destination_port_hex = Classify._port_convert(destination_port)
692 return hex_mask[:-8] + source_port_hex + destination_port_hex
695 def _port_convert(port):
696 """Convert port number for classify hex table format.
698 :param port: TCP/UDP port number.
700 :returns: TCP/UDP port number in 4-digit hexadecimal format.
703 return '{0:04x}'.format(int(port))
706 def _compute_base_mask(ip_version):
707 """Compute base classify hex mask based on IP version.
709 :param ip_version: Version of IP protocol.
710 :type ip_version: str
711 :returns: Base hex mask.
714 if ip_version == 'ip4':
716 # base value of classify hex table for IPv4 TCP/UDP ports
717 elif ip_version == 'ip6':
719 # base value of classify hex table for IPv6 TCP/UDP ports
721 raise ValueError("Invalid IP version!")
724 def get_classify_table_data(node, table_index):
725 """Retrieve settings for classify table by ID.
727 :param node: VPP node to retrieve classify data from.
728 :param table_index: Index of a specific classify table.
730 :type table_index: int
731 :returns: Classify table settings.
734 cmd = 'classify_table_info'
735 err_msg = "Failed to get 'classify_table_info' on host {host}".format(
738 table_id=int(table_index)
740 with PapiExecutor(node) as papi_exec:
741 data = papi_exec.add(cmd, **args).get_replies(err_msg).\
742 verify_reply(err_msg=err_msg)
747 def get_classify_session_data(node, table_index):
748 """Retrieve settings for all classify sessions in a table.
750 :param node: VPP node to retrieve classify data from.
751 :param table_index: Index of a classify table.
753 :type table_index: int
754 :returns: List of classify session settings.
758 table_id=int(table_index)
760 with PapiExecutor(node) as papi_exec:
761 dump = papi_exec.add("classify_session_dump", **args).\
762 get_dump().reply[0]["api_reply"]["classify_session_details"]
767 def vpp_log_plugin_acl_settings(node):
768 """Retrieve configured settings from the ACL plugin and write to robot
771 :param node: VPP node.
774 PapiExecutor.dump_and_log(node, ["acl_dump", ])
777 def vpp_log_plugin_acl_interface_assignment(node):
778 """Retrieve interface assignment from the ACL plugin and write to robot
781 :param node: VPP node.
784 PapiExecutor.dump_and_log(node, ["acl_interface_list_dump", ])
787 def set_acl_list_for_interface(node, interface, acl_type, acl_idx=None):
788 """Set the list of input or output ACLs applied to the interface. It
789 unapplies any previously applied ACLs.
791 :param node: VPP node to set ACL on.
792 :param interface: Interface name or sw_if_index.
793 :param acl_type: Type of ACL(s) - input or output.
794 :param acl_idx: Index(ies) of ACLs to be applied on the interface.
796 :type interface: str or int
800 if isinstance(interface, basestring):
801 sw_if_index = Topology.get_interface_sw_index(node, interface)
803 sw_if_index = int(interface)
805 acls = acl_idx if isinstance(acl_idx, list) else list()
807 Classify._acl_interface_set_acl_list(node=node,
808 sw_if_index=sw_if_index,
813 def add_replace_acl_multi_entries(node, acl_idx=None, rules=None):
814 """Add a new ACL or replace the existing one. To replace an existing
815 ACL, pass the ID of this ACL.
817 :param node: VPP node to set ACL on.
818 :param acl_idx: ID of ACL. (Optional)
819 :param rules: Required rules. (Optional)
824 reg_ex_src_ip = re.compile(r'(src [0-9a-fA-F.:/\d{1,2}]*)')
825 reg_ex_dst_ip = re.compile(r'(dst [0-9a-fA-F.:/\d{1,2}]*)')
826 reg_ex_sport = re.compile(r'(sport \d{1,5})')
827 reg_ex_dport = re.compile(r'(dport \d{1,5})')
830 for rule in rules.split(", "):
832 acl_rule["is_permit"] = 1 if "permit" in rule else 0
833 acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
835 groups = re.search(reg_ex_src_ip, rule)
837 grp = groups.group(1).split(' ')[1].split('/')
838 acl_rule["src_ip_addr"] = ip_address(unicode(grp[0])).packed
839 acl_rule["src_ip_prefix_len"] = int(grp[1])
841 groups = re.search(reg_ex_dst_ip, rule)
843 grp = groups.group(1).split(' ')[1].split('/')
844 acl_rule["dst_ip_addr"] = ip_address(unicode(grp[0])).packed
845 acl_rule["dst_ip_prefix_len"] = int(grp[1])
847 groups = re.search(reg_ex_sport, rule)
849 port = int(groups.group(1).split(' ')[1])
850 acl_rule["srcport_or_icmptype_first"] = port
851 acl_rule["srcport_or_icmptype_last"] = port
853 groups = re.search(reg_ex_dport, rule)
855 port = int(groups.group(1).split(' ')[1])
856 acl_rule["dstport_or_icmpcode_first"] = port
857 acl_rule["dstport_or_icmpcode_last"] = port
859 acl_rule["proto"] = 0
861 acl_rules.append(acl_rule)
863 Classify._acl_add_replace(node, acl_idx=acl_idx, rules=acl_rules)
866 def add_macip_acl_multi_entries(node, rules=""):
867 """Add a new MACIP ACL.
869 :param node: VPP node to set MACIP ACL on.
870 :param rules: Required MACIP rules.
874 reg_ex_ip = re.compile(r'(ip [0-9a-fA-F.:/\d{1,2}]*)')
875 reg_ex_mac = re.compile(r'(mac \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
876 reg_ex_mask = re.compile(r'(mask \S\S:\S\S:\S\S:\S\S:\S\S:\S\S)')
879 for rule in rules.split(", "):
881 acl_rule["is_permit"] = 1 if "permit" in rule else 0
882 acl_rule["is_ipv6"] = 1 if "ipv6" in rule else 0
884 groups = re.search(reg_ex_mac, rule)
886 mac = groups.group(1).split(' ')[1].replace(':', '')
887 acl_rule["src_mac"] = unicode(mac)
889 groups = re.search(reg_ex_mask, rule)
891 mask = groups.group(1).split(' ')[1].replace(':', '')
892 acl_rule["src_mac_mask"] = unicode(mask)
894 groups = re.search(reg_ex_ip, rule)
896 grp = groups.group(1).split(' ')[1].split('/')
897 acl_rule["src_ip_addr"] = ip_address(unicode(grp[0])).packed
898 acl_rule["src_ip_prefix_len"] = int(grp[1])
900 acl_rules.append(acl_rule)
902 Classify._macip_acl_add(node=node, rules=acl_rules)
905 def vpp_log_macip_acl_settings(node):
906 """Retrieve configured MACIP settings from the ACL plugin and write to
909 :param node: VPP node.
912 PapiExecutor.dump_and_log(node, ["macip_acl_dump", ])
915 def add_del_macip_acl_interface(node, interface, action, acl_idx):
916 """Apply/un-apply the MACIP ACL to/from a given interface.
918 :param node: VPP node to set MACIP ACL on.
919 :param interface: Interface name or sw_if_index.
920 :param action: Required action - add or del.
921 :param acl_idx: ACL index to be applied on the interface.
923 :type interface: str or int
925 :type acl_idx: str or int
926 :raises RuntimeError: If unable to set MACIP ACL for the interface.
928 if isinstance(interface, basestring):
929 sw_if_index = Topology.get_interface_sw_index(node, interface)
931 sw_if_index = interface
933 is_add = 1 if action == "add" else 0
935 cmd = 'macip_acl_interface_add_del'
936 err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
940 sw_if_index=int(sw_if_index),
941 acl_index=int(acl_idx)
943 with PapiExecutor(node) as papi_exec:
944 papi_exec.add(cmd, **args).get_replies(err_msg).\
945 verify_reply(err_msg=err_msg)
948 def vpp_log_macip_acl_interface_assignment(node):
949 """Get interface list and associated MACIP ACLs and write to robot log.
951 :param node: VPP node.
954 cmd = 'macip_acl_interface_get'
955 err_msg = "Failed to get 'macip_acl_interface' on host {host}".format(
957 with PapiExecutor(node) as papi_exec:
958 rpl = papi_exec.add(cmd).get_replies(err_msg).reply[0]["api_reply"]
959 logger.info(rpl["macip_acl_interface_get_reply"])