1 # Copyright (c) 2020 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """IPsec utilities library."""
18 from enum import Enum, IntEnum
20 from random import choice
21 from string import ascii_letters
23 from ipaddress import ip_network, ip_address
25 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
27 from resources.libraries.python.IPAddress import IPAddress
28 from resources.libraries.python.IPUtil import IPUtil
29 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
30 from resources.libraries.python.ssh import scp_node
31 from resources.libraries.python.topology import Topology
32 from resources.libraries.python.VatExecutor import VatExecutor
36 """Generate random string as a key.
38 :param length: Length of generated payload.
40 :returns: The generated payload.
44 choice(ascii_letters) for _ in range(length)
45 ).encode(encoding=u"utf-8")
48 class PolicyAction(Enum):
50 BYPASS = (u"bypass", 0)
51 DISCARD = (u"discard", 1)
52 PROTECT = (u"protect", 3)
54 def __init__(self, policy_name, policy_int_repr):
55 self.policy_name = policy_name
56 self.policy_int_repr = policy_int_repr
59 class CryptoAlg(Enum):
60 """Encryption algorithms."""
61 AES_CBC_128 = (u"aes-cbc-128", 1, u"AES-CBC", 16)
62 AES_CBC_256 = (u"aes-cbc-256", 3, u"AES-CBC", 32)
63 AES_GCM_128 = (u"aes-gcm-128", 7, u"AES-GCM", 16)
64 AES_GCM_256 = (u"aes-gcm-256", 9, u"AES-GCM", 32)
66 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
67 self.alg_name = alg_name
68 self.alg_int_repr = alg_int_repr
69 self.scapy_name = scapy_name
70 self.key_len = key_len
74 """Integrity algorithm."""
75 SHA_256_128 = (u"sha-256-128", 4, u"SHA2-256-128", 32)
76 SHA_512_256 = (u"sha-512-256", 6, u"SHA2-512-256", 64)
78 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
79 self.alg_name = alg_name
80 self.alg_int_repr = alg_int_repr
81 self.scapy_name = scapy_name
82 self.key_len = key_len
85 class IPsecProto(IntEnum):
87 IPSEC_API_PROTO_ESP = 50
88 IPSEC_API_PROTO_AH = 51
91 class IPsecSadFlags(IntEnum):
92 """IPsec Security Association Database flags."""
93 IPSEC_API_SAD_FLAG_NONE = 0
94 IPSEC_API_SAD_FLAG_IS_TUNNEL = 4
95 IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 8
99 """IPsec utilities."""
102 def policy_action_bypass():
103 """Return policy action bypass.
105 :returns: PolicyAction enum BYPASS object.
108 return PolicyAction.BYPASS
111 def policy_action_discard():
112 """Return policy action discard.
114 :returns: PolicyAction enum DISCARD object.
117 return PolicyAction.DISCARD
120 def policy_action_protect():
121 """Return policy action protect.
123 :returns: PolicyAction enum PROTECT object.
126 return PolicyAction.PROTECT
129 def crypto_alg_aes_cbc_128():
130 """Return encryption algorithm aes-cbc-128.
132 :returns: CryptoAlg enum AES_CBC_128 object.
135 return CryptoAlg.AES_CBC_128
138 def crypto_alg_aes_cbc_256():
139 """Return encryption algorithm aes-cbc-256.
141 :returns: CryptoAlg enum AES_CBC_256 object.
144 return CryptoAlg.AES_CBC_256
147 def crypto_alg_aes_gcm_128():
148 """Return encryption algorithm aes-gcm-128.
150 :returns: CryptoAlg enum AES_GCM_128 object.
153 return CryptoAlg.AES_GCM_128
156 def crypto_alg_aes_gcm_256():
157 """Return encryption algorithm aes-gcm-256.
159 :returns: CryptoAlg enum AES_GCM_128 object.
162 return CryptoAlg.AES_GCM_256
165 def get_crypto_alg_key_len(crypto_alg):
166 """Return encryption algorithm key length.
168 :param crypto_alg: Encryption algorithm.
169 :type crypto_alg: CryptoAlg
170 :returns: Key length.
173 return crypto_alg.key_len
176 def get_crypto_alg_scapy_name(crypto_alg):
177 """Return encryption algorithm scapy name.
179 :param crypto_alg: Encryption algorithm.
180 :type crypto_alg: CryptoAlg
181 :returns: Algorithm scapy name.
184 return crypto_alg.scapy_name
187 def integ_alg_sha_256_128():
188 """Return integrity algorithm SHA-256-128.
190 :returns: IntegAlg enum SHA_256_128 object.
193 return IntegAlg.SHA_256_128
196 def integ_alg_sha_512_256():
197 """Return integrity algorithm SHA-512-256.
199 :returns: IntegAlg enum SHA_512_256 object.
202 return IntegAlg.SHA_512_256
205 def get_integ_alg_key_len(integ_alg):
206 """Return integrity algorithm key length.
208 :param integ_alg: Integrity algorithm.
209 :type integ_alg: IntegAlg
210 :returns: Key length.
213 return integ_alg.key_len
216 def get_integ_alg_scapy_name(integ_alg):
217 """Return integrity algorithm scapy name.
219 :param integ_alg: Integrity algorithm.
220 :type integ_alg: IntegAlg
221 :returns: Algorithm scapy name.
224 return integ_alg.scapy_name
227 def ipsec_proto_esp():
228 """Return IPSec protocol ESP.
230 :returns: IPsecProto enum ESP object.
233 return int(IPsecProto.IPSEC_API_PROTO_ESP)
236 def ipsec_proto_ah():
237 """Return IPSec protocol AH.
239 :returns: IPsecProto enum AH object.
242 return int(IPsecProto.IPSEC_API_PROTO_AH)
245 def vpp_ipsec_select_backend(node, protocol, index=1):
246 """Select IPsec backend.
248 :param node: VPP node to select IPsec backend on.
249 :param protocol: IPsec protocol.
250 :param index: Backend index.
252 :type protocol: IPsecProto
254 :raises RuntimeError: If failed to select IPsec backend or if no API
257 cmd = u"ipsec_select_backend"
258 err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
263 with PapiSocketExecutor(node) as papi_exec:
264 papi_exec.add(cmd, **args).get_reply(err_msg)
267 def vpp_ipsec_set_async_mode(node, async_enable=1):
268 """Set IPsec async mode on|off.
270 :param node: VPP node to set IPsec async mode.
271 :param async_enable: Async mode on or off.
273 :type async_enable: int
274 :raises RuntimeError: If failed to set IPsec async mode or if no API
277 cmd = u"ipsec_set_async_mode"
278 err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
280 async_enable=async_enable
282 with PapiSocketExecutor(node) as papi_exec:
283 papi_exec.add(cmd, **args).get_reply(err_msg)
286 def vpp_ipsec_add_sad_entry(
287 node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
288 integ_key=u"", tunnel_src=None, tunnel_dst=None):
289 """Create Security Association Database entry on the VPP node.
291 :param node: VPP node to add SAD entry on.
292 :param sad_id: SAD entry ID.
293 :param spi: Security Parameter Index of this SAD entry.
294 :param crypto_alg: The encryption algorithm name.
295 :param crypto_key: The encryption key string.
296 :param integ_alg: The integrity algorithm name.
297 :param integ_key: The integrity key string.
298 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
299 specified ESP transport mode is used.
300 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
301 not specified ESP transport mode is used.
305 :type crypto_alg: CryptoAlg
306 :type crypto_key: str
307 :type integ_alg: IntegAlg
309 :type tunnel_src: str
310 :type tunnel_dst: str
312 if isinstance(crypto_key, str):
313 crypto_key = crypto_key.encode(encoding=u"utf-8")
314 if isinstance(integ_key, str):
315 integ_key = integ_key.encode(encoding=u"utf-8")
317 length=len(crypto_key),
321 length=len(integ_key),
322 data=integ_key if integ_key else 0
325 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
326 if tunnel_src and tunnel_dst:
327 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
328 src_addr = ip_address(tunnel_src)
329 dst_addr = ip_address(tunnel_dst)
330 if src_addr.version == 6:
332 flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
337 cmd = u"ipsec_sad_entry_add_del"
338 err_msg = f"Failed to add Security Association Database entry " \
339 f"on host {node[u'host']}"
343 crypto_algorithm=crypto_alg.alg_int_repr,
345 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
348 tunnel_src=str(src_addr),
349 tunnel_dst=str(dst_addr),
350 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
351 udp_src_port=4500, # default value in api
352 udp_dst_port=4500 # default value in api
358 with PapiSocketExecutor(node) as papi_exec:
359 papi_exec.add(cmd, **args).get_reply(err_msg)
362 def vpp_ipsec_add_sad_entries(
363 node, n_entries, sad_id, spi, crypto_alg, crypto_key,
364 integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
365 """Create multiple Security Association Database entries on VPP node.
367 :param node: VPP node to add SAD entry on.
368 :param n_entries: Number of SAD entries to be created.
369 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
371 :param spi: Security Parameter Index of first SAD entry. All subsequent
372 SAD entries will have spi incremented by 1.
373 :param crypto_alg: The encryption algorithm name.
374 :param crypto_key: The encryption key string.
375 :param integ_alg: The integrity algorithm name.
376 :param integ_key: The integrity key string.
377 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
378 specified ESP transport mode is used.
379 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
380 not specified ESP transport mode is used.
385 :type crypto_alg: CryptoAlg
386 :type crypto_key: str
387 :type integ_alg: IntegAlg
389 :type tunnel_src: str
390 :type tunnel_dst: str
392 if isinstance(crypto_key, str):
393 crypto_key = crypto_key.encode(encoding=u"utf-8")
394 if isinstance(integ_key, str):
395 integ_key = integ_key.encode(encoding=u"utf-8")
396 if tunnel_src and tunnel_dst:
397 src_addr = ip_address(tunnel_src)
398 dst_addr = ip_address(tunnel_dst)
403 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
406 if int(n_entries) > 10:
407 tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
409 with open(tmp_filename, 'w') as tmp_file:
410 for i in range(n_entries):
411 integ = f"integ-alg {integ_alg.alg_name} " \
412 f"integ-key {integ_key.hex()}" \
413 if integ_alg else u""
414 tunnel = f"tunnel-src {src_addr + i * addr_incr} " \
415 f"tunnel-dst {dst_addr + i * addr_incr}" \
416 if tunnel_src and tunnel_dst else u""
417 conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
418 f"crypto-alg {crypto_alg.alg_name} " \
419 f"crypto-key {crypto_key.hex()} " \
420 f"{integ} {tunnel}\n"
424 tmp_filename, node, timeout=300, json_out=False,
427 os.remove(tmp_filename)
431 length=len(crypto_key),
435 length=len(integ_key),
436 data=integ_key if integ_key else 0
439 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
440 if tunnel_src and tunnel_dst:
441 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
442 if src_addr.version == 6:
444 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
447 cmd = u"ipsec_sad_entry_add_del"
448 err_msg = f"Failed to add Security Association Database entry " \
449 f"on host {node[u'host']}"
454 crypto_algorithm=crypto_alg.alg_int_repr,
456 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
459 tunnel_src=str(src_addr),
460 tunnel_dst=str(dst_addr),
461 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
462 udp_src_port=4500, # default value in api
463 udp_dst_port=4500 # default value in api
469 with PapiSocketExecutor(node) as papi_exec:
470 for i in range(n_entries):
471 args[u"entry"][u"sad_id"] = int(sad_id) + i
472 args[u"entry"][u"spi"] = int(spi) + i
473 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
474 if tunnel_src and tunnel_dst else src_addr
475 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
476 if tunnel_src and tunnel_dst else dst_addr
477 history = bool(not 1 < i < n_entries - 2)
478 papi_exec.add(cmd, history=history, **args)
479 papi_exec.get_replies(err_msg)
482 def vpp_ipsec_set_ip_route(
483 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
485 """Set IP address and route on interface.
487 :param node: VPP node to add config on.
488 :param n_tunnels: Number of tunnels to create.
489 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
490 :param traffic_addr: Traffic destination IP address to route.
491 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
492 :param interface: Interface key on node 1.
493 :param raddr_range: Mask specifying range of Policy selector Remote IP
494 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
498 :type tunnel_src: str
499 :type traffic_addr: str
500 :type tunnel_dst: str
502 :type raddr_range: int
504 tunnel_src = ip_address(tunnel_src)
505 tunnel_dst = ip_address(tunnel_dst)
506 traffic_addr = ip_address(traffic_addr)
507 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
508 else 1 << (32 - raddr_range)
510 if int(n_tunnels) > 10:
511 tmp_filename = u"/tmp/ipsec_set_ip.script"
513 with open(tmp_filename, 'w') as tmp_file:
514 if_name = Topology.get_interface_name(node, interface)
515 for i in range(n_tunnels):
516 conf = f"exec set interface ip address {if_name} " \
517 f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
518 f"exec ip route add {traffic_addr + i}/" \
519 f"{128 if traffic_addr.version == 6 else 32} " \
520 f"via {tunnel_dst + i * addr_incr} {if_name}\n"
522 VatExecutor().execute_script(
523 tmp_filename, node, timeout=300, json_out=False,
526 os.remove(tmp_filename)
529 cmd1 = u"sw_interface_add_del_address"
531 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
536 cmd2 = u"ip_route_add_del"
542 err_msg = f"Failed to configure IP addresses and IP routes " \
543 f"on interface {interface} on host {node[u'host']}"
545 with PapiSocketExecutor(node) as papi_exec:
546 for i in range(n_tunnels):
547 args1[u"prefix"] = IPUtil.create_prefix_object(
548 tunnel_src + i * addr_incr, raddr_range
550 args2[u"route"] = IPUtil.compose_vpp_route_structure(
551 node, traffic_addr + i,
552 prefix_len=128 if traffic_addr.version == 6 else 32,
553 interface=interface, gateway=tunnel_dst + i * addr_incr
555 history = bool(not 1 < i < n_tunnels - 2)
556 papi_exec.add(cmd1, history=history, **args1).\
557 add(cmd2, history=history, **args2)
558 papi_exec.get_replies(err_msg)
561 def vpp_ipsec_add_spd(node, spd_id):
562 """Create Security Policy Database on the VPP node.
564 :param node: VPP node to add SPD on.
565 :param spd_id: SPD ID.
569 cmd = u"ipsec_spd_add_del"
570 err_msg = f"Failed to add Security Policy Database " \
571 f"on host {node[u'host']}"
576 with PapiSocketExecutor(node) as papi_exec:
577 papi_exec.add(cmd, **args).get_reply(err_msg)
580 def vpp_ipsec_spd_add_if(node, spd_id, interface):
581 """Add interface to the Security Policy Database.
583 :param node: VPP node.
584 :param spd_id: SPD ID to add interface on.
585 :param interface: Interface name or sw_if_index.
588 :type interface: str or int
590 cmd = u"ipsec_interface_add_del_spd"
591 err_msg = f"Failed to add interface {interface} to Security Policy " \
592 f"Database {spd_id} on host {node[u'host']}"
595 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
598 with PapiSocketExecutor(node) as papi_exec:
599 papi_exec.add(cmd, **args).get_reply(err_msg)
602 def vpp_ipsec_policy_add(
603 node, spd_id, priority, action, inbound=True, sa_id=None,
604 laddr_range=None, raddr_range=None, proto=None, lport_range=None,
605 rport_range=None, is_ipv6=False):
606 """Create Security Policy Database entry on the VPP node.
608 :param node: VPP node to add SPD entry on.
609 :param spd_id: SPD ID to add entry on.
610 :param priority: SPD entry priority, higher number = higher priority.
611 :param action: Policy action.
612 :param inbound: If True policy is for inbound traffic, otherwise
614 :param sa_id: SAD entry ID for protect action.
615 :param laddr_range: Policy selector local IPv4 or IPv6 address range in
616 format IP/prefix or IP/mask. If no mask is provided,
617 it's considered to be /32.
618 :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
619 format IP/prefix or IP/mask. If no mask is provided,
620 it's considered to be /32.
621 :param proto: Policy selector next layer protocol number.
622 :param lport_range: Policy selector local TCP/UDP port range in format
623 <port_start>-<port_end>.
624 :param rport_range: Policy selector remote TCP/UDP port range in format
625 <port_start>-<port_end>.
626 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
627 not defined so it will default to address ::/0, otherwise False.
631 :type action: PolicyAction
634 :type laddr_range: string
635 :type raddr_range: string
637 :type lport_range: string
638 :type rport_range: string
641 if laddr_range is None:
642 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
644 if raddr_range is None:
645 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
647 cmd = u"ipsec_spd_entry_add_del"
648 err_msg = f"Failed to add entry to Security Policy Database {spd_id} " \
649 f"on host {node[u'host']}"
653 priority=int(priority),
654 is_outbound=not inbound,
655 sa_id=int(sa_id) if sa_id else 0,
656 policy=action.policy_int_repr,
657 protocol=int(proto) if proto else 0,
658 remote_address_start=IPAddress.create_ip_address_object(
659 ip_network(raddr_range, strict=False).network_address
661 remote_address_stop=IPAddress.create_ip_address_object(
662 ip_network(raddr_range, strict=False).broadcast_address
664 local_address_start=IPAddress.create_ip_address_object(
665 ip_network(laddr_range, strict=False).network_address
667 local_address_stop=IPAddress.create_ip_address_object(
668 ip_network(laddr_range, strict=False).broadcast_address
670 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
672 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
674 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
676 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
683 with PapiSocketExecutor(node) as papi_exec:
684 papi_exec.add(cmd, **args).get_reply(err_msg)
687 def vpp_ipsec_spd_add_entries(
688 node, n_entries, spd_id, priority, inbound, sa_id, raddr_ip,
690 """Create multiple Security Policy Database entries on the VPP node.
692 :param node: VPP node to add SPD entries on.
693 :param n_entries: Number of SPD entries to be added.
694 :param spd_id: SPD ID to add entries on.
695 :param priority: SPD entries priority, higher number = higher priority.
696 :param inbound: If True policy is for inbound traffic, otherwise
698 :param sa_id: SAD entry ID for first entry. Each subsequent entry will
699 SAD entry ID incremented by 1.
700 :param raddr_ip: Policy selector remote IPv4 start address for the first
701 entry. Remote IPv4 end address will be calculated depending on
702 raddr_range parameter. Each subsequent entry will have start address
703 next after IPv4 end address of previous entry.
704 :param raddr_range: Required IP addres range.
712 :type raddr_range: int
714 raddr_ip = ip_address(raddr_ip)
715 if int(n_entries) > 10:
716 tmp_filename = f"/tmp/ipsec_spd_{sa_id}_add_del_entry.script"
718 with open(tmp_filename, 'w') as tmp_file:
719 for i in range(n_entries):
720 direction = u'inbound' if inbound else u'outbound'
721 tunnel = f"exec ipsec policy add spd {spd_id} " \
722 f"priority {priority} {direction} " \
723 f"action protect sa {sa_id+i} " \
724 f"remote-ip-range {raddr_ip + i * (raddr_range + 1)} " \
725 f"- {raddr_ip + (i + 1) * raddr_range + i} " \
726 f"local-ip-range 0.0.0.0 - 255.255.255.255\n"
727 tmp_file.write(tunnel)
728 VatExecutor().execute_script(
729 tmp_filename, node, timeout=300, json_out=False,
732 os.remove(tmp_filename)
735 laddr_range = u"::/0" if raddr_ip.version == 6 else u"0.0.0.0/0"
737 cmd = u"ipsec_spd_entry_add_del"
738 err_msg = f"ailed to add entry to Security Policy Database '{spd_id} " \
739 f"on host {node[u'host']}"
743 priority=int(priority),
744 is_outbound=not inbound,
745 sa_id=int(sa_id) if sa_id else 0,
746 policy=getattr(PolicyAction.PROTECT, u"policy_int_repr"),
748 remote_address_start=IPAddress.create_ip_address_object(raddr_ip),
749 remote_address_stop=IPAddress.create_ip_address_object(raddr_ip),
750 local_address_start=IPAddress.create_ip_address_object(
751 ip_network(laddr_range, strict=False).network_address
753 local_address_stop=IPAddress.create_ip_address_object(
754 ip_network(laddr_range, strict=False).broadcast_address
757 remote_port_stop=65535,
759 local_port_stop=65535
766 with PapiSocketExecutor(node) as papi_exec:
767 for i in range(n_entries):
768 args[u"entry"][u"remote_address_start"][u"un"] = \
769 IPAddress.union_addr(raddr_ip + i)
770 args[u"entry"][u"remote_address_stop"][u"un"] = \
771 IPAddress.union_addr(raddr_ip + i)
772 history = bool(not 1 < i < n_entries - 2)
773 papi_exec.add(cmd, history=history, **args)
774 papi_exec.get_replies(err_msg)
777 def _ipsec_create_tunnel_interfaces_dut1_vat(
778 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
779 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
780 """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
782 :param nodes: VPP nodes to create tunnel interfaces.
783 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
784 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
785 IPv4/IPv6 address (ip2).
786 :param if1_key: VPP node 1 interface key from topology file.
787 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
788 interface key from topology file.
789 :param n_tunnels: Number of tunnel interfaces to be there at the end.
790 :param crypto_alg: The encryption algorithm name.
791 :param integ_alg: The integrity algorithm name.
792 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
793 first tunnel in direction node2->node1.
794 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
795 :param addr_incr: IP / IPv6 address incremental step.
796 :param existing_tunnels: Number of tunnel interfaces before creation.
797 Useful mainly for reconf tests. Default 0.
803 :type crypto_alg: CryptoAlg
804 :type integ_alg: IntegAlg
805 :type raddr_ip2: IPv4Address or IPv6Address
808 :type existing_tunnels: int
810 tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
811 if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
813 ckeys = [bytes()] * existing_tunnels
814 ikeys = [bytes()] * existing_tunnels
817 with open(tmp_fn1, u"w") as tmp_f1:
818 rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
819 if u"DUT2" in nodes.keys() \
820 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
821 if not existing_tunnels:
823 f"exec create loopback interface\n"
824 f"exec set interface state loop0 up\n"
825 f"exec set interface ip address {if1_n} "
826 f"{tun_ips[u'ip2'] - 1}/"
827 f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
828 f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
831 for i in range(existing_tunnels, n_tunnels):
833 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
837 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
839 integ = f"integ_alg {integ_alg.alg_name} " \
840 f"local_integ_key {ikeys[i].hex()} " \
841 f"remote_integ_key {ikeys[i].hex()} "
845 f"exec set interface ip address loop0 "
846 f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
847 f"ipsec_tunnel_if_add_del "
848 f"local_spi {spi_d[u'spi_1'] + i} "
849 f"remote_spi {spi_d[u'spi_2'] + i} "
850 f"crypto_alg {crypto_alg.alg_name} "
851 f"local_crypto_key {ckeys[i].hex()} "
852 f"remote_crypto_key {ckeys[i].hex()} "
854 f"local_ip {tun_ips[u'ip1'] + i * addr_incr} "
855 f"remote_ip {tun_ips[u'ip2']} "
859 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
860 copy_on_execute=True,
861 history=bool(n_tunnels < 100)
865 with open(tmp_fn1, 'w') as tmp_f1:
866 for i in range(existing_tunnels, n_tunnels):
868 f"exec set interface unnumbered ipip{i} use {if1_n}\n"
869 f"exec set interface state ipip{i} up\n"
870 f"exec ip route add "
871 f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
875 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
876 copy_on_execute=True,
877 history=bool(n_tunnels < 100)
884 def _ipsec_create_tunnel_interfaces_dut2_vat(
885 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
886 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
887 """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
889 :param nodes: VPP nodes to create tunnel interfaces.
890 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
891 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
892 IPv4/IPv6 address (ip2).
893 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
894 interface key from topology file.
895 :param n_tunnels: Number of tunnel interfaces to be there at the end.
896 :param crypto_alg: The encryption algorithm name.
897 :param ckeys: List of encryption keys.
898 :param integ_alg: The integrity algorithm name.
899 :param ikeys: List of integrity keys.
900 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
901 :param addr_incr: IP / IPv6 address incremental step.
902 :param existing_tunnels: Number of tunnel interfaces before creation.
903 Useful mainly for reconf tests. Default 0.
908 :type crypto_alg: CryptoAlg
910 :type integ_alg: IntegAlg
914 :type existing_tunnels: int
916 tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
917 if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
920 with open(tmp_fn2, 'w') as tmp_f2:
921 if not existing_tunnels:
923 f"exec set interface ip address {if2_n}"
924 f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
926 for i in range(existing_tunnels, n_tunnels):
928 integ = f"integ_alg {integ_alg.alg_name} " \
929 f"local_integ_key {ikeys[i].hex()} " \
930 f"remote_integ_key {ikeys[i].hex()} "
934 f"ipsec_tunnel_if_add_del "
935 f"local_spi {spi_d[u'spi_2'] + i} "
936 f"remote_spi {spi_d[u'spi_1'] + i} "
937 f"crypto_alg {crypto_alg.alg_name} "
938 f"local_crypto_key {ckeys[i].hex()} "
939 f"remote_crypto_key {ckeys[i].hex()} "
941 f"local_ip {tun_ips[u'ip2']} "
942 f"remote_ip {tun_ips[u'ip1'] + i * addr_incr} "
946 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
947 copy_on_execute=True,
948 history=bool(n_tunnels < 100)
952 with open(tmp_fn2, 'w') as tmp_f2:
953 if not existing_tunnels:
955 f"exec ip route add {tun_ips[u'ip1']}/8 "
956 f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
958 for i in range(existing_tunnels, n_tunnels):
960 f"exec set interface unnumbered ipip{i} use {if2_n}\n"
961 f"exec set interface state ipip{i} up\n"
962 f"exec ip route add "
963 f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
967 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
968 copy_on_execute=True,
969 history=bool(n_tunnels < 100)
974 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
975 """Create loopback interface and set IP address on VPP node 1 interface
978 :param nodes: VPP nodes to create tunnel interfaces.
979 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
980 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
981 IPv4/IPv6 address (ip2).
982 :param if1_key: VPP node 1 interface key from topology file.
983 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
984 interface key from topology file.
990 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
991 # Create loopback interface on DUT1, set it to up state
992 cmd = u"create_loopback"
996 err_msg = f"Failed to create loopback interface " \
997 f"on host {nodes[u'DUT1'][u'host']}"
998 loop_sw_if_idx = papi_exec.add(cmd, **args). \
999 get_sw_if_index(err_msg)
1000 cmd = u"sw_interface_set_flags"
1002 sw_if_index=loop_sw_if_idx,
1003 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1005 err_msg = f"Failed to set loopback interface state up " \
1006 f"on host {nodes[u'DUT1'][u'host']}"
1007 papi_exec.add(cmd, **args).get_reply(err_msg)
1008 # Set IP address on VPP node 1 interface
1009 cmd = u"sw_interface_add_del_address"
1011 sw_if_index=InterfaceUtil.get_interface_index(
1012 nodes[u"DUT1"], if1_key
1016 prefix=IPUtil.create_prefix_object(
1017 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1021 err_msg = f"Failed to set IP address on interface {if1_key} " \
1022 f"on host {nodes[u'DUT1'][u'host']}"
1023 papi_exec.add(cmd, **args).get_reply(err_msg)
1024 cmd2 = u"ip_neighbor_add_del"
1028 sw_if_index=Topology.get_interface_sw_index(
1029 nodes[u"DUT1"], if1_key
1033 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1034 if u"DUT2" in nodes.keys()
1035 else Topology.get_interface_mac(
1036 nodes[u"TG"], if2_key
1039 ip_address=tun_ips[u"ip2"].compressed
1042 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1043 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1045 return loop_sw_if_idx
1048 def _ipsec_create_tunnel_interfaces_dut1_papi(
1049 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1050 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1051 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1053 :param nodes: VPP nodes to create tunnel interfaces.
1054 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1055 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1056 IPv4/IPv6 address (ip2).
1057 :param if1_key: VPP node 1 interface key from topology file.
1058 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1059 interface key from topology file.
1060 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1061 :param crypto_alg: The encryption algorithm name.
1062 :param integ_alg: The integrity algorithm name.
1063 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1064 first tunnel in direction node2->node1.
1065 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1066 :param addr_incr: IP / IPv6 address incremental step.
1067 :param existing_tunnels: Number of tunnel interfaces before creation.
1068 Useful mainly for reconf tests. Default 0.
1073 :type n_tunnels: int
1074 :type crypto_alg: CryptoAlg
1075 :type integ_alg: IntegAlg
1076 :type raddr_ip2: IPv4Address or IPv6Address
1077 :type addr_incr: int
1079 :type existing_tunnels: int
1081 if not existing_tunnels:
1082 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1083 nodes, tun_ips, if1_key, if2_key
1086 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1087 nodes[u"DUT1"], u"loop0"
1089 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1090 # Configure IP addresses on loop0 interface
1091 cmd = u"sw_interface_add_del_address"
1093 sw_if_index=loop_sw_if_idx,
1098 for i in range(existing_tunnels, n_tunnels):
1099 args[u"prefix"] = IPUtil.create_prefix_object(
1100 tun_ips[u"ip1"] + i * addr_incr,
1101 128 if tun_ips[u"ip1"].version == 6 else 32
1104 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1106 # Configure IPsec tunnel interfaces
1107 cmd = u"ipsec_tunnel_if_add_del"
1114 crypto_alg=crypto_alg.alg_int_repr,
1115 local_crypto_key_len=0,
1116 local_crypto_key=None,
1117 remote_crypto_key_len=0,
1118 remote_crypto_key=None,
1119 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1120 local_integ_key_len=0,
1121 local_integ_key=None,
1122 remote_integ_key_len=0,
1123 remote_integ_key=None,
1126 ipsec_tunnels = [None] * existing_tunnels
1127 ckeys = [bytes()] * existing_tunnels
1128 ikeys = [bytes()] * existing_tunnels
1129 for i in range(existing_tunnels, n_tunnels):
1131 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1135 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1137 args[u"local_spi"] = spi_d[u"spi_1"] + i
1138 args[u"remote_spi"] = spi_d[u"spi_2"] + i
1139 args[u"local_ip"] = IPAddress.create_ip_address_object(
1140 tun_ips[u"ip1"] + i * addr_incr
1142 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1145 args[u"local_crypto_key_len"] = len(ckeys[i])
1146 args[u"local_crypto_key"] = ckeys[i]
1147 args[u"remote_crypto_key_len"] = len(ckeys[i])
1148 args[u"remote_crypto_key"] = ckeys[i]
1150 args[u"local_integ_key_len"] = len(ikeys[i])
1151 args[u"local_integ_key"] = ikeys[i]
1152 args[u"remote_integ_key_len"] = len(ikeys[i])
1153 args[u"remote_integ_key"] = ikeys[i]
1155 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1157 err_msg = f"Failed to add IPsec tunnel interfaces on host" \
1158 f" {nodes[u'DUT1'][u'host']}"
1159 ipsec_tunnels.extend(
1161 reply[u"sw_if_index"]
1162 for reply in papi_exec.get_replies(err_msg)
1163 if u"sw_if_index" in reply
1166 # Configure unnumbered interfaces
1167 cmd = u"sw_interface_set_unnumbered"
1170 sw_if_index=InterfaceUtil.get_interface_index(
1171 nodes[u"DUT1"], if1_key
1173 unnumbered_sw_if_index=0
1175 for i in range(existing_tunnels, n_tunnels):
1176 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1178 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1181 cmd = u"sw_interface_set_flags"
1184 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1186 for i in range(existing_tunnels, n_tunnels):
1187 args[u"sw_if_index"] = ipsec_tunnels[i]
1189 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1191 # Configure IP routes
1192 cmd = u"ip_route_add_del"
1198 for i in range(existing_tunnels, n_tunnels):
1199 args[u"route"] = IPUtil.compose_vpp_route_structure(
1200 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1201 prefix_len=128 if raddr_ip2.version == 6 else 32,
1202 interface=ipsec_tunnels[i]
1205 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1207 err_msg = f"Failed to add IP routes on host " \
1208 f"{nodes[u'DUT1'][u'host']}"
1209 papi_exec.get_replies(err_msg)
1214 def _ipsec_create_tunnel_interfaces_dut2_papi(
1215 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1216 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1217 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1219 :param nodes: VPP nodes to create tunnel interfaces.
1220 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1221 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1222 IPv4/IPv6 address (ip2).
1223 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1224 interface key from topology file.
1225 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1226 :param crypto_alg: The encryption algorithm name.
1227 :param ckeys: List of encryption keys.
1228 :param integ_alg: The integrity algorithm name.
1229 :param ikeys: List of integrity keys.
1230 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1231 :param addr_incr: IP / IPv6 address incremental step.
1232 :param existing_tunnels: Number of tunnel interfaces before creation.
1233 Useful mainly for reconf tests. Default 0.
1237 :type n_tunnels: int
1238 :type crypto_alg: CryptoAlg
1240 :type integ_alg: IntegAlg
1242 :type addr_incr: int
1244 :type existing_tunnels: int
1246 with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1247 if not existing_tunnels:
1248 # Set IP address on VPP node 2 interface
1249 cmd = u"sw_interface_add_del_address"
1251 sw_if_index=InterfaceUtil.get_interface_index(
1252 nodes[u"DUT2"], if2_key
1256 prefix=IPUtil.create_prefix_object(
1257 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1261 err_msg = f"Failed to set IP address on interface {if2_key} " \
1262 f"on host {nodes[u'DUT2'][u'host']}"
1263 papi_exec.add(cmd, **args).get_reply(err_msg)
1264 # Configure IPsec tunnel interfaces
1265 cmd = u"ipsec_tunnel_if_add_del"
1268 local_ip=IPAddress.create_ip_address_object(tun_ips[u"ip2"]),
1272 crypto_alg=crypto_alg.alg_int_repr,
1273 local_crypto_key_len=0,
1274 local_crypto_key=None,
1275 remote_crypto_key_len=0,
1276 remote_crypto_key=None,
1277 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1278 local_integ_key_len=0,
1279 local_integ_key=None,
1280 remote_integ_key_len=0,
1281 remote_integ_key=None,
1284 ipsec_tunnels = [None] * existing_tunnels
1285 for i in range(existing_tunnels, n_tunnels):
1286 args[u"local_spi"] = spi_d[u"spi_2"] + i
1287 args[u"remote_spi"] = spi_d[u"spi_1"] + i
1288 args[u"local_ip"] = IPAddress.create_ip_address_object(
1291 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1292 tun_ips[u"ip1"] + i * addr_incr
1294 args[u"local_crypto_key_len"] = len(ckeys[i])
1295 args[u"local_crypto_key"] = ckeys[i]
1296 args[u"remote_crypto_key_len"] = len(ckeys[i])
1297 args[u"remote_crypto_key"] = ckeys[i]
1299 args[u"local_integ_key_len"] = len(ikeys[i])
1300 args[u"local_integ_key"] = ikeys[i]
1301 args[u"remote_integ_key_len"] = len(ikeys[i])
1302 args[u"remote_integ_key"] = ikeys[i]
1304 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1306 err_msg = f"Failed to add IPsec tunnel interfaces " \
1307 f"on host {nodes[u'DUT2'][u'host']}"
1308 ipsec_tunnels.extend(
1310 reply[u"sw_if_index"]
1311 for reply in papi_exec.get_replies(err_msg)
1312 if u"sw_if_index" in reply
1315 if not existing_tunnels:
1316 # Configure IP route
1317 cmd = u"ip_route_add_del"
1318 route = IPUtil.compose_vpp_route_structure(
1319 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1320 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1322 gateway=(tun_ips[u"ip2"] - 1).compressed
1329 papi_exec.add(cmd, **args)
1330 # Configure unnumbered interfaces
1331 cmd = u"sw_interface_set_unnumbered"
1334 sw_if_index=InterfaceUtil.get_interface_index(
1335 nodes[u"DUT2"], if2_key
1337 unnumbered_sw_if_index=0
1339 for i in range(existing_tunnels, n_tunnels):
1340 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1342 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1345 cmd = u"sw_interface_set_flags"
1348 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1350 for i in range(existing_tunnels, n_tunnels):
1351 args[u"sw_if_index"] = ipsec_tunnels[i]
1353 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1355 # Configure IP routes
1356 cmd = u"ip_route_add_del"
1362 for i in range(existing_tunnels, n_tunnels):
1363 args[u"route"] = IPUtil.compose_vpp_route_structure(
1364 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1365 prefix_len=128 if raddr_ip1.version == 6 else 32,
1366 interface=ipsec_tunnels[i]
1369 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1371 err_msg = f"Failed to add IP routes " \
1372 f"on host {nodes[u'DUT2'][u'host']}"
1373 papi_exec.get_replies(err_msg)
1376 def vpp_ipsec_create_tunnel_interfaces(
1377 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1378 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1379 existing_tunnels=0):
1380 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1382 :param nodes: VPP nodes to create tunnel interfaces.
1383 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1385 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1387 :param if1_key: VPP node 1 interface key from topology file.
1388 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1389 interface key from topology file.
1390 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1391 :param crypto_alg: The encryption algorithm name.
1392 :param integ_alg: The integrity algorithm name.
1393 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1394 first tunnel in direction node1->node2.
1395 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1396 first tunnel in direction node2->node1.
1397 :param raddr_range: Mask specifying range of Policy selector Remote
1398 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1399 and to 128 in case of IPv6.
1400 :param existing_tunnels: Number of tunnel interfaces before creation.
1401 Useful mainly for reconf tests. Default 0.
1403 :type tun_if1_ip_addr: str
1404 :type tun_if2_ip_addr: str
1407 :type n_tunnels: int
1408 :type crypto_alg: CryptoAlg
1409 :type integ_alg: IntegAlg
1410 :type raddr_ip1: string
1411 :type raddr_ip2: string
1412 :type raddr_range: int
1413 :type existing_tunnels: int
1415 n_tunnels = int(n_tunnels)
1416 existing_tunnels = int(existing_tunnels)
1422 ip1=ip_address(tun_if1_ip_addr),
1423 ip2=ip_address(tun_if2_ip_addr)
1425 raddr_ip1 = ip_address(raddr_ip1)
1426 raddr_ip2 = ip_address(raddr_ip2)
1427 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1428 else 1 << (32 - raddr_range)
1430 if n_tunnels - existing_tunnels > 10:
1431 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1432 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1433 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1435 if u"DUT2" not in nodes.keys():
1436 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1437 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1438 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1439 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1442 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1443 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1444 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1446 if u"DUT2" not in nodes.keys():
1447 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1448 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1449 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1450 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1453 return None, None, None, None
1456 def _create_ipsec_script_files(dut, instances):
1457 """Create script files for configuring IPsec in containers
1459 :param dut: DUT node on which to create the script files
1460 :param instances: number of containers on DUT node
1462 :type instances: int
1465 for cnf in range(0, instances):
1467 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1469 scripts.append(open(script_filename, 'w'))
1473 def _close_and_copy_ipsec_script_files(
1474 dut, nodes, instances, scripts):
1475 """Close created scripts and copy them to containers
1477 :param dut: DUT node on which to create the script files
1478 :param nodes: VPP nodes
1479 :param instances: number of containers on DUT node
1480 :param scripts: dictionary holding the script files
1483 :type instances: int
1486 for cnf in range(0, instances):
1487 scripts[cnf].close()
1489 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1491 scp_node(nodes[dut], script_filename, script_filename)
1495 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1496 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1497 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1498 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1500 :param nodes: VPP nodes to create tunnel interfaces.
1501 :param if1_ip_addr: VPP node 1 interface IP4 address.
1502 :param if2_ip_addr: VPP node 2 interface IP4 address.
1503 :param n_tunnels: Number of tunnell interfaces to create.
1504 :param crypto_alg: The encryption algorithm name.
1505 :param integ_alg: The integrity algorithm name.
1506 :param raddr_ip1: Policy selector remote IPv4 start address for the
1507 first tunnel in direction node1->node2.
1508 :param raddr_ip2: Policy selector remote IPv4 start address for the
1509 first tunnel in direction node2->node1.
1510 :param raddr_range: Mask specifying range of Policy selector Remote
1511 IPv4 addresses. Valid values are from 1 to 32.
1512 :param n_instances: Number of containers.
1514 :type if1_ip_addr: str
1515 :type if2_ip_addr: str
1516 :type n_tunnels: int
1517 :type crypto_alg: CryptoAlg
1518 :type integ_alg: IntegAlg
1519 :type raddr_ip1: string
1520 :type raddr_ip2: string
1521 :type raddr_range: int
1522 :type n_instances: int
1526 addr_incr = 1 << (32 - raddr_range)
1528 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1529 u"DUT1", n_instances
1531 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1532 u"DUT2", n_instances
1535 for cnf in range(0, n_instances):
1536 dut1_scripts[cnf].write(
1537 u"create loopback interface\n"
1538 u"set interface state loop0 up\n\n"
1540 dut2_scripts[cnf].write(
1541 f"ip route add {if1_ip_addr}/8 via "
1542 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1545 for tnl in range(0, n_tunnels):
1546 cnf = tnl % n_instances
1548 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1553 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1556 f"integ-alg {integ_alg.alg_name} "
1557 f"local-integ-key {ikey} "
1558 f"remote-integ-key {ikey} "
1560 # Configure tunnel end point(s) on left side
1561 dut1_scripts[cnf].write(
1562 u"set interface ip address loop0 "
1563 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1564 f"create ipsec tunnel "
1565 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1566 f"local-spi {spi_1 + tnl} "
1567 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1568 f"remote-spi {spi_2 + tnl} "
1569 f"crypto-alg {crypto_alg.alg_name} "
1570 f"local-crypto-key {ckey} "
1571 f"remote-crypto-key {ckey} "
1572 f"instance {tnl // n_instances} "
1575 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1576 f"set interface state ipip{tnl // n_instances} up\n"
1577 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1578 f"via ipip{tnl // n_instances}\n\n"
1580 # Configure tunnel end point(s) on right side
1581 dut2_scripts[cnf].write(
1582 f"set ip neighbor memif1/{cnf + 1} "
1583 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1584 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1585 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1586 f"local-spi {spi_2 + tnl} "
1587 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1588 f"remote-spi {spi_1 + tnl} "
1589 f"crypto-alg {crypto_alg.alg_name} "
1590 f"local-crypto-key {ckey} "
1591 f"remote-crypto-key {ckey} "
1592 f"instance {tnl // n_instances} "
1595 f"set interface unnumbered ipip{tnl // n_instances} "
1596 f"use memif1/{cnf + 1}\n"
1597 f"set interface state ipip{tnl // n_instances} up\n"
1598 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1599 f"via ipip{tnl // n_instances}\n\n"
1602 IPsecUtil._close_and_copy_ipsec_script_files(
1603 u"DUT1", nodes, n_instances, dut1_scripts)
1604 IPsecUtil._close_and_copy_ipsec_script_files(
1605 u"DUT2", nodes, n_instances, dut2_scripts)
1608 def vpp_ipsec_add_multiple_tunnels(
1609 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1610 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
1611 """Create multiple IPsec tunnels between two VPP nodes.
1613 :param nodes: VPP nodes to create tunnels.
1614 :param interface1: Interface name or sw_if_index on node 1.
1615 :param interface2: Interface name or sw_if_index on node 2.
1616 :param n_tunnels: Number of tunnels to create.
1617 :param crypto_alg: The encryption algorithm name.
1618 :param integ_alg: The integrity algorithm name.
1619 :param tunnel_ip1: Tunnel node1 IPv4 address.
1620 :param tunnel_ip2: Tunnel node2 IPv4 address.
1621 :param raddr_ip1: Policy selector remote IPv4 start address for the
1622 first tunnel in direction node1->node2.
1623 :param raddr_ip2: Policy selector remote IPv4 start address for the
1624 first tunnel in direction node2->node1.
1625 :param raddr_range: Mask specifying range of Policy selector Remote
1626 IPv4 addresses. Valid values are from 1 to 32.
1628 :type interface1: str or int
1629 :type interface2: str or int
1630 :type n_tunnels: int
1631 :type crypto_alg: CryptoAlg
1632 :type integ_alg: IntegAlg
1633 :type tunnel_ip1: str
1634 :type tunnel_ip2: str
1635 :type raddr_ip1: string
1636 :type raddr_ip2: string
1637 :type raddr_range: int
1647 crypto_key = gen_key(
1648 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1650 integ_key = gen_key(
1651 IPsecUtil.get_integ_alg_key_len(integ_alg)
1652 ).decode() if integ_alg else u""
1654 IPsecUtil.vpp_ipsec_set_ip_route(
1655 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1656 interface1, raddr_range)
1657 IPsecUtil.vpp_ipsec_set_ip_route(
1658 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1659 interface2, raddr_range)
1661 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1662 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1663 IPsecUtil.vpp_ipsec_policy_add(
1664 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1665 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1667 IPsecUtil.vpp_ipsec_policy_add(
1668 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1669 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1672 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1673 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1674 IPsecUtil.vpp_ipsec_policy_add(
1675 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1676 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1678 IPsecUtil.vpp_ipsec_policy_add(
1679 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1680 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1683 IPsecUtil.vpp_ipsec_add_sad_entries(
1684 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1685 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1687 IPsecUtil.vpp_ipsec_spd_add_entries(
1688 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, False, sa_id_1, raddr_ip2
1691 IPsecUtil.vpp_ipsec_add_sad_entries(
1692 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1693 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1695 IPsecUtil.vpp_ipsec_spd_add_entries(
1696 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, True, sa_id_1, raddr_ip2
1699 IPsecUtil.vpp_ipsec_add_sad_entries(
1700 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1701 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1704 IPsecUtil.vpp_ipsec_spd_add_entries(
1705 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, False, sa_id_2, raddr_ip1
1708 IPsecUtil.vpp_ipsec_add_sad_entries(
1709 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1710 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1713 IPsecUtil.vpp_ipsec_spd_add_entries(
1714 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, True, sa_id_2, raddr_ip1
1718 def vpp_ipsec_show(node):
1719 """Run "show ipsec" debug CLI command.
1721 :param node: Node to run command on.
1724 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec")