1 # Copyright (c) 2023 Cisco and/or its affiliates.
2 # Copyright (c) 2023 PANTHEON.tech s.r.o.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 """IPsec utilities library."""
19 from enum import Enum, IntEnum
21 from ipaddress import ip_network, ip_address
22 from random import choice
23 from string import ascii_letters
25 from 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 :param node: VPP node to set IPsec async mode.
320 :param async_enable: Async mode on or off.
322 :type async_enable: int
323 :raises RuntimeError: If failed to set IPsec async mode or if no API
326 cmd = u"ipsec_set_async_mode"
327 err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
329 async_enable=async_enable
331 with PapiSocketExecutor(node) as papi_exec:
332 papi_exec.add(cmd, **args).get_reply(err_msg)
335 def vpp_ipsec_crypto_sw_scheduler_set_worker(
336 node, workers, crypto_enable=False):
337 """Enable or disable crypto on specific vpp worker threads.
339 :param node: VPP node to enable or disable crypto for worker threads.
340 :param workers: List of VPP thread numbers.
341 :param crypto_enable: Disable or enable crypto work.
343 :type workers: Iterable[int]
344 :type crypto_enable: bool
345 :raises RuntimeError: If failed to enable or disable crypto for worker
346 thread or if no API reply received.
348 for worker in workers:
349 cmd = u"crypto_sw_scheduler_set_worker"
350 err_msg = f"Failed to disable/enable crypto for worker thread " \
351 f"on host {node[u'host']}"
353 worker_index=worker - 1,
354 crypto_enable=crypto_enable
356 with PapiSocketExecutor(node) as papi_exec:
357 papi_exec.add(cmd, **args).get_reply(err_msg)
360 def vpp_ipsec_crypto_sw_scheduler_set_worker_on_all_duts(
361 nodes, workers, crypto_enable=False):
362 """Enable or disable crypto on specific vpp worker threads.
364 :param node: VPP node to enable or disable crypto for worker threads.
365 :param workers: List of VPP thread numbers.
366 :param crypto_enable: Disable or enable crypto work.
368 :type workers: Iterable[int]
369 :type crypto_enable: bool
370 :raises RuntimeError: If failed to enable or disable crypto for worker
371 thread or if no API reply received.
373 for node in nodes.values():
374 if node[u"type"] == NodeType.DUT:
375 thread_data = VPPUtil.vpp_show_threads(node)
376 worker_cnt = len(thread_data) - 1
380 for item in thread_data:
381 if str(item.cpu_id) in workers.split(u","):
382 worker_ids.append(item.id)
384 IPsecUtil.vpp_ipsec_crypto_sw_scheduler_set_worker(
385 node, workers=worker_ids, crypto_enable=crypto_enable
389 def vpp_ipsec_add_sad_entry(
390 node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
391 integ_key=u"", tunnel_src=None, tunnel_dst=None):
392 """Create Security Association Database entry on the VPP node.
394 :param node: VPP node to add SAD entry on.
395 :param sad_id: SAD entry ID.
396 :param spi: Security Parameter Index of this SAD entry.
397 :param crypto_alg: The encryption algorithm name.
398 :param crypto_key: The encryption key string.
399 :param integ_alg: The integrity algorithm name.
400 :param integ_key: The integrity key string.
401 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
402 specified ESP transport mode is used.
403 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
404 not specified ESP transport mode is used.
408 :type crypto_alg: CryptoAlg
409 :type crypto_key: str
410 :type integ_alg: Optional[IntegAlg]
412 :type tunnel_src: str
413 :type tunnel_dst: str
415 if isinstance(crypto_key, str):
416 crypto_key = crypto_key.encode(encoding=u"utf-8")
417 if isinstance(integ_key, str):
418 integ_key = integ_key.encode(encoding=u"utf-8")
420 length=len(crypto_key),
424 length=len(integ_key),
425 data=integ_key if integ_key else 0
428 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
429 if tunnel_src and tunnel_dst:
430 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
431 src_addr = ip_address(tunnel_src)
432 dst_addr = ip_address(tunnel_dst)
433 if src_addr.version == 6:
435 flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
440 cmd = u"ipsec_sad_entry_add"
441 err_msg = f"Failed to add Security Association Database entry " \
442 f"on host {node[u'host']}"
446 crypto_algorithm=crypto_alg.alg_int_repr,
448 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
455 encap_decap_flags=int(
456 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
458 dscp=int(IpDscp.IP_API_DSCP_CS0),
460 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
461 udp_src_port=4500, # default value in api
462 udp_dst_port=4500 # default value in api
464 args = dict(entry=sad_entry)
465 with PapiSocketExecutor(node) as papi_exec:
466 papi_exec.add(cmd, **args).get_reply(err_msg)
469 def vpp_ipsec_add_sad_entries(
470 node, n_entries, sad_id, spi, crypto_alg, crypto_key,
471 integ_alg=None, integ_key=u"", tunnel_src=None,tunnel_dst=None,
472 tunnel_addr_incr=True):
473 """Create multiple Security Association Database entries on VPP node.
475 :param node: VPP node to add SAD entry on.
476 :param n_entries: Number of SAD entries to be created.
477 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
479 :param spi: Security Parameter Index of first SAD entry. All subsequent
480 SAD entries will have spi incremented by 1.
481 :param crypto_alg: The encryption algorithm name.
482 :param crypto_key: The encryption key string.
483 :param integ_alg: The integrity algorithm name.
484 :param integ_key: The integrity key string.
485 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
486 specified ESP transport mode is used.
487 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
488 not specified ESP transport mode is used.
489 :param tunnel_addr_incr: Enable or disable tunnel IP address
495 :type crypto_alg: CryptoAlg
496 :type crypto_key: str
497 :type integ_alg: Optional[IntegAlg]
499 :type tunnel_src: str
500 :type tunnel_dst: str
501 :type tunnel_addr_incr: bool
503 if isinstance(crypto_key, str):
504 crypto_key = crypto_key.encode(encoding=u"utf-8")
505 if isinstance(integ_key, str):
506 integ_key = integ_key.encode(encoding=u"utf-8")
507 if tunnel_src and tunnel_dst:
508 src_addr = ip_address(tunnel_src)
509 dst_addr = ip_address(tunnel_dst)
515 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
521 length=len(crypto_key),
525 length=len(integ_key),
526 data=integ_key if integ_key else 0
529 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
530 if tunnel_src and tunnel_dst:
531 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
532 if src_addr.version == 6:
534 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
537 cmd = u"ipsec_sad_entry_add"
538 err_msg = f"Failed to add Security Association Database entry " \
539 f"on host {node[u'host']}"
544 crypto_algorithm=crypto_alg.alg_int_repr,
546 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
553 encap_decap_flags=int(
554 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
556 dscp=int(IpDscp.IP_API_DSCP_CS0),
558 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
559 udp_src_port=4500, # default value in api
560 udp_dst_port=4500, # default value in api
562 args = dict(entry=sad_entry)
563 with PapiSocketExecutor(node, is_async=True) as papi_exec:
564 for i in range(n_entries):
565 args[u"entry"][u"sad_id"] = int(sad_id) + i
566 args[u"entry"][u"spi"] = int(spi) + i
567 args[u"entry"][u"tunnel"][u"src"] = (
568 str(src_addr + i * addr_incr)
569 if tunnel_src and tunnel_dst else src_addr
571 args[u"entry"][u"tunnel"][u"dst"] = (
572 str(dst_addr + i * addr_incr)
573 if tunnel_src and tunnel_dst else dst_addr
575 history = bool(not 1 < i < n_entries - 2)
576 papi_exec.add(cmd, history=history, **args)
577 papi_exec.get_replies(err_msg)
580 def vpp_ipsec_set_ip_route(
581 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
582 raddr_range, dst_mac=None):
583 """Set IP address and route on interface.
585 :param node: VPP node to add config on.
586 :param n_tunnels: Number of tunnels to create.
587 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
588 :param traffic_addr: Traffic destination IP address to route.
589 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
590 :param interface: Interface key on node 1.
591 :param raddr_range: Mask specifying range of Policy selector Remote IP
592 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
594 :param dst_mac: The MAC address of destination tunnels.
597 :type tunnel_src: str
598 :type traffic_addr: str
599 :type tunnel_dst: str
601 :type raddr_range: int
604 tunnel_src = ip_address(tunnel_src)
605 tunnel_dst = ip_address(tunnel_dst)
606 traffic_addr = ip_address(traffic_addr)
607 tunnel_dst_prefix = 128 if tunnel_dst.version == 6 else 32
608 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
609 else 1 << (32 - raddr_range)
611 cmd1 = u"sw_interface_add_del_address"
613 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
618 cmd2 = u"ip_route_add_del"
624 cmd3 = u"ip_neighbor_add_del"
628 sw_if_index=Topology.get_interface_sw_index(node, interface),
630 mac_address=str(dst_mac),
634 err_msg = f"Failed to configure IP addresses, IP routes and " \
635 f"IP neighbor on interface {interface} on host {node[u'host']}" \
637 else f"Failed to configure IP addresses and IP routes " \
638 f"on interface {interface} on host {node[u'host']}"
640 with PapiSocketExecutor(node, is_async=True) as papi_exec:
641 for i in range(n_tunnels):
642 tunnel_dst_addr = tunnel_dst + i * addr_incr
643 args1[u"prefix"] = IPUtil.create_prefix_object(
644 tunnel_src + i * addr_incr, raddr_range
646 args2[u"route"] = IPUtil.compose_vpp_route_structure(
647 node, traffic_addr + i,
648 prefix_len=tunnel_dst_prefix,
649 interface=interface, gateway=tunnel_dst_addr
651 history = bool(not 1 < i < n_tunnels - 2)
652 papi_exec.add(cmd1, history=history, **args1)
653 papi_exec.add(cmd2, history=history, **args2)
655 args2[u"route"] = IPUtil.compose_vpp_route_structure(
656 node, tunnel_dst_addr,
657 prefix_len=tunnel_dst_prefix,
658 interface=interface, gateway=tunnel_dst_addr
660 papi_exec.add(cmd2, history=history, **args2)
663 args3[u"neighbor"][u"ip_address"] = ip_address(
666 papi_exec.add(cmd3, history=history, **args3)
667 papi_exec.get_replies(err_msg)
670 def vpp_ipsec_add_spd(node, spd_id):
671 """Create Security Policy Database on the VPP node.
673 :param node: VPP node to add SPD on.
674 :param spd_id: SPD ID.
678 cmd = u"ipsec_spd_add_del"
679 err_msg = f"Failed to add Security Policy Database " \
680 f"on host {node[u'host']}"
685 with PapiSocketExecutor(node) as papi_exec:
686 papi_exec.add(cmd, **args).get_reply(err_msg)
689 def vpp_ipsec_spd_add_if(node, spd_id, interface):
690 """Add interface to the Security Policy Database.
692 :param node: VPP node.
693 :param spd_id: SPD ID to add interface on.
694 :param interface: Interface name or sw_if_index.
697 :type interface: str or int
699 cmd = u"ipsec_interface_add_del_spd"
700 err_msg = f"Failed to add interface {interface} to Security Policy " \
701 f"Database {spd_id} on host {node[u'host']}"
704 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
707 with PapiSocketExecutor(node) as papi_exec:
708 papi_exec.add(cmd, **args).get_reply(err_msg)
711 def vpp_ipsec_create_spds_match_nth_entry(
712 node, dir1_interface, dir2_interface, entry_amount,
713 local_addr_range, remote_addr_range, action=PolicyAction.BYPASS,
714 inbound=False, bidirectional=True):
715 """Create one matching SPD entry for inbound or outbound traffic on
716 a DUT for each traffic direction and also create entry_amount - 1
717 non-matching SPD entries. Create a Security Policy Database on each
718 outbound interface where these entries will be configured.
719 The matching SPD entry will have the lowest priority, input action and
720 will be configured to match the IP flow. The non-matching entries will
721 be the same, except with higher priority and non-matching IP flows.
723 Action Protect is currently not supported.
725 :param node: VPP node to configured the SPDs and their entries.
726 :param dir1_interface: The interface in direction 1 where the entries
728 :param dir2_interface: The interface in direction 2 where the entries
730 :param entry_amount: The number of SPD entries to configure. If
731 entry_amount == 1, no non-matching entries will be configured.
732 :param local_addr_range: Matching local address range in direction 1
733 in format IP/prefix or IP/mask. If no mask is provided, it's
734 considered to be /32.
735 :param remote_addr_range: Matching remote address range in
736 direction 1 in format IP/prefix or IP/mask. If no mask is
737 provided, it's considered to be /32.
738 :param action: Policy action.
739 :param inbound: If True policy is for inbound traffic, otherwise
741 :param bidirectional: When True, will create SPDs in both directions
742 of traffic. When False, only in one direction.
744 :type dir1_interface: Union[string, int]
745 :type dir2_interface: Union[string, int]
746 :type entry_amount: int
747 :type local_addr_range:
748 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
749 :type remote_addr_range:
750 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
751 :type action: IPsecUtil.PolicyAction
753 :type bidirectional: bool
754 :raises NotImplementedError: When the action is PolicyAction.PROTECT.
757 if action == PolicyAction.PROTECT:
758 raise NotImplementedError('Policy action PROTECT is not supported.')
762 matching_priority = 1
764 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir1)
765 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir1, dir1_interface)
766 # matching entry direction 1
767 IPsecUtil.vpp_ipsec_add_spd_entry(
768 node, spd_id_dir1, matching_priority, action,
769 inbound=inbound, laddr_range=local_addr_range,
770 raddr_range=remote_addr_range
774 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir2)
775 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir2, dir2_interface)
777 # matching entry direction 2, the address ranges are switched
778 IPsecUtil.vpp_ipsec_add_spd_entry(
779 node, spd_id_dir2, matching_priority, action,
780 inbound=inbound, laddr_range=remote_addr_range,
781 raddr_range=local_addr_range
784 # non-matching entries
785 no_match_entry_amount = entry_amount - 1
786 if no_match_entry_amount > 0:
787 # create a NetworkIncrement representation of the network,
788 # then skip the matching network
789 no_match_local_addr_range = NetworkIncrement(
790 ip_network(local_addr_range)
792 next(no_match_local_addr_range)
794 no_match_remote_addr_range = NetworkIncrement(
795 ip_network(remote_addr_range)
797 next(no_match_remote_addr_range)
799 # non-matching entries direction 1
800 IPsecUtil.vpp_ipsec_add_spd_entries(
801 node, no_match_entry_amount, spd_id_dir1,
802 ObjIncrement(matching_priority + 1, 1), action,
803 inbound=inbound, laddr_range=no_match_local_addr_range,
804 raddr_range=no_match_remote_addr_range
808 # reset the networks so that we're using a unified config
809 # the address ranges are switched
810 no_match_remote_addr_range = NetworkIncrement(
811 ip_network(local_addr_range)
813 next(no_match_remote_addr_range)
815 no_match_local_addr_range = NetworkIncrement(
816 ip_network(remote_addr_range)
818 next(no_match_local_addr_range)
819 # non-matching entries direction 2
820 IPsecUtil.vpp_ipsec_add_spd_entries(
821 node, no_match_entry_amount, spd_id_dir2,
822 ObjIncrement(matching_priority + 1, 1), action,
823 inbound=inbound, laddr_range=no_match_local_addr_range,
824 raddr_range=no_match_remote_addr_range
827 IPsecUtil.vpp_ipsec_show_all(node)
830 def _vpp_ipsec_add_spd_entry_internal(
831 executor, spd_id, priority, action, inbound=True, sa_id=None,
832 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
833 rport_range=None, is_ipv6=False):
834 """Prepare to create Security Policy Database entry on the VPP node.
836 This just adds one more command to the executor.
837 The call site shall get replies once all entries are added,
838 to get speed benefit from async PAPI.
840 :param executor: Open PAPI executor (async handling) to add commands to.
841 :param spd_id: SPD ID to add entry on.
842 :param priority: SPD entry priority, higher number = higher priority.
843 :param action: Policy action.
844 :param inbound: If True policy is for inbound traffic, otherwise
846 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
847 :param proto: Policy selector next layer protocol number.
848 :param laddr_range: Policy selector local IPv4 or IPv6 address range
849 in format IP/prefix or IP/mask. If no mask is provided,
850 it's considered to be /32.
851 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
852 in format IP/prefix or IP/mask. If no mask is provided,
853 it's considered to be /32.
854 :param lport_range: Policy selector local TCP/UDP port range in format
855 <port_start>-<port_end>.
856 :param rport_range: Policy selector remote TCP/UDP port range in format
857 <port_start>-<port_end>.
858 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
859 not defined so it will default to address ::/0, otherwise False.
860 :type executor: PapiSocketExecutor
863 :type action: IPsecUtil.PolicyAction
867 :type laddr_range: string
868 :type raddr_range: string
869 :type lport_range: string
870 :type rport_range: string
873 if laddr_range is None:
874 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
876 if raddr_range is None:
877 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
879 local_net = ip_network(laddr_range, strict=False)
880 remote_net = ip_network(raddr_range, strict=False)
882 cmd = u"ipsec_spd_entry_add_del_v2"
886 priority=int(priority),
887 is_outbound=not inbound,
888 sa_id=int(sa_id) if sa_id else 0,
890 protocol=255 if proto is None else int(proto),
891 remote_address_start=IPAddress.create_ip_address_object(
892 remote_net.network_address
894 remote_address_stop=IPAddress.create_ip_address_object(
895 remote_net.broadcast_address
897 local_address_start=IPAddress.create_ip_address_object(
898 local_net.network_address
900 local_address_stop=IPAddress.create_ip_address_object(
901 local_net.broadcast_address
903 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
905 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
907 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
909 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
916 executor.add(cmd, **args)
919 def vpp_ipsec_add_spd_entry(
920 node, spd_id, priority, action, inbound=True, sa_id=None,
921 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
922 rport_range=None, is_ipv6=False):
923 """Create Security Policy Database entry on the VPP node.
925 :param node: VPP node to add SPD entry on.
926 :param spd_id: SPD ID to add entry on.
927 :param priority: SPD entry priority, higher number = higher priority.
928 :param action: Policy action.
929 :param inbound: If True policy is for inbound traffic, otherwise
931 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
932 :param proto: Policy selector next layer protocol number.
933 :param laddr_range: Policy selector local IPv4 or IPv6 address range
934 in format IP/prefix or IP/mask. If no mask is provided,
935 it's considered to be /32.
936 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
937 in format IP/prefix or IP/mask. If no mask is provided,
938 it's considered to be /32.
939 :param lport_range: Policy selector local TCP/UDP port range in format
940 <port_start>-<port_end>.
941 :param rport_range: Policy selector remote TCP/UDP port range in format
942 <port_start>-<port_end>.
943 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
944 not defined so it will default to address ::/0, otherwise False.
948 :type action: IPsecUtil.PolicyAction
952 :type laddr_range: string
953 :type raddr_range: string
954 :type lport_range: string
955 :type rport_range: string
958 err_msg = f"Failed to add entry to Security Policy Database " \
959 f"{spd_id} on host {node[u'host']}"
960 with PapiSocketExecutor(node, is_async=True) as papi_exec:
961 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
962 papi_exec, spd_id, priority, action, inbound, sa_id, proto,
963 laddr_range, raddr_range, lport_range, rport_range, is_ipv6
965 papi_exec.get_replies(err_msg)
968 def vpp_ipsec_add_spd_entries(
969 node, n_entries, spd_id, priority, action, inbound, sa_id=None,
970 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
971 rport_range=None, is_ipv6=False):
972 """Create multiple Security Policy Database entries on the VPP node.
974 :param node: VPP node to add SPD entries on.
975 :param n_entries: Number of SPD entries to be added.
976 :param spd_id: SPD ID to add entries on.
977 :param priority: SPD entries priority, higher number = higher priority.
978 :param action: Policy action.
979 :param inbound: If True policy is for inbound traffic, otherwise
981 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
982 :param proto: Policy selector next layer protocol number.
983 :param laddr_range: Policy selector local IPv4 or IPv6 address range
984 in format IP/prefix or IP/mask. If no mask is provided,
985 it's considered to be /32.
986 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
987 in format IP/prefix or IP/mask. If no mask is provided,
988 it's considered to be /32.
989 :param lport_range: Policy selector local TCP/UDP port range in format
990 <port_start>-<port_end>.
991 :param rport_range: Policy selector remote TCP/UDP port range in format
992 <port_start>-<port_end>.
993 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
994 not defined so it will default to address ::/0, otherwise False.
998 :type priority: IPsecUtil.ObjIncrement
999 :type action: IPsecUtil.PolicyAction
1001 :type sa_id: IPsecUtil.ObjIncrement
1003 :type laddr_range: IPsecUtil.NetworkIncrement
1004 :type raddr_range: IPsecUtil.NetworkIncrement
1005 :type lport_range: string
1006 :type rport_range: string
1009 if laddr_range is None:
1010 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1011 laddr_range = NetworkIncrement(ip_network(laddr_range), 0)
1013 if raddr_range is None:
1014 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1015 raddr_range = NetworkIncrement(ip_network(raddr_range), 0)
1017 lport_range_start = 0
1018 lport_range_stop = 65535
1020 lport_range_start, lport_range_stop = lport_range.split('-')
1022 rport_range_start = 0
1023 rport_range_stop = 65535
1025 rport_range_start, rport_range_stop = rport_range.split('-')
1027 err_msg = f"Failed to add entry to Security Policy Database " \
1028 f"{spd_id} on host {node[u'host']}"
1029 with PapiSocketExecutor(node, is_async=True) as papi_exec:
1030 for _ in range(n_entries):
1031 IPsecUtil._vpp_ipsec_add_spd_entry_internal(
1032 papi_exec, spd_id, next(priority), action, inbound,
1033 next(sa_id) if sa_id is not None else sa_id,
1034 proto, next(laddr_range), next(raddr_range), lport_range,
1035 rport_range, is_ipv6
1037 papi_exec.get_replies(err_msg)
1040 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1041 """Create loopback interface and set IP address on VPP node 1 interface
1044 :param nodes: VPP nodes to create tunnel interfaces.
1045 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1046 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1047 IPv4/IPv6 address (ip2).
1048 :param if1_key: VPP node 1 interface key from topology file.
1049 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1050 interface key from topology file.
1056 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1057 # Create loopback interface on DUT1, set it to up state
1058 cmd = u"create_loopback_instance"
1064 err_msg = f"Failed to create loopback interface " \
1065 f"on host {nodes[u'DUT1'][u'host']}"
1066 papi_exec.add(cmd, **args)
1067 loop_sw_if_idx = papi_exec.get_sw_if_index(err_msg)
1068 cmd = u"sw_interface_set_flags"
1070 sw_if_index=loop_sw_if_idx,
1071 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1073 err_msg = f"Failed to set loopback interface state up " \
1074 f"on host {nodes[u'DUT1'][u'host']}"
1075 papi_exec.add(cmd, **args).get_reply(err_msg)
1076 # Set IP address on VPP node 1 interface
1077 cmd = u"sw_interface_add_del_address"
1079 sw_if_index=InterfaceUtil.get_interface_index(
1080 nodes[u"DUT1"], if1_key
1084 prefix=IPUtil.create_prefix_object(
1085 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1089 err_msg = f"Failed to set IP address on interface {if1_key} " \
1090 f"on host {nodes[u'DUT1'][u'host']}"
1091 papi_exec.add(cmd, **args).get_reply(err_msg)
1092 cmd2 = u"ip_neighbor_add_del"
1096 sw_if_index=Topology.get_interface_sw_index(
1097 nodes[u"DUT1"], if1_key
1101 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1102 if u"DUT2" in nodes.keys()
1103 else Topology.get_interface_mac(
1104 nodes[u"TG"], if2_key
1107 ip_address=tun_ips[u"ip2"].compressed
1110 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1111 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1113 return loop_sw_if_idx
1116 def _ipsec_create_tunnel_interfaces_dut1_papi(
1117 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1118 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1119 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1121 Generate random keys and return them (so DUT2 or TG can decrypt).
1123 :param nodes: VPP nodes to create tunnel interfaces.
1124 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1125 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1126 IPv4/IPv6 address (ip2).
1127 :param if1_key: VPP node 1 interface key from topology file.
1128 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1129 interface key from topology file.
1130 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1131 :param crypto_alg: The encryption algorithm name.
1132 :param integ_alg: The integrity algorithm name.
1133 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1134 first tunnel in direction node2->node1.
1135 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1136 :param addr_incr: IP / IPv6 address incremental step.
1137 :param existing_tunnels: Number of tunnel interfaces before creation.
1138 Useful mainly for reconf tests. Default 0.
1143 :type n_tunnels: int
1144 :type crypto_alg: CryptoAlg
1145 :type integ_alg: Optional[IntegAlg]
1146 :type raddr_ip2: IPv4Address or IPv6Address
1147 :type addr_incr: int
1149 :type existing_tunnels: int
1150 :returns: Generated ckeys and ikeys.
1151 :rtype: List[bytes], List[bytes]
1153 if not existing_tunnels:
1154 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1155 nodes, tun_ips, if1_key, if2_key
1158 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1159 nodes[u"DUT1"], u"loop0"
1161 with PapiSocketExecutor(nodes[u"DUT1"], is_async=True) as papi_exec:
1162 # Configure IP addresses on loop0 interface
1163 cmd = u"sw_interface_add_del_address"
1165 sw_if_index=loop_sw_if_idx,
1170 for i in range(existing_tunnels, n_tunnels):
1171 args[u"prefix"] = IPUtil.create_prefix_object(
1172 tun_ips[u"ip1"] + i * addr_incr,
1173 128 if tun_ips[u"ip1"].version == 6 else 32
1176 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1178 # Configure IPIP tunnel interfaces
1179 cmd = u"ipip_add_tunnel"
1181 instance=Constants.BITWISE_NON_ZERO,
1186 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1188 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1189 dscp=int(IpDscp.IP_API_DSCP_CS0)
1194 ipip_tunnels = [None] * existing_tunnels
1195 for i in range(existing_tunnels, n_tunnels):
1196 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1197 tun_ips[u"ip1"] + i * addr_incr
1199 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1203 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1205 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1206 f" {nodes[u'DUT1'][u'host']}"
1207 ipip_tunnels.extend(
1209 reply[u"sw_if_index"]
1210 for reply in papi_exec.get_replies(err_msg)
1211 if u"sw_if_index" in reply
1214 # Configure IPSec SAD entries
1215 ckeys = [bytes()] * existing_tunnels
1216 ikeys = [bytes()] * existing_tunnels
1217 cmd = u"ipsec_sad_entry_add"
1229 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1230 crypto_algorithm=crypto_alg.alg_int_repr,
1232 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1233 integrity_key=i_key,
1239 encap_decap_flags=int(
1240 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1242 dscp=int(IpDscp.IP_API_DSCP_CS0),
1245 udp_src_port=IPSEC_UDP_PORT_NONE,
1246 udp_dst_port=IPSEC_UDP_PORT_NONE,
1248 args = dict(entry=sad_entry)
1249 for i in range(existing_tunnels, n_tunnels):
1251 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1254 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1256 # SAD entry for outband / tx path
1257 args[u"entry"][u"sad_id"] = i
1258 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1260 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1261 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1263 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1264 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1265 args[u"entry"][u"flags"] = int(
1266 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1269 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1271 # SAD entry for inband / rx path
1272 args[u"entry"][u"sad_id"] = 100000 + i
1273 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1275 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1276 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1278 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1279 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1280 args[u"entry"][u"flags"] = int(
1281 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1282 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1285 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1287 err_msg = f"Failed to add IPsec SAD entries on host" \
1288 f" {nodes[u'DUT1'][u'host']}"
1289 papi_exec.get_replies(err_msg)
1290 # Add protection for tunnels with IPSEC
1291 cmd = u"ipsec_tunnel_protect_update"
1294 via_label=MPLS_LABEL_INVALID,
1295 obj_id=Constants.BITWISE_NON_ZERO
1297 ipsec_tunnel_protect = dict(
1305 tunnel=ipsec_tunnel_protect
1307 for i in range(existing_tunnels, n_tunnels):
1308 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1309 args[u"tunnel"][u"sa_out"] = i
1310 args[u"tunnel"][u"sa_in"] = [100000 + i]
1312 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1314 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1315 f"on host {nodes[u'DUT1'][u'host']}"
1316 papi_exec.get_replies(err_msg)
1318 # Configure unnumbered interfaces
1319 cmd = u"sw_interface_set_unnumbered"
1322 sw_if_index=InterfaceUtil.get_interface_index(
1323 nodes[u"DUT1"], if1_key
1325 unnumbered_sw_if_index=0
1327 for i in range(existing_tunnels, n_tunnels):
1328 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1330 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1333 cmd = u"sw_interface_set_flags"
1336 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1338 for i in range(existing_tunnels, n_tunnels):
1339 args[u"sw_if_index"] = ipip_tunnels[i]
1341 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1343 # Configure IP routes
1344 cmd = u"ip_route_add_del"
1350 for i in range(existing_tunnels, n_tunnels):
1351 args[u"route"] = IPUtil.compose_vpp_route_structure(
1352 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1353 prefix_len=128 if raddr_ip2.version == 6 else 32,
1354 interface=ipip_tunnels[i]
1357 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1359 err_msg = f"Failed to add IP routes on host " \
1360 f"{nodes[u'DUT1'][u'host']}"
1361 papi_exec.get_replies(err_msg)
1366 def _ipsec_create_tunnel_interfaces_dut2_papi(
1367 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1368 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1369 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1371 This method accesses keys generated by DUT1 method
1372 and does not return anything.
1374 :param nodes: VPP nodes to create tunnel interfaces.
1375 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1376 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1377 IPv4/IPv6 address (ip2).
1378 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1379 interface key from topology file.
1380 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1381 :param crypto_alg: The encryption algorithm name.
1382 :param ckeys: List of encryption keys.
1383 :param integ_alg: The integrity algorithm name.
1384 :param ikeys: List of integrity keys.
1385 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1386 :param addr_incr: IP / IPv6 address incremental step.
1387 :param existing_tunnels: Number of tunnel interfaces before creation.
1388 Useful mainly for reconf tests. Default 0.
1392 :type n_tunnels: int
1393 :type crypto_alg: CryptoAlg
1394 :type ckeys: Sequence[bytes]
1395 :type integ_alg: Optional[IntegAlg]
1396 :type ikeys: Sequence[bytes]
1397 :type addr_incr: int
1399 :type existing_tunnels: int
1401 with PapiSocketExecutor(nodes[u"DUT2"], is_async=True) as papi_exec:
1402 if not existing_tunnels:
1403 # Set IP address on VPP node 2 interface
1404 cmd = u"sw_interface_add_del_address"
1406 sw_if_index=InterfaceUtil.get_interface_index(
1407 nodes[u"DUT2"], if2_key
1411 prefix=IPUtil.create_prefix_object(
1412 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1416 err_msg = f"Failed to set IP address on interface {if2_key} " \
1417 f"on host {nodes[u'DUT2'][u'host']}"
1418 papi_exec.add(cmd, **args).get_replies(err_msg)
1419 # Configure IPIP tunnel interfaces
1420 cmd = u"ipip_add_tunnel"
1422 instance=Constants.BITWISE_NON_ZERO,
1427 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1429 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1430 dscp=int(IpDscp.IP_API_DSCP_CS0)
1435 ipip_tunnels = [None] * existing_tunnels
1436 for i in range(existing_tunnels, n_tunnels):
1437 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1440 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1441 tun_ips[u"ip1"] + i * addr_incr
1444 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1446 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1447 f" {nodes[u'DUT2'][u'host']}"
1448 ipip_tunnels.extend(
1450 reply[u"sw_if_index"]
1451 for reply in papi_exec.get_replies(err_msg)
1452 if u"sw_if_index" in reply
1455 # Configure IPSec SAD entries
1456 cmd = u"ipsec_sad_entry_add"
1468 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1469 crypto_algorithm=crypto_alg.alg_int_repr,
1471 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1472 integrity_key=i_key,
1478 encap_decap_flags=int(
1479 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1481 dscp=int(IpDscp.IP_API_DSCP_CS0),
1484 udp_src_port=IPSEC_UDP_PORT_NONE,
1485 udp_dst_port=IPSEC_UDP_PORT_NONE,
1487 args = dict(entry=sad_entry)
1488 for i in range(existing_tunnels, n_tunnels):
1490 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1493 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1495 # SAD entry for outband / tx path
1496 args[u"entry"][u"sad_id"] = 100000 + i
1497 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1499 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1500 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1502 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1503 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1504 args[u"entry"][u"flags"] = int(
1505 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1508 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1510 # SAD entry for inband / rx path
1511 args[u"entry"][u"sad_id"] = i
1512 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1514 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1515 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1517 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1518 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1519 args[u"entry"][u"flags"] = int(
1520 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1521 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1524 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1526 err_msg = f"Failed to add IPsec SAD entries on host" \
1527 f" {nodes[u'DUT2'][u'host']}"
1528 papi_exec.get_replies(err_msg)
1529 # Add protection for tunnels with IPSEC
1530 cmd = u"ipsec_tunnel_protect_update"
1533 via_label=MPLS_LABEL_INVALID,
1534 obj_id=Constants.BITWISE_NON_ZERO
1536 ipsec_tunnel_protect = dict(
1544 tunnel=ipsec_tunnel_protect
1546 for i in range(existing_tunnels, n_tunnels):
1547 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1548 args[u"tunnel"][u"sa_out"] = 100000 + i
1549 args[u"tunnel"][u"sa_in"] = [i]
1551 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1553 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1554 f"on host {nodes[u'DUT2'][u'host']}"
1555 papi_exec.get_replies(err_msg)
1557 if not existing_tunnels:
1558 # Configure IP route
1559 cmd = u"ip_route_add_del"
1560 route = IPUtil.compose_vpp_route_structure(
1561 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1562 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1564 gateway=(tun_ips[u"ip2"] - 1).compressed
1571 papi_exec.add(cmd, **args)
1572 # Configure unnumbered interfaces
1573 cmd = u"sw_interface_set_unnumbered"
1576 sw_if_index=InterfaceUtil.get_interface_index(
1577 nodes[u"DUT2"], if2_key
1579 unnumbered_sw_if_index=0
1581 for i in range(existing_tunnels, n_tunnels):
1582 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1584 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1587 cmd = u"sw_interface_set_flags"
1590 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1592 for i in range(existing_tunnels, n_tunnels):
1593 args[u"sw_if_index"] = ipip_tunnels[i]
1595 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1597 # Configure IP routes
1598 cmd = u"ip_route_add_del"
1604 for i in range(existing_tunnels, n_tunnels):
1605 args[u"route"] = IPUtil.compose_vpp_route_structure(
1606 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1607 prefix_len=128 if raddr_ip1.version == 6 else 32,
1608 interface=ipip_tunnels[i]
1611 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1613 err_msg = f"Failed to add IP routes " \
1614 f"on host {nodes[u'DUT2'][u'host']}"
1615 papi_exec.get_replies(err_msg)
1618 def vpp_ipsec_create_tunnel_interfaces(
1619 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1620 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1621 existing_tunnels=0, return_keys=False):
1622 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1624 Some deployments (e.g. devicetest) need to know the generated keys.
1625 But other deployments (e.g. scale perf test) would get spammed
1626 if we returned keys every time.
1628 :param nodes: VPP nodes to create tunnel interfaces.
1629 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1631 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1633 :param if1_key: VPP node 1 interface key from topology file.
1634 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1635 interface key from topology file.
1636 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1637 :param crypto_alg: The encryption algorithm name.
1638 :param integ_alg: The integrity algorithm name.
1639 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1640 first tunnel in direction node1->node2.
1641 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1642 first tunnel in direction node2->node1.
1643 :param raddr_range: Mask specifying range of Policy selector Remote
1644 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1645 and to 128 in case of IPv6.
1646 :param existing_tunnels: Number of tunnel interfaces before creation.
1647 Useful mainly for reconf tests. Default 0.
1648 :param return_keys: Whether generated keys should be returned.
1650 :type tun_if1_ip_addr: str
1651 :type tun_if2_ip_addr: str
1654 :type n_tunnels: int
1655 :type crypto_alg: CryptoAlg
1656 :type integ_alg: Optonal[IntegAlg]
1657 :type raddr_ip1: string
1658 :type raddr_ip2: string
1659 :type raddr_range: int
1660 :type existing_tunnels: int
1661 :type return_keys: bool
1662 :returns: Ckeys, ikeys, spi_1, spi_2.
1663 :rtype: Optional[List[bytes], List[bytes], int, int]
1665 n_tunnels = int(n_tunnels)
1666 existing_tunnels = int(existing_tunnels)
1672 ip1=ip_address(tun_if1_ip_addr),
1673 ip2=ip_address(tun_if2_ip_addr)
1675 raddr_ip1 = ip_address(raddr_ip1)
1676 raddr_ip2 = ip_address(raddr_ip2)
1677 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1678 else 1 << (32 - raddr_range)
1680 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1681 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1682 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1684 if u"DUT2" in nodes.keys():
1685 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1686 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1687 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1692 return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1696 def _create_ipsec_script_files(dut, instances):
1697 """Create script files for configuring IPsec in containers
1699 :param dut: DUT node on which to create the script files
1700 :param instances: number of containers on DUT node
1702 :type instances: int
1705 for cnf in range(0, instances):
1707 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1709 scripts.append(open(script_filename, 'w'))
1713 def _close_and_copy_ipsec_script_files(
1714 dut, nodes, instances, scripts):
1715 """Close created scripts and copy them to containers
1717 :param dut: DUT node on which to create the script files
1718 :param nodes: VPP nodes
1719 :param instances: number of containers on DUT node
1720 :param scripts: dictionary holding the script files
1723 :type instances: int
1726 for cnf in range(0, instances):
1727 scripts[cnf].close()
1729 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1731 scp_node(nodes[dut], script_filename, script_filename)
1735 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1736 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1737 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1738 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1740 :param nodes: VPP nodes to create tunnel interfaces.
1741 :param if1_ip_addr: VPP node 1 interface IP4 address.
1742 :param if2_ip_addr: VPP node 2 interface IP4 address.
1743 :param n_tunnels: Number of tunnell interfaces to create.
1744 :param crypto_alg: The encryption algorithm name.
1745 :param integ_alg: The integrity algorithm name.
1746 :param raddr_ip1: Policy selector remote IPv4 start address for the
1747 first tunnel in direction node1->node2.
1748 :param raddr_ip2: Policy selector remote IPv4 start address for the
1749 first tunnel in direction node2->node1.
1750 :param raddr_range: Mask specifying range of Policy selector Remote
1751 IPv4 addresses. Valid values are from 1 to 32.
1752 :param n_instances: Number of containers.
1754 :type if1_ip_addr: str
1755 :type if2_ip_addr: str
1756 :type n_tunnels: int
1757 :type crypto_alg: CryptoAlg
1758 :type integ_alg: Optional[IntegAlg]
1759 :type raddr_ip1: string
1760 :type raddr_ip2: string
1761 :type raddr_range: int
1762 :type n_instances: int
1766 addr_incr = 1 << (32 - raddr_range)
1768 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1769 u"DUT1", n_instances
1771 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1772 u"DUT2", n_instances
1775 for cnf in range(0, n_instances):
1776 dut1_scripts[cnf].write(
1777 u"create loopback interface\n"
1778 u"set interface state loop0 up\n\n"
1780 dut2_scripts[cnf].write(
1781 f"ip route add {if1_ip_addr}/8 via "
1782 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1785 for tnl in range(0, n_tunnels):
1786 cnf = tnl % n_instances
1788 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1792 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1796 f"integ-alg {integ_alg.alg_name} "
1797 f"local-integ-key {ikey} "
1798 f"remote-integ-key {ikey} "
1800 # Configure tunnel end point(s) on left side
1801 dut1_scripts[cnf].write(
1802 u"set interface ip address loop0 "
1803 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1804 f"create ipsec tunnel "
1805 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1806 f"local-spi {spi_1 + tnl} "
1807 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1808 f"remote-spi {spi_2 + tnl} "
1809 f"crypto-alg {crypto_alg.alg_name} "
1810 f"local-crypto-key {ckey} "
1811 f"remote-crypto-key {ckey} "
1812 f"instance {tnl // n_instances} "
1815 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1816 f"set interface state ipip{tnl // n_instances} up\n"
1817 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1818 f"via ipip{tnl // n_instances}\n\n"
1820 # Configure tunnel end point(s) on right side
1821 dut2_scripts[cnf].write(
1822 f"set ip neighbor memif1/{cnf + 1} "
1823 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1824 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1825 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1826 f"local-spi {spi_2 + tnl} "
1827 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1828 f"remote-spi {spi_1 + tnl} "
1829 f"crypto-alg {crypto_alg.alg_name} "
1830 f"local-crypto-key {ckey} "
1831 f"remote-crypto-key {ckey} "
1832 f"instance {tnl // n_instances} "
1835 f"set interface unnumbered ipip{tnl // n_instances} "
1836 f"use memif1/{cnf + 1}\n"
1837 f"set interface state ipip{tnl // n_instances} up\n"
1838 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1839 f"via ipip{tnl // n_instances}\n\n"
1842 IPsecUtil._close_and_copy_ipsec_script_files(
1843 u"DUT1", nodes, n_instances, dut1_scripts)
1844 IPsecUtil._close_and_copy_ipsec_script_files(
1845 u"DUT2", nodes, n_instances, dut2_scripts)
1848 def vpp_ipsec_add_multiple_tunnels(
1849 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1850 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range,
1851 tunnel_addr_incr=True):
1852 """Create multiple IPsec tunnels between two VPP nodes.
1854 :param nodes: VPP nodes to create tunnels.
1855 :param interface1: Interface name or sw_if_index on node 1.
1856 :param interface2: Interface name or sw_if_index on node 2.
1857 :param n_tunnels: Number of tunnels to create.
1858 :param crypto_alg: The encryption algorithm name.
1859 :param integ_alg: The integrity algorithm name.
1860 :param tunnel_ip1: Tunnel node1 IPv4 address.
1861 :param tunnel_ip2: Tunnel node2 IPv4 address.
1862 :param raddr_ip1: Policy selector remote IPv4 start address for the
1863 first tunnel in direction node1->node2.
1864 :param raddr_ip2: Policy selector remote IPv4 start address for the
1865 first tunnel in direction node2->node1.
1866 :param raddr_range: Mask specifying range of Policy selector Remote
1867 IPv4 addresses. Valid values are from 1 to 32.
1868 :param tunnel_addr_incr: Enable or disable tunnel IP address
1871 :type interface1: str or int
1872 :type interface2: str or int
1873 :type n_tunnels: int
1874 :type crypto_alg: CryptoAlg
1875 :type integ_alg: Optional[IntegAlg]
1876 :type tunnel_ip1: str
1877 :type tunnel_ip2: str
1878 :type raddr_ip1: string
1879 :type raddr_ip2: string
1880 :type raddr_range: int
1881 :type tunnel_addr_incr: bool
1891 crypto_key = gen_key(
1892 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1894 integ_key = gen_key(
1895 IPsecUtil.get_integ_alg_key_len(integ_alg)
1896 ).decode() if integ_alg else u""
1898 rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
1899 if u"DUT2" in nodes.keys() \
1900 else Topology.get_interface_mac(nodes[u"TG"], interface2)
1901 IPsecUtil.vpp_ipsec_set_ip_route(
1902 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1903 interface1, raddr_range, rmac)
1905 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1906 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1908 addr_incr = 1 << (128 - 96) if ip_address(tunnel_ip1).version == 6 \
1910 for i in range(n_tunnels//(addr_incr**2)+1):
1911 dut1_local_outbound_range = \
1912 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1913 False).with_prefixlen
1914 dut1_remote_outbound_range = \
1915 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1916 False).with_prefixlen
1918 IPsecUtil.vpp_ipsec_add_spd_entry(
1919 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1920 proto=50, laddr_range=dut1_local_outbound_range,
1921 raddr_range=dut1_remote_outbound_range
1923 IPsecUtil.vpp_ipsec_add_spd_entry(
1924 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1925 proto=50, laddr_range=dut1_remote_outbound_range,
1926 raddr_range=dut1_local_outbound_range
1929 IPsecUtil.vpp_ipsec_add_sad_entries(
1930 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1931 integ_alg, integ_key, tunnel_ip1, tunnel_ip2, tunnel_addr_incr
1934 IPsecUtil.vpp_ipsec_add_spd_entries(
1935 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1936 action=PolicyAction.PROTECT, inbound=False,
1937 sa_id=ObjIncrement(sa_id_1, 1),
1938 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
1941 IPsecUtil.vpp_ipsec_add_sad_entries(
1942 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1943 integ_alg, integ_key, tunnel_ip2, tunnel_ip1, tunnel_addr_incr
1945 IPsecUtil.vpp_ipsec_add_spd_entries(
1946 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
1947 action=PolicyAction.PROTECT, inbound=True,
1948 sa_id=ObjIncrement(sa_id_2, 1),
1949 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
1952 if u"DUT2" in nodes.keys():
1953 rmac = Topology.get_interface_mac(nodes[u"DUT1"], interface1)
1954 IPsecUtil.vpp_ipsec_set_ip_route(
1955 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1956 interface2, raddr_range, rmac)
1958 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1959 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1960 for i in range(n_tunnels//(addr_incr**2)+1):
1961 dut2_local_outbound_range = \
1962 ip_network(f"{ip_address(tunnel_ip1) + i*(addr_incr**3)}/8",
1963 False).with_prefixlen
1964 dut2_remote_outbound_range = \
1965 ip_network(f"{ip_address(tunnel_ip2) + i*(addr_incr**3)}/8",
1966 False).with_prefixlen
1968 IPsecUtil.vpp_ipsec_add_spd_entry(
1969 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1970 inbound=False, proto=50, laddr_range=dut2_remote_outbound_range,
1971 raddr_range=dut2_local_outbound_range
1973 IPsecUtil.vpp_ipsec_add_spd_entry(
1974 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
1975 inbound=True, proto=50, laddr_range=dut2_local_outbound_range,
1976 raddr_range=dut2_remote_outbound_range
1979 IPsecUtil.vpp_ipsec_add_sad_entries(
1980 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
1981 crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2,
1984 IPsecUtil.vpp_ipsec_add_spd_entries(
1985 nodes[u"DUT2"], n_tunnels, spd_id,
1986 priority=ObjIncrement(p_lo, 0),
1987 action=PolicyAction.PROTECT, inbound=True,
1988 sa_id=ObjIncrement(sa_id_1, 1),
1989 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
1992 IPsecUtil.vpp_ipsec_add_sad_entries(
1993 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
1994 crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1,
1997 IPsecUtil.vpp_ipsec_add_spd_entries(
1998 nodes[u"DUT2"], n_tunnels, spd_id,
1999 priority=ObjIncrement(p_lo, 0),
2000 action=PolicyAction.PROTECT, inbound=False,
2001 sa_id=ObjIncrement(sa_id_2, 1),
2002 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
2006 def vpp_ipsec_show_all(node):
2007 """Run "show ipsec all" debug CLI command.
2009 :param node: Node to run command on.
2012 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec all")
2015 def show_ipsec_security_association(node):
2016 """Show IPSec security association.
2018 :param node: DUT node.
2024 PapiSocketExecutor.dump_and_log(node, cmds)
2027 def vpp_ipsec_flow_enale_rss(node, proto, type, function="default"):
2028 """Ipsec flow enable rss action.
2030 :param node: DUT node.
2031 :param proto: The flow protocol.
2032 :param type: RSS type.
2033 :param function: RSS function.
2039 :returns: flow_index.
2041 # TODO: to be fixed to use full PAPI when it is ready in VPP
2042 cmd = f"test flow add src-ip any proto {proto} rss function " \
2043 f"{function} rss types {type}"
2044 stdout = PapiSocketExecutor.run_cli_cmd(node, cmd)
2045 flow_index = stdout.split()[1]
2050 def vpp_create_ipsec_flows_on_dut(
2051 node, n_flows, rx_queues, spi_start, interface):
2052 """Create mutiple ipsec flows and enable flows onto interface.
2054 :param node: DUT node.
2055 :param n_flows: Number of flows to create.
2056 :param rx_queues: NUmber of RX queues.
2057 :param spi_start: The start spi.
2058 :param interface: Name of the interface.
2062 :type rx_queues: int
2063 :type spi_start: int
2064 :type interface: str
2065 :returns: flow_index.
2068 for i in range(0, n_flows):
2069 rx_queue = i%rx_queues
2072 flow_index = FlowUtil.vpp_create_ip4_ipsec_flow(
2073 node, "ESP", spi, "redirect-to-queue", value=rx_queue)
2074 FlowUtil.vpp_flow_enable(node, interface, flow_index)