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."""
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_NONE = 0xffff
43 """Generate random string as a key.
45 :param length: Length of generated payload.
47 :returns: The generated payload.
51 choice(ascii_letters) for _ in range(length)
52 ).encode(encoding=u"utf-8")
55 class PolicyAction(Enum):
57 BYPASS = (u"bypass", 0)
58 DISCARD = (u"discard", 1)
59 PROTECT = (u"protect", 3)
61 def __init__(self, policy_name, policy_int_repr):
62 self.policy_name = policy_name
63 self.policy_int_repr = policy_int_repr
66 return self.policy_name
69 return self.policy_int_repr
72 class CryptoAlg(Enum):
73 """Encryption algorithms."""
74 AES_CBC_128 = (u"aes-cbc-128", 1, u"AES-CBC", 16)
75 AES_CBC_256 = (u"aes-cbc-256", 3, u"AES-CBC", 32)
76 AES_GCM_128 = (u"aes-gcm-128", 7, u"AES-GCM", 16)
77 AES_GCM_256 = (u"aes-gcm-256", 9, u"AES-GCM", 32)
79 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
80 self.alg_name = alg_name
81 self.alg_int_repr = alg_int_repr
82 self.scapy_name = scapy_name
83 self.key_len = key_len
87 """Integrity algorithm."""
88 SHA_256_128 = (u"sha-256-128", 4, u"SHA2-256-128", 32)
89 SHA_512_256 = (u"sha-512-256", 6, u"SHA2-512-256", 64)
91 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
92 self.alg_name = alg_name
93 self.alg_int_repr = alg_int_repr
94 self.scapy_name = scapy_name
95 self.key_len = key_len
98 class IPsecProto(IntEnum):
100 IPSEC_API_PROTO_ESP = 50
101 IPSEC_API_PROTO_AH = 51
104 class IPsecSadFlags(IntEnum):
105 """IPsec Security Association Database flags."""
106 IPSEC_API_SAD_FLAG_NONE = 0
107 # Enable extended sequence numbers
108 IPSEC_API_SAD_FLAG_USE_ESN = 0x01
109 # Enable Anti - replay
110 IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY = 0x02
111 # IPsec tunnel mode if non-zero, else transport mode
112 IPSEC_API_SAD_FLAG_IS_TUNNEL = 0x04
113 # IPsec tunnel mode is IPv6 if non-zero, else IPv4 tunnel
114 # only valid if is_tunnel is non-zero
115 IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 0x08
116 # Enable UDP encapsulation for NAT traversal
117 IPSEC_API_SAD_FLAG_UDP_ENCAP = 0x10
118 # IPsec SA is or inbound traffic
119 IPSEC_API_SAD_FLAG_IS_INBOUND = 0x40
122 class TunnelEncpaDecapFlags(IntEnum):
123 """Flags controlling tunnel behaviour."""
124 TUNNEL_API_ENCAP_DECAP_FLAG_NONE = 0
125 # at encap, copy the DF bit of the payload into the tunnel header
126 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF = 1
127 # at encap, set the DF bit in the tunnel header
128 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF = 2
129 # at encap, copy the DSCP bits of the payload into the tunnel header
130 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP = 4
131 # at encap, copy the ECN bit of the payload into the tunnel header
132 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN = 8
133 # at decap, copy the ECN bit of the tunnel header into the payload
134 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_ECN = 16
137 class TunnelMode(IntEnum):
140 TUNNEL_API_MODE_P2P = 0
142 TUNNEL_API_MODE_MP = 1
146 """IPsec utilities."""
149 def policy_action_bypass():
150 """Return policy action bypass.
152 :returns: PolicyAction enum BYPASS object.
155 return PolicyAction.BYPASS
158 def policy_action_discard():
159 """Return policy action discard.
161 :returns: PolicyAction enum DISCARD object.
164 return PolicyAction.DISCARD
167 def policy_action_protect():
168 """Return policy action protect.
170 :returns: PolicyAction enum PROTECT object.
173 return PolicyAction.PROTECT
176 def crypto_alg_aes_cbc_128():
177 """Return encryption algorithm aes-cbc-128.
179 :returns: CryptoAlg enum AES_CBC_128 object.
182 return CryptoAlg.AES_CBC_128
185 def crypto_alg_aes_cbc_256():
186 """Return encryption algorithm aes-cbc-256.
188 :returns: CryptoAlg enum AES_CBC_256 object.
191 return CryptoAlg.AES_CBC_256
194 def crypto_alg_aes_gcm_128():
195 """Return encryption algorithm aes-gcm-128.
197 :returns: CryptoAlg enum AES_GCM_128 object.
200 return CryptoAlg.AES_GCM_128
203 def crypto_alg_aes_gcm_256():
204 """Return encryption algorithm aes-gcm-256.
206 :returns: CryptoAlg enum AES_GCM_128 object.
209 return CryptoAlg.AES_GCM_256
212 def get_crypto_alg_key_len(crypto_alg):
213 """Return encryption algorithm key length.
215 :param crypto_alg: Encryption algorithm.
216 :type crypto_alg: CryptoAlg
217 :returns: Key length.
220 return crypto_alg.key_len
223 def get_crypto_alg_scapy_name(crypto_alg):
224 """Return encryption algorithm scapy name.
226 :param crypto_alg: Encryption algorithm.
227 :type crypto_alg: CryptoAlg
228 :returns: Algorithm scapy name.
231 return crypto_alg.scapy_name
234 def integ_alg_sha_256_128():
235 """Return integrity algorithm SHA-256-128.
237 :returns: IntegAlg enum SHA_256_128 object.
240 return IntegAlg.SHA_256_128
243 def integ_alg_sha_512_256():
244 """Return integrity algorithm SHA-512-256.
246 :returns: IntegAlg enum SHA_512_256 object.
249 return IntegAlg.SHA_512_256
252 def get_integ_alg_key_len(integ_alg):
253 """Return integrity algorithm key length.
255 None argument is accepted, returning zero.
257 :param integ_alg: Integrity algorithm.
258 :type integ_alg: Optional[IntegAlg]
259 :returns: Key length.
262 return 0 if integ_alg is None else integ_alg.key_len
265 def get_integ_alg_scapy_name(integ_alg):
266 """Return integrity algorithm scapy name.
268 :param integ_alg: Integrity algorithm.
269 :type integ_alg: IntegAlg
270 :returns: Algorithm scapy name.
273 return integ_alg.scapy_name
276 def ipsec_proto_esp():
277 """Return IPSec protocol ESP.
279 :returns: IPsecProto enum ESP object.
282 return int(IPsecProto.IPSEC_API_PROTO_ESP)
285 def ipsec_proto_ah():
286 """Return IPSec protocol AH.
288 :returns: IPsecProto enum AH object.
291 return int(IPsecProto.IPSEC_API_PROTO_AH)
294 def vpp_ipsec_select_backend(node, protocol, index=1):
295 """Select IPsec backend.
297 :param node: VPP node to select IPsec backend on.
298 :param protocol: IPsec protocol.
299 :param index: Backend index.
301 :type protocol: IPsecProto
303 :raises RuntimeError: If failed to select IPsec backend or if no API
306 cmd = u"ipsec_select_backend"
307 err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
312 with PapiSocketExecutor(node) as papi_exec:
313 papi_exec.add(cmd, **args).get_reply(err_msg)
316 def vpp_ipsec_set_async_mode(node, async_enable=1):
317 """Set IPsec async mode on|off.
319 Unconditionally, attempt to switch crypto dispatch into polling mode.
321 :param node: VPP node to set IPsec async mode.
322 :param async_enable: Async mode on or off.
324 :type async_enable: int
325 :raises RuntimeError: If failed to set IPsec async mode or if no API
328 with PapiSocketExecutor(node) as papi_exec:
329 cmd = u"ipsec_set_async_mode"
330 err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
332 async_enable=async_enable
334 papi_exec.add(cmd, **args).get_reply(err_msg)
335 cmd = "crypto_set_async_dispatch_v2"
336 err_msg = "Failed to set dispatch mode."
337 args = dict(mode=0, adaptive=False)
339 papi_exec.add(cmd, **args).get_reply(err_msg)
340 except (AttributeError, RuntimeError):
341 # Expected when VPP build does not have the _v2 yet
342 # (after and before the first CRC check).
343 # TODO: Fail here when testing of pre-23.10 builds is over.
347 def vpp_ipsec_crypto_sw_scheduler_set_worker(
348 node, workers, crypto_enable=False):
349 """Enable or disable crypto on specific vpp worker threads.
351 :param node: VPP node to enable or disable crypto for worker threads.
352 :param workers: List of VPP thread numbers.
353 :param crypto_enable: Disable or enable crypto work.
355 :type workers: Iterable[int]
356 :type crypto_enable: bool
357 :raises RuntimeError: If failed to enable or disable crypto for worker
358 thread or if no API reply received.
360 for worker in workers:
361 cmd = u"crypto_sw_scheduler_set_worker"
362 err_msg = f"Failed to disable/enable crypto for worker thread " \
363 f"on host {node[u'host']}"
365 worker_index=worker - 1,
366 crypto_enable=crypto_enable
368 with PapiSocketExecutor(node) as papi_exec:
369 papi_exec.add(cmd, **args).get_reply(err_msg)
372 def vpp_ipsec_crypto_sw_scheduler_set_worker_on_all_duts(
373 nodes, crypto_enable=False):
374 """Enable or disable crypto on specific vpp worker threads.
376 :param node: VPP node to enable or disable crypto for worker threads.
377 :param crypto_enable: Disable or enable crypto work.
379 :type crypto_enable: bool
380 :raises RuntimeError: If failed to enable or disable crypto for worker
381 thread or if no API reply received.
383 for node_name, node in nodes.items():
384 if node["type"] == NodeType.DUT:
385 thread_data = VPPUtil.vpp_show_threads(node)
386 worker_cnt = len(thread_data) - 1
390 workers = BuiltIn().get_variable_value(
391 f"${{{node_name}_cpu_dp}}"
393 for item in thread_data:
394 if str(item.cpu_id) in workers.split(u","):
395 worker_ids.append(item.id)
397 IPsecUtil.vpp_ipsec_crypto_sw_scheduler_set_worker(
398 node, workers=worker_ids, crypto_enable=crypto_enable
402 def vpp_ipsec_add_sad_entry(
403 node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
404 integ_key=u"", tunnel_src=None, tunnel_dst=None):
405 """Create Security Association Database entry on the VPP node.
407 :param node: VPP node to add SAD entry on.
408 :param sad_id: SAD entry ID.
409 :param spi: Security Parameter Index of this SAD entry.
410 :param crypto_alg: The encryption algorithm name.
411 :param crypto_key: The encryption key string.
412 :param integ_alg: The integrity algorithm name.
413 :param integ_key: The integrity key string.
414 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
415 specified ESP transport mode is used.
416 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
417 not specified ESP transport mode is used.
421 :type crypto_alg: CryptoAlg
422 :type crypto_key: str
423 :type integ_alg: Optional[IntegAlg]
425 :type tunnel_src: str
426 :type tunnel_dst: str
428 if isinstance(crypto_key, str):
429 crypto_key = crypto_key.encode(encoding=u"utf-8")
430 if isinstance(integ_key, str):
431 integ_key = integ_key.encode(encoding=u"utf-8")
433 length=len(crypto_key),
437 length=len(integ_key),
438 data=integ_key if integ_key else 0
441 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
442 if tunnel_src and tunnel_dst:
443 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
444 src_addr = ip_address(tunnel_src)
445 dst_addr = ip_address(tunnel_dst)
446 if src_addr.version == 6:
448 flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
453 cmd = u"ipsec_sad_entry_add"
454 err_msg = f"Failed to add Security Association Database entry " \
455 f"on host {node[u'host']}"
459 crypto_algorithm=crypto_alg.alg_int_repr,
461 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
468 encap_decap_flags=int(
469 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
471 dscp=int(IpDscp.IP_API_DSCP_CS0),
473 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
474 udp_src_port=4500, # default value in api
475 udp_dst_port=4500 # default value in api
477 args = dict(entry=sad_entry)
478 with PapiSocketExecutor(node) as papi_exec:
479 papi_exec.add(cmd, **args).get_reply(err_msg)
482 def vpp_ipsec_add_sad_entries(
483 node, n_entries, sad_id, spi, crypto_alg, crypto_key,
484 integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None,
485 tunnel_addr_incr=True):
486 """Create multiple Security Association Database entries on VPP node.
488 :param node: VPP node to add SAD entry on.
489 :param n_entries: Number of SAD entries to be created.
490 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
492 :param spi: Security Parameter Index of first SAD entry. All subsequent
493 SAD entries will have spi incremented by 1.
494 :param crypto_alg: The encryption algorithm name.
495 :param crypto_key: The encryption key string.
496 :param integ_alg: The integrity algorithm name.
497 :param integ_key: The integrity key string.
498 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
499 specified ESP transport mode is used.
500 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
501 not specified ESP transport mode is used.
502 :param tunnel_addr_incr: Enable or disable tunnel IP address
508 :type crypto_alg: CryptoAlg
509 :type crypto_key: str
510 :type integ_alg: Optional[IntegAlg]
512 :type tunnel_src: str
513 :type tunnel_dst: str
514 :type tunnel_addr_incr: bool
516 if isinstance(crypto_key, str):
517 crypto_key = crypto_key.encode(encoding=u"utf-8")
518 if isinstance(integ_key, str):
519 integ_key = integ_key.encode(encoding=u"utf-8")
520 if tunnel_src and tunnel_dst:
521 src_addr = ip_address(tunnel_src)
522 dst_addr = ip_address(tunnel_dst)
528 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
534 length=len(crypto_key),
538 length=len(integ_key),
539 data=integ_key if integ_key else 0
542 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
543 if tunnel_src and tunnel_dst:
544 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
545 if src_addr.version == 6:
547 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
550 cmd = u"ipsec_sad_entry_add"
551 err_msg = f"Failed to add Security Association Database entry " \
552 f"on host {node[u'host']}"
557 crypto_algorithm=crypto_alg.alg_int_repr,
559 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
566 encap_decap_flags=int(
567 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
569 dscp=int(IpDscp.IP_API_DSCP_CS0),
571 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
572 udp_src_port=4500, # default value in api
573 udp_dst_port=4500, # default value in api
575 args = dict(entry=sad_entry)
576 with PapiSocketExecutor(node, is_async=True) as papi_exec:
577 for i in range(n_entries):
578 args[u"entry"][u"sad_id"] = int(sad_id) + i
579 args[u"entry"][u"spi"] = int(spi) + i
580 args[u"entry"][u"tunnel"][u"src"] = (
581 str(src_addr + i * addr_incr)
582 if tunnel_src and tunnel_dst else src_addr
584 args[u"entry"][u"tunnel"][u"dst"] = (
585 str(dst_addr + i * addr_incr)
586 if tunnel_src and tunnel_dst else dst_addr
588 history = bool(not 1 < i < n_entries - 2)
589 papi_exec.add(cmd, history=history, **args)
590 papi_exec.get_replies(err_msg)
593 def vpp_ipsec_set_ip_route(
594 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
595 raddr_range, dst_mac=None):
596 """Set IP address and route on interface.
598 :param node: VPP node to add config on.
599 :param n_tunnels: Number of tunnels to create.
600 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
601 :param traffic_addr: Traffic destination IP address to route.
602 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
603 :param interface: Interface key on node 1.
604 :param raddr_range: Mask specifying range of Policy selector Remote IP
605 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
607 :param dst_mac: The MAC address of destination tunnels.
610 :type tunnel_src: str
611 :type traffic_addr: str
612 :type tunnel_dst: str
614 :type raddr_range: int
617 tunnel_src = ip_address(tunnel_src)
618 tunnel_dst = ip_address(tunnel_dst)
619 traffic_addr = ip_address(traffic_addr)
620 tunnel_dst_prefix = 128 if tunnel_dst.version == 6 else 32
621 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
622 else 1 << (32 - raddr_range)
624 cmd1 = u"sw_interface_add_del_address"
626 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
631 cmd2 = u"ip_route_add_del"
637 cmd3 = u"ip_neighbor_add_del"
641 sw_if_index=Topology.get_interface_sw_index(node, interface),
643 mac_address=str(dst_mac),
647 err_msg = f"Failed to configure IP addresses, IP routes and " \
648 f"IP neighbor on interface {interface} on host {node[u'host']}" \
650 else f"Failed to configure IP addresses and IP routes " \
651 f"on interface {interface} on host {node[u'host']}"
653 with PapiSocketExecutor(node, is_async=True) as papi_exec:
654 for i in range(n_tunnels):
655 tunnel_dst_addr = tunnel_dst + i * addr_incr
656 args1[u"prefix"] = IPUtil.create_prefix_object(
657 tunnel_src + i * addr_incr, raddr_range
659 args2[u"route"] = IPUtil.compose_vpp_route_structure(
660 node, traffic_addr + i,
661 prefix_len=tunnel_dst_prefix,
662 interface=interface, gateway=tunnel_dst_addr
664 history = bool(not 1 < i < n_tunnels - 2)
665 papi_exec.add(cmd1, history=history, **args1)
666 papi_exec.add(cmd2, history=history, **args2)
668 args2[u"route"] = IPUtil.compose_vpp_route_structure(
669 node, tunnel_dst_addr,
670 prefix_len=tunnel_dst_prefix,
671 interface=interface, gateway=tunnel_dst_addr
673 papi_exec.add(cmd2, history=history, **args2)
676 args3[u"neighbor"][u"ip_address"] = ip_address(
679 papi_exec.add(cmd3, history=history, **args3)
680 papi_exec.get_replies(err_msg)
683 def vpp_ipsec_add_spd(node, spd_id):
684 """Create Security Policy Database on the VPP node.
686 :param node: VPP node to add SPD on.
687 :param spd_id: SPD ID.
691 cmd = u"ipsec_spd_add_del"
692 err_msg = f"Failed to add Security Policy Database " \
693 f"on host {node[u'host']}"
698 with PapiSocketExecutor(node) as papi_exec:
699 papi_exec.add(cmd, **args).get_reply(err_msg)
702 def vpp_ipsec_spd_add_if(node, spd_id, interface):
703 """Add interface to the Security Policy Database.
705 :param node: VPP node.
706 :param spd_id: SPD ID to add interface on.
707 :param interface: Interface name or sw_if_index.
710 :type interface: str or int
712 cmd = u"ipsec_interface_add_del_spd"
713 err_msg = f"Failed to add interface {interface} to Security Policy " \
714 f"Database {spd_id} on host {node[u'host']}"
717 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
720 with PapiSocketExecutor(node) as papi_exec:
721 papi_exec.add(cmd, **args).get_reply(err_msg)
724 def vpp_ipsec_create_spds_match_nth_entry(
725 node, dir1_interface, dir2_interface, entry_amount,
726 local_addr_range, remote_addr_range, action=PolicyAction.BYPASS,
727 inbound=False, bidirectional=True):
728 """Create one matching SPD entry for inbound or outbound traffic on
729 a DUT for each traffic direction and also create entry_amount - 1
730 non-matching SPD entries. Create a Security Policy Database on each
731 outbound interface where these entries will be configured.
732 The matching SPD entry will have the lowest priority, input action and
733 will be configured to match the IP flow. The non-matching entries will
734 be the same, except with higher priority and non-matching IP flows.
736 Action Protect is currently not supported.
738 :param node: VPP node to configured the SPDs and their entries.
739 :param dir1_interface: The interface in direction 1 where the entries
741 :param dir2_interface: The interface in direction 2 where the entries
743 :param entry_amount: The number of SPD entries to configure. If
744 entry_amount == 1, no non-matching entries will be configured.
745 :param local_addr_range: Matching local address range in direction 1
746 in format IP/prefix or IP/mask. If no mask is provided, it's
747 considered to be /32.
748 :param remote_addr_range: Matching remote address range in
749 direction 1 in format IP/prefix or IP/mask. If no mask is
750 provided, it's considered to be /32.
751 :param action: Policy action.
752 :param inbound: If True policy is for inbound traffic, otherwise
754 :param bidirectional: When True, will create SPDs in both directions
755 of traffic. When False, only in one direction.
757 :type dir1_interface: Union[string, int]
758 :type dir2_interface: Union[string, int]
759 :type entry_amount: int
760 :type local_addr_range:
761 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
762 :type remote_addr_range:
763 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
764 :type action: IPsecUtil.PolicyAction
766 :type bidirectional: bool
767 :raises NotImplementedError: When the action is PolicyAction.PROTECT.
770 if action == PolicyAction.PROTECT:
771 raise NotImplementedError('Policy action PROTECT is not supported.')
775 matching_priority = 1
777 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir1)
778 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir1, dir1_interface)
779 # matching entry direction 1
780 IPsecUtil.vpp_ipsec_add_spd_entry(
781 node, spd_id_dir1, matching_priority, action,
782 inbound=inbound, laddr_range=local_addr_range,
783 raddr_range=remote_addr_range
787 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir2)
788 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir2, dir2_interface)
790 # matching entry direction 2, the address ranges are switched
791 IPsecUtil.vpp_ipsec_add_spd_entry(
792 node, spd_id_dir2, matching_priority, action,
793 inbound=inbound, laddr_range=remote_addr_range,
794 raddr_range=local_addr_range
797 # non-matching entries
798 no_match_entry_amount = entry_amount - 1
799 if no_match_entry_amount > 0:
800 # create a NetworkIncrement representation of the network,
801 # then skip the matching network
802 no_match_local_addr_range = NetworkIncrement(
803 ip_network(local_addr_range)
805 next(no_match_local_addr_range)
807 no_match_remote_addr_range = NetworkIncrement(
808 ip_network(remote_addr_range)
810 next(no_match_remote_addr_range)
812 # non-matching entries direction 1
813 IPsecUtil.vpp_ipsec_add_spd_entries(
814 node, no_match_entry_amount, spd_id_dir1,
815 ObjIncrement(matching_priority + 1, 1), action,
816 inbound=inbound, laddr_range=no_match_local_addr_range,
817 raddr_range=no_match_remote_addr_range
821 # reset the networks so that we're using a unified config
822 # the address ranges are switched
823 no_match_remote_addr_range = NetworkIncrement(
824 ip_network(local_addr_range)
826 next(no_match_remote_addr_range)
828 no_match_local_addr_range = NetworkIncrement(
829 ip_network(remote_addr_range)
831 next(no_match_local_addr_range)
832 # non-matching entries direction 2
833 IPsecUtil.vpp_ipsec_add_spd_entries(
834 node, no_match_entry_amount, spd_id_dir2,
835 ObjIncrement(matching_priority + 1, 1), action,
836 inbound=inbound, laddr_range=no_match_local_addr_range,
837 raddr_range=no_match_remote_addr_range
840 IPsecUtil.vpp_ipsec_show_all(node)
843 def _vpp_ipsec_add_spd_entry_internal(
844 executor, spd_id, priority, action, inbound=True, sa_id=None,
845 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
846 rport_range=None, is_ipv6=False):
847 """Prepare to create Security Policy Database entry on the VPP node.
849 This just adds one more command to the executor.
850 The call site shall get replies once all entries are added,
851 to get speed benefit from async PAPI.
853 :param executor: Open PAPI executor (async handling) to add commands to.
854 :param spd_id: SPD ID to add entry on.
855 :param priority: SPD entry priority, higher number = higher priority.
856 :param action: Policy action.
857 :param inbound: If True policy is for inbound traffic, otherwise
859 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
860 :param proto: Policy selector next layer protocol number.
861 :param laddr_range: Policy selector local IPv4 or IPv6 address range
862 in format IP/prefix or IP/mask. If no mask is provided,
863 it's considered to be /32.
864 :param raddr_range: Policy selector remote 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 lport_range: Policy selector local TCP/UDP port range in format
868 <port_start>-<port_end>.
869 :param rport_range: Policy selector remote TCP/UDP port range in format
870 <port_start>-<port_end>.
871 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
872 not defined so it will default to address ::/0, otherwise False.
873 :type executor: PapiSocketExecutor
876 :type action: IPsecUtil.PolicyAction
880 :type laddr_range: string
881 :type raddr_range: string
882 :type lport_range: string
883 :type rport_range: string
886 if laddr_range is None:
887 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
889 if raddr_range is None:
890 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
892 local_net = ip_network(laddr_range, strict=False)
893 remote_net = ip_network(raddr_range, strict=False)
895 cmd = u"ipsec_spd_entry_add_del_v2"
899 priority=int(priority),
900 is_outbound=not inbound,
901 sa_id=int(sa_id) if sa_id else 0,
903 protocol=255 if proto is None else int(proto),
904 remote_address_start=IPAddress.create_ip_address_object(
905 remote_net.network_address
907 remote_address_stop=IPAddress.create_ip_address_object(
908 remote_net.broadcast_address
910 local_address_start=IPAddress.create_ip_address_object(
911 local_net.network_address
913 local_address_stop=IPAddress.create_ip_address_object(
914 local_net.broadcast_address
916 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
918 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
920 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
922 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
929 executor.add(cmd, **args)
932 def vpp_ipsec_add_spd_entry(
933 node, spd_id, priority, action, inbound=True, sa_id=None,
934 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
935 rport_range=None, is_ipv6=False):
936 """Create Security Policy Database entry on the VPP node.
938 :param node: VPP node to add SPD entry on.
939 :param spd_id: SPD ID to add entry on.
940 :param priority: SPD entry priority, higher number = higher priority.
941 :param action: Policy action.
942 :param inbound: If True policy is for inbound traffic, otherwise
944 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
945 :param proto: Policy selector next layer protocol number.
946 :param laddr_range: Policy selector local IPv4 or IPv6 address range
947 in format IP/prefix or IP/mask. If no mask is provided,
948 it's considered to be /32.
949 :param raddr_range: Policy selector remote 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 lport_range: Policy selector local TCP/UDP port range in format
953 <port_start>-<port_end>.
954 :param rport_range: Policy selector remote TCP/UDP port range in format
955 <port_start>-<port_end>.
956 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
957 not defined so it will default to address ::/0, otherwise False.
961 :type action: IPsecUtil.PolicyAction
965 :type laddr_range: string
966 :type raddr_range: string
967 :type lport_range: string
968 :type rport_range: string
971 err_msg = f"Failed to add entry to Security Policy Database " \
972 f"{spd_id} on host {node[u'host']}"
973 with PapiSocketExecutor(node, is_async=True) as papi_exec:
974 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
975 papi_exec, spd_id, priority, action, inbound, sa_id, proto,
976 laddr_range, raddr_range, lport_range, rport_range, is_ipv6
978 papi_exec.get_replies(err_msg)
981 def vpp_ipsec_add_spd_entries(
982 node, n_entries, spd_id, priority, action, inbound, sa_id=None,
983 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
984 rport_range=None, is_ipv6=False):
985 """Create multiple Security Policy Database entries on the VPP node.
987 :param node: VPP node to add SPD entries on.
988 :param n_entries: Number of SPD entries to be added.
989 :param spd_id: SPD ID to add entries on.
990 :param priority: SPD entries priority, higher number = higher priority.
991 :param action: Policy action.
992 :param inbound: If True policy is for inbound traffic, otherwise
994 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
995 :param proto: Policy selector next layer protocol number.
996 :param laddr_range: Policy selector local IPv4 or IPv6 address range
997 in format IP/prefix or IP/mask. If no mask is provided,
998 it's considered to be /32.
999 :param raddr_range: Policy selector remote 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 lport_range: Policy selector local TCP/UDP port range in format
1003 <port_start>-<port_end>.
1004 :param rport_range: Policy selector remote TCP/UDP port range in format
1005 <port_start>-<port_end>.
1006 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
1007 not defined so it will default to address ::/0, otherwise False.
1009 :type n_entries: int
1011 :type priority: IPsecUtil.ObjIncrement
1012 :type action: IPsecUtil.PolicyAction
1014 :type sa_id: IPsecUtil.ObjIncrement
1016 :type laddr_range: IPsecUtil.NetworkIncrement
1017 :type raddr_range: IPsecUtil.NetworkIncrement
1018 :type lport_range: string
1019 :type rport_range: string
1022 if laddr_range is None:
1023 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1024 laddr_range = NetworkIncrement(ip_network(laddr_range), 0)
1026 if raddr_range is None:
1027 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1028 raddr_range = NetworkIncrement(ip_network(raddr_range), 0)
1030 lport_range_start = 0
1031 lport_range_stop = 65535
1033 lport_range_start, lport_range_stop = lport_range.split('-')
1035 rport_range_start = 0
1036 rport_range_stop = 65535
1038 rport_range_start, rport_range_stop = rport_range.split('-')
1040 err_msg = f"Failed to add entry to Security Policy Database " \
1041 f"{spd_id} on host {node[u'host']}"
1042 with PapiSocketExecutor(node, is_async=True) as papi_exec:
1043 for _ in range(n_entries):
1044 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
1045 papi_exec, spd_id, next(priority), action, inbound,
1046 next(sa_id) if sa_id is not None else sa_id,
1047 proto, next(laddr_range), next(raddr_range), lport_range,
1048 rport_range, is_ipv6
1050 papi_exec.get_replies(err_msg)
1053 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1054 """Create loopback interface and set IP address on VPP node 1 interface
1057 :param nodes: VPP nodes to create tunnel interfaces.
1058 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1059 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1060 IPv4/IPv6 address (ip2).
1061 :param if1_key: VPP node 1 interface key from topology file.
1062 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1063 interface key from topology file.
1069 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1070 # Create loopback interface on DUT1, set it to up state
1071 cmd = u"create_loopback_instance"
1077 err_msg = f"Failed to create loopback interface " \
1078 f"on host {nodes[u'DUT1'][u'host']}"
1079 papi_exec.add(cmd, **args)
1080 loop_sw_if_idx = papi_exec.get_sw_if_index(err_msg)
1081 cmd = u"sw_interface_set_flags"
1083 sw_if_index=loop_sw_if_idx,
1084 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1086 err_msg = f"Failed to set loopback interface state up " \
1087 f"on host {nodes[u'DUT1'][u'host']}"
1088 papi_exec.add(cmd, **args).get_reply(err_msg)
1089 # Set IP address on VPP node 1 interface
1090 cmd = u"sw_interface_add_del_address"
1092 sw_if_index=InterfaceUtil.get_interface_index(
1093 nodes[u"DUT1"], if1_key
1097 prefix=IPUtil.create_prefix_object(
1098 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1102 err_msg = f"Failed to set IP address on interface {if1_key} " \
1103 f"on host {nodes[u'DUT1'][u'host']}"
1104 papi_exec.add(cmd, **args).get_reply(err_msg)
1105 cmd2 = u"ip_neighbor_add_del"
1109 sw_if_index=Topology.get_interface_sw_index(
1110 nodes[u"DUT1"], if1_key
1114 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1115 if u"DUT2" in nodes.keys()
1116 else Topology.get_interface_mac(
1117 nodes[u"TG"], if2_key
1120 ip_address=tun_ips[u"ip2"].compressed
1123 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1124 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1126 return loop_sw_if_idx
1129 def _ipsec_create_tunnel_interfaces_dut1_papi(
1130 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1131 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1132 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1134 Generate random keys and return them (so DUT2 or TG can decrypt).
1136 :param nodes: VPP nodes to create tunnel interfaces.
1137 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1138 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1139 IPv4/IPv6 address (ip2).
1140 :param if1_key: VPP node 1 interface key from topology file.
1141 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1142 interface key from topology file.
1143 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1144 :param crypto_alg: The encryption algorithm name.
1145 :param integ_alg: The integrity algorithm name.
1146 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1147 first tunnel in direction node2->node1.
1148 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1149 :param addr_incr: IP / IPv6 address incremental step.
1150 :param existing_tunnels: Number of tunnel interfaces before creation.
1151 Useful mainly for reconf tests. Default 0.
1156 :type n_tunnels: int
1157 :type crypto_alg: CryptoAlg
1158 :type integ_alg: Optional[IntegAlg]
1159 :type raddr_ip2: IPv4Address or IPv6Address
1160 :type addr_incr: int
1162 :type existing_tunnels: int
1163 :returns: Generated ckeys and ikeys.
1164 :rtype: List[bytes], List[bytes]
1166 if not existing_tunnels:
1167 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1168 nodes, tun_ips, if1_key, if2_key
1171 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1172 nodes[u"DUT1"], u"loop0"
1174 with PapiSocketExecutor(nodes[u"DUT1"], is_async=True) as papi_exec:
1175 # Configure IP addresses on loop0 interface
1176 cmd = u"sw_interface_add_del_address"
1178 sw_if_index=loop_sw_if_idx,
1183 for i in range(existing_tunnels, n_tunnels):
1184 args[u"prefix"] = IPUtil.create_prefix_object(
1185 tun_ips[u"ip1"] + i * addr_incr,
1186 128 if tun_ips[u"ip1"].version == 6 else 32
1189 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1191 # Configure IPIP tunnel interfaces
1192 cmd = u"ipip_add_tunnel"
1194 instance=Constants.BITWISE_NON_ZERO,
1199 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1201 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1202 dscp=int(IpDscp.IP_API_DSCP_CS0)
1207 ipip_tunnels = [None] * existing_tunnels
1208 for i in range(existing_tunnels, n_tunnels):
1209 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1210 tun_ips[u"ip1"] + i * addr_incr
1212 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1216 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1218 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1219 f" {nodes[u'DUT1'][u'host']}"
1220 ipip_tunnels.extend(
1222 reply[u"sw_if_index"]
1223 for reply in papi_exec.get_replies(err_msg)
1224 if u"sw_if_index" in reply
1227 # Configure IPSec SAD entries
1228 ckeys = [bytes()] * existing_tunnels
1229 ikeys = [bytes()] * existing_tunnels
1230 cmd = u"ipsec_sad_entry_add"
1242 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1243 crypto_algorithm=crypto_alg.alg_int_repr,
1245 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1246 integrity_key=i_key,
1252 encap_decap_flags=int(
1253 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1255 dscp=int(IpDscp.IP_API_DSCP_CS0),
1258 udp_src_port=IPSEC_UDP_PORT_NONE,
1259 udp_dst_port=IPSEC_UDP_PORT_NONE,
1261 args = dict(entry=sad_entry)
1262 for i in range(existing_tunnels, n_tunnels):
1264 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1267 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1269 # SAD entry for outband / tx path
1270 args[u"entry"][u"sad_id"] = i
1271 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1273 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1274 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1276 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1277 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1278 args[u"entry"][u"flags"] = int(
1279 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1282 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1284 # SAD entry for inband / rx path
1285 args[u"entry"][u"sad_id"] = 100000 + i
1286 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1288 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1289 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1291 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1292 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1293 args[u"entry"][u"flags"] = int(
1294 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1295 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1298 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1300 err_msg = f"Failed to add IPsec SAD entries on host" \
1301 f" {nodes[u'DUT1'][u'host']}"
1302 papi_exec.get_replies(err_msg)
1303 # Add protection for tunnels with IPSEC
1304 cmd = u"ipsec_tunnel_protect_update"
1307 via_label=MPLS_LABEL_INVALID,
1308 obj_id=Constants.BITWISE_NON_ZERO
1310 ipsec_tunnel_protect = dict(
1318 tunnel=ipsec_tunnel_protect
1320 for i in range(existing_tunnels, n_tunnels):
1321 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1322 args[u"tunnel"][u"sa_out"] = i
1323 args[u"tunnel"][u"sa_in"] = [100000 + i]
1325 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1327 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1328 f"on host {nodes[u'DUT1'][u'host']}"
1329 papi_exec.get_replies(err_msg)
1331 # Configure unnumbered interfaces
1332 cmd = u"sw_interface_set_unnumbered"
1335 sw_if_index=InterfaceUtil.get_interface_index(
1336 nodes[u"DUT1"], if1_key
1338 unnumbered_sw_if_index=0
1340 for i in range(existing_tunnels, n_tunnels):
1341 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1343 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1346 cmd = u"sw_interface_set_flags"
1349 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1351 for i in range(existing_tunnels, n_tunnels):
1352 args[u"sw_if_index"] = ipip_tunnels[i]
1354 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1356 # Configure IP routes
1357 cmd = u"ip_route_add_del"
1363 for i in range(existing_tunnels, n_tunnels):
1364 args[u"route"] = IPUtil.compose_vpp_route_structure(
1365 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1366 prefix_len=128 if raddr_ip2.version == 6 else 32,
1367 interface=ipip_tunnels[i]
1370 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1372 err_msg = f"Failed to add IP routes on host " \
1373 f"{nodes[u'DUT1'][u'host']}"
1374 papi_exec.get_replies(err_msg)
1379 def _ipsec_create_tunnel_interfaces_dut2_papi(
1380 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1381 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1382 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1384 This method accesses keys generated by DUT1 method
1385 and does not return anything.
1387 :param nodes: VPP nodes to create tunnel interfaces.
1388 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1389 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1390 IPv4/IPv6 address (ip2).
1391 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1392 interface key from topology file.
1393 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1394 :param crypto_alg: The encryption algorithm name.
1395 :param ckeys: List of encryption keys.
1396 :param integ_alg: The integrity algorithm name.
1397 :param ikeys: List of integrity keys.
1398 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1399 :param addr_incr: IP / IPv6 address incremental step.
1400 :param existing_tunnels: Number of tunnel interfaces before creation.
1401 Useful mainly for reconf tests. Default 0.
1405 :type n_tunnels: int
1406 :type crypto_alg: CryptoAlg
1407 :type ckeys: Sequence[bytes]
1408 :type integ_alg: Optional[IntegAlg]
1409 :type ikeys: Sequence[bytes]
1410 :type addr_incr: int
1412 :type existing_tunnels: int
1414 with PapiSocketExecutor(nodes[u"DUT2"], is_async=True) as papi_exec:
1415 if not existing_tunnels:
1416 # Set IP address on VPP node 2 interface
1417 cmd = u"sw_interface_add_del_address"
1419 sw_if_index=InterfaceUtil.get_interface_index(
1420 nodes[u"DUT2"], if2_key
1424 prefix=IPUtil.create_prefix_object(
1425 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1429 err_msg = f"Failed to set IP address on interface {if2_key} " \
1430 f"on host {nodes[u'DUT2'][u'host']}"
1431 papi_exec.add(cmd, **args).get_replies(err_msg)
1432 # Configure IPIP tunnel interfaces
1433 cmd = u"ipip_add_tunnel"
1435 instance=Constants.BITWISE_NON_ZERO,
1440 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1442 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1443 dscp=int(IpDscp.IP_API_DSCP_CS0)
1448 ipip_tunnels = [None] * existing_tunnels
1449 for i in range(existing_tunnels, n_tunnels):
1450 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1453 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1454 tun_ips[u"ip1"] + i * addr_incr
1457 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1459 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1460 f" {nodes[u'DUT2'][u'host']}"
1461 ipip_tunnels.extend(
1463 reply[u"sw_if_index"]
1464 for reply in papi_exec.get_replies(err_msg)
1465 if u"sw_if_index" in reply
1468 # Configure IPSec SAD entries
1469 cmd = u"ipsec_sad_entry_add"
1481 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1482 crypto_algorithm=crypto_alg.alg_int_repr,
1484 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1485 integrity_key=i_key,
1491 encap_decap_flags=int(
1492 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1494 dscp=int(IpDscp.IP_API_DSCP_CS0),
1497 udp_src_port=IPSEC_UDP_PORT_NONE,
1498 udp_dst_port=IPSEC_UDP_PORT_NONE,
1500 args = dict(entry=sad_entry)
1501 for i in range(existing_tunnels, n_tunnels):
1503 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1506 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1508 # SAD entry for outband / tx path
1509 args[u"entry"][u"sad_id"] = 100000 + i
1510 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1512 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1513 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1515 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1516 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1517 args[u"entry"][u"flags"] = int(
1518 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1521 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1523 # SAD entry for inband / rx path
1524 args[u"entry"][u"sad_id"] = i
1525 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1527 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1528 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1530 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1531 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1532 args[u"entry"][u"flags"] = int(
1533 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1534 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1537 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1539 err_msg = f"Failed to add IPsec SAD entries on host" \
1540 f" {nodes[u'DUT2'][u'host']}"
1541 papi_exec.get_replies(err_msg)
1542 # Add protection for tunnels with IPSEC
1543 cmd = u"ipsec_tunnel_protect_update"
1546 via_label=MPLS_LABEL_INVALID,
1547 obj_id=Constants.BITWISE_NON_ZERO
1549 ipsec_tunnel_protect = dict(
1557 tunnel=ipsec_tunnel_protect
1559 for i in range(existing_tunnels, n_tunnels):
1560 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1561 args[u"tunnel"][u"sa_out"] = 100000 + i
1562 args[u"tunnel"][u"sa_in"] = [i]
1564 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1566 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1567 f"on host {nodes[u'DUT2'][u'host']}"
1568 papi_exec.get_replies(err_msg)
1570 if not existing_tunnels:
1571 # Configure IP route
1572 cmd = u"ip_route_add_del"
1573 route = IPUtil.compose_vpp_route_structure(
1574 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1575 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1577 gateway=(tun_ips[u"ip2"] - 1).compressed
1584 papi_exec.add(cmd, **args)
1585 # Configure unnumbered interfaces
1586 cmd = u"sw_interface_set_unnumbered"
1589 sw_if_index=InterfaceUtil.get_interface_index(
1590 nodes[u"DUT2"], if2_key
1592 unnumbered_sw_if_index=0
1594 for i in range(existing_tunnels, n_tunnels):
1595 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1597 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1600 cmd = u"sw_interface_set_flags"
1603 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1605 for i in range(existing_tunnels, n_tunnels):
1606 args[u"sw_if_index"] = ipip_tunnels[i]
1608 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1610 # Configure IP routes
1611 cmd = u"ip_route_add_del"
1617 for i in range(existing_tunnels, n_tunnels):
1618 args[u"route"] = IPUtil.compose_vpp_route_structure(
1619 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1620 prefix_len=128 if raddr_ip1.version == 6 else 32,
1621 interface=ipip_tunnels[i]
1624 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1626 err_msg = f"Failed to add IP routes " \
1627 f"on host {nodes[u'DUT2'][u'host']}"
1628 papi_exec.get_replies(err_msg)
1631 def vpp_ipsec_create_tunnel_interfaces(
1632 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1633 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1634 existing_tunnels=0, return_keys=False):
1635 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1637 Some deployments (e.g. devicetest) need to know the generated keys.
1638 But other deployments (e.g. scale perf test) would get spammed
1639 if we returned keys every time.
1641 :param nodes: VPP nodes to create tunnel interfaces.
1642 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1644 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1646 :param if1_key: VPP node 1 interface key from topology file.
1647 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1648 interface key from topology file.
1649 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1650 :param crypto_alg: The encryption algorithm name.
1651 :param integ_alg: The integrity algorithm name.
1652 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1653 first tunnel in direction node1->node2.
1654 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1655 first tunnel in direction node2->node1.
1656 :param raddr_range: Mask specifying range of Policy selector Remote
1657 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1658 and to 128 in case of IPv6.
1659 :param existing_tunnels: Number of tunnel interfaces before creation.
1660 Useful mainly for reconf tests. Default 0.
1661 :param return_keys: Whether generated keys should be returned.
1663 :type tun_if1_ip_addr: str
1664 :type tun_if2_ip_addr: str
1667 :type n_tunnels: int
1668 :type crypto_alg: CryptoAlg
1669 :type integ_alg: Optonal[IntegAlg]
1670 :type raddr_ip1: string
1671 :type raddr_ip2: string
1672 :type raddr_range: int
1673 :type existing_tunnels: int
1674 :type return_keys: bool
1675 :returns: Ckeys, ikeys, spi_1, spi_2.
1676 :rtype: Optional[List[bytes], List[bytes], int, int]
1678 n_tunnels = int(n_tunnels)
1679 existing_tunnels = int(existing_tunnels)
1685 ip1=ip_address(tun_if1_ip_addr),
1686 ip2=ip_address(tun_if2_ip_addr)
1688 raddr_ip1 = ip_address(raddr_ip1)
1689 raddr_ip2 = ip_address(raddr_ip2)
1690 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1691 else 1 << (32 - raddr_range)
1693 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1694 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1695 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1697 if u"DUT2" in nodes.keys():
1698 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1699 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1700 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1705 return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1709 def _create_ipsec_script_files(dut, instances):
1710 """Create script files for configuring IPsec in containers
1712 :param dut: DUT node on which to create the script files
1713 :param instances: number of containers on DUT node
1715 :type instances: int
1718 for cnf in range(0, instances):
1720 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1722 scripts.append(open(script_filename, 'w'))
1726 def _close_and_copy_ipsec_script_files(
1727 dut, nodes, instances, scripts):
1728 """Close created scripts and copy them to containers
1730 :param dut: DUT node on which to create the script files
1731 :param nodes: VPP nodes
1732 :param instances: number of containers on DUT node
1733 :param scripts: dictionary holding the script files
1736 :type instances: int
1739 for cnf in range(0, instances):
1740 scripts[cnf].close()
1742 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1744 scp_node(nodes[dut], script_filename, script_filename)
1748 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1749 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1750 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1751 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1753 :param nodes: VPP nodes to create tunnel interfaces.
1754 :param if1_ip_addr: VPP node 1 interface IP4 address.
1755 :param if2_ip_addr: VPP node 2 interface IP4 address.
1756 :param n_tunnels: Number of tunnell interfaces to create.
1757 :param crypto_alg: The encryption algorithm name.
1758 :param integ_alg: The integrity algorithm name.
1759 :param raddr_ip1: Policy selector remote IPv4 start address for the
1760 first tunnel in direction node1->node2.
1761 :param raddr_ip2: Policy selector remote IPv4 start address for the
1762 first tunnel in direction node2->node1.
1763 :param raddr_range: Mask specifying range of Policy selector Remote
1764 IPv4 addresses. Valid values are from 1 to 32.
1765 :param n_instances: Number of containers.
1767 :type if1_ip_addr: str
1768 :type if2_ip_addr: str
1769 :type n_tunnels: int
1770 :type crypto_alg: CryptoAlg
1771 :type integ_alg: Optional[IntegAlg]
1772 :type raddr_ip1: string
1773 :type raddr_ip2: string
1774 :type raddr_range: int
1775 :type n_instances: int
1779 addr_incr = 1 << (32 - raddr_range)
1781 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1782 u"DUT1", n_instances
1784 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1785 u"DUT2", n_instances
1788 for cnf in range(0, n_instances):
1789 dut1_scripts[cnf].write(
1790 u"create loopback interface\n"
1791 u"set interface state loop0 up\n\n"
1793 dut2_scripts[cnf].write(
1794 f"ip route add {if1_ip_addr}/8 via "
1795 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1798 for tnl in range(0, n_tunnels):
1799 cnf = tnl % n_instances
1801 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1805 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1809 f"integ-alg {integ_alg.alg_name} "
1810 f"local-integ-key {ikey} "
1811 f"remote-integ-key {ikey} "
1813 # Configure tunnel end point(s) on left side
1814 dut1_scripts[cnf].write(
1815 u"set interface ip address loop0 "
1816 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1817 f"create ipsec tunnel "
1818 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1819 f"local-spi {spi_1 + tnl} "
1820 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1821 f"remote-spi {spi_2 + tnl} "
1822 f"crypto-alg {crypto_alg.alg_name} "
1823 f"local-crypto-key {ckey} "
1824 f"remote-crypto-key {ckey} "
1825 f"instance {tnl // n_instances} "
1828 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1829 f"set interface state ipip{tnl // n_instances} up\n"
1830 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1831 f"via ipip{tnl // n_instances}\n\n"
1833 # Configure tunnel end point(s) on right side
1834 dut2_scripts[cnf].write(
1835 f"set ip neighbor memif1/{cnf + 1} "
1836 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1837 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1838 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1839 f"local-spi {spi_2 + tnl} "
1840 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1841 f"remote-spi {spi_1 + tnl} "
1842 f"crypto-alg {crypto_alg.alg_name} "
1843 f"local-crypto-key {ckey} "
1844 f"remote-crypto-key {ckey} "
1845 f"instance {tnl // n_instances} "
1848 f"set interface unnumbered ipip{tnl // n_instances} "
1849 f"use memif1/{cnf + 1}\n"
1850 f"set interface state ipip{tnl // n_instances} up\n"
1851 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1852 f"via ipip{tnl // n_instances}\n\n"
1855 IPsecUtil._close_and_copy_ipsec_script_files(
1856 u"DUT1", nodes, n_instances, dut1_scripts)
1857 IPsecUtil._close_and_copy_ipsec_script_files(
1858 u"DUT2", nodes, n_instances, dut2_scripts)
1861 def vpp_ipsec_add_multiple_tunnels(
1862 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1863 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range,
1864 tunnel_addr_incr=True):
1865 """Create multiple IPsec tunnels between two VPP nodes.
1867 :param nodes: VPP nodes to create tunnels.
1868 :param interface1: Interface name or sw_if_index on node 1.
1869 :param interface2: Interface name or sw_if_index on node 2.
1870 :param n_tunnels: Number of tunnels to create.
1871 :param crypto_alg: The encryption algorithm name.
1872 :param integ_alg: The integrity algorithm name.
1873 :param tunnel_ip1: Tunnel node1 IPv4 address.
1874 :param tunnel_ip2: Tunnel node2 IPv4 address.
1875 :param raddr_ip1: Policy selector remote IPv4 start address for the
1876 first tunnel in direction node1->node2.
1877 :param raddr_ip2: Policy selector remote IPv4 start address for the
1878 first tunnel in direction node2->node1.
1879 :param raddr_range: Mask specifying range of Policy selector Remote
1880 IPv4 addresses. Valid values are from 1 to 32.
1881 :param tunnel_addr_incr: Enable or disable tunnel IP address
1884 :type interface1: str or int
1885 :type interface2: str or int
1886 :type n_tunnels: int
1887 :type crypto_alg: CryptoAlg
1888 :type integ_alg: Optional[IntegAlg]
1889 :type tunnel_ip1: str
1890 :type tunnel_ip2: str
1891 :type raddr_ip1: string
1892 :type raddr_ip2: string
1893 :type raddr_range: int
1894 :type tunnel_addr_incr: bool
1904 crypto_key = gen_key(
1905 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1907 integ_key = gen_key(
1908 IPsecUtil.get_integ_alg_key_len(integ_alg)
1909 ).decode() if integ_alg else u""
1911 rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
1912 if u"DUT2" in nodes.keys() \
1913 else Topology.get_interface_mac(nodes[u"TG"], interface2)
1914 IPsecUtil.vpp_ipsec_set_ip_route(
1915 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1916 interface1, raddr_range, rmac)
1918 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1919 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1921 addr_incr = 1 << (128 - 96) if ip_address(tunnel_ip1).version == 6 \
1923 for i in range(n_tunnels//(addr_incr**2)+1):
1924 dut1_local_outbound_range = \
1925 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1926 False).with_prefixlen
1927 dut1_remote_outbound_range = \
1928 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1929 False).with_prefixlen
1931 IPsecUtil.vpp_ipsec_add_spd_entry(
1932 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1933 proto=50, laddr_range=dut1_local_outbound_range,
1934 raddr_range=dut1_remote_outbound_range
1936 IPsecUtil.vpp_ipsec_add_spd_entry(
1937 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1938 proto=50, laddr_range=dut1_remote_outbound_range,
1939 raddr_range=dut1_local_outbound_range
1942 IPsecUtil.vpp_ipsec_add_sad_entries(
1943 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1944 integ_alg, integ_key, tunnel_ip1, tunnel_ip2, tunnel_addr_incr
1947 IPsecUtil.vpp_ipsec_add_spd_entries(
1948 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1949 action=PolicyAction.PROTECT, inbound=False,
1950 sa_id=ObjIncrement(sa_id_1, 1),
1951 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
1954 IPsecUtil.vpp_ipsec_add_sad_entries(
1955 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1956 integ_alg, integ_key, tunnel_ip2, tunnel_ip1, tunnel_addr_incr
1958 IPsecUtil.vpp_ipsec_add_spd_entries(
1959 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1960 action=PolicyAction.PROTECT, inbound=True,
1961 sa_id=ObjIncrement(sa_id_2, 1),
1962 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
1965 if u"DUT2" in nodes.keys():
1966 rmac = Topology.get_interface_mac(nodes[u"DUT1"], interface1)
1967 IPsecUtil.vpp_ipsec_set_ip_route(
1968 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1969 interface2, raddr_range, rmac)
1971 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1972 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1973 for i in range(n_tunnels//(addr_incr**2)+1):
1974 dut2_local_outbound_range = \
1975 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1976 False).with_prefixlen
1977 dut2_remote_outbound_range = \
1978 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1979 False).with_prefixlen
1981 IPsecUtil.vpp_ipsec_add_spd_entry(
1982 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1983 inbound=False, proto=50,
1984 laddr_range=dut2_remote_outbound_range,
1985 raddr_range=dut2_local_outbound_range
1987 IPsecUtil.vpp_ipsec_add_spd_entry(
1988 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1989 inbound=True, proto=50,
1990 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
2086 flow_index = FlowUtil.vpp_create_ip4_ipsec_flow(
2087 node, "ESP", spi, "redirect-to-queue", value=rx_queue)
2088 FlowUtil.vpp_flow_enable(node, interface, flow_index)