1 # Copyright (c) 2024 Cisco and/or its affiliates.
2 # Copyright (c) 2024 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."""
17 from enum import Enum, IntEnum
19 from ipaddress import ip_network, ip_address
20 from random import choice
21 from string import ascii_letters
23 from robot.libraries.BuiltIn import BuiltIn
25 from resources.libraries.python.Constants import Constants
26 from resources.libraries.python.IncrementUtil import ObjIncrement
27 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
29 from resources.libraries.python.IPAddress import IPAddress
30 from resources.libraries.python.IPUtil import IPUtil, IpDscp, \
31 MPLS_LABEL_INVALID, NetworkIncrement
32 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
33 from resources.libraries.python.ssh import scp_node
34 from resources.libraries.python.topology import Topology, NodeType
35 from resources.libraries.python.VPPUtil import VPPUtil
36 from resources.libraries.python.FlowUtil import FlowUtil
39 IPSEC_UDP_PORT_DEFAULT = 4500
40 IPSEC_REPLAY_WINDOW_DEFAULT = 64
44 """Generate random string as a key.
46 :param length: Length of generated payload.
48 :returns: The generated payload.
52 choice(ascii_letters) for _ in range(length)
53 ).encode(encoding=u"utf-8")
56 class PolicyAction(Enum):
58 BYPASS = (u"bypass", 0)
59 DISCARD = (u"discard", 1)
60 PROTECT = (u"protect", 3)
62 def __init__(self, policy_name, policy_int_repr):
63 self.policy_name = policy_name
64 self.policy_int_repr = policy_int_repr
67 return self.policy_name
70 return self.policy_int_repr
73 class CryptoAlg(Enum):
74 """Encryption algorithms."""
75 AES_CBC_128 = (u"aes-cbc-128", 1, u"AES-CBC", 16)
76 AES_CBC_256 = (u"aes-cbc-256", 3, u"AES-CBC", 32)
77 AES_GCM_128 = (u"aes-gcm-128", 7, u"AES-GCM", 16)
78 AES_GCM_256 = (u"aes-gcm-256", 9, u"AES-GCM", 32)
80 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
81 self.alg_name = alg_name
82 self.alg_int_repr = alg_int_repr
83 self.scapy_name = scapy_name
84 self.key_len = key_len
88 """Integrity algorithm."""
89 SHA_256_128 = (u"sha-256-128", 4, u"SHA2-256-128", 32)
90 SHA_512_256 = (u"sha-512-256", 6, u"SHA2-512-256", 64)
92 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
93 self.alg_name = alg_name
94 self.alg_int_repr = alg_int_repr
95 self.scapy_name = scapy_name
96 self.key_len = key_len
99 class IPsecProto(IntEnum):
100 """IPsec protocol."""
101 IPSEC_API_PROTO_ESP = 50
102 IPSEC_API_PROTO_AH = 51
105 class IPsecSadFlags(IntEnum):
106 """IPsec Security Association Database flags."""
107 IPSEC_API_SAD_FLAG_NONE = 0
108 # Enable extended sequence numbers
109 IPSEC_API_SAD_FLAG_USE_ESN = 0x01
110 # Enable Anti - replay
111 IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY = 0x02
112 # IPsec tunnel mode if non-zero, else transport mode
113 IPSEC_API_SAD_FLAG_IS_TUNNEL = 0x04
114 # IPsec tunnel mode is IPv6 if non-zero, else IPv4 tunnel
115 # only valid if is_tunnel is non-zero
116 IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 0x08
117 # Enable UDP encapsulation for NAT traversal
118 IPSEC_API_SAD_FLAG_UDP_ENCAP = 0x10
119 # IPsec SA is or inbound traffic
120 IPSEC_API_SAD_FLAG_IS_INBOUND = 0x40
123 class TunnelEncpaDecapFlags(IntEnum):
124 """Flags controlling tunnel behaviour."""
125 TUNNEL_API_ENCAP_DECAP_FLAG_NONE = 0
126 # at encap, copy the DF bit of the payload into the tunnel header
127 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF = 1
128 # at encap, set the DF bit in the tunnel header
129 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF = 2
130 # at encap, copy the DSCP bits of the payload into the tunnel header
131 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP = 4
132 # at encap, copy the ECN bit of the payload into the tunnel header
133 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN = 8
134 # at decap, copy the ECN bit of the tunnel header into the payload
135 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_ECN = 16
138 class TunnelMode(IntEnum):
141 TUNNEL_API_MODE_P2P = 0
143 TUNNEL_API_MODE_MP = 1
147 """IPsec utilities."""
150 def policy_action_bypass():
151 """Return policy action bypass.
153 :returns: PolicyAction enum BYPASS object.
156 return PolicyAction.BYPASS
159 def policy_action_discard():
160 """Return policy action discard.
162 :returns: PolicyAction enum DISCARD object.
165 return PolicyAction.DISCARD
168 def policy_action_protect():
169 """Return policy action protect.
171 :returns: PolicyAction enum PROTECT object.
174 return PolicyAction.PROTECT
177 def crypto_alg_aes_cbc_128():
178 """Return encryption algorithm aes-cbc-128.
180 :returns: CryptoAlg enum AES_CBC_128 object.
183 return CryptoAlg.AES_CBC_128
186 def crypto_alg_aes_cbc_256():
187 """Return encryption algorithm aes-cbc-256.
189 :returns: CryptoAlg enum AES_CBC_256 object.
192 return CryptoAlg.AES_CBC_256
195 def crypto_alg_aes_gcm_128():
196 """Return encryption algorithm aes-gcm-128.
198 :returns: CryptoAlg enum AES_GCM_128 object.
201 return CryptoAlg.AES_GCM_128
204 def crypto_alg_aes_gcm_256():
205 """Return encryption algorithm aes-gcm-256.
207 :returns: CryptoAlg enum AES_GCM_128 object.
210 return CryptoAlg.AES_GCM_256
213 def get_crypto_alg_key_len(crypto_alg):
214 """Return encryption algorithm key length.
216 :param crypto_alg: Encryption algorithm.
217 :type crypto_alg: CryptoAlg
218 :returns: Key length.
221 return crypto_alg.key_len
224 def get_crypto_alg_scapy_name(crypto_alg):
225 """Return encryption algorithm scapy name.
227 :param crypto_alg: Encryption algorithm.
228 :type crypto_alg: CryptoAlg
229 :returns: Algorithm scapy name.
232 return crypto_alg.scapy_name
235 def integ_alg_sha_256_128():
236 """Return integrity algorithm SHA-256-128.
238 :returns: IntegAlg enum SHA_256_128 object.
241 return IntegAlg.SHA_256_128
244 def integ_alg_sha_512_256():
245 """Return integrity algorithm SHA-512-256.
247 :returns: IntegAlg enum SHA_512_256 object.
250 return IntegAlg.SHA_512_256
253 def get_integ_alg_key_len(integ_alg):
254 """Return integrity algorithm key length.
256 None argument is accepted, returning zero.
258 :param integ_alg: Integrity algorithm.
259 :type integ_alg: Optional[IntegAlg]
260 :returns: Key length.
263 return 0 if integ_alg is None else integ_alg.key_len
266 def get_integ_alg_scapy_name(integ_alg):
267 """Return integrity algorithm scapy name.
269 :param integ_alg: Integrity algorithm.
270 :type integ_alg: IntegAlg
271 :returns: Algorithm scapy name.
274 return integ_alg.scapy_name
277 def ipsec_proto_esp():
278 """Return IPSec protocol ESP.
280 :returns: IPsecProto enum ESP object.
283 return int(IPsecProto.IPSEC_API_PROTO_ESP)
286 def ipsec_proto_ah():
287 """Return IPSec protocol AH.
289 :returns: IPsecProto enum AH object.
292 return int(IPsecProto.IPSEC_API_PROTO_AH)
295 def vpp_ipsec_select_backend(node, protocol, index=1):
296 """Select IPsec backend.
298 :param node: VPP node to select IPsec backend on.
299 :param protocol: IPsec protocol.
300 :param index: Backend index.
302 :type protocol: IPsecProto
304 :raises RuntimeError: If failed to select IPsec backend or if no API
307 cmd = u"ipsec_select_backend"
308 err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
313 with PapiSocketExecutor(node) as papi_exec:
314 papi_exec.add(cmd, **args).get_reply(err_msg)
317 def vpp_ipsec_set_async_mode(node, async_enable=1):
318 """Set IPsec async mode on|off.
320 Unconditionally, attempt to switch crypto dispatch into polling mode.
322 :param node: VPP node to set IPsec async mode.
323 :param async_enable: Async mode on or off.
325 :type async_enable: int
326 :raises RuntimeError: If failed to set IPsec async mode or if no API
329 with PapiSocketExecutor(node) as papi_exec:
330 cmd = u"ipsec_set_async_mode"
331 err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
333 async_enable=async_enable
335 papi_exec.add(cmd, **args).get_reply(err_msg)
336 cmd = "crypto_set_async_dispatch_v2"
337 err_msg = "Failed to set dispatch mode."
338 args = dict(mode=0, adaptive=False)
340 papi_exec.add(cmd, **args).get_reply(err_msg)
341 except (AttributeError, RuntimeError):
342 # Expected when VPP build does not have the _v2 yet
343 # (after and before the first CRC check).
344 # TODO: Fail here when testing of pre-23.10 builds is over.
348 def vpp_ipsec_crypto_sw_scheduler_set_worker(
349 node, workers, crypto_enable=False):
350 """Enable or disable crypto on specific vpp worker threads.
352 :param node: VPP node to enable or disable crypto for worker threads.
353 :param workers: List of VPP thread numbers.
354 :param crypto_enable: Disable or enable crypto work.
356 :type workers: Iterable[int]
357 :type crypto_enable: bool
358 :raises RuntimeError: If failed to enable or disable crypto for worker
359 thread or if no API reply received.
361 for worker in workers:
362 cmd = u"crypto_sw_scheduler_set_worker"
363 err_msg = f"Failed to disable/enable crypto for worker thread " \
364 f"on host {node[u'host']}"
366 worker_index=worker - 1,
367 crypto_enable=crypto_enable
369 with PapiSocketExecutor(node) as papi_exec:
370 papi_exec.add(cmd, **args).get_reply(err_msg)
373 def vpp_ipsec_crypto_sw_scheduler_set_worker_on_all_duts(
374 nodes, crypto_enable=False):
375 """Enable or disable crypto on specific vpp worker threads.
377 :param node: VPP node to enable or disable crypto for worker threads.
378 :param crypto_enable: Disable or enable crypto work.
380 :type crypto_enable: bool
381 :raises RuntimeError: If failed to enable or disable crypto for worker
382 thread or if no API reply received.
384 for node_name, node in nodes.items():
385 if node["type"] == NodeType.DUT:
386 thread_data = VPPUtil.vpp_show_threads(node)
387 worker_cnt = len(thread_data) - 1
391 workers = BuiltIn().get_variable_value(
392 f"${{{node_name}_cpu_dp}}"
394 for item in thread_data:
395 if str(item.cpu_id) in workers.split(u","):
396 worker_ids.append(item.id)
398 IPsecUtil.vpp_ipsec_crypto_sw_scheduler_set_worker(
399 node, workers=worker_ids, crypto_enable=crypto_enable
403 def vpp_ipsec_add_sad_entry(
404 node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
405 integ_key=u"", tunnel_src=None, tunnel_dst=None):
406 """Create Security Association Database entry on the VPP node.
408 :param node: VPP node to add SAD entry on.
409 :param sad_id: SAD entry ID.
410 :param spi: Security Parameter Index of this SAD entry.
411 :param crypto_alg: The encryption algorithm name.
412 :param crypto_key: The encryption key string.
413 :param integ_alg: The integrity algorithm name.
414 :param integ_key: The integrity key string.
415 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
416 specified ESP transport mode is used.
417 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
418 not specified ESP transport mode is used.
422 :type crypto_alg: CryptoAlg
423 :type crypto_key: str
424 :type integ_alg: Optional[IntegAlg]
426 :type tunnel_src: str
427 :type tunnel_dst: str
429 if isinstance(crypto_key, str):
430 crypto_key = crypto_key.encode(encoding=u"utf-8")
431 if isinstance(integ_key, str):
432 integ_key = integ_key.encode(encoding=u"utf-8")
434 length=len(crypto_key),
438 length=len(integ_key),
439 data=integ_key if integ_key else 0
442 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
443 if tunnel_src and tunnel_dst:
444 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
445 src_addr = ip_address(tunnel_src)
446 dst_addr = ip_address(tunnel_dst)
447 if src_addr.version == 6:
449 flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
454 cmd = u"ipsec_sad_entry_add_v2"
455 err_msg = f"Failed to add Security Association Database entry " \
456 f"on host {node[u'host']}"
460 crypto_algorithm=crypto_alg.alg_int_repr,
462 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
469 encap_decap_flags=int(
470 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
472 dscp=int(IpDscp.IP_API_DSCP_CS0),
474 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
475 udp_src_port=IPSEC_UDP_PORT_DEFAULT,
476 udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
477 anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
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_v2"
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=IPSEC_UDP_PORT_DEFAULT,
575 udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
576 anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
578 args = dict(entry=sad_entry)
579 with PapiSocketExecutor(node, is_async=True) as papi_exec:
580 for i in range(n_entries):
581 args[u"entry"][u"sad_id"] = int(sad_id) + i
582 args[u"entry"][u"spi"] = int(spi) + i
583 args[u"entry"][u"tunnel"][u"src"] = (
584 str(src_addr + i * addr_incr)
585 if tunnel_src and tunnel_dst else src_addr
587 args[u"entry"][u"tunnel"][u"dst"] = (
588 str(dst_addr + i * addr_incr)
589 if tunnel_src and tunnel_dst else dst_addr
591 history = bool(not 1 < i < n_entries - 2)
592 papi_exec.add(cmd, history=history, **args)
593 papi_exec.get_replies(err_msg)
596 def vpp_ipsec_set_ip_route(
597 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
598 raddr_range, dst_mac=None):
599 """Set IP address and route on interface.
601 :param node: VPP node to add config on.
602 :param n_tunnels: Number of tunnels to create.
603 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
604 :param traffic_addr: Traffic destination IP address to route.
605 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
606 :param interface: Interface key on node 1.
607 :param raddr_range: Mask specifying range of Policy selector Remote IP
608 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
610 :param dst_mac: The MAC address of destination tunnels.
613 :type tunnel_src: str
614 :type traffic_addr: str
615 :type tunnel_dst: str
617 :type raddr_range: int
620 tunnel_src = ip_address(tunnel_src)
621 tunnel_dst = ip_address(tunnel_dst)
622 traffic_addr = ip_address(traffic_addr)
623 tunnel_dst_prefix = 128 if tunnel_dst.version == 6 else 32
624 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
625 else 1 << (32 - raddr_range)
627 cmd1 = u"sw_interface_add_del_address"
629 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
634 cmd2 = u"ip_route_add_del"
640 cmd3 = u"ip_neighbor_add_del"
644 sw_if_index=Topology.get_interface_sw_index(node, interface),
646 mac_address=str(dst_mac),
650 err_msg = f"Failed to configure IP addresses, IP routes and " \
651 f"IP neighbor on interface {interface} on host {node[u'host']}" \
653 else f"Failed to configure IP addresses and IP routes " \
654 f"on interface {interface} on host {node[u'host']}"
656 with PapiSocketExecutor(node, is_async=True) as papi_exec:
657 for i in range(n_tunnels):
658 tunnel_dst_addr = tunnel_dst + i * addr_incr
659 args1[u"prefix"] = IPUtil.create_prefix_object(
660 tunnel_src + i * addr_incr, raddr_range
662 args2[u"route"] = IPUtil.compose_vpp_route_structure(
663 node, traffic_addr + i,
664 prefix_len=tunnel_dst_prefix,
665 interface=interface, gateway=tunnel_dst_addr
667 history = bool(not 1 < i < n_tunnels - 2)
668 papi_exec.add(cmd1, history=history, **args1)
669 papi_exec.add(cmd2, history=history, **args2)
671 args2[u"route"] = IPUtil.compose_vpp_route_structure(
672 node, tunnel_dst_addr,
673 prefix_len=tunnel_dst_prefix,
674 interface=interface, gateway=tunnel_dst_addr
676 papi_exec.add(cmd2, history=history, **args2)
679 args3[u"neighbor"][u"ip_address"] = ip_address(
682 papi_exec.add(cmd3, history=history, **args3)
683 papi_exec.get_replies(err_msg)
686 def vpp_ipsec_add_spd(node, spd_id):
687 """Create Security Policy Database on the VPP node.
689 :param node: VPP node to add SPD on.
690 :param spd_id: SPD ID.
694 cmd = u"ipsec_spd_add_del"
695 err_msg = f"Failed to add Security Policy Database " \
696 f"on host {node[u'host']}"
701 with PapiSocketExecutor(node) as papi_exec:
702 papi_exec.add(cmd, **args).get_reply(err_msg)
705 def vpp_ipsec_spd_add_if(node, spd_id, interface):
706 """Add interface to the Security Policy Database.
708 :param node: VPP node.
709 :param spd_id: SPD ID to add interface on.
710 :param interface: Interface name or sw_if_index.
713 :type interface: str or int
715 cmd = u"ipsec_interface_add_del_spd"
716 err_msg = f"Failed to add interface {interface} to Security Policy " \
717 f"Database {spd_id} on host {node[u'host']}"
720 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
723 with PapiSocketExecutor(node) as papi_exec:
724 papi_exec.add(cmd, **args).get_reply(err_msg)
727 def vpp_ipsec_create_spds_match_nth_entry(
728 node, dir1_interface, dir2_interface, entry_amount,
729 local_addr_range, remote_addr_range, action=PolicyAction.BYPASS,
730 inbound=False, bidirectional=True):
731 """Create one matching SPD entry for inbound or outbound traffic on
732 a DUT for each traffic direction and also create entry_amount - 1
733 non-matching SPD entries. Create a Security Policy Database on each
734 outbound interface where these entries will be configured.
735 The matching SPD entry will have the lowest priority, input action and
736 will be configured to match the IP flow. The non-matching entries will
737 be the same, except with higher priority and non-matching IP flows.
739 Action Protect is currently not supported.
741 :param node: VPP node to configured the SPDs and their entries.
742 :param dir1_interface: The interface in direction 1 where the entries
744 :param dir2_interface: The interface in direction 2 where the entries
746 :param entry_amount: The number of SPD entries to configure. If
747 entry_amount == 1, no non-matching entries will be configured.
748 :param local_addr_range: Matching local address range in direction 1
749 in format IP/prefix or IP/mask. If no mask is provided, it's
750 considered to be /32.
751 :param remote_addr_range: Matching remote address range in
752 direction 1 in format IP/prefix or IP/mask. If no mask is
753 provided, it's considered to be /32.
754 :param action: Policy action.
755 :param inbound: If True policy is for inbound traffic, otherwise
757 :param bidirectional: When True, will create SPDs in both directions
758 of traffic. When False, only in one direction.
760 :type dir1_interface: Union[string, int]
761 :type dir2_interface: Union[string, int]
762 :type entry_amount: int
763 :type local_addr_range:
764 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
765 :type remote_addr_range:
766 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
767 :type action: IPsecUtil.PolicyAction
769 :type bidirectional: bool
770 :raises NotImplementedError: When the action is PolicyAction.PROTECT.
773 if action == PolicyAction.PROTECT:
774 raise NotImplementedError('Policy action PROTECT is not supported.')
778 matching_priority = 1
780 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir1)
781 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir1, dir1_interface)
782 # matching entry direction 1
783 IPsecUtil.vpp_ipsec_add_spd_entry(
784 node, spd_id_dir1, matching_priority, action,
785 inbound=inbound, laddr_range=local_addr_range,
786 raddr_range=remote_addr_range
790 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir2)
791 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir2, dir2_interface)
793 # matching entry direction 2, the address ranges are switched
794 IPsecUtil.vpp_ipsec_add_spd_entry(
795 node, spd_id_dir2, matching_priority, action,
796 inbound=inbound, laddr_range=remote_addr_range,
797 raddr_range=local_addr_range
800 # non-matching entries
801 no_match_entry_amount = entry_amount - 1
802 if no_match_entry_amount > 0:
803 # create a NetworkIncrement representation of the network,
804 # then skip the matching network
805 no_match_local_addr_range = NetworkIncrement(
806 ip_network(local_addr_range)
808 next(no_match_local_addr_range)
810 no_match_remote_addr_range = NetworkIncrement(
811 ip_network(remote_addr_range)
813 next(no_match_remote_addr_range)
815 # non-matching entries direction 1
816 IPsecUtil.vpp_ipsec_add_spd_entries(
817 node, no_match_entry_amount, spd_id_dir1,
818 ObjIncrement(matching_priority + 1, 1), action,
819 inbound=inbound, laddr_range=no_match_local_addr_range,
820 raddr_range=no_match_remote_addr_range
824 # reset the networks so that we're using a unified config
825 # the address ranges are switched
826 no_match_remote_addr_range = NetworkIncrement(
827 ip_network(local_addr_range)
829 next(no_match_remote_addr_range)
831 no_match_local_addr_range = NetworkIncrement(
832 ip_network(remote_addr_range)
834 next(no_match_local_addr_range)
835 # non-matching entries direction 2
836 IPsecUtil.vpp_ipsec_add_spd_entries(
837 node, no_match_entry_amount, spd_id_dir2,
838 ObjIncrement(matching_priority + 1, 1), action,
839 inbound=inbound, laddr_range=no_match_local_addr_range,
840 raddr_range=no_match_remote_addr_range
843 IPsecUtil.vpp_ipsec_show_all(node)
846 def _vpp_ipsec_add_spd_entry_internal(
847 executor, spd_id, priority, action, inbound=True, sa_id=None,
848 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
849 rport_range=None, is_ipv6=False):
850 """Prepare to create Security Policy Database entry on the VPP node.
852 This just adds one more command to the executor.
853 The call site shall get replies once all entries are added,
854 to get speed benefit from async PAPI.
856 :param executor: Open PAPI executor (async handling) to add commands to.
857 :param spd_id: SPD ID to add entry on.
858 :param priority: SPD entry priority, higher number = higher priority.
859 :param action: Policy action.
860 :param inbound: If True policy is for inbound traffic, otherwise
862 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
863 :param proto: Policy selector next layer protocol number.
864 :param laddr_range: Policy selector local IPv4 or IPv6 address range
865 in format IP/prefix or IP/mask. If no mask is provided,
866 it's considered to be /32.
867 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
868 in format IP/prefix or IP/mask. If no mask is provided,
869 it's considered to be /32.
870 :param lport_range: Policy selector local TCP/UDP port range in format
871 <port_start>-<port_end>.
872 :param rport_range: Policy selector remote TCP/UDP port range in format
873 <port_start>-<port_end>.
874 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
875 not defined so it will default to address ::/0, otherwise False.
876 :type executor: PapiSocketExecutor
879 :type action: IPsecUtil.PolicyAction
883 :type laddr_range: string
884 :type raddr_range: string
885 :type lport_range: string
886 :type rport_range: string
889 if laddr_range is None:
890 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
892 if raddr_range is None:
893 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
895 local_net = ip_network(laddr_range, strict=False)
896 remote_net = ip_network(raddr_range, strict=False)
898 cmd = u"ipsec_spd_entry_add_del_v2"
902 priority=int(priority),
903 is_outbound=not inbound,
904 sa_id=int(sa_id) if sa_id else 0,
906 protocol=255 if proto is None else int(proto),
907 remote_address_start=IPAddress.create_ip_address_object(
908 remote_net.network_address
910 remote_address_stop=IPAddress.create_ip_address_object(
911 remote_net.broadcast_address
913 local_address_start=IPAddress.create_ip_address_object(
914 local_net.network_address
916 local_address_stop=IPAddress.create_ip_address_object(
917 local_net.broadcast_address
919 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
921 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
923 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
925 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
932 executor.add(cmd, **args)
935 def vpp_ipsec_add_spd_entry(
936 node, spd_id, priority, action, inbound=True, sa_id=None,
937 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
938 rport_range=None, is_ipv6=False):
939 """Create Security Policy Database entry on the VPP node.
941 :param node: VPP node to add SPD entry on.
942 :param spd_id: SPD ID to add entry on.
943 :param priority: SPD entry priority, higher number = higher priority.
944 :param action: Policy action.
945 :param inbound: If True policy is for inbound traffic, otherwise
947 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
948 :param proto: Policy selector next layer protocol number.
949 :param laddr_range: Policy selector local IPv4 or IPv6 address range
950 in format IP/prefix or IP/mask. If no mask is provided,
951 it's considered to be /32.
952 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
953 in format IP/prefix or IP/mask. If no mask is provided,
954 it's considered to be /32.
955 :param lport_range: Policy selector local TCP/UDP port range in format
956 <port_start>-<port_end>.
957 :param rport_range: Policy selector remote TCP/UDP port range in format
958 <port_start>-<port_end>.
959 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
960 not defined so it will default to address ::/0, otherwise False.
964 :type action: IPsecUtil.PolicyAction
968 :type laddr_range: string
969 :type raddr_range: string
970 :type lport_range: string
971 :type rport_range: string
974 err_msg = f"Failed to add entry to Security Policy Database " \
975 f"{spd_id} on host {node[u'host']}"
976 with PapiSocketExecutor(node, is_async=True) as papi_exec:
977 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
978 papi_exec, spd_id, priority, action, inbound, sa_id, proto,
979 laddr_range, raddr_range, lport_range, rport_range, is_ipv6
981 papi_exec.get_replies(err_msg)
984 def vpp_ipsec_add_spd_entries(
985 node, n_entries, spd_id, priority, action, inbound, sa_id=None,
986 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
987 rport_range=None, is_ipv6=False):
988 """Create multiple Security Policy Database entries on the VPP node.
990 :param node: VPP node to add SPD entries on.
991 :param n_entries: Number of SPD entries to be added.
992 :param spd_id: SPD ID to add entries on.
993 :param priority: SPD entries priority, higher number = higher priority.
994 :param action: Policy action.
995 :param inbound: If True policy is for inbound traffic, otherwise
997 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
998 :param proto: Policy selector next layer protocol number.
999 :param laddr_range: Policy selector local IPv4 or IPv6 address range
1000 in format IP/prefix or IP/mask. If no mask is provided,
1001 it's considered to be /32.
1002 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
1003 in format IP/prefix or IP/mask. If no mask is provided,
1004 it's considered to be /32.
1005 :param lport_range: Policy selector local TCP/UDP port range in format
1006 <port_start>-<port_end>.
1007 :param rport_range: Policy selector remote TCP/UDP port range in format
1008 <port_start>-<port_end>.
1009 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
1010 not defined so it will default to address ::/0, otherwise False.
1012 :type n_entries: int
1014 :type priority: IPsecUtil.ObjIncrement
1015 :type action: IPsecUtil.PolicyAction
1017 :type sa_id: IPsecUtil.ObjIncrement
1019 :type laddr_range: IPsecUtil.NetworkIncrement
1020 :type raddr_range: IPsecUtil.NetworkIncrement
1021 :type lport_range: string
1022 :type rport_range: string
1025 if laddr_range is None:
1026 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1027 laddr_range = NetworkIncrement(ip_network(laddr_range), 0)
1029 if raddr_range is None:
1030 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1031 raddr_range = NetworkIncrement(ip_network(raddr_range), 0)
1033 lport_range_start = 0
1034 lport_range_stop = 65535
1036 lport_range_start, lport_range_stop = lport_range.split('-')
1038 rport_range_start = 0
1039 rport_range_stop = 65535
1041 rport_range_start, rport_range_stop = rport_range.split('-')
1043 err_msg = f"Failed to add entry to Security Policy Database " \
1044 f"{spd_id} on host {node[u'host']}"
1045 with PapiSocketExecutor(node, is_async=True) as papi_exec:
1046 for _ in range(n_entries):
1047 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
1048 papi_exec, spd_id, next(priority), action, inbound,
1049 next(sa_id) if sa_id is not None else sa_id,
1050 proto, next(laddr_range), next(raddr_range), lport_range,
1051 rport_range, is_ipv6
1053 papi_exec.get_replies(err_msg)
1056 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1057 """Create loopback interface and set IP address on VPP node 1 interface
1060 :param nodes: VPP nodes to create tunnel interfaces.
1061 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1062 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1063 IPv4/IPv6 address (ip2).
1064 :param if1_key: VPP node 1 interface key from topology file.
1065 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1066 interface key from topology file.
1072 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1073 # Create loopback interface on DUT1, set it to up state
1074 cmd = u"create_loopback_instance"
1080 err_msg = f"Failed to create loopback interface " \
1081 f"on host {nodes[u'DUT1'][u'host']}"
1082 papi_exec.add(cmd, **args)
1083 loop_sw_if_idx = papi_exec.get_sw_if_index(err_msg)
1084 cmd = u"sw_interface_set_flags"
1086 sw_if_index=loop_sw_if_idx,
1087 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1089 err_msg = f"Failed to set loopback interface state up " \
1090 f"on host {nodes[u'DUT1'][u'host']}"
1091 papi_exec.add(cmd, **args).get_reply(err_msg)
1092 # Set IP address on VPP node 1 interface
1093 cmd = u"sw_interface_add_del_address"
1095 sw_if_index=InterfaceUtil.get_interface_index(
1096 nodes[u"DUT1"], if1_key
1100 prefix=IPUtil.create_prefix_object(
1101 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1105 err_msg = f"Failed to set IP address on interface {if1_key} " \
1106 f"on host {nodes[u'DUT1'][u'host']}"
1107 papi_exec.add(cmd, **args).get_reply(err_msg)
1108 cmd2 = u"ip_neighbor_add_del"
1112 sw_if_index=Topology.get_interface_sw_index(
1113 nodes[u"DUT1"], if1_key
1117 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1118 if u"DUT2" in nodes.keys()
1119 else Topology.get_interface_mac(
1120 nodes[u"TG"], if2_key
1123 ip_address=tun_ips[u"ip2"].compressed
1126 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1127 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1129 return loop_sw_if_idx
1132 def _ipsec_create_tunnel_interfaces_dut1_papi(
1133 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1134 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1135 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1137 Generate random keys and return them (so DUT2 or TG can decrypt).
1139 :param nodes: VPP nodes to create tunnel interfaces.
1140 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1141 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1142 IPv4/IPv6 address (ip2).
1143 :param if1_key: VPP node 1 interface key from topology file.
1144 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1145 interface key from topology file.
1146 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1147 :param crypto_alg: The encryption algorithm name.
1148 :param integ_alg: The integrity algorithm name.
1149 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1150 first tunnel in direction node2->node1.
1151 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1152 :param addr_incr: IP / IPv6 address incremental step.
1153 :param existing_tunnels: Number of tunnel interfaces before creation.
1154 Useful mainly for reconf tests. Default 0.
1159 :type n_tunnels: int
1160 :type crypto_alg: CryptoAlg
1161 :type integ_alg: Optional[IntegAlg]
1162 :type raddr_ip2: IPv4Address or IPv6Address
1163 :type addr_incr: int
1165 :type existing_tunnels: int
1166 :returns: Generated ckeys and ikeys.
1167 :rtype: List[bytes], List[bytes]
1169 if not existing_tunnels:
1170 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1171 nodes, tun_ips, if1_key, if2_key
1174 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1175 nodes[u"DUT1"], u"loop0"
1177 with PapiSocketExecutor(nodes[u"DUT1"], is_async=True) as papi_exec:
1178 # Configure IP addresses on loop0 interface
1179 cmd = u"sw_interface_add_del_address"
1181 sw_if_index=loop_sw_if_idx,
1186 for i in range(existing_tunnels, n_tunnels):
1187 args[u"prefix"] = IPUtil.create_prefix_object(
1188 tun_ips[u"ip1"] + i * addr_incr,
1189 128 if tun_ips[u"ip1"].version == 6 else 32
1192 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1194 # Configure IPIP tunnel interfaces
1195 cmd = u"ipip_add_tunnel"
1197 instance=Constants.BITWISE_NON_ZERO,
1202 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1204 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1205 dscp=int(IpDscp.IP_API_DSCP_CS0)
1210 ipip_tunnels = [None] * existing_tunnels
1211 for i in range(existing_tunnels, n_tunnels):
1212 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1213 tun_ips[u"ip1"] + i * addr_incr
1215 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1219 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1221 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1222 f" {nodes[u'DUT1'][u'host']}"
1223 ipip_tunnels.extend(
1225 reply[u"sw_if_index"]
1226 for reply in papi_exec.get_replies(err_msg)
1227 if u"sw_if_index" in reply
1230 # Configure IPSec SAD entries
1231 ckeys = [bytes()] * existing_tunnels
1232 ikeys = [bytes()] * existing_tunnels
1233 cmd = u"ipsec_sad_entry_add_v2"
1245 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1246 crypto_algorithm=crypto_alg.alg_int_repr,
1248 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1249 integrity_key=i_key,
1255 encap_decap_flags=int(
1256 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1258 dscp=int(IpDscp.IP_API_DSCP_CS0),
1261 udp_src_port=IPSEC_UDP_PORT_DEFAULT,
1262 udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
1263 anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
1265 args = dict(entry=sad_entry)
1266 for i in range(existing_tunnels, n_tunnels):
1268 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1271 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1273 # SAD entry for outband / tx path
1274 args[u"entry"][u"sad_id"] = i
1275 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1277 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1278 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1280 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1281 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1282 args[u"entry"][u"flags"] = int(
1283 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1286 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1288 # SAD entry for inband / rx path
1289 args[u"entry"][u"sad_id"] = 100000 + i
1290 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1292 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1293 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1295 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1296 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1297 args[u"entry"][u"flags"] = int(
1298 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1299 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1302 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1304 err_msg = f"Failed to add IPsec SAD entries on host" \
1305 f" {nodes[u'DUT1'][u'host']}"
1306 papi_exec.get_replies(err_msg)
1307 # Add protection for tunnels with IPSEC
1308 cmd = u"ipsec_tunnel_protect_update"
1311 via_label=MPLS_LABEL_INVALID,
1312 obj_id=Constants.BITWISE_NON_ZERO
1314 ipsec_tunnel_protect = dict(
1322 tunnel=ipsec_tunnel_protect
1324 for i in range(existing_tunnels, n_tunnels):
1325 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1326 args[u"tunnel"][u"sa_out"] = i
1327 args[u"tunnel"][u"sa_in"] = [100000 + i]
1329 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1331 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1332 f"on host {nodes[u'DUT1'][u'host']}"
1333 papi_exec.get_replies(err_msg)
1335 # Configure unnumbered interfaces
1336 cmd = u"sw_interface_set_unnumbered"
1339 sw_if_index=InterfaceUtil.get_interface_index(
1340 nodes[u"DUT1"], if1_key
1342 unnumbered_sw_if_index=0
1344 for i in range(existing_tunnels, n_tunnels):
1345 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1347 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1350 cmd = u"sw_interface_set_flags"
1353 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1355 for i in range(existing_tunnels, n_tunnels):
1356 args[u"sw_if_index"] = ipip_tunnels[i]
1358 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1360 # Configure IP routes
1361 cmd = u"ip_route_add_del"
1367 for i in range(existing_tunnels, n_tunnels):
1368 args[u"route"] = IPUtil.compose_vpp_route_structure(
1369 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1370 prefix_len=128 if raddr_ip2.version == 6 else 32,
1371 interface=ipip_tunnels[i]
1374 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1376 err_msg = f"Failed to add IP routes on host " \
1377 f"{nodes[u'DUT1'][u'host']}"
1378 papi_exec.get_replies(err_msg)
1383 def _ipsec_create_tunnel_interfaces_dut2_papi(
1384 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1385 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1386 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1388 This method accesses keys generated by DUT1 method
1389 and does not return anything.
1391 :param nodes: VPP nodes to create tunnel interfaces.
1392 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1393 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1394 IPv4/IPv6 address (ip2).
1395 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1396 interface key from topology file.
1397 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1398 :param crypto_alg: The encryption algorithm name.
1399 :param ckeys: List of encryption keys.
1400 :param integ_alg: The integrity algorithm name.
1401 :param ikeys: List of integrity keys.
1402 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1403 :param addr_incr: IP / IPv6 address incremental step.
1404 :param existing_tunnels: Number of tunnel interfaces before creation.
1405 Useful mainly for reconf tests. Default 0.
1409 :type n_tunnels: int
1410 :type crypto_alg: CryptoAlg
1411 :type ckeys: Sequence[bytes]
1412 :type integ_alg: Optional[IntegAlg]
1413 :type ikeys: Sequence[bytes]
1414 :type addr_incr: int
1416 :type existing_tunnels: int
1418 with PapiSocketExecutor(nodes[u"DUT2"], is_async=True) as papi_exec:
1419 if not existing_tunnels:
1420 # Set IP address on VPP node 2 interface
1421 cmd = u"sw_interface_add_del_address"
1423 sw_if_index=InterfaceUtil.get_interface_index(
1424 nodes[u"DUT2"], if2_key
1428 prefix=IPUtil.create_prefix_object(
1429 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1433 err_msg = f"Failed to set IP address on interface {if2_key} " \
1434 f"on host {nodes[u'DUT2'][u'host']}"
1435 papi_exec.add(cmd, **args).get_replies(err_msg)
1436 # Configure IPIP tunnel interfaces
1437 cmd = u"ipip_add_tunnel"
1439 instance=Constants.BITWISE_NON_ZERO,
1444 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1446 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1447 dscp=int(IpDscp.IP_API_DSCP_CS0)
1452 ipip_tunnels = [None] * existing_tunnels
1453 for i in range(existing_tunnels, n_tunnels):
1454 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1457 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1458 tun_ips[u"ip1"] + i * addr_incr
1461 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1463 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1464 f" {nodes[u'DUT2'][u'host']}"
1465 ipip_tunnels.extend(
1467 reply[u"sw_if_index"]
1468 for reply in papi_exec.get_replies(err_msg)
1469 if u"sw_if_index" in reply
1472 # Configure IPSec SAD entries
1473 cmd = u"ipsec_sad_entry_add_v2"
1485 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1486 crypto_algorithm=crypto_alg.alg_int_repr,
1488 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1489 integrity_key=i_key,
1495 encap_decap_flags=int(
1496 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1498 dscp=int(IpDscp.IP_API_DSCP_CS0),
1501 udp_src_port=IPSEC_UDP_PORT_DEFAULT,
1502 udp_dst_port=IPSEC_UDP_PORT_DEFAULT,
1503 anti_replay_window_size=IPSEC_REPLAY_WINDOW_DEFAULT,
1505 args = dict(entry=sad_entry)
1506 for i in range(existing_tunnels, n_tunnels):
1508 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1511 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1513 # SAD entry for outband / tx path
1514 args[u"entry"][u"sad_id"] = 100000 + i
1515 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1517 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1518 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1520 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1521 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1522 args[u"entry"][u"flags"] = int(
1523 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1526 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1528 # SAD entry for inband / rx path
1529 args[u"entry"][u"sad_id"] = i
1530 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1532 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1533 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1535 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1536 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1537 args[u"entry"][u"flags"] = int(
1538 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1539 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1542 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1544 err_msg = f"Failed to add IPsec SAD entries on host" \
1545 f" {nodes[u'DUT2'][u'host']}"
1546 papi_exec.get_replies(err_msg)
1547 # Add protection for tunnels with IPSEC
1548 cmd = u"ipsec_tunnel_protect_update"
1551 via_label=MPLS_LABEL_INVALID,
1552 obj_id=Constants.BITWISE_NON_ZERO
1554 ipsec_tunnel_protect = dict(
1562 tunnel=ipsec_tunnel_protect
1564 for i in range(existing_tunnels, n_tunnels):
1565 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1566 args[u"tunnel"][u"sa_out"] = 100000 + i
1567 args[u"tunnel"][u"sa_in"] = [i]
1569 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1571 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1572 f"on host {nodes[u'DUT2'][u'host']}"
1573 papi_exec.get_replies(err_msg)
1575 if not existing_tunnels:
1576 # Configure IP route
1577 cmd = u"ip_route_add_del"
1578 route = IPUtil.compose_vpp_route_structure(
1579 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1580 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1582 gateway=(tun_ips[u"ip2"] - 1).compressed
1589 papi_exec.add(cmd, **args)
1590 # Configure unnumbered interfaces
1591 cmd = u"sw_interface_set_unnumbered"
1594 sw_if_index=InterfaceUtil.get_interface_index(
1595 nodes[u"DUT2"], if2_key
1597 unnumbered_sw_if_index=0
1599 for i in range(existing_tunnels, n_tunnels):
1600 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1602 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1605 cmd = u"sw_interface_set_flags"
1608 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1610 for i in range(existing_tunnels, n_tunnels):
1611 args[u"sw_if_index"] = ipip_tunnels[i]
1613 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1615 # Configure IP routes
1616 cmd = u"ip_route_add_del"
1622 for i in range(existing_tunnels, n_tunnels):
1623 args[u"route"] = IPUtil.compose_vpp_route_structure(
1624 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1625 prefix_len=128 if raddr_ip1.version == 6 else 32,
1626 interface=ipip_tunnels[i]
1629 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1631 err_msg = f"Failed to add IP routes " \
1632 f"on host {nodes[u'DUT2'][u'host']}"
1633 papi_exec.get_replies(err_msg)
1636 def vpp_ipsec_create_tunnel_interfaces(
1637 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1638 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1639 existing_tunnels=0, return_keys=False):
1640 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1642 Some deployments (e.g. devicetest) need to know the generated keys.
1643 But other deployments (e.g. scale perf test) would get spammed
1644 if we returned keys every time.
1646 :param nodes: VPP nodes to create tunnel interfaces.
1647 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1649 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1651 :param if1_key: VPP node 1 interface key from topology file.
1652 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1653 interface key from topology file.
1654 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1655 :param crypto_alg: The encryption algorithm name.
1656 :param integ_alg: The integrity algorithm name.
1657 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1658 first tunnel in direction node1->node2.
1659 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1660 first tunnel in direction node2->node1.
1661 :param raddr_range: Mask specifying range of Policy selector Remote
1662 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1663 and to 128 in case of IPv6.
1664 :param existing_tunnels: Number of tunnel interfaces before creation.
1665 Useful mainly for reconf tests. Default 0.
1666 :param return_keys: Whether generated keys should be returned.
1668 :type tun_if1_ip_addr: str
1669 :type tun_if2_ip_addr: str
1672 :type n_tunnels: int
1673 :type crypto_alg: CryptoAlg
1674 :type integ_alg: Optonal[IntegAlg]
1675 :type raddr_ip1: string
1676 :type raddr_ip2: string
1677 :type raddr_range: int
1678 :type existing_tunnels: int
1679 :type return_keys: bool
1680 :returns: Ckeys, ikeys, spi_1, spi_2.
1681 :rtype: Optional[List[bytes], List[bytes], int, int]
1683 n_tunnels = int(n_tunnels)
1684 existing_tunnels = int(existing_tunnels)
1690 ip1=ip_address(tun_if1_ip_addr),
1691 ip2=ip_address(tun_if2_ip_addr)
1693 raddr_ip1 = ip_address(raddr_ip1)
1694 raddr_ip2 = ip_address(raddr_ip2)
1695 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1696 else 1 << (32 - raddr_range)
1698 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1699 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1700 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1702 if u"DUT2" in nodes.keys():
1703 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1704 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1705 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1710 return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1714 def _create_ipsec_script_files(dut, instances):
1715 """Create script files for configuring IPsec in containers
1717 :param dut: DUT node on which to create the script files
1718 :param instances: number of containers on DUT node
1720 :type instances: int
1723 for cnf in range(0, instances):
1725 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1727 scripts.append(open(script_filename, 'w'))
1731 def _close_and_copy_ipsec_script_files(
1732 dut, nodes, instances, scripts):
1733 """Close created scripts and copy them to containers
1735 :param dut: DUT node on which to create the script files
1736 :param nodes: VPP nodes
1737 :param instances: number of containers on DUT node
1738 :param scripts: dictionary holding the script files
1741 :type instances: int
1744 for cnf in range(0, instances):
1745 scripts[cnf].close()
1747 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1749 scp_node(nodes[dut], script_filename, script_filename)
1753 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1754 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1755 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1756 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1758 :param nodes: VPP nodes to create tunnel interfaces.
1759 :param if1_ip_addr: VPP node 1 interface IP4 address.
1760 :param if2_ip_addr: VPP node 2 interface IP4 address.
1761 :param n_tunnels: Number of tunnell interfaces to create.
1762 :param crypto_alg: The encryption algorithm name.
1763 :param integ_alg: The integrity algorithm name.
1764 :param raddr_ip1: Policy selector remote IPv4 start address for the
1765 first tunnel in direction node1->node2.
1766 :param raddr_ip2: Policy selector remote IPv4 start address for the
1767 first tunnel in direction node2->node1.
1768 :param raddr_range: Mask specifying range of Policy selector Remote
1769 IPv4 addresses. Valid values are from 1 to 32.
1770 :param n_instances: Number of containers.
1772 :type if1_ip_addr: str
1773 :type if2_ip_addr: str
1774 :type n_tunnels: int
1775 :type crypto_alg: CryptoAlg
1776 :type integ_alg: Optional[IntegAlg]
1777 :type raddr_ip1: string
1778 :type raddr_ip2: string
1779 :type raddr_range: int
1780 :type n_instances: int
1784 addr_incr = 1 << (32 - raddr_range)
1786 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1787 u"DUT1", n_instances
1789 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1790 u"DUT2", n_instances
1793 for cnf in range(0, n_instances):
1794 dut1_scripts[cnf].write(
1795 u"create loopback interface\n"
1796 u"set interface state loop0 up\n\n"
1798 dut2_scripts[cnf].write(
1799 f"ip route add {if1_ip_addr}/8 via "
1800 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1803 for tnl in range(0, n_tunnels):
1804 cnf = tnl % n_instances
1806 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1810 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1814 f"integ-alg {integ_alg.alg_name} "
1815 f"local-integ-key {ikey} "
1816 f"remote-integ-key {ikey} "
1818 # Configure tunnel end point(s) on left side
1819 dut1_scripts[cnf].write(
1820 u"set interface ip address loop0 "
1821 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1822 f"create ipsec tunnel "
1823 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1824 f"local-spi {spi_1 + tnl} "
1825 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1826 f"remote-spi {spi_2 + tnl} "
1827 f"crypto-alg {crypto_alg.alg_name} "
1828 f"local-crypto-key {ckey} "
1829 f"remote-crypto-key {ckey} "
1830 f"instance {tnl // n_instances} "
1833 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1834 f"set interface state ipip{tnl // n_instances} up\n"
1835 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1836 f"via ipip{tnl // n_instances}\n\n"
1838 # Configure tunnel end point(s) on right side
1839 dut2_scripts[cnf].write(
1840 f"set ip neighbor memif1/{cnf + 1} "
1841 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1842 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1843 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1844 f"local-spi {spi_2 + tnl} "
1845 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1846 f"remote-spi {spi_1 + tnl} "
1847 f"crypto-alg {crypto_alg.alg_name} "
1848 f"local-crypto-key {ckey} "
1849 f"remote-crypto-key {ckey} "
1850 f"instance {tnl // n_instances} "
1853 f"set interface unnumbered ipip{tnl // n_instances} "
1854 f"use memif1/{cnf + 1}\n"
1855 f"set interface state ipip{tnl // n_instances} up\n"
1856 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1857 f"via ipip{tnl // n_instances}\n\n"
1860 IPsecUtil._close_and_copy_ipsec_script_files(
1861 u"DUT1", nodes, n_instances, dut1_scripts)
1862 IPsecUtil._close_and_copy_ipsec_script_files(
1863 u"DUT2", nodes, n_instances, dut2_scripts)
1866 def vpp_ipsec_add_multiple_tunnels(
1867 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1868 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range,
1869 tunnel_addr_incr=True):
1870 """Create multiple IPsec tunnels between two VPP nodes.
1872 :param nodes: VPP nodes to create tunnels.
1873 :param interface1: Interface name or sw_if_index on node 1.
1874 :param interface2: Interface name or sw_if_index on node 2.
1875 :param n_tunnels: Number of tunnels to create.
1876 :param crypto_alg: The encryption algorithm name.
1877 :param integ_alg: The integrity algorithm name.
1878 :param tunnel_ip1: Tunnel node1 IPv4 address.
1879 :param tunnel_ip2: Tunnel node2 IPv4 address.
1880 :param raddr_ip1: Policy selector remote IPv4 start address for the
1881 first tunnel in direction node1->node2.
1882 :param raddr_ip2: Policy selector remote IPv4 start address for the
1883 first tunnel in direction node2->node1.
1884 :param raddr_range: Mask specifying range of Policy selector Remote
1885 IPv4 addresses. Valid values are from 1 to 32.
1886 :param tunnel_addr_incr: Enable or disable tunnel IP address
1889 :type interface1: str or int
1890 :type interface2: str or int
1891 :type n_tunnels: int
1892 :type crypto_alg: CryptoAlg
1893 :type integ_alg: Optional[IntegAlg]
1894 :type tunnel_ip1: str
1895 :type tunnel_ip2: str
1896 :type raddr_ip1: string
1897 :type raddr_ip2: string
1898 :type raddr_range: int
1899 :type tunnel_addr_incr: bool
1909 crypto_key = gen_key(
1910 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1912 integ_key = gen_key(
1913 IPsecUtil.get_integ_alg_key_len(integ_alg)
1914 ).decode() if integ_alg else u""
1916 rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
1917 if u"DUT2" in nodes.keys() \
1918 else Topology.get_interface_mac(nodes[u"TG"], interface2)
1919 IPsecUtil.vpp_ipsec_set_ip_route(
1920 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1921 interface1, raddr_range, rmac)
1923 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1924 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1926 addr_incr = 1 << (128 - 96) if ip_address(tunnel_ip1).version == 6 \
1928 for i in range(n_tunnels//(addr_incr**2)+1):
1929 dut1_local_outbound_range = \
1930 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1931 False).with_prefixlen
1932 dut1_remote_outbound_range = \
1933 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1934 False).with_prefixlen
1936 IPsecUtil.vpp_ipsec_add_spd_entry(
1937 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1938 proto=50, laddr_range=dut1_local_outbound_range,
1939 raddr_range=dut1_remote_outbound_range
1941 IPsecUtil.vpp_ipsec_add_spd_entry(
1942 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1943 proto=50, laddr_range=dut1_remote_outbound_range,
1944 raddr_range=dut1_local_outbound_range
1947 IPsecUtil.vpp_ipsec_add_sad_entries(
1948 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1949 integ_alg, integ_key, tunnel_ip1, tunnel_ip2, tunnel_addr_incr
1952 IPsecUtil.vpp_ipsec_add_spd_entries(
1953 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1954 action=PolicyAction.PROTECT, inbound=False,
1955 sa_id=ObjIncrement(sa_id_1, 1),
1956 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
1959 IPsecUtil.vpp_ipsec_add_sad_entries(
1960 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1961 integ_alg, integ_key, tunnel_ip2, tunnel_ip1, tunnel_addr_incr
1963 IPsecUtil.vpp_ipsec_add_spd_entries(
1964 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1965 action=PolicyAction.PROTECT, inbound=True,
1966 sa_id=ObjIncrement(sa_id_2, 1),
1967 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
1970 if u"DUT2" in nodes.keys():
1971 rmac = Topology.get_interface_mac(nodes[u"DUT1"], interface1)
1972 IPsecUtil.vpp_ipsec_set_ip_route(
1973 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1974 interface2, raddr_range, rmac)
1976 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1977 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1978 for i in range(n_tunnels//(addr_incr**2)+1):
1979 dut2_local_outbound_range = \
1980 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1981 False).with_prefixlen
1982 dut2_remote_outbound_range = \
1983 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1984 False).with_prefixlen
1986 IPsecUtil.vpp_ipsec_add_spd_entry(
1987 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1988 inbound=False, proto=50,
1989 laddr_range=dut2_remote_outbound_range,
1990 raddr_range=dut2_local_outbound_range
1992 IPsecUtil.vpp_ipsec_add_spd_entry(
1993 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1994 inbound=True, proto=50,
1995 laddr_range=dut2_local_outbound_range,
1996 raddr_range=dut2_remote_outbound_range
1999 IPsecUtil.vpp_ipsec_add_sad_entries(
2000 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
2001 crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2,
2004 IPsecUtil.vpp_ipsec_add_spd_entries(
2005 nodes[u"DUT2"], n_tunnels, spd_id,
2006 priority=ObjIncrement(p_lo, 0),
2007 action=PolicyAction.PROTECT, inbound=True,
2008 sa_id=ObjIncrement(sa_id_1, 1),
2009 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
2012 IPsecUtil.vpp_ipsec_add_sad_entries(
2013 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
2014 crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1,
2017 IPsecUtil.vpp_ipsec_add_spd_entries(
2018 nodes[u"DUT2"], n_tunnels, spd_id,
2019 priority=ObjIncrement(p_lo, 0),
2020 action=PolicyAction.PROTECT, inbound=False,
2021 sa_id=ObjIncrement(sa_id_2, 1),
2022 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
2026 def vpp_ipsec_show_all(node):
2027 """Run "show ipsec all" debug CLI command.
2029 :param node: Node to run command on.
2032 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec all")
2035 def show_ipsec_security_association(node):
2036 """Show IPSec security association.
2038 :param node: DUT node.
2041 cmd = "ipsec_sa_v5_dump"
2042 PapiSocketExecutor.dump_and_log(node, [cmd])
2045 def vpp_ipsec_flow_enale_rss(node, proto, type, function="default"):
2046 """Ipsec flow enable rss action.
2048 :param node: DUT node.
2049 :param proto: The flow protocol.
2050 :param type: RSS type.
2051 :param function: RSS function.
2057 :returns: flow_index.
2059 # TODO: to be fixed to use full PAPI when it is ready in VPP
2060 cmd = f"test flow add src-ip any proto {proto} rss function " \
2061 f"{function} rss types {type}"
2062 stdout = PapiSocketExecutor.run_cli_cmd(node, cmd)
2063 flow_index = stdout.split()[1]
2068 def vpp_create_ipsec_flows_on_dut(
2069 node, n_flows, rx_queues, spi_start, interface):
2070 """Create mutiple ipsec flows and enable flows onto interface.
2072 :param node: DUT node.
2073 :param n_flows: Number of flows to create.
2074 :param rx_queues: NUmber of RX queues.
2075 :param spi_start: The start spi.
2076 :param interface: Name of the interface.
2080 :type rx_queues: int
2081 :type spi_start: int
2082 :type interface: str
2083 :returns: flow_index.
2086 for i in range(0, n_flows):
2087 rx_queue = i%rx_queues
2089 flow_index = FlowUtil.vpp_create_ip4_ipsec_flow(
2090 node, "ESP", spi, "redirect-to-queue", value=rx_queue)
2091 FlowUtil.vpp_flow_enable(node, interface, flow_index)