1 # Copyright (c) 2021 Cisco and/or its affiliates.
2 # Copyright (c) 2021 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.VatExecutor import VatExecutor
36 from resources.libraries.python.VPPUtil import VPPUtil
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_del_v2"
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,
451 tunnel_src=str(src_addr),
452 tunnel_dst=str(dst_addr),
454 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
456 dscp=int(IpDscp.IP_API_DSCP_CS0),
457 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
458 udp_src_port=4500, # default value in api
459 udp_dst_port=4500 # default value in api
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 """Create multiple Security Association Database entries on VPP node.
474 :param node: VPP node to add SAD entry on.
475 :param n_entries: Number of SAD entries to be created.
476 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
478 :param spi: Security Parameter Index of first SAD entry. All subsequent
479 SAD entries will have spi incremented by 1.
480 :param crypto_alg: The encryption algorithm name.
481 :param crypto_key: The encryption key string.
482 :param integ_alg: The integrity algorithm name.
483 :param integ_key: The integrity key string.
484 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
485 specified ESP transport mode is used.
486 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
487 not specified ESP transport mode is used.
492 :type crypto_alg: CryptoAlg
493 :type crypto_key: str
494 :type integ_alg: Optional[IntegAlg]
496 :type tunnel_src: str
497 :type tunnel_dst: str
499 if isinstance(crypto_key, str):
500 crypto_key = crypto_key.encode(encoding=u"utf-8")
501 if isinstance(integ_key, str):
502 integ_key = integ_key.encode(encoding=u"utf-8")
503 if tunnel_src and tunnel_dst:
504 src_addr = ip_address(tunnel_src)
505 dst_addr = ip_address(tunnel_dst)
510 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
513 if int(n_entries) > 10:
514 tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
516 with open(tmp_filename, 'w') as tmp_file:
517 for i in range(n_entries):
518 integ = f"integ-alg {integ_alg.alg_name} " \
519 f"integ-key {integ_key.hex()}" \
520 if integ_alg else u""
521 tunnel = f"tunnel src {src_addr + i * addr_incr} " \
522 f"tunnel dst {dst_addr + i * addr_incr}" \
523 if tunnel_src and tunnel_dst else u""
524 conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
525 f"crypto-alg {crypto_alg.alg_name} " \
526 f"crypto-key {crypto_key.hex()} " \
527 f"{integ} {tunnel}\n"
531 tmp_filename, node, timeout=300, json_out=False,
534 os.remove(tmp_filename)
538 length=len(crypto_key),
542 length=len(integ_key),
543 data=integ_key if integ_key else 0
546 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
547 if tunnel_src and tunnel_dst:
548 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
549 if src_addr.version == 6:
551 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
554 cmd = u"ipsec_sad_entry_add_del_v2"
555 err_msg = f"Failed to add Security Association Database entry " \
556 f"on host {node[u'host']}"
561 crypto_algorithm=crypto_alg.alg_int_repr,
563 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
566 tunnel_src=str(src_addr),
567 tunnel_dst=str(dst_addr),
569 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
571 dscp=int(IpDscp.IP_API_DSCP_CS0),
572 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
573 udp_src_port=4500, # default value in api
574 udp_dst_port=4500 # default value in api
580 with PapiSocketExecutor(node) as papi_exec:
581 for i in range(n_entries):
582 args[u"entry"][u"sad_id"] = int(sad_id) + i
583 args[u"entry"][u"spi"] = int(spi) + i
584 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
585 if tunnel_src and tunnel_dst else src_addr
586 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
587 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 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
621 else 1 << (32 - raddr_range)
623 if int(n_tunnels) > 10:
624 tmp_filename = u"/tmp/ipsec_set_ip.script"
626 with open(tmp_filename, 'w') as tmp_file:
627 if_name = Topology.get_interface_name(node, interface)
628 for i in range(n_tunnels):
629 conf = f"exec set interface ip address {if_name} " \
630 f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
631 f"exec ip route add {traffic_addr + i}/" \
632 f"{128 if traffic_addr.version == 6 else 32} " \
633 f"via {tunnel_dst + i * addr_incr} {if_name}\n"
635 conf = f"{conf}exec set ip neighbor {if_name} " \
636 f"{tunnel_dst + i * addr_incr} {dst_mac}\n"
639 VatExecutor().execute_script(
640 tmp_filename, node, timeout=300, json_out=False,
643 os.remove(tmp_filename)
646 cmd1 = u"sw_interface_add_del_address"
648 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
653 cmd2 = u"ip_route_add_del"
659 cmd3 = u"ip_neighbor_add_del"
663 sw_if_index=Topology.get_interface_sw_index(node, interface),
665 mac_address=str(dst_mac),
669 err_msg = f"Failed to configure IP addresses, IP routes and " \
670 f"IP neighbor on interface {interface} on host {node[u'host']}" \
672 else f"Failed to configure IP addresses and IP routes " \
673 f"on interface {interface} on host {node[u'host']}"
675 with PapiSocketExecutor(node) as papi_exec:
676 for i in range(n_tunnels):
677 args1[u"prefix"] = IPUtil.create_prefix_object(
678 tunnel_src + i * addr_incr, raddr_range
680 args2[u"route"] = IPUtil.compose_vpp_route_structure(
681 node, traffic_addr + i,
682 prefix_len=128 if traffic_addr.version == 6 else 32,
683 interface=interface, gateway=tunnel_dst + i * addr_incr
685 history = bool(not 1 < i < n_tunnels - 2)
686 papi_exec.add(cmd1, history=history, **args1).\
687 add(cmd2, history=history, **args2)
689 args3[u"neighbor"][u"ip_address"] = ip_address(
690 tunnel_dst + i * addr_incr
692 papi_exec.add(cmd3, history=history, **args3)
693 papi_exec.get_replies(err_msg)
696 def vpp_ipsec_add_spd(node, spd_id):
697 """Create Security Policy Database on the VPP node.
699 :param node: VPP node to add SPD on.
700 :param spd_id: SPD ID.
704 cmd = u"ipsec_spd_add_del"
705 err_msg = f"Failed to add Security Policy Database " \
706 f"on host {node[u'host']}"
711 with PapiSocketExecutor(node) as papi_exec:
712 papi_exec.add(cmd, **args).get_reply(err_msg)
715 def vpp_ipsec_spd_add_if(node, spd_id, interface):
716 """Add interface to the Security Policy Database.
718 :param node: VPP node.
719 :param spd_id: SPD ID to add interface on.
720 :param interface: Interface name or sw_if_index.
723 :type interface: str or int
725 cmd = u"ipsec_interface_add_del_spd"
726 err_msg = f"Failed to add interface {interface} to Security Policy " \
727 f"Database {spd_id} on host {node[u'host']}"
730 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
733 with PapiSocketExecutor(node) as papi_exec:
734 papi_exec.add(cmd, **args).get_reply(err_msg)
737 def vpp_ipsec_create_spds_match_nth_entry(
738 node, dir1_interface, dir2_interface, entry_amount,
739 local_addr_range, remote_addr_range, action=PolicyAction.BYPASS,
740 inbound=False, bidirectional=True):
741 """Create one matching SPD entry for inbound or outbound traffic on
742 a DUT for each traffic direction and also create entry_amount - 1
743 non-matching SPD entries. Create a Security Policy Database on each
744 outbound interface where these entries will be configured.
745 The matching SPD entry will have the lowest priority, input action and
746 will be configured to match the IP flow. The non-matching entries will
747 be the same, except with higher priority and non-matching IP flows.
749 Action Protect is currently not supported.
751 :param node: VPP node to configured the SPDs and their entries.
752 :param dir1_interface: The interface in direction 1 where the entries
754 :param dir2_interface: The interface in direction 2 where the entries
756 :param entry_amount: The number of SPD entries to configure. If
757 entry_amount == 1, no non-matching entries will be configured.
758 :param local_addr_range: Matching local address range in direction 1
759 in format IP/prefix or IP/mask. If no mask is provided, it's
760 considered to be /32.
761 :param remote_addr_range: Matching remote address range in
762 direction 1 in format IP/prefix or IP/mask. If no mask is
763 provided, it's considered to be /32.
764 :param action: Policy action.
765 :param inbound: If True policy is for inbound traffic, otherwise
767 :param bidirectional: When True, will create SPDs in both directions
768 of traffic. When False, only in one direction.
770 :type dir1_interface: Union[string, int]
771 :type dir2_interface: Union[string, int]
772 :type entry_amount: int
773 :type local_addr_range:
774 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
775 :type remote_addr_range:
776 Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
777 :type action: IPsecUtil.PolicyAction
779 :type bidirectional: bool
780 :raises NotImplemented: When the action is PolicyAction.PROTECT.
783 if action == PolicyAction.PROTECT:
784 raise NotImplemented('Policy action PROTECT is not supported.')
788 matching_priority = 1
790 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir1)
791 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir1, dir1_interface)
792 # matching entry direction 1
793 IPsecUtil.vpp_ipsec_add_spd_entry(
794 node, spd_id_dir1, matching_priority, action,
795 inbound=inbound, laddr_range=local_addr_range,
796 raddr_range=remote_addr_range
800 IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir2)
801 IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir2, dir2_interface)
803 # matching entry direction 2, the address ranges are switched
804 IPsecUtil.vpp_ipsec_add_spd_entry(
805 node, spd_id_dir2, matching_priority, action,
806 inbound=inbound, laddr_range=remote_addr_range,
807 raddr_range=local_addr_range
810 # non-matching entries
811 no_match_entry_amount = entry_amount - 1
812 if no_match_entry_amount > 0:
813 # create a NetworkIncrement representation of the network,
814 # then skip the matching network
815 no_match_local_addr_range = NetworkIncrement(
816 ip_network(local_addr_range), 1
818 next(no_match_local_addr_range)
820 no_match_remote_addr_range = NetworkIncrement(
821 ip_network(remote_addr_range), 1
823 next(no_match_remote_addr_range)
825 # non-matching entries direction 1
826 IPsecUtil.vpp_ipsec_add_spd_entries(
827 node, no_match_entry_amount, spd_id_dir1,
828 ObjIncrement(matching_priority + 1, 1), action,
829 inbound=inbound, laddr_range=no_match_local_addr_range,
830 raddr_range=no_match_remote_addr_range
834 # reset the networks so that we're using a unified config
835 # the address ranges are switched
836 no_match_remote_addr_range = NetworkIncrement(
837 ip_network(local_addr_range), 1
839 next(no_match_remote_addr_range)
841 no_match_local_addr_range = NetworkIncrement(
842 ip_network(remote_addr_range), 1
844 next(no_match_local_addr_range)
845 # non-matching entries direction 2
846 IPsecUtil.vpp_ipsec_add_spd_entries(
847 node, no_match_entry_amount, spd_id_dir2,
848 ObjIncrement(matching_priority + 1, 1), action,
849 inbound=inbound, laddr_range=no_match_local_addr_range,
850 raddr_range=no_match_remote_addr_range
853 IPsecUtil.vpp_ipsec_show_all(node)
856 def vpp_ipsec_add_spd_entry(
857 node, spd_id, priority, action, inbound=True, sa_id=None,
858 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
859 rport_range=None, is_ipv6=False):
860 """Create Security Policy Database entry on the VPP node.
862 :param node: VPP node to add SPD entry on.
863 :param spd_id: SPD ID to add entry on.
864 :param priority: SPD entry priority, higher number = higher priority.
865 :param action: Policy action.
866 :param inbound: If True policy is for inbound traffic, otherwise
868 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
869 :param proto: Policy selector next layer protocol number.
870 :param laddr_range: Policy selector local IPv4 or IPv6 address range
871 in format IP/prefix or IP/mask. If no mask is provided,
872 it's considered to be /32.
873 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
874 in format IP/prefix or IP/mask. If no mask is provided,
875 it's considered to be /32.
876 :param lport_range: Policy selector local TCP/UDP port range in format
877 <port_start>-<port_end>.
878 :param rport_range: Policy selector remote TCP/UDP port range in format
879 <port_start>-<port_end>.
880 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
881 not defined so it will default to address ::/0, otherwise False.
885 :type action: IPsecUtil.PolicyAction
889 :type laddr_range: string
890 :type raddr_range: string
891 :type lport_range: string
892 :type rport_range: string
895 if laddr_range is None:
896 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
898 if raddr_range is None:
899 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
901 local_net = ip_network(laddr_range, strict=False)
902 remote_net = ip_network(raddr_range, strict=False)
904 cmd = u"ipsec_spd_entry_add_del"
905 err_msg = f"Failed to add entry to Security Policy Database " \
906 f"{spd_id} on host {node[u'host']}"
910 priority=int(priority),
911 is_outbound=not inbound,
912 sa_id=int(sa_id) if sa_id else 0,
914 protocol=int(proto) if proto else 0,
915 remote_address_start=IPAddress.create_ip_address_object(
916 remote_net.network_address
918 remote_address_stop=IPAddress.create_ip_address_object(
919 remote_net.broadcast_address
921 local_address_start=IPAddress.create_ip_address_object(
922 local_net.network_address
924 local_address_stop=IPAddress.create_ip_address_object(
925 local_net.broadcast_address
927 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
929 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
931 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
933 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
940 with PapiSocketExecutor(node) as papi_exec:
941 papi_exec.add(cmd, **args).get_reply(err_msg)
944 def vpp_ipsec_add_spd_entries(
945 node, n_entries, spd_id, priority, action, inbound, sa_id=None,
946 proto=None, laddr_range=None, raddr_range=None, lport_range=None,
947 rport_range=None, is_ipv6=False):
948 """Create multiple Security Policy Database entries on the VPP node.
950 :param node: VPP node to add SPD entries on.
951 :param n_entries: Number of SPD entries to be added.
952 :param spd_id: SPD ID to add entries on.
953 :param priority: SPD entries priority, higher number = higher priority.
954 :param action: Policy action.
955 :param inbound: If True policy is for inbound traffic, otherwise
957 :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
958 :param proto: Policy selector next layer protocol number.
959 :param laddr_range: Policy selector local IPv4 or IPv6 address range
960 in format IP/prefix or IP/mask. If no mask is provided,
961 it's considered to be /32.
962 :param raddr_range: Policy selector remote IPv4 or IPv6 address range
963 in format IP/prefix or IP/mask. If no mask is provided,
964 it's considered to be /32.
965 :param lport_range: Policy selector local TCP/UDP port range in format
966 <port_start>-<port_end>.
967 :param rport_range: Policy selector remote TCP/UDP port range in format
968 <port_start>-<port_end>.
969 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
970 not defined so it will default to address ::/0, otherwise False.
974 :type priority: IPsecUtil.ObjIncrement
975 :type action: IPsecUtil.PolicyAction
977 :type sa_id: IPsecUtil.ObjIncrement
979 :type laddr_range: IPsecUtil.NetworkIncrement
980 :type raddr_range: IPsecUtil.NetworkIncrement
981 :type lport_range: string
982 :type rport_range: string
985 if laddr_range is None:
986 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
987 laddr_range = NetworkIncrement(ip_network(laddr_range), 0)
989 if raddr_range is None:
990 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
991 raddr_range = NetworkIncrement(ip_network(raddr_range), 0)
993 lport_range_start = 0
994 lport_range_stop = 65535
996 lport_range_start, lport_range_stop = lport_range.split('-')
998 rport_range_start = 0
999 rport_range_stop = 65535
1001 rport_range_start, rport_range_stop = rport_range.split('-')
1003 if int(n_entries) > 10:
1004 tmp_filename = f"/tmp/ipsec_spd_{spd_id}_add_del_entry.script"
1006 with open(tmp_filename, 'w') as tmp_file:
1007 for i in range(n_entries):
1008 direction = u'inbound' if inbound else u'outbound'
1009 sa = f' sa {sa_id.inc_fmt()}' if sa_id is not None else ''
1010 protocol = f' protocol {protocol}' if proto else ''
1011 local_port_range = f' local-port-range ' \
1012 f'{lport_range_start} - {lport_range_stop}' \
1013 if lport_range else ''
1014 remote_port_range = f' remote-port-range ' \
1015 f'{rport_range_start} - {rport_range_stop}' \
1016 if rport_range else ''
1018 spd_cfg = f"exec ipsec policy add spd {spd_id} " \
1019 f"priority {priority.inc_fmt()} {direction}" \
1020 f"{protocol} action {action}{sa} " \
1021 f"local-ip-range {laddr_range.inc_fmt()} " \
1022 f"remote-ip-range {raddr_range.inc_fmt()}" \
1023 f"{local_port_range}{remote_port_range}\n"
1025 tmp_file.write(spd_cfg)
1027 VatExecutor().execute_script(
1028 tmp_filename, node, timeout=300, json_out=False,
1029 copy_on_execute=True
1031 os.remove(tmp_filename)
1034 for i in range(n_entries):
1035 IPsecUtil.vpp_ipsec_add_spd_entry(
1036 node, spd_id, next(priority), action, inbound,
1037 next(sa_id) if sa_id is not None else sa_id,
1038 proto, next(laddr_range), next(raddr_range), lport_range,
1039 rport_range, is_ipv6
1043 def _ipsec_create_tunnel_interfaces_dut1_vat(
1044 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1045 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1046 """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
1048 Generate random keys and return them (so DUT2 or TG can decrypt).
1050 :param nodes: VPP nodes to create tunnel interfaces.
1051 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1052 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1053 IPv4/IPv6 address (ip2).
1054 :param if1_key: VPP node 1 interface key from topology file.
1055 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1056 interface key from topology file.
1057 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1058 :param crypto_alg: The encryption algorithm name.
1059 :param integ_alg: The integrity algorithm name.
1060 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1061 first tunnel in direction node2->node1.
1062 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1063 :param addr_incr: IP / IPv6 address incremental step.
1064 :param existing_tunnels: Number of tunnel interfaces before creation.
1065 Useful mainly for reconf tests. Default 0.
1070 :type n_tunnels: int
1071 :type crypto_alg: CryptoAlg
1072 :type integ_alg: Optional[IntegAlg]
1073 :type raddr_ip2: IPv4Address or IPv6Address
1074 :type addr_incr: int
1076 :type existing_tunnels: int
1077 :returns: Generated ckeys and ikeys.
1078 :rtype: List[bytes], List[bytes]
1080 tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
1081 if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
1083 ckeys = [bytes()] * existing_tunnels
1084 ikeys = [bytes()] * existing_tunnels
1087 with open(tmp_fn1, u"w") as tmp_f1:
1088 rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
1089 if u"DUT2" in nodes.keys() \
1090 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
1091 if not existing_tunnels:
1093 f"exec create loopback interface\n"
1094 f"exec set interface state loop0 up\n"
1095 f"exec set interface ip address {if1_n} "
1096 f"{tun_ips[u'ip2'] - 1}/"
1097 f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
1098 f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
1101 for i in range(existing_tunnels, n_tunnels):
1103 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1106 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1109 integ = f"integ-alg {integ_alg.alg_name} " \
1110 f"integ-key {ikeys[i].hex()} "
1114 f"exec set interface ip address loop0 "
1115 f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
1116 f"exec create ipip tunnel "
1117 f"src {tun_ips[u'ip1'] + i * addr_incr} "
1118 f"dst {tun_ips[u'ip2']} "
1120 f"exec ipsec sa add {i} "
1121 f"spi {spi_d[u'spi_1'] + i} "
1122 f"crypto-alg {crypto_alg.alg_name} "
1123 f"crypto-key {ckeys[i].hex()} "
1126 f"exec ipsec sa add {100000 + i} "
1127 f"spi {spi_d[u'spi_2'] + i} "
1128 f"crypto-alg {crypto_alg.alg_name} "
1129 f"crypto-key {ckeys[i].hex()} "
1132 f"exec ipsec tunnel protect ipip{i} "
1134 f"sa-in {100000 + i} "
1138 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
1139 copy_on_execute=True,
1140 history=bool(n_tunnels < 100)
1144 with open(tmp_fn1, 'w') as tmp_f1:
1145 for i in range(existing_tunnels, n_tunnels):
1147 f"exec set interface unnumbered ipip{i} use {if1_n}\n"
1148 f"exec set interface state ipip{i} up\n"
1149 f"exec ip route add "
1150 f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
1154 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
1155 copy_on_execute=True,
1156 history=bool(n_tunnels < 100)
1163 def _ipsec_create_tunnel_interfaces_dut2_vat(
1164 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1165 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1166 """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
1168 This method accesses keys generated by DUT1 method
1169 and does not return anything.
1171 :param nodes: VPP nodes to create tunnel interfaces.
1172 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1173 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1174 IPv4/IPv6 address (ip2).
1175 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1176 interface key from topology file.
1177 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1178 :param crypto_alg: The encryption algorithm name.
1179 :param ckeys: List of encryption keys.
1180 :param integ_alg: The integrity algorithm name.
1181 :param ikeys: List of integrity keys.
1182 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1183 :param addr_incr: IP / IPv6 address incremental step.
1184 :param existing_tunnels: Number of tunnel interfaces before creation.
1185 Useful mainly for reconf tests. Default 0.
1189 :type n_tunnels: int
1190 :type crypto_alg: CryptoAlg
1191 :type ckeys: Sequence[bytes]
1192 :type integ_alg: Optional[IntegAlg]
1193 :type ikeys: Sequence[bytes]
1194 :type addr_incr: int
1196 :type existing_tunnels: int
1198 tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
1199 if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
1202 with open(tmp_fn2, 'w') as tmp_f2:
1203 if not existing_tunnels:
1205 f"exec set interface ip address {if2_n}"
1206 f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
1208 for i in range(existing_tunnels, n_tunnels):
1210 integ = f"integ-alg {integ_alg.alg_name} " \
1211 f"integ-key {ikeys[i].hex()} "
1215 f"exec create ipip tunnel "
1216 f"src {tun_ips[u'ip2']} "
1217 f"dst {tun_ips[u'ip1'] + i * addr_incr} "
1219 f"exec ipsec sa add {100000 + i} "
1220 f"spi {spi_d[u'spi_2'] + i} "
1221 f"crypto-alg {crypto_alg.alg_name} "
1222 f"crypto-key {ckeys[i].hex()} "
1225 f"exec ipsec sa add {i} "
1226 f"spi {spi_d[u'spi_1'] + i} "
1227 f"crypto-alg {crypto_alg.alg_name} "
1228 f"crypto-key {ckeys[i].hex()} "
1231 f"exec ipsec tunnel protect ipip{i} "
1232 f"sa-out {100000 + i} "
1237 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1238 copy_on_execute=True,
1239 history=bool(n_tunnels < 100)
1243 with open(tmp_fn2, 'w') as tmp_f2:
1244 if not existing_tunnels:
1246 f"exec ip route add {tun_ips[u'ip1']}/8 "
1247 f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
1249 for i in range(existing_tunnels, n_tunnels):
1251 f"exec set interface unnumbered ipip{i} use {if2_n}\n"
1252 f"exec set interface state ipip{i} up\n"
1253 f"exec ip route add "
1254 f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
1258 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1259 copy_on_execute=True,
1260 history=bool(n_tunnels < 100)
1265 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1266 """Create loopback interface and set IP address on VPP node 1 interface
1269 :param nodes: VPP nodes to create tunnel interfaces.
1270 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1271 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1272 IPv4/IPv6 address (ip2).
1273 :param if1_key: VPP node 1 interface key from topology file.
1274 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1275 interface key from topology file.
1281 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1282 # Create loopback interface on DUT1, set it to up state
1283 cmd = u"create_loopback_instance"
1289 err_msg = f"Failed to create loopback interface " \
1290 f"on host {nodes[u'DUT1'][u'host']}"
1291 loop_sw_if_idx = papi_exec.add(cmd, **args). \
1292 get_sw_if_index(err_msg)
1293 cmd = u"sw_interface_set_flags"
1295 sw_if_index=loop_sw_if_idx,
1296 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1298 err_msg = f"Failed to set loopback interface state up " \
1299 f"on host {nodes[u'DUT1'][u'host']}"
1300 papi_exec.add(cmd, **args).get_reply(err_msg)
1301 # Set IP address on VPP node 1 interface
1302 cmd = u"sw_interface_add_del_address"
1304 sw_if_index=InterfaceUtil.get_interface_index(
1305 nodes[u"DUT1"], if1_key
1309 prefix=IPUtil.create_prefix_object(
1310 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1314 err_msg = f"Failed to set IP address on interface {if1_key} " \
1315 f"on host {nodes[u'DUT1'][u'host']}"
1316 papi_exec.add(cmd, **args).get_reply(err_msg)
1317 cmd2 = u"ip_neighbor_add_del"
1321 sw_if_index=Topology.get_interface_sw_index(
1322 nodes[u"DUT1"], if1_key
1326 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1327 if u"DUT2" in nodes.keys()
1328 else Topology.get_interface_mac(
1329 nodes[u"TG"], if2_key
1332 ip_address=tun_ips[u"ip2"].compressed
1335 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1336 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1338 return loop_sw_if_idx
1341 def _ipsec_create_tunnel_interfaces_dut1_papi(
1342 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1343 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1344 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1346 Generate random keys and return them (so DUT2 or TG can decrypt).
1348 :param nodes: VPP nodes to create tunnel interfaces.
1349 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1350 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1351 IPv4/IPv6 address (ip2).
1352 :param if1_key: VPP node 1 interface key from topology file.
1353 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1354 interface key from topology file.
1355 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1356 :param crypto_alg: The encryption algorithm name.
1357 :param integ_alg: The integrity algorithm name.
1358 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1359 first tunnel in direction node2->node1.
1360 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1361 :param addr_incr: IP / IPv6 address incremental step.
1362 :param existing_tunnels: Number of tunnel interfaces before creation.
1363 Useful mainly for reconf tests. Default 0.
1368 :type n_tunnels: int
1369 :type crypto_alg: CryptoAlg
1370 :type integ_alg: Optional[IntegAlg]
1371 :type raddr_ip2: IPv4Address or IPv6Address
1372 :type addr_incr: int
1374 :type existing_tunnels: int
1375 :returns: Generated ckeys and ikeys.
1376 :rtype: List[bytes], List[bytes]
1378 if not existing_tunnels:
1379 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1380 nodes, tun_ips, if1_key, if2_key
1383 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1384 nodes[u"DUT1"], u"loop0"
1386 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1387 # Configure IP addresses on loop0 interface
1388 cmd = u"sw_interface_add_del_address"
1390 sw_if_index=loop_sw_if_idx,
1395 for i in range(existing_tunnels, n_tunnels):
1396 args[u"prefix"] = IPUtil.create_prefix_object(
1397 tun_ips[u"ip1"] + i * addr_incr,
1398 128 if tun_ips[u"ip1"].version == 6 else 32
1401 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1403 # Configure IPIP tunnel interfaces
1404 cmd = u"ipip_add_tunnel"
1406 instance=Constants.BITWISE_NON_ZERO,
1411 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1413 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1414 dscp=int(IpDscp.IP_API_DSCP_CS0)
1419 ipip_tunnels = [None] * existing_tunnels
1420 for i in range(existing_tunnels, n_tunnels):
1421 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1422 tun_ips[u"ip1"] + i * addr_incr
1424 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1428 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1430 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1431 f" {nodes[u'DUT1'][u'host']}"
1432 ipip_tunnels.extend(
1434 reply[u"sw_if_index"]
1435 for reply in papi_exec.get_replies(err_msg)
1436 if u"sw_if_index" in reply
1439 # Configure IPSec SAD entries
1440 ckeys = [bytes()] * existing_tunnels
1441 ikeys = [bytes()] * existing_tunnels
1442 cmd = u"ipsec_sad_entry_add_del_v2"
1454 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1455 crypto_algorithm=crypto_alg.alg_int_repr,
1457 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1458 integrity_key=i_key,
1463 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1465 dscp=int(IpDscp.IP_API_DSCP_CS0),
1468 udp_src_port=IPSEC_UDP_PORT_NONE,
1469 udp_dst_port=IPSEC_UDP_PORT_NONE
1475 for i in range(existing_tunnels, n_tunnels):
1477 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1480 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1482 # SAD entry for outband / tx path
1483 args[u"entry"][u"sad_id"] = i
1484 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1486 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1487 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1489 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1490 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1491 args[u"entry"][u"flags"] = int(
1492 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1495 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1497 # SAD entry for inband / rx path
1498 args[u"entry"][u"sad_id"] = 100000 + i
1499 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1501 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1502 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1504 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1505 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1506 args[u"entry"][u"flags"] = int(
1507 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1508 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1511 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1513 err_msg = f"Failed to add IPsec SAD entries on host" \
1514 f" {nodes[u'DUT1'][u'host']}"
1515 papi_exec.get_replies(err_msg)
1516 # Add protection for tunnels with IPSEC
1517 cmd = u"ipsec_tunnel_protect_update"
1520 via_label=MPLS_LABEL_INVALID,
1521 obj_id=Constants.BITWISE_NON_ZERO
1523 ipsec_tunnel_protect = dict(
1531 tunnel=ipsec_tunnel_protect
1533 for i in range(existing_tunnels, n_tunnels):
1534 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1535 args[u"tunnel"][u"sa_out"] = i
1536 args[u"tunnel"][u"sa_in"] = [100000 + i]
1538 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1540 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1541 f"on host {nodes[u'DUT1'][u'host']}"
1542 papi_exec.get_replies(err_msg)
1544 # Configure unnumbered interfaces
1545 cmd = u"sw_interface_set_unnumbered"
1548 sw_if_index=InterfaceUtil.get_interface_index(
1549 nodes[u"DUT1"], if1_key
1551 unnumbered_sw_if_index=0
1553 for i in range(existing_tunnels, n_tunnels):
1554 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1556 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1559 cmd = u"sw_interface_set_flags"
1562 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1564 for i in range(existing_tunnels, n_tunnels):
1565 args[u"sw_if_index"] = ipip_tunnels[i]
1567 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1569 # Configure IP routes
1570 cmd = u"ip_route_add_del"
1576 for i in range(existing_tunnels, n_tunnels):
1577 args[u"route"] = IPUtil.compose_vpp_route_structure(
1578 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1579 prefix_len=128 if raddr_ip2.version == 6 else 32,
1580 interface=ipip_tunnels[i]
1583 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1585 err_msg = f"Failed to add IP routes on host " \
1586 f"{nodes[u'DUT1'][u'host']}"
1587 papi_exec.get_replies(err_msg)
1592 def _ipsec_create_tunnel_interfaces_dut2_papi(
1593 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1594 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1595 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1597 This method accesses keys generated by DUT1 method
1598 and does not return anything.
1600 :param nodes: VPP nodes to create tunnel interfaces.
1601 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1602 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1603 IPv4/IPv6 address (ip2).
1604 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1605 interface key from topology file.
1606 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1607 :param crypto_alg: The encryption algorithm name.
1608 :param ckeys: List of encryption keys.
1609 :param integ_alg: The integrity algorithm name.
1610 :param ikeys: List of integrity keys.
1611 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1612 :param addr_incr: IP / IPv6 address incremental step.
1613 :param existing_tunnels: Number of tunnel interfaces before creation.
1614 Useful mainly for reconf tests. Default 0.
1618 :type n_tunnels: int
1619 :type crypto_alg: CryptoAlg
1620 :type ckeys: Sequence[bytes]
1621 :type integ_alg: Optional[IntegAlg]
1622 :type ikeys: Sequence[bytes]
1623 :type addr_incr: int
1625 :type existing_tunnels: int
1627 with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1628 if not existing_tunnels:
1629 # Set IP address on VPP node 2 interface
1630 cmd = u"sw_interface_add_del_address"
1632 sw_if_index=InterfaceUtil.get_interface_index(
1633 nodes[u"DUT2"], if2_key
1637 prefix=IPUtil.create_prefix_object(
1638 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1642 err_msg = f"Failed to set IP address on interface {if2_key} " \
1643 f"on host {nodes[u'DUT2'][u'host']}"
1644 papi_exec.add(cmd, **args).get_reply(err_msg)
1645 # Configure IPIP tunnel interfaces
1646 cmd = u"ipip_add_tunnel"
1648 instance=Constants.BITWISE_NON_ZERO,
1653 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1655 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1656 dscp=int(IpDscp.IP_API_DSCP_CS0)
1661 ipip_tunnels = [None] * existing_tunnels
1662 for i in range(existing_tunnels, n_tunnels):
1663 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1666 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1667 tun_ips[u"ip1"] + i * addr_incr
1670 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1672 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1673 f" {nodes[u'DUT2'][u'host']}"
1674 ipip_tunnels.extend(
1676 reply[u"sw_if_index"]
1677 for reply in papi_exec.get_replies(err_msg)
1678 if u"sw_if_index" in reply
1681 # Configure IPSec SAD entries
1682 cmd = u"ipsec_sad_entry_add_del_v2"
1694 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1696 crypto_algorithm=crypto_alg.alg_int_repr,
1698 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1699 integrity_key=i_key,
1705 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1707 dscp=int(IpDscp.IP_API_DSCP_CS0),
1710 udp_src_port=IPSEC_UDP_PORT_NONE,
1711 udp_dst_port=IPSEC_UDP_PORT_NONE
1717 for i in range(existing_tunnels, n_tunnels):
1719 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1722 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1724 # SAD entry for outband / tx path
1725 args[u"entry"][u"sad_id"] = 100000 + i
1726 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1728 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1729 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1731 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1732 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1733 args[u"entry"][u"flags"] = int(
1734 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1737 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1739 # SAD entry for inband / rx path
1740 args[u"entry"][u"sad_id"] = i
1741 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1743 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1744 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1746 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1747 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1748 args[u"entry"][u"flags"] = int(
1749 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1750 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1753 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1755 err_msg = f"Failed to add IPsec SAD entries on host" \
1756 f" {nodes[u'DUT2'][u'host']}"
1757 papi_exec.get_replies(err_msg)
1758 # Add protection for tunnels with IPSEC
1759 cmd = u"ipsec_tunnel_protect_update"
1762 via_label=MPLS_LABEL_INVALID,
1763 obj_id=Constants.BITWISE_NON_ZERO
1765 ipsec_tunnel_protect = dict(
1773 tunnel=ipsec_tunnel_protect
1775 for i in range(existing_tunnels, n_tunnels):
1776 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1777 args[u"tunnel"][u"sa_out"] = 100000 + i
1778 args[u"tunnel"][u"sa_in"] = [i]
1780 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1782 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1783 f"on host {nodes[u'DUT2'][u'host']}"
1784 papi_exec.get_replies(err_msg)
1786 if not existing_tunnels:
1787 # Configure IP route
1788 cmd = u"ip_route_add_del"
1789 route = IPUtil.compose_vpp_route_structure(
1790 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1791 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1793 gateway=(tun_ips[u"ip2"] - 1).compressed
1800 papi_exec.add(cmd, **args)
1801 # Configure unnumbered interfaces
1802 cmd = u"sw_interface_set_unnumbered"
1805 sw_if_index=InterfaceUtil.get_interface_index(
1806 nodes[u"DUT2"], if2_key
1808 unnumbered_sw_if_index=0
1810 for i in range(existing_tunnels, n_tunnels):
1811 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1813 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1816 cmd = u"sw_interface_set_flags"
1819 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1821 for i in range(existing_tunnels, n_tunnels):
1822 args[u"sw_if_index"] = ipip_tunnels[i]
1824 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1826 # Configure IP routes
1827 cmd = u"ip_route_add_del"
1833 for i in range(existing_tunnels, n_tunnels):
1834 args[u"route"] = IPUtil.compose_vpp_route_structure(
1835 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1836 prefix_len=128 if raddr_ip1.version == 6 else 32,
1837 interface=ipip_tunnels[i]
1840 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1842 err_msg = f"Failed to add IP routes " \
1843 f"on host {nodes[u'DUT2'][u'host']}"
1844 papi_exec.get_replies(err_msg)
1847 def vpp_ipsec_create_tunnel_interfaces(
1848 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1849 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1850 existing_tunnels=0, return_keys=False):
1851 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1853 Some deployments (e.g. devicetest) need to know the generated keys.
1854 But other deployments (e.g. scale perf test) would get spammed
1855 if we returned keys every time.
1857 :param nodes: VPP nodes to create tunnel interfaces.
1858 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1860 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1862 :param if1_key: VPP node 1 interface key from topology file.
1863 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1864 interface key from topology file.
1865 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1866 :param crypto_alg: The encryption algorithm name.
1867 :param integ_alg: The integrity algorithm name.
1868 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1869 first tunnel in direction node1->node2.
1870 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1871 first tunnel in direction node2->node1.
1872 :param raddr_range: Mask specifying range of Policy selector Remote
1873 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1874 and to 128 in case of IPv6.
1875 :param existing_tunnels: Number of tunnel interfaces before creation.
1876 Useful mainly for reconf tests. Default 0.
1877 :param return_keys: Whether generated keys should be returned.
1879 :type tun_if1_ip_addr: str
1880 :type tun_if2_ip_addr: str
1883 :type n_tunnels: int
1884 :type crypto_alg: CryptoAlg
1885 :type integ_alg: Optonal[IntegAlg]
1886 :type raddr_ip1: string
1887 :type raddr_ip2: string
1888 :type raddr_range: int
1889 :type existing_tunnels: int
1890 :type return_keys: bool
1891 :returns: Ckeys, ikeys, spi_1, spi_2.
1892 :rtype: Optional[List[bytes], List[bytes], int, int]
1894 n_tunnels = int(n_tunnels)
1895 existing_tunnels = int(existing_tunnels)
1901 ip1=ip_address(tun_if1_ip_addr),
1902 ip2=ip_address(tun_if2_ip_addr)
1904 raddr_ip1 = ip_address(raddr_ip1)
1905 raddr_ip2 = ip_address(raddr_ip2)
1906 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1907 else 1 << (32 - raddr_range)
1909 if n_tunnels - existing_tunnels > 10:
1910 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1911 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1912 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1914 if u"DUT2" in nodes.keys():
1915 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1916 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1917 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1921 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1922 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1923 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1925 if u"DUT2" in nodes.keys():
1926 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1927 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1928 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1933 return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1937 def _create_ipsec_script_files(dut, instances):
1938 """Create script files for configuring IPsec in containers
1940 :param dut: DUT node on which to create the script files
1941 :param instances: number of containers on DUT node
1943 :type instances: int
1946 for cnf in range(0, instances):
1948 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1950 scripts.append(open(script_filename, 'w'))
1954 def _close_and_copy_ipsec_script_files(
1955 dut, nodes, instances, scripts):
1956 """Close created scripts and copy them to containers
1958 :param dut: DUT node on which to create the script files
1959 :param nodes: VPP nodes
1960 :param instances: number of containers on DUT node
1961 :param scripts: dictionary holding the script files
1964 :type instances: int
1967 for cnf in range(0, instances):
1968 scripts[cnf].close()
1970 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1972 scp_node(nodes[dut], script_filename, script_filename)
1976 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1977 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1978 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1979 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1981 :param nodes: VPP nodes to create tunnel interfaces.
1982 :param if1_ip_addr: VPP node 1 interface IP4 address.
1983 :param if2_ip_addr: VPP node 2 interface IP4 address.
1984 :param n_tunnels: Number of tunnell interfaces to create.
1985 :param crypto_alg: The encryption algorithm name.
1986 :param integ_alg: The integrity algorithm name.
1987 :param raddr_ip1: Policy selector remote IPv4 start address for the
1988 first tunnel in direction node1->node2.
1989 :param raddr_ip2: Policy selector remote IPv4 start address for the
1990 first tunnel in direction node2->node1.
1991 :param raddr_range: Mask specifying range of Policy selector Remote
1992 IPv4 addresses. Valid values are from 1 to 32.
1993 :param n_instances: Number of containers.
1995 :type if1_ip_addr: str
1996 :type if2_ip_addr: str
1997 :type n_tunnels: int
1998 :type crypto_alg: CryptoAlg
1999 :type integ_alg: Optional[IntegAlg]
2000 :type raddr_ip1: string
2001 :type raddr_ip2: string
2002 :type raddr_range: int
2003 :type n_instances: int
2007 addr_incr = 1 << (32 - raddr_range)
2009 dut1_scripts = IPsecUtil._create_ipsec_script_files(
2010 u"DUT1", n_instances
2012 dut2_scripts = IPsecUtil._create_ipsec_script_files(
2013 u"DUT2", n_instances
2016 for cnf in range(0, n_instances):
2017 dut1_scripts[cnf].write(
2018 u"create loopback interface\n"
2019 u"set interface state loop0 up\n\n"
2021 dut2_scripts[cnf].write(
2022 f"ip route add {if1_ip_addr}/8 via "
2023 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
2026 for tnl in range(0, n_tunnels):
2027 cnf = tnl % n_instances
2029 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
2033 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
2037 f"integ-alg {integ_alg.alg_name} "
2038 f"local-integ-key {ikey} "
2039 f"remote-integ-key {ikey} "
2041 # Configure tunnel end point(s) on left side
2042 dut1_scripts[cnf].write(
2043 u"set interface ip address loop0 "
2044 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
2045 f"create ipsec tunnel "
2046 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
2047 f"local-spi {spi_1 + tnl} "
2048 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
2049 f"remote-spi {spi_2 + tnl} "
2050 f"crypto-alg {crypto_alg.alg_name} "
2051 f"local-crypto-key {ckey} "
2052 f"remote-crypto-key {ckey} "
2053 f"instance {tnl // n_instances} "
2056 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
2057 f"set interface state ipip{tnl // n_instances} up\n"
2058 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
2059 f"via ipip{tnl // n_instances}\n\n"
2061 # Configure tunnel end point(s) on right side
2062 dut2_scripts[cnf].write(
2063 f"set ip neighbor memif1/{cnf + 1} "
2064 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
2065 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
2066 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
2067 f"local-spi {spi_2 + tnl} "
2068 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
2069 f"remote-spi {spi_1 + tnl} "
2070 f"crypto-alg {crypto_alg.alg_name} "
2071 f"local-crypto-key {ckey} "
2072 f"remote-crypto-key {ckey} "
2073 f"instance {tnl // n_instances} "
2076 f"set interface unnumbered ipip{tnl // n_instances} "
2077 f"use memif1/{cnf + 1}\n"
2078 f"set interface state ipip{tnl // n_instances} up\n"
2079 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
2080 f"via ipip{tnl // n_instances}\n\n"
2083 IPsecUtil._close_and_copy_ipsec_script_files(
2084 u"DUT1", nodes, n_instances, dut1_scripts)
2085 IPsecUtil._close_and_copy_ipsec_script_files(
2086 u"DUT2", nodes, n_instances, dut2_scripts)
2089 def vpp_ipsec_add_multiple_tunnels(
2090 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
2091 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
2092 """Create multiple IPsec tunnels between two VPP nodes.
2094 :param nodes: VPP nodes to create tunnels.
2095 :param interface1: Interface name or sw_if_index on node 1.
2096 :param interface2: Interface name or sw_if_index on node 2.
2097 :param n_tunnels: Number of tunnels to create.
2098 :param crypto_alg: The encryption algorithm name.
2099 :param integ_alg: The integrity algorithm name.
2100 :param tunnel_ip1: Tunnel node1 IPv4 address.
2101 :param tunnel_ip2: Tunnel node2 IPv4 address.
2102 :param raddr_ip1: Policy selector remote IPv4 start address for the
2103 first tunnel in direction node1->node2.
2104 :param raddr_ip2: Policy selector remote IPv4 start address for the
2105 first tunnel in direction node2->node1.
2106 :param raddr_range: Mask specifying range of Policy selector Remote
2107 IPv4 addresses. Valid values are from 1 to 32.
2109 :type interface1: str or int
2110 :type interface2: str or int
2111 :type n_tunnels: int
2112 :type crypto_alg: CryptoAlg
2113 :type integ_alg: Optional[IntegAlg]
2114 :type tunnel_ip1: str
2115 :type tunnel_ip2: str
2116 :type raddr_ip1: string
2117 :type raddr_ip2: string
2118 :type raddr_range: int
2128 crypto_key = gen_key(
2129 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
2131 integ_key = gen_key(
2132 IPsecUtil.get_integ_alg_key_len(integ_alg)
2133 ).decode() if integ_alg else u""
2135 rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
2136 if u"DUT2" in nodes.keys() \
2137 else Topology.get_interface_mac(nodes[u"TG"], interface2)
2138 IPsecUtil.vpp_ipsec_set_ip_route(
2139 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
2140 interface1, raddr_range, rmac)
2142 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
2143 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
2144 IPsecUtil.vpp_ipsec_add_spd_entry(
2145 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
2146 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
2148 IPsecUtil.vpp_ipsec_add_spd_entry(
2149 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
2150 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
2153 IPsecUtil.vpp_ipsec_add_sad_entries(
2154 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
2155 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
2158 IPsecUtil.vpp_ipsec_add_spd_entries(
2159 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2160 action=PolicyAction.PROTECT, inbound=False,
2161 sa_id=ObjIncrement(sa_id_1, 1),
2162 raddr_range=NetworkIncrement(ip_network(raddr_ip2), 1)
2165 IPsecUtil.vpp_ipsec_add_sad_entries(
2166 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
2167 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
2169 IPsecUtil.vpp_ipsec_add_spd_entries(
2170 nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2171 action=PolicyAction.PROTECT, inbound=True,
2172 sa_id=ObjIncrement(sa_id_2, 1),
2173 raddr_range=NetworkIncrement(ip_network(raddr_ip1), 1)
2176 if u"DUT2" in nodes.keys():
2177 IPsecUtil.vpp_ipsec_set_ip_route(
2178 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
2179 interface2, raddr_range)
2181 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
2182 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
2183 IPsecUtil.vpp_ipsec_add_spd_entry(
2184 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2185 inbound=False, proto=50, laddr_range=u"100.0.0.0/8",
2186 raddr_range=u"100.0.0.0/8"
2188 IPsecUtil.vpp_ipsec_add_spd_entry(
2189 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2190 inbound=True, proto=50, laddr_range=u"100.0.0.0/8",
2191 raddr_range=u"100.0.0.0/8"
2194 IPsecUtil.vpp_ipsec_add_sad_entries(
2195 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
2196 crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2
2198 IPsecUtil.vpp_ipsec_add_spd_entries(
2199 nodes[u"DUT2"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2200 action=PolicyAction.PROTECT, inbound=True,
2201 sa_id=ObjIncrement(sa_id_1, 1),
2202 raddr_range=NetworkIncrement(ip_network(raddr_ip2), 1)
2205 IPsecUtil.vpp_ipsec_add_sad_entries(
2206 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
2207 crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1
2209 IPsecUtil.vpp_ipsec_add_spd_entries(
2210 nodes[u"DUT2"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2211 action=PolicyAction.PROTECT, inbound=False,
2212 sa_id=ObjIncrement(sa_id_2, 1),
2213 raddr_range=NetworkIncrement(ip_network(raddr_ip1), 1)
2217 def vpp_ipsec_show_all(node):
2218 """Run "show ipsec all" debug CLI command.
2220 :param node: Node to run command on.
2223 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec all")
2226 def show_ipsec_security_association(node):
2227 """Show IPSec security association.
2229 :param node: DUT node.
2235 PapiSocketExecutor.dump_and_log(node, cmds)