1 # Copyright (c) 2023 Cisco and/or its affiliates.
2 # Copyright (c) 2023 PANTHEON.tech s.r.o.
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 """IPsec utilities library."""
19 from enum import Enum, IntEnum
21 from ipaddress import ip_network, ip_address
22 from random import choice
23 from string import ascii_letters
25 from robot.libraries.BuiltIn import BuiltIn
27 from resources.libraries.python.Constants import Constants
28 from resources.libraries.python.IncrementUtil import ObjIncrement
29 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
31 from resources.libraries.python.IPAddress import IPAddress
32 from resources.libraries.python.IPUtil import IPUtil, IpDscp, \
33 MPLS_LABEL_INVALID, NetworkIncrement
34 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
35 from resources.libraries.python.ssh import scp_node
36 from resources.libraries.python.topology import Topology, NodeType
37 from resources.libraries.python.VPPUtil import VPPUtil
38 from resources.libraries.python.FlowUtil import FlowUtil
41 IPSEC_UDP_PORT_NONE = 0xffff
45 """Generate random string as a key.
47 :param length: Length of generated payload.
49 :returns: The generated payload.
53 choice(ascii_letters) for _ in range(length)
54 ).encode(encoding=u"utf-8")
57 class PolicyAction(Enum):
59 BYPASS = (u"bypass", 0)
60 DISCARD = (u"discard", 1)
61 PROTECT = (u"protect", 3)
63 def __init__(self, policy_name, policy_int_repr):
64 self.policy_name = policy_name
65 self.policy_int_repr = policy_int_repr
68 return self.policy_name
71 return self.policy_int_repr
74 class CryptoAlg(Enum):
75 """Encryption algorithms."""
76 AES_CBC_128 = (u"aes-cbc-128", 1, u"AES-CBC", 16)
77 AES_CBC_256 = (u"aes-cbc-256", 3, u"AES-CBC", 32)
78 AES_GCM_128 = (u"aes-gcm-128", 7, u"AES-GCM", 16)
79 AES_GCM_256 = (u"aes-gcm-256", 9, u"AES-GCM", 32)
81 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
82 self.alg_name = alg_name
83 self.alg_int_repr = alg_int_repr
84 self.scapy_name = scapy_name
85 self.key_len = key_len
89 """Integrity algorithm."""
90 SHA_256_128 = (u"sha-256-128", 4, u"SHA2-256-128", 32)
91 SHA_512_256 = (u"sha-512-256", 6, u"SHA2-512-256", 64)
93 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
94 self.alg_name = alg_name
95 self.alg_int_repr = alg_int_repr
96 self.scapy_name = scapy_name
97 self.key_len = key_len
100 class IPsecProto(IntEnum):
101 """IPsec protocol."""
102 IPSEC_API_PROTO_ESP = 50
103 IPSEC_API_PROTO_AH = 51
106 class IPsecSadFlags(IntEnum):
107 """IPsec Security Association Database flags."""
108 IPSEC_API_SAD_FLAG_NONE = 0
109 # Enable extended sequence numbers
110 IPSEC_API_SAD_FLAG_USE_ESN = 0x01
111 # Enable Anti - replay
112 IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY = 0x02
113 # IPsec tunnel mode if non-zero, else transport mode
114 IPSEC_API_SAD_FLAG_IS_TUNNEL = 0x04
115 # IPsec tunnel mode is IPv6 if non-zero, else IPv4 tunnel
116 # only valid if is_tunnel is non-zero
117 IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 0x08
118 # Enable UDP encapsulation for NAT traversal
119 IPSEC_API_SAD_FLAG_UDP_ENCAP = 0x10
120 # IPsec SA is or inbound traffic
121 IPSEC_API_SAD_FLAG_IS_INBOUND = 0x40
124 class TunnelEncpaDecapFlags(IntEnum):
125 """Flags controlling tunnel behaviour."""
126 TUNNEL_API_ENCAP_DECAP_FLAG_NONE = 0
127 # at encap, copy the DF bit of the payload into the tunnel header
128 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF = 1
129 # at encap, set the DF bit in the tunnel header
130 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF = 2
131 # at encap, copy the DSCP bits of the payload into the tunnel header
132 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP = 4
133 # at encap, copy the ECN bit of the payload into the tunnel header
134 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN = 8
135 # at decap, copy the ECN bit of the tunnel header into the payload
136 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_ECN = 16
139 class TunnelMode(IntEnum):
142 TUNNEL_API_MODE_P2P = 0
144 TUNNEL_API_MODE_MP = 1
148 """IPsec utilities."""
151 def policy_action_bypass():
152 """Return policy action bypass.
154 :returns: PolicyAction enum BYPASS object.
157 return PolicyAction.BYPASS
160 def policy_action_discard():
161 """Return policy action discard.
163 :returns: PolicyAction enum DISCARD object.
166 return PolicyAction.DISCARD
169 def policy_action_protect():
170 """Return policy action protect.
172 :returns: PolicyAction enum PROTECT object.
175 return PolicyAction.PROTECT
178 def crypto_alg_aes_cbc_128():
179 """Return encryption algorithm aes-cbc-128.
181 :returns: CryptoAlg enum AES_CBC_128 object.
184 return CryptoAlg.AES_CBC_128
187 def crypto_alg_aes_cbc_256():
188 """Return encryption algorithm aes-cbc-256.
190 :returns: CryptoAlg enum AES_CBC_256 object.
193 return CryptoAlg.AES_CBC_256
196 def crypto_alg_aes_gcm_128():
197 """Return encryption algorithm aes-gcm-128.
199 :returns: CryptoAlg enum AES_GCM_128 object.
202 return CryptoAlg.AES_GCM_128
205 def crypto_alg_aes_gcm_256():
206 """Return encryption algorithm aes-gcm-256.
208 :returns: CryptoAlg enum AES_GCM_128 object.
211 return CryptoAlg.AES_GCM_256
214 def get_crypto_alg_key_len(crypto_alg):
215 """Return encryption algorithm key length.
217 :param crypto_alg: Encryption algorithm.
218 :type crypto_alg: CryptoAlg
219 :returns: Key length.
222 return crypto_alg.key_len
225 def get_crypto_alg_scapy_name(crypto_alg):
226 """Return encryption algorithm scapy name.
228 :param crypto_alg: Encryption algorithm.
229 :type crypto_alg: CryptoAlg
230 :returns: Algorithm scapy name.
233 return crypto_alg.scapy_name
236 def integ_alg_sha_256_128():
237 """Return integrity algorithm SHA-256-128.
239 :returns: IntegAlg enum SHA_256_128 object.
242 return IntegAlg.SHA_256_128
245 def integ_alg_sha_512_256():
246 """Return integrity algorithm SHA-512-256.
248 :returns: IntegAlg enum SHA_512_256 object.
251 return IntegAlg.SHA_512_256
254 def get_integ_alg_key_len(integ_alg):
255 """Return integrity algorithm key length.
257 None argument is accepted, returning zero.
259 :param integ_alg: Integrity algorithm.
260 :type integ_alg: Optional[IntegAlg]
261 :returns: Key length.
264 return 0 if integ_alg is None else integ_alg.key_len
267 def get_integ_alg_scapy_name(integ_alg):
268 """Return integrity algorithm scapy name.
270 :param integ_alg: Integrity algorithm.
271 :type integ_alg: IntegAlg
272 :returns: Algorithm scapy name.
275 return integ_alg.scapy_name
278 def ipsec_proto_esp():
279 """Return IPSec protocol ESP.
281 :returns: IPsecProto enum ESP object.
284 return int(IPsecProto.IPSEC_API_PROTO_ESP)
287 def ipsec_proto_ah():
288 """Return IPSec protocol AH.
290 :returns: IPsecProto enum AH object.
293 return int(IPsecProto.IPSEC_API_PROTO_AH)
296 def vpp_ipsec_select_backend(node, protocol, index=1):
297 """Select IPsec backend.
299 :param node: VPP node to select IPsec backend on.
300 :param protocol: IPsec protocol.
301 :param index: Backend index.
303 :type protocol: IPsecProto
305 :raises RuntimeError: If failed to select IPsec backend or if no API
308 cmd = u"ipsec_select_backend"
309 err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
314 with PapiSocketExecutor(node) as papi_exec:
315 papi_exec.add(cmd, **args).get_reply(err_msg)
318 def vpp_ipsec_set_async_mode(node, async_enable=1):
319 """Set IPsec async mode on|off.
321 Unconditionally, attempt to switch crypto dispatch into polling mode.
323 :param node: VPP node to set IPsec async mode.
324 :param async_enable: Async mode on or off.
326 :type async_enable: int
327 :raises RuntimeError: If failed to set IPsec async mode or if no API
330 with PapiSocketExecutor(node) as papi_exec:
331 cmd = u"ipsec_set_async_mode"
332 err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
334 async_enable=async_enable
336 papi_exec.add(cmd, **args).get_reply(err_msg)
337 cmd = "crypto_set_async_dispatch_v2"
338 err_msg = "Failed to set dispatch mode."
339 args = dict(mode=0, adaptive=False)
341 papi_exec.add(cmd, **args).get_reply(err_msg)
342 except (AttributeError, RuntimeError):
343 # Expected when VPP build does not have the _v2 yet
344 # (after and before the first CRC check).
345 # TODO: Fail here when testing of pre-23.10 builds is over.
349 def vpp_ipsec_crypto_sw_scheduler_set_worker(
350 node, workers, crypto_enable=False):
351 """Enable or disable crypto on specific vpp worker threads.
353 :param node: VPP node to enable or disable crypto for worker threads.
354 :param workers: List of VPP thread numbers.
355 :param crypto_enable: Disable or enable crypto work.
357 :type workers: Iterable[int]
358 :type crypto_enable: bool
359 :raises RuntimeError: If failed to enable or disable crypto for worker
360 thread or if no API reply received.
362 for worker in workers:
363 cmd = u"crypto_sw_scheduler_set_worker"
364 err_msg = f"Failed to disable/enable crypto for worker thread " \
365 f"on host {node[u'host']}"
367 worker_index=worker - 1,
368 crypto_enable=crypto_enable
370 with PapiSocketExecutor(node) as papi_exec:
371 papi_exec.add(cmd, **args).get_reply(err_msg)
374 def vpp_ipsec_crypto_sw_scheduler_set_worker_on_all_duts(
375 nodes, crypto_enable=False):
376 """Enable or disable crypto on specific vpp worker threads.
378 :param node: VPP node to enable or disable crypto for worker threads.
379 :param crypto_enable: Disable or enable crypto work.
381 :type crypto_enable: bool
382 :raises RuntimeError: If failed to enable or disable crypto for worker
383 thread or if no API reply received.
385 for node_name, node in nodes.items():
386 if node["type"] == NodeType.DUT:
387 thread_data = VPPUtil.vpp_show_threads(node)
388 worker_cnt = len(thread_data) - 1
392 workers = BuiltIn().get_variable_value(
393 f"${{{node_name}_cpu_dp}}"
395 for item in thread_data:
396 if str(item.cpu_id) in workers.split(u","):
397 worker_ids.append(item.id)
399 IPsecUtil.vpp_ipsec_crypto_sw_scheduler_set_worker(
400 node, workers=worker_ids, crypto_enable=crypto_enable
404 def vpp_ipsec_add_sad_entry(
405 node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
406 integ_key=u"", tunnel_src=None, tunnel_dst=None):
407 """Create Security Association Database entry on the VPP node.
409 :param node: VPP node to add SAD entry on.
410 :param sad_id: SAD entry ID.
411 :param spi: Security Parameter Index of this SAD entry.
412 :param crypto_alg: The encryption algorithm name.
413 :param crypto_key: The encryption key string.
414 :param integ_alg: The integrity algorithm name.
415 :param integ_key: The integrity key string.
416 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
417 specified ESP transport mode is used.
418 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
419 not specified ESP transport mode is used.
423 :type crypto_alg: CryptoAlg
424 :type crypto_key: str
425 :type integ_alg: Optional[IntegAlg]
427 :type tunnel_src: str
428 :type tunnel_dst: str
430 if isinstance(crypto_key, str):
431 crypto_key = crypto_key.encode(encoding=u"utf-8")
432 if isinstance(integ_key, str):
433 integ_key = integ_key.encode(encoding=u"utf-8")
435 length=len(crypto_key),
439 length=len(integ_key),
440 data=integ_key if integ_key else 0
443 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
444 if tunnel_src and tunnel_dst:
445 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
446 src_addr = ip_address(tunnel_src)
447 dst_addr = ip_address(tunnel_dst)
448 if src_addr.version == 6:
450 flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
455 cmd = u"ipsec_sad_entry_add"
456 err_msg = f"Failed to add Security Association Database entry " \
457 f"on host {node[u'host']}"
461 crypto_algorithm=crypto_alg.alg_int_repr,
463 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
470 encap_decap_flags=int(
471 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
473 dscp=int(IpDscp.IP_API_DSCP_CS0),
475 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
476 udp_src_port=4500, # default value in api
477 udp_dst_port=4500 # default value in api
479 args = dict(entry=sad_entry)
480 with PapiSocketExecutor(node) as papi_exec:
481 papi_exec.add(cmd, **args).get_reply(err_msg)
484 def vpp_ipsec_add_sad_entries(
485 node, n_entries, sad_id, spi, crypto_alg, crypto_key,
486 integ_alg=None, integ_key=u"", tunnel_src=None,tunnel_dst=None,
487 tunnel_addr_incr=True):
488 """Create multiple Security Association Database entries on VPP node.
490 :param node: VPP node to add SAD entry on.
491 :param n_entries: Number of SAD entries to be created.
492 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
494 :param spi: Security Parameter Index of first SAD entry. All subsequent
495 SAD entries will have spi incremented by 1.
496 :param crypto_alg: The encryption algorithm name.
497 :param crypto_key: The encryption key string.
498 :param integ_alg: The integrity algorithm name.
499 :param integ_key: The integrity key string.
500 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
501 specified ESP transport mode is used.
502 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
503 not specified ESP transport mode is used.
504 :param tunnel_addr_incr: Enable or disable tunnel IP address
510 :type crypto_alg: CryptoAlg
511 :type crypto_key: str
512 :type integ_alg: Optional[IntegAlg]
514 :type tunnel_src: str
515 :type tunnel_dst: str
516 :type tunnel_addr_incr: bool
518 if isinstance(crypto_key, str):
519 crypto_key = crypto_key.encode(encoding=u"utf-8")
520 if isinstance(integ_key, str):
521 integ_key = integ_key.encode(encoding=u"utf-8")
522 if tunnel_src and tunnel_dst:
523 src_addr = ip_address(tunnel_src)
524 dst_addr = ip_address(tunnel_dst)
530 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
536 length=len(crypto_key),
540 length=len(integ_key),
541 data=integ_key if integ_key else 0
544 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
545 if tunnel_src and tunnel_dst:
546 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
547 if src_addr.version == 6:
549 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
552 cmd = u"ipsec_sad_entry_add"
553 err_msg = f"Failed to add Security Association Database entry " \
554 f"on host {node[u'host']}"
559 crypto_algorithm=crypto_alg.alg_int_repr,
561 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
568 encap_decap_flags=int(
569 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
571 dscp=int(IpDscp.IP_API_DSCP_CS0),
573 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
574 udp_src_port=4500, # default value in api
575 udp_dst_port=4500, # default value in api
577 args = dict(entry=sad_entry)
578 with PapiSocketExecutor(node, is_async=True) as papi_exec:
579 for i in range(n_entries):
580 args[u"entry"][u"sad_id"] = int(sad_id) + i
581 args[u"entry"][u"spi"] = int(spi) + i
582 args[u"entry"][u"tunnel"][u"src"] = (
583 str(src_addr + i * addr_incr)
584 if tunnel_src and tunnel_dst else src_addr
586 args[u"entry"][u"tunnel"][u"dst"] = (
587 str(dst_addr + i * addr_incr)
588 if tunnel_src and tunnel_dst else dst_addr
590 history = bool(not 1 < i < n_entries - 2)
591 papi_exec.add(cmd, history=history, **args)
592 papi_exec.get_replies(err_msg)
595 def vpp_ipsec_set_ip_route(
596 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
597 raddr_range, dst_mac=None):
598 """Set IP address and route on interface.
600 :param node: VPP node to add config on.
601 :param n_tunnels: Number of tunnels to create.
602 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
603 :param traffic_addr: Traffic destination IP address to route.
604 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
605 :param interface: Interface key on node 1.
606 :param raddr_range: Mask specifying range of Policy selector Remote IP
607 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
609 :param dst_mac: The MAC address of destination tunnels.
612 :type tunnel_src: str
613 :type traffic_addr: str
614 :type tunnel_dst: str
616 :type raddr_range: int
619 tunnel_src = ip_address(tunnel_src)
620 tunnel_dst = ip_address(tunnel_dst)
621 traffic_addr = ip_address(traffic_addr)
622 tunnel_dst_prefix = 128 if tunnel_dst.version == 6 else 32
623 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
624 else 1 << (32 - raddr_range)
626 cmd1 = u"sw_interface_add_del_address"
628 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
633 cmd2 = u"ip_route_add_del"
639 cmd3 = u"ip_neighbor_add_del"
643 sw_if_index=Topology.get_interface_sw_index(node, interface),
645 mac_address=str(dst_mac),
649 err_msg = f"Failed to configure IP addresses, IP routes and " \
650 f"IP neighbor on interface {interface} on host {node[u'host']}" \
652 else f"Failed to configure IP addresses and IP routes " \
653 f"on interface {interface} on host {node[u'host']}"
655 with PapiSocketExecutor(node, is_async=True) as papi_exec:
656 for i in range(n_tunnels):
657 tunnel_dst_addr = tunnel_dst + i * addr_incr
658 args1[u"prefix"] = IPUtil.create_prefix_object(
659 tunnel_src + i * addr_incr, raddr_range
661 args2[u"route"] = IPUtil.compose_vpp_route_structure(
662 node, traffic_addr + i,
663 prefix_len=tunnel_dst_prefix,
664 interface=interface, gateway=tunnel_dst_addr
666 history = bool(not 1 < i < n_tunnels - 2)
667 papi_exec.add(cmd1, history=history, **args1)
668 papi_exec.add(cmd2, history=history, **args2)
670 args2[u"route"] = IPUtil.compose_vpp_route_structure(
671 node, tunnel_dst_addr,
672 prefix_len=tunnel_dst_prefix,
673 interface=interface, gateway=tunnel_dst_addr
675 papi_exec.add(cmd2, history=history, **args2)
678 args3[u"neighbor"][u"ip_address"] = ip_address(
681 papi_exec.add(cmd3, history=history, **args3)
682 papi_exec.get_replies(err_msg)
685 def vpp_ipsec_add_spd(node, spd_id):
686 """Create Security Policy Database on the VPP node.
688 :param node: VPP node to add SPD on.
689 :param spd_id: SPD ID.
693 cmd = u"ipsec_spd_add_del"
694 err_msg = f"Failed to add Security Policy Database " \
695 f"on host {node[u'host']}"
700 with PapiSocketExecutor(node) as papi_exec:
701 papi_exec.add(cmd, **args).get_reply(err_msg)
704 def vpp_ipsec_spd_add_if(node, spd_id, interface):
705 """Add interface to the Security Policy Database.
707 :param node: VPP node.
708 :param spd_id: SPD ID to add interface on.
709 :param interface: Interface name or sw_if_index.
712 :type interface: str or int
714 cmd = u"ipsec_interface_add_del_spd"
715 err_msg = f"Failed to add interface {interface} to Security Policy " \
716 f"Database {spd_id} on host {node[u'host']}"
719 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
722 with PapiSocketExecutor(node) as papi_exec:
723 papi_exec.add(cmd, **args).get_reply(err_msg)
726 def vpp_ipsec_create_spds_match_nth_entry(
727 node, dir1_interface, dir2_interface, entry_amount,
728 local_addr_range, remote_addr_range, action=PolicyAction.BYPASS,
729 inbound=False, bidirectional=True):
730 """Create one matching SPD entry for inbound or outbound traffic on
731 a DUT for each traffic direction and also create entry_amount - 1
732 non-matching SPD entries. Create a Security Policy Database on each
733 outbound interface where these entries will be configured.
734 The matching SPD entry will have the lowest priority, input action and
735 will be configured to match the IP flow. The non-matching entries will
736 be the same, except with higher priority and non-matching IP flows.
738 Action Protect is currently not supported.
740 :param node: VPP node to configured the SPDs and their entries.
741 :param dir1_interface: The interface in direction 1 where the entries
743 :param dir2_interface: The interface in direction 2 where the entries
745 :param entry_amount: The number of SPD entries to configure. If
746 entry_amount == 1, no non-matching entries will be configured.
747 :param local_addr_range: Matching local address range in direction 1
748 in format IP/prefix or IP/mask. If no mask is provided, it's
749 considered to be /32.
750 :param remote_addr_range: Matching remote address range in
751 direction 1 in format IP/prefix or IP/mask. If no mask is
752 provided, it's considered to be /32.
753 :param action: Policy action.
754 :param inbound: If True policy is for inbound traffic, otherwise
756 :param bidirectional: When True, will create SPDs in both directions
757 of traffic. When False, only in one direction.
759 :type dir1_interface: Union[string, int]
760 :type dir2_interface: Union[string, int]
761 :type entry_amount: int
762 :type local_addr_range:
763 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
764 :type remote_addr_range:
765 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
766 :type action: IPsecUtil.PolicyAction
768 :type bidirectional: bool
769 :raises NotImplementedError: When the action is PolicyAction.PROTECT.
772 if action == PolicyAction.PROTECT:
773 raise NotImplementedError('Policy action PROTECT is not supported.')
777 matching_priority = 1
779 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir1)
780 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir1, dir1_interface)
781 # matching entry direction 1
782 IPsecUtil.vpp_ipsec_add_spd_entry(
783 node, spd_id_dir1, matching_priority, action,
784 inbound=inbound, laddr_range=local_addr_range,
785 raddr_range=remote_addr_range
789 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir2)
790 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir2, dir2_interface)
792 # matching entry direction 2, the address ranges are switched
793 IPsecUtil.vpp_ipsec_add_spd_entry(
794 node, spd_id_dir2, matching_priority, action,
795 inbound=inbound, laddr_range=remote_addr_range,
796 raddr_range=local_addr_range
799 # non-matching entries
800 no_match_entry_amount = entry_amount - 1
801 if no_match_entry_amount > 0:
802 # create a NetworkIncrement representation of the network,
803 # then skip the matching network
804 no_match_local_addr_range = NetworkIncrement(
805 ip_network(local_addr_range)
807 next(no_match_local_addr_range)
809 no_match_remote_addr_range = NetworkIncrement(
810 ip_network(remote_addr_range)
812 next(no_match_remote_addr_range)
814 # non-matching entries direction 1
815 IPsecUtil.vpp_ipsec_add_spd_entries(
816 node, no_match_entry_amount, spd_id_dir1,
817 ObjIncrement(matching_priority + 1, 1), action,
818 inbound=inbound, laddr_range=no_match_local_addr_range,
819 raddr_range=no_match_remote_addr_range
823 # reset the networks so that we're using a unified config
824 # the address ranges are switched
825 no_match_remote_addr_range = NetworkIncrement(
826 ip_network(local_addr_range)
828 next(no_match_remote_addr_range)
830 no_match_local_addr_range = NetworkIncrement(
831 ip_network(remote_addr_range)
833 next(no_match_local_addr_range)
834 # non-matching entries direction 2
835 IPsecUtil.vpp_ipsec_add_spd_entries(
836 node, no_match_entry_amount, spd_id_dir2,
837 ObjIncrement(matching_priority + 1, 1), action,
838 inbound=inbound, laddr_range=no_match_local_addr_range,
839 raddr_range=no_match_remote_addr_range
842 IPsecUtil.vpp_ipsec_show_all(node)
845 def _vpp_ipsec_add_spd_entry_internal(
846 executor, spd_id, priority, action, inbound=True, sa_id=None,
847 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
848 rport_range=None, is_ipv6=False):
849 """Prepare to create Security Policy Database entry on the VPP node.
851 This just adds one more command to the executor.
852 The call site shall get replies once all entries are added,
853 to get speed benefit from async PAPI.
855 :param executor: Open PAPI executor (async handling) to add commands to.
856 :param spd_id: SPD ID to add entry on.
857 :param priority: SPD entry priority, higher number = higher priority.
858 :param action: Policy action.
859 :param inbound: If True policy is for inbound traffic, otherwise
861 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
862 :param proto: Policy selector next layer protocol number.
863 :param laddr_range: Policy selector local IPv4 or IPv6 address range
864 in format IP/prefix or IP/mask. If no mask is provided,
865 it's considered to be /32.
866 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
867 in format IP/prefix or IP/mask. If no mask is provided,
868 it's considered to be /32.
869 :param lport_range: Policy selector local TCP/UDP port range in format
870 <port_start>-<port_end>.
871 :param rport_range: Policy selector remote TCP/UDP port range in format
872 <port_start>-<port_end>.
873 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
874 not defined so it will default to address ::/0, otherwise False.
875 :type executor: PapiSocketExecutor
878 :type action: IPsecUtil.PolicyAction
882 :type laddr_range: string
883 :type raddr_range: string
884 :type lport_range: string
885 :type rport_range: string
888 if laddr_range is None:
889 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
891 if raddr_range is None:
892 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
894 local_net = ip_network(laddr_range, strict=False)
895 remote_net = ip_network(raddr_range, strict=False)
897 cmd = u"ipsec_spd_entry_add_del_v2"
901 priority=int(priority),
902 is_outbound=not inbound,
903 sa_id=int(sa_id) if sa_id else 0,
905 protocol=255 if proto is None else int(proto),
906 remote_address_start=IPAddress.create_ip_address_object(
907 remote_net.network_address
909 remote_address_stop=IPAddress.create_ip_address_object(
910 remote_net.broadcast_address
912 local_address_start=IPAddress.create_ip_address_object(
913 local_net.network_address
915 local_address_stop=IPAddress.create_ip_address_object(
916 local_net.broadcast_address
918 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
920 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
922 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
924 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
931 executor.add(cmd, **args)
934 def vpp_ipsec_add_spd_entry(
935 node, spd_id, priority, action, inbound=True, sa_id=None,
936 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
937 rport_range=None, is_ipv6=False):
938 """Create Security Policy Database entry on the VPP node.
940 :param node: VPP node to add SPD entry on.
941 :param spd_id: SPD ID to add entry on.
942 :param priority: SPD entry priority, higher number = higher priority.
943 :param action: Policy action.
944 :param inbound: If True policy is for inbound traffic, otherwise
946 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
947 :param proto: Policy selector next layer protocol number.
948 :param laddr_range: Policy selector local IPv4 or IPv6 address range
949 in format IP/prefix or IP/mask. If no mask is provided,
950 it's considered to be /32.
951 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
952 in format IP/prefix or IP/mask. If no mask is provided,
953 it's considered to be /32.
954 :param lport_range: Policy selector local TCP/UDP port range in format
955 <port_start>-<port_end>.
956 :param rport_range: Policy selector remote TCP/UDP port range in format
957 <port_start>-<port_end>.
958 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
959 not defined so it will default to address ::/0, otherwise False.
963 :type action: IPsecUtil.PolicyAction
967 :type laddr_range: string
968 :type raddr_range: string
969 :type lport_range: string
970 :type rport_range: string
973 err_msg = f"Failed to add entry to Security Policy Database " \
974 f"{spd_id} on host {node[u'host']}"
975 with PapiSocketExecutor(node, is_async=True) as papi_exec:
976 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
977 papi_exec, spd_id, priority, action, inbound, sa_id, proto,
978 laddr_range, raddr_range, lport_range, rport_range, is_ipv6
980 papi_exec.get_replies(err_msg)
983 def vpp_ipsec_add_spd_entries(
984 node, n_entries, spd_id, priority, action, inbound, sa_id=None,
985 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
986 rport_range=None, is_ipv6=False):
987 """Create multiple Security Policy Database entries on the VPP node.
989 :param node: VPP node to add SPD entries on.
990 :param n_entries: Number of SPD entries to be added.
991 :param spd_id: SPD ID to add entries on.
992 :param priority: SPD entries priority, higher number = higher priority.
993 :param action: Policy action.
994 :param inbound: If True policy is for inbound traffic, otherwise
996 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
997 :param proto: Policy selector next layer protocol number.
998 :param laddr_range: Policy selector local IPv4 or IPv6 address range
999 in format IP/prefix or IP/mask. If no mask is provided,
1000 it's considered to be /32.
1001 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
1002 in format IP/prefix or IP/mask. If no mask is provided,
1003 it's considered to be /32.
1004 :param lport_range: Policy selector local TCP/UDP port range in format
1005 <port_start>-<port_end>.
1006 :param rport_range: Policy selector remote TCP/UDP port range in format
1007 <port_start>-<port_end>.
1008 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
1009 not defined so it will default to address ::/0, otherwise False.
1011 :type n_entries: int
1013 :type priority: IPsecUtil.ObjIncrement
1014 :type action: IPsecUtil.PolicyAction
1016 :type sa_id: IPsecUtil.ObjIncrement
1018 :type laddr_range: IPsecUtil.NetworkIncrement
1019 :type raddr_range: IPsecUtil.NetworkIncrement
1020 :type lport_range: string
1021 :type rport_range: string
1024 if laddr_range is None:
1025 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1026 laddr_range = NetworkIncrement(ip_network(laddr_range), 0)
1028 if raddr_range is None:
1029 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1030 raddr_range = NetworkIncrement(ip_network(raddr_range), 0)
1032 lport_range_start = 0
1033 lport_range_stop = 65535
1035 lport_range_start, lport_range_stop = lport_range.split('-')
1037 rport_range_start = 0
1038 rport_range_stop = 65535
1040 rport_range_start, rport_range_stop = rport_range.split('-')
1042 err_msg = f"Failed to add entry to Security Policy Database " \
1043 f"{spd_id} on host {node[u'host']}"
1044 with PapiSocketExecutor(node, is_async=True) as papi_exec:
1045 for _ in range(n_entries):
1046 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
1047 papi_exec, spd_id, next(priority), action, inbound,
1048 next(sa_id) if sa_id is not None else sa_id,
1049 proto, next(laddr_range), next(raddr_range), lport_range,
1050 rport_range, is_ipv6
1052 papi_exec.get_replies(err_msg)
1055 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1056 """Create loopback interface and set IP address on VPP node 1 interface
1059 :param nodes: VPP nodes to create tunnel interfaces.
1060 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1061 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1062 IPv4/IPv6 address (ip2).
1063 :param if1_key: VPP node 1 interface key from topology file.
1064 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1065 interface key from topology file.
1071 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1072 # Create loopback interface on DUT1, set it to up state
1073 cmd = u"create_loopback_instance"
1079 err_msg = f"Failed to create loopback interface " \
1080 f"on host {nodes[u'DUT1'][u'host']}"
1081 papi_exec.add(cmd, **args)
1082 loop_sw_if_idx = papi_exec.get_sw_if_index(err_msg)
1083 cmd = u"sw_interface_set_flags"
1085 sw_if_index=loop_sw_if_idx,
1086 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1088 err_msg = f"Failed to set loopback interface state up " \
1089 f"on host {nodes[u'DUT1'][u'host']}"
1090 papi_exec.add(cmd, **args).get_reply(err_msg)
1091 # Set IP address on VPP node 1 interface
1092 cmd = u"sw_interface_add_del_address"
1094 sw_if_index=InterfaceUtil.get_interface_index(
1095 nodes[u"DUT1"], if1_key
1099 prefix=IPUtil.create_prefix_object(
1100 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1104 err_msg = f"Failed to set IP address on interface {if1_key} " \
1105 f"on host {nodes[u'DUT1'][u'host']}"
1106 papi_exec.add(cmd, **args).get_reply(err_msg)
1107 cmd2 = u"ip_neighbor_add_del"
1111 sw_if_index=Topology.get_interface_sw_index(
1112 nodes[u"DUT1"], if1_key
1116 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1117 if u"DUT2" in nodes.keys()
1118 else Topology.get_interface_mac(
1119 nodes[u"TG"], if2_key
1122 ip_address=tun_ips[u"ip2"].compressed
1125 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1126 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1128 return loop_sw_if_idx
1131 def _ipsec_create_tunnel_interfaces_dut1_papi(
1132 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1133 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1134 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1136 Generate random keys and return them (so DUT2 or TG can decrypt).
1138 :param nodes: VPP nodes to create tunnel interfaces.
1139 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1140 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1141 IPv4/IPv6 address (ip2).
1142 :param if1_key: VPP node 1 interface key from topology file.
1143 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1144 interface key from topology file.
1145 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1146 :param crypto_alg: The encryption algorithm name.
1147 :param integ_alg: The integrity algorithm name.
1148 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1149 first tunnel in direction node2->node1.
1150 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1151 :param addr_incr: IP / IPv6 address incremental step.
1152 :param existing_tunnels: Number of tunnel interfaces before creation.
1153 Useful mainly for reconf tests. Default 0.
1158 :type n_tunnels: int
1159 :type crypto_alg: CryptoAlg
1160 :type integ_alg: Optional[IntegAlg]
1161 :type raddr_ip2: IPv4Address or IPv6Address
1162 :type addr_incr: int
1164 :type existing_tunnels: int
1165 :returns: Generated ckeys and ikeys.
1166 :rtype: List[bytes], List[bytes]
1168 if not existing_tunnels:
1169 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1170 nodes, tun_ips, if1_key, if2_key
1173 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1174 nodes[u"DUT1"], u"loop0"
1176 with PapiSocketExecutor(nodes[u"DUT1"], is_async=True) as papi_exec:
1177 # Configure IP addresses on loop0 interface
1178 cmd = u"sw_interface_add_del_address"
1180 sw_if_index=loop_sw_if_idx,
1185 for i in range(existing_tunnels, n_tunnels):
1186 args[u"prefix"] = IPUtil.create_prefix_object(
1187 tun_ips[u"ip1"] + i * addr_incr,
1188 128 if tun_ips[u"ip1"].version == 6 else 32
1191 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1193 # Configure IPIP tunnel interfaces
1194 cmd = u"ipip_add_tunnel"
1196 instance=Constants.BITWISE_NON_ZERO,
1201 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1203 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1204 dscp=int(IpDscp.IP_API_DSCP_CS0)
1209 ipip_tunnels = [None] * existing_tunnels
1210 for i in range(existing_tunnels, n_tunnels):
1211 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1212 tun_ips[u"ip1"] + i * addr_incr
1214 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1218 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1220 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1221 f" {nodes[u'DUT1'][u'host']}"
1222 ipip_tunnels.extend(
1224 reply[u"sw_if_index"]
1225 for reply in papi_exec.get_replies(err_msg)
1226 if u"sw_if_index" in reply
1229 # Configure IPSec SAD entries
1230 ckeys = [bytes()] * existing_tunnels
1231 ikeys = [bytes()] * existing_tunnels
1232 cmd = u"ipsec_sad_entry_add"
1244 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1245 crypto_algorithm=crypto_alg.alg_int_repr,
1247 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1248 integrity_key=i_key,
1254 encap_decap_flags=int(
1255 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1257 dscp=int(IpDscp.IP_API_DSCP_CS0),
1260 udp_src_port=IPSEC_UDP_PORT_NONE,
1261 udp_dst_port=IPSEC_UDP_PORT_NONE,
1263 args = dict(entry=sad_entry)
1264 for i in range(existing_tunnels, n_tunnels):
1266 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1269 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1271 # SAD entry for outband / tx path
1272 args[u"entry"][u"sad_id"] = i
1273 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1275 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1276 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1278 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1279 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1280 args[u"entry"][u"flags"] = int(
1281 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1284 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1286 # SAD entry for inband / rx path
1287 args[u"entry"][u"sad_id"] = 100000 + i
1288 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1290 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1291 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1293 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1294 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1295 args[u"entry"][u"flags"] = int(
1296 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1297 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1300 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1302 err_msg = f"Failed to add IPsec SAD entries on host" \
1303 f" {nodes[u'DUT1'][u'host']}"
1304 papi_exec.get_replies(err_msg)
1305 # Add protection for tunnels with IPSEC
1306 cmd = u"ipsec_tunnel_protect_update"
1309 via_label=MPLS_LABEL_INVALID,
1310 obj_id=Constants.BITWISE_NON_ZERO
1312 ipsec_tunnel_protect = dict(
1320 tunnel=ipsec_tunnel_protect
1322 for i in range(existing_tunnels, n_tunnels):
1323 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1324 args[u"tunnel"][u"sa_out"] = i
1325 args[u"tunnel"][u"sa_in"] = [100000 + i]
1327 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1329 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1330 f"on host {nodes[u'DUT1'][u'host']}"
1331 papi_exec.get_replies(err_msg)
1333 # Configure unnumbered interfaces
1334 cmd = u"sw_interface_set_unnumbered"
1337 sw_if_index=InterfaceUtil.get_interface_index(
1338 nodes[u"DUT1"], if1_key
1340 unnumbered_sw_if_index=0
1342 for i in range(existing_tunnels, n_tunnels):
1343 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1345 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1348 cmd = u"sw_interface_set_flags"
1351 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1353 for i in range(existing_tunnels, n_tunnels):
1354 args[u"sw_if_index"] = ipip_tunnels[i]
1356 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1358 # Configure IP routes
1359 cmd = u"ip_route_add_del"
1365 for i in range(existing_tunnels, n_tunnels):
1366 args[u"route"] = IPUtil.compose_vpp_route_structure(
1367 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1368 prefix_len=128 if raddr_ip2.version == 6 else 32,
1369 interface=ipip_tunnels[i]
1372 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1374 err_msg = f"Failed to add IP routes on host " \
1375 f"{nodes[u'DUT1'][u'host']}"
1376 papi_exec.get_replies(err_msg)
1381 def _ipsec_create_tunnel_interfaces_dut2_papi(
1382 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1383 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1384 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1386 This method accesses keys generated by DUT1 method
1387 and does not return anything.
1389 :param nodes: VPP nodes to create tunnel interfaces.
1390 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1391 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1392 IPv4/IPv6 address (ip2).
1393 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1394 interface key from topology file.
1395 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1396 :param crypto_alg: The encryption algorithm name.
1397 :param ckeys: List of encryption keys.
1398 :param integ_alg: The integrity algorithm name.
1399 :param ikeys: List of integrity keys.
1400 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1401 :param addr_incr: IP / IPv6 address incremental step.
1402 :param existing_tunnels: Number of tunnel interfaces before creation.
1403 Useful mainly for reconf tests. Default 0.
1407 :type n_tunnels: int
1408 :type crypto_alg: CryptoAlg
1409 :type ckeys: Sequence[bytes]
1410 :type integ_alg: Optional[IntegAlg]
1411 :type ikeys: Sequence[bytes]
1412 :type addr_incr: int
1414 :type existing_tunnels: int
1416 with PapiSocketExecutor(nodes[u"DUT2"], is_async=True) as papi_exec:
1417 if not existing_tunnels:
1418 # Set IP address on VPP node 2 interface
1419 cmd = u"sw_interface_add_del_address"
1421 sw_if_index=InterfaceUtil.get_interface_index(
1422 nodes[u"DUT2"], if2_key
1426 prefix=IPUtil.create_prefix_object(
1427 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1431 err_msg = f"Failed to set IP address on interface {if2_key} " \
1432 f"on host {nodes[u'DUT2'][u'host']}"
1433 papi_exec.add(cmd, **args).get_replies(err_msg)
1434 # Configure IPIP tunnel interfaces
1435 cmd = u"ipip_add_tunnel"
1437 instance=Constants.BITWISE_NON_ZERO,
1442 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1444 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1445 dscp=int(IpDscp.IP_API_DSCP_CS0)
1450 ipip_tunnels = [None] * existing_tunnels
1451 for i in range(existing_tunnels, n_tunnels):
1452 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1455 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1456 tun_ips[u"ip1"] + i * addr_incr
1459 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1461 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1462 f" {nodes[u'DUT2'][u'host']}"
1463 ipip_tunnels.extend(
1465 reply[u"sw_if_index"]
1466 for reply in papi_exec.get_replies(err_msg)
1467 if u"sw_if_index" in reply
1470 # Configure IPSec SAD entries
1471 cmd = u"ipsec_sad_entry_add"
1483 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1484 crypto_algorithm=crypto_alg.alg_int_repr,
1486 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1487 integrity_key=i_key,
1493 encap_decap_flags=int(
1494 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1496 dscp=int(IpDscp.IP_API_DSCP_CS0),
1499 udp_src_port=IPSEC_UDP_PORT_NONE,
1500 udp_dst_port=IPSEC_UDP_PORT_NONE,
1502 args = dict(entry=sad_entry)
1503 for i in range(existing_tunnels, n_tunnels):
1505 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1508 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1510 # SAD entry for outband / tx path
1511 args[u"entry"][u"sad_id"] = 100000 + i
1512 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1514 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1515 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1517 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1518 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1519 args[u"entry"][u"flags"] = int(
1520 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1523 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1525 # SAD entry for inband / rx path
1526 args[u"entry"][u"sad_id"] = i
1527 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1529 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1530 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1532 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1533 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1534 args[u"entry"][u"flags"] = int(
1535 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1536 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1539 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1541 err_msg = f"Failed to add IPsec SAD entries on host" \
1542 f" {nodes[u'DUT2'][u'host']}"
1543 papi_exec.get_replies(err_msg)
1544 # Add protection for tunnels with IPSEC
1545 cmd = u"ipsec_tunnel_protect_update"
1548 via_label=MPLS_LABEL_INVALID,
1549 obj_id=Constants.BITWISE_NON_ZERO
1551 ipsec_tunnel_protect = dict(
1559 tunnel=ipsec_tunnel_protect
1561 for i in range(existing_tunnels, n_tunnels):
1562 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1563 args[u"tunnel"][u"sa_out"] = 100000 + i
1564 args[u"tunnel"][u"sa_in"] = [i]
1566 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1568 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1569 f"on host {nodes[u'DUT2'][u'host']}"
1570 papi_exec.get_replies(err_msg)
1572 if not existing_tunnels:
1573 # Configure IP route
1574 cmd = u"ip_route_add_del"
1575 route = IPUtil.compose_vpp_route_structure(
1576 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1577 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1579 gateway=(tun_ips[u"ip2"] - 1).compressed
1586 papi_exec.add(cmd, **args)
1587 # Configure unnumbered interfaces
1588 cmd = u"sw_interface_set_unnumbered"
1591 sw_if_index=InterfaceUtil.get_interface_index(
1592 nodes[u"DUT2"], if2_key
1594 unnumbered_sw_if_index=0
1596 for i in range(existing_tunnels, n_tunnels):
1597 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1599 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1602 cmd = u"sw_interface_set_flags"
1605 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1607 for i in range(existing_tunnels, n_tunnels):
1608 args[u"sw_if_index"] = ipip_tunnels[i]
1610 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1612 # Configure IP routes
1613 cmd = u"ip_route_add_del"
1619 for i in range(existing_tunnels, n_tunnels):
1620 args[u"route"] = IPUtil.compose_vpp_route_structure(
1621 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1622 prefix_len=128 if raddr_ip1.version == 6 else 32,
1623 interface=ipip_tunnels[i]
1626 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1628 err_msg = f"Failed to add IP routes " \
1629 f"on host {nodes[u'DUT2'][u'host']}"
1630 papi_exec.get_replies(err_msg)
1633 def vpp_ipsec_create_tunnel_interfaces(
1634 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1635 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1636 existing_tunnels=0, return_keys=False):
1637 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1639 Some deployments (e.g. devicetest) need to know the generated keys.
1640 But other deployments (e.g. scale perf test) would get spammed
1641 if we returned keys every time.
1643 :param nodes: VPP nodes to create tunnel interfaces.
1644 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1646 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1648 :param if1_key: VPP node 1 interface key from topology file.
1649 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1650 interface key from topology file.
1651 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1652 :param crypto_alg: The encryption algorithm name.
1653 :param integ_alg: The integrity algorithm name.
1654 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1655 first tunnel in direction node1->node2.
1656 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1657 first tunnel in direction node2->node1.
1658 :param raddr_range: Mask specifying range of Policy selector Remote
1659 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1660 and to 128 in case of IPv6.
1661 :param existing_tunnels: Number of tunnel interfaces before creation.
1662 Useful mainly for reconf tests. Default 0.
1663 :param return_keys: Whether generated keys should be returned.
1665 :type tun_if1_ip_addr: str
1666 :type tun_if2_ip_addr: str
1669 :type n_tunnels: int
1670 :type crypto_alg: CryptoAlg
1671 :type integ_alg: Optonal[IntegAlg]
1672 :type raddr_ip1: string
1673 :type raddr_ip2: string
1674 :type raddr_range: int
1675 :type existing_tunnels: int
1676 :type return_keys: bool
1677 :returns: Ckeys, ikeys, spi_1, spi_2.
1678 :rtype: Optional[List[bytes], List[bytes], int, int]
1680 n_tunnels = int(n_tunnels)
1681 existing_tunnels = int(existing_tunnels)
1687 ip1=ip_address(tun_if1_ip_addr),
1688 ip2=ip_address(tun_if2_ip_addr)
1690 raddr_ip1 = ip_address(raddr_ip1)
1691 raddr_ip2 = ip_address(raddr_ip2)
1692 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1693 else 1 << (32 - raddr_range)
1695 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1696 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1697 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1699 if u"DUT2" in nodes.keys():
1700 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1701 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1702 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1707 return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1711 def _create_ipsec_script_files(dut, instances):
1712 """Create script files for configuring IPsec in containers
1714 :param dut: DUT node on which to create the script files
1715 :param instances: number of containers on DUT node
1717 :type instances: int
1720 for cnf in range(0, instances):
1722 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1724 scripts.append(open(script_filename, 'w'))
1728 def _close_and_copy_ipsec_script_files(
1729 dut, nodes, instances, scripts):
1730 """Close created scripts and copy them to containers
1732 :param dut: DUT node on which to create the script files
1733 :param nodes: VPP nodes
1734 :param instances: number of containers on DUT node
1735 :param scripts: dictionary holding the script files
1738 :type instances: int
1741 for cnf in range(0, instances):
1742 scripts[cnf].close()
1744 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1746 scp_node(nodes[dut], script_filename, script_filename)
1750 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1751 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1752 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1753 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1755 :param nodes: VPP nodes to create tunnel interfaces.
1756 :param if1_ip_addr: VPP node 1 interface IP4 address.
1757 :param if2_ip_addr: VPP node 2 interface IP4 address.
1758 :param n_tunnels: Number of tunnell interfaces to create.
1759 :param crypto_alg: The encryption algorithm name.
1760 :param integ_alg: The integrity algorithm name.
1761 :param raddr_ip1: Policy selector remote IPv4 start address for the
1762 first tunnel in direction node1->node2.
1763 :param raddr_ip2: Policy selector remote IPv4 start address for the
1764 first tunnel in direction node2->node1.
1765 :param raddr_range: Mask specifying range of Policy selector Remote
1766 IPv4 addresses. Valid values are from 1 to 32.
1767 :param n_instances: Number of containers.
1769 :type if1_ip_addr: str
1770 :type if2_ip_addr: str
1771 :type n_tunnels: int
1772 :type crypto_alg: CryptoAlg
1773 :type integ_alg: Optional[IntegAlg]
1774 :type raddr_ip1: string
1775 :type raddr_ip2: string
1776 :type raddr_range: int
1777 :type n_instances: int
1781 addr_incr = 1 << (32 - raddr_range)
1783 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1784 u"DUT1", n_instances
1786 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1787 u"DUT2", n_instances
1790 for cnf in range(0, n_instances):
1791 dut1_scripts[cnf].write(
1792 u"create loopback interface\n"
1793 u"set interface state loop0 up\n\n"
1795 dut2_scripts[cnf].write(
1796 f"ip route add {if1_ip_addr}/8 via "
1797 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1800 for tnl in range(0, n_tunnels):
1801 cnf = tnl % n_instances
1803 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1807 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1811 f"integ-alg {integ_alg.alg_name} "
1812 f"local-integ-key {ikey} "
1813 f"remote-integ-key {ikey} "
1815 # Configure tunnel end point(s) on left side
1816 dut1_scripts[cnf].write(
1817 u"set interface ip address loop0 "
1818 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1819 f"create ipsec tunnel "
1820 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1821 f"local-spi {spi_1 + tnl} "
1822 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1823 f"remote-spi {spi_2 + tnl} "
1824 f"crypto-alg {crypto_alg.alg_name} "
1825 f"local-crypto-key {ckey} "
1826 f"remote-crypto-key {ckey} "
1827 f"instance {tnl // n_instances} "
1830 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1831 f"set interface state ipip{tnl // n_instances} up\n"
1832 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1833 f"via ipip{tnl // n_instances}\n\n"
1835 # Configure tunnel end point(s) on right side
1836 dut2_scripts[cnf].write(
1837 f"set ip neighbor memif1/{cnf + 1} "
1838 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1839 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1840 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1841 f"local-spi {spi_2 + tnl} "
1842 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1843 f"remote-spi {spi_1 + tnl} "
1844 f"crypto-alg {crypto_alg.alg_name} "
1845 f"local-crypto-key {ckey} "
1846 f"remote-crypto-key {ckey} "
1847 f"instance {tnl // n_instances} "
1850 f"set interface unnumbered ipip{tnl // n_instances} "
1851 f"use memif1/{cnf + 1}\n"
1852 f"set interface state ipip{tnl // n_instances} up\n"
1853 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1854 f"via ipip{tnl // n_instances}\n\n"
1857 IPsecUtil._close_and_copy_ipsec_script_files(
1858 u"DUT1", nodes, n_instances, dut1_scripts)
1859 IPsecUtil._close_and_copy_ipsec_script_files(
1860 u"DUT2", nodes, n_instances, dut2_scripts)
1863 def vpp_ipsec_add_multiple_tunnels(
1864 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1865 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range,
1866 tunnel_addr_incr=True):
1867 """Create multiple IPsec tunnels between two VPP nodes.
1869 :param nodes: VPP nodes to create tunnels.
1870 :param interface1: Interface name or sw_if_index on node 1.
1871 :param interface2: Interface name or sw_if_index on node 2.
1872 :param n_tunnels: Number of tunnels to create.
1873 :param crypto_alg: The encryption algorithm name.
1874 :param integ_alg: The integrity algorithm name.
1875 :param tunnel_ip1: Tunnel node1 IPv4 address.
1876 :param tunnel_ip2: Tunnel node2 IPv4 address.
1877 :param raddr_ip1: Policy selector remote IPv4 start address for the
1878 first tunnel in direction node1->node2.
1879 :param raddr_ip2: Policy selector remote IPv4 start address for the
1880 first tunnel in direction node2->node1.
1881 :param raddr_range: Mask specifying range of Policy selector Remote
1882 IPv4 addresses. Valid values are from 1 to 32.
1883 :param tunnel_addr_incr: Enable or disable tunnel IP address
1886 :type interface1: str or int
1887 :type interface2: str or int
1888 :type n_tunnels: int
1889 :type crypto_alg: CryptoAlg
1890 :type integ_alg: Optional[IntegAlg]
1891 :type tunnel_ip1: str
1892 :type tunnel_ip2: str
1893 :type raddr_ip1: string
1894 :type raddr_ip2: string
1895 :type raddr_range: int
1896 :type tunnel_addr_incr: bool
1906 crypto_key = gen_key(
1907 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1909 integ_key = gen_key(
1910 IPsecUtil.get_integ_alg_key_len(integ_alg)
1911 ).decode() if integ_alg else u""
1913 rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
1914 if u"DUT2" in nodes.keys() \
1915 else Topology.get_interface_mac(nodes[u"TG"], interface2)
1916 IPsecUtil.vpp_ipsec_set_ip_route(
1917 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1918 interface1, raddr_range, rmac)
1920 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1921 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1923 addr_incr = 1 << (128 - 96) if ip_address(tunnel_ip1).version == 6 \
1925 for i in range(n_tunnels//(addr_incr**2)+1):
1926 dut1_local_outbound_range = \
1927 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1928 False).with_prefixlen
1929 dut1_remote_outbound_range = \
1930 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1931 False).with_prefixlen
1933 IPsecUtil.vpp_ipsec_add_spd_entry(
1934 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1935 proto=50, laddr_range=dut1_local_outbound_range,
1936 raddr_range=dut1_remote_outbound_range
1938 IPsecUtil.vpp_ipsec_add_spd_entry(
1939 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1940 proto=50, laddr_range=dut1_remote_outbound_range,
1941 raddr_range=dut1_local_outbound_range
1944 IPsecUtil.vpp_ipsec_add_sad_entries(
1945 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1946 integ_alg, integ_key, tunnel_ip1, tunnel_ip2, tunnel_addr_incr
1949 IPsecUtil.vpp_ipsec_add_spd_entries(
1950 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1951 action=PolicyAction.PROTECT, inbound=False,
1952 sa_id=ObjIncrement(sa_id_1, 1),
1953 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
1956 IPsecUtil.vpp_ipsec_add_sad_entries(
1957 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1958 integ_alg, integ_key, tunnel_ip2, tunnel_ip1, tunnel_addr_incr
1960 IPsecUtil.vpp_ipsec_add_spd_entries(
1961 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1962 action=PolicyAction.PROTECT, inbound=True,
1963 sa_id=ObjIncrement(sa_id_2, 1),
1964 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
1967 if u"DUT2" in nodes.keys():
1968 rmac = Topology.get_interface_mac(nodes[u"DUT1"], interface1)
1969 IPsecUtil.vpp_ipsec_set_ip_route(
1970 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1971 interface2, raddr_range, rmac)
1973 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1974 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1975 for i in range(n_tunnels//(addr_incr**2)+1):
1976 dut2_local_outbound_range = \
1977 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1978 False).with_prefixlen
1979 dut2_remote_outbound_range = \
1980 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1981 False).with_prefixlen
1983 IPsecUtil.vpp_ipsec_add_spd_entry(
1984 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1985 inbound=False, proto=50, laddr_range=dut2_remote_outbound_range,
1986 raddr_range=dut2_local_outbound_range
1988 IPsecUtil.vpp_ipsec_add_spd_entry(
1989 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1990 inbound=True, proto=50, laddr_range=dut2_local_outbound_range,
1991 raddr_range=dut2_remote_outbound_range
1994 IPsecUtil.vpp_ipsec_add_sad_entries(
1995 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
1996 crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2,
1999 IPsecUtil.vpp_ipsec_add_spd_entries(
2000 nodes[u"DUT2"], n_tunnels, spd_id,
2001 priority=ObjIncrement(p_lo, 0),
2002 action=PolicyAction.PROTECT, inbound=True,
2003 sa_id=ObjIncrement(sa_id_1, 1),
2004 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
2007 IPsecUtil.vpp_ipsec_add_sad_entries(
2008 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
2009 crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1,
2012 IPsecUtil.vpp_ipsec_add_spd_entries(
2013 nodes[u"DUT2"], n_tunnels, spd_id,
2014 priority=ObjIncrement(p_lo, 0),
2015 action=PolicyAction.PROTECT, inbound=False,
2016 sa_id=ObjIncrement(sa_id_2, 1),
2017 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
2021 def vpp_ipsec_show_all(node):
2022 """Run "show ipsec all" debug CLI command.
2024 :param node: Node to run command on.
2027 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec all")
2030 def show_ipsec_security_association(node):
2031 """Show IPSec security association.
2033 :param node: DUT node.
2039 PapiSocketExecutor.dump_and_log(node, cmds)
2042 def vpp_ipsec_flow_enale_rss(node, proto, type, function="default"):
2043 """Ipsec flow enable rss action.
2045 :param node: DUT node.
2046 :param proto: The flow protocol.
2047 :param type: RSS type.
2048 :param function: RSS function.
2054 :returns: flow_index.
2056 # TODO: to be fixed to use full PAPI when it is ready in VPP
2057 cmd = f"test flow add src-ip any proto {proto} rss function " \
2058 f"{function} rss types {type}"
2059 stdout = PapiSocketExecutor.run_cli_cmd(node, cmd)
2060 flow_index = stdout.split()[1]
2065 def vpp_create_ipsec_flows_on_dut(
2066 node, n_flows, rx_queues, spi_start, interface):
2067 """Create mutiple ipsec flows and enable flows onto interface.
2069 :param node: DUT node.
2070 :param n_flows: Number of flows to create.
2071 :param rx_queues: NUmber of RX queues.
2072 :param spi_start: The start spi.
2073 :param interface: Name of the interface.
2077 :type rx_queues: int
2078 :type spi_start: int
2079 :type interface: str
2080 :returns: flow_index.
2083 for i in range(0, n_flows):
2084 rx_queue = i%rx_queues
2087 flow_index = FlowUtil.vpp_create_ip4_ipsec_flow(
2088 node, "ESP", spi, "redirect-to-queue", value=rx_queue)
2089 FlowUtil.vpp_flow_enable(node, interface, flow_index)