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_add_sad_entry(
268 node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
269 integ_key=u"", tunnel_src=None, tunnel_dst=None):
270 """Create Security Association Database entry on the VPP node.
272 :param node: VPP node to add SAD entry on.
273 :param sad_id: SAD entry ID.
274 :param spi: Security Parameter Index of this SAD entry.
275 :param crypto_alg: The encryption algorithm name.
276 :param crypto_key: The encryption key string.
277 :param integ_alg: The integrity algorithm name.
278 :param integ_key: The integrity key string.
279 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
280 specified ESP transport mode is used.
281 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
282 not specified ESP transport mode is used.
286 :type crypto_alg: CryptoAlg
287 :type crypto_key: str
288 :type integ_alg: IntegAlg
290 :type tunnel_src: str
291 :type tunnel_dst: str
293 if isinstance(crypto_key, str):
294 crypto_key = crypto_key.encode(encoding=u"utf-8")
295 if isinstance(integ_key, str):
296 integ_key = integ_key.encode(encoding=u"utf-8")
298 length=len(crypto_key),
302 length=len(integ_key),
303 data=integ_key if integ_key else 0
306 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
307 if tunnel_src and tunnel_dst:
308 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
309 src_addr = ip_address(tunnel_src)
310 dst_addr = ip_address(tunnel_dst)
311 if src_addr.version == 6:
313 flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
318 cmd = u"ipsec_sad_entry_add_del"
319 err_msg = f"Failed to add Security Association Database entry " \
320 f"on host {node[u'host']}"
324 crypto_algorithm=crypto_alg.alg_int_repr,
326 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
329 tunnel_src=str(src_addr),
330 tunnel_dst=str(dst_addr),
331 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP)
337 with PapiSocketExecutor(node) as papi_exec:
338 papi_exec.add(cmd, **args).get_reply(err_msg)
341 def vpp_ipsec_add_sad_entries(
342 node, n_entries, sad_id, spi, crypto_alg, crypto_key,
343 integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
344 """Create multiple Security Association Database entries on VPP node.
346 :param node: VPP node to add SAD entry on.
347 :param n_entries: Number of SAD entries to be created.
348 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
350 :param spi: Security Parameter Index of first SAD entry. All subsequent
351 SAD entries will have spi incremented by 1.
352 :param crypto_alg: The encryption algorithm name.
353 :param crypto_key: The encryption key string.
354 :param integ_alg: The integrity algorithm name.
355 :param integ_key: The integrity key string.
356 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
357 specified ESP transport mode is used.
358 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
359 not specified ESP transport mode is used.
364 :type crypto_alg: CryptoAlg
365 :type crypto_key: str
366 :type integ_alg: IntegAlg
368 :type tunnel_src: str
369 :type tunnel_dst: str
371 if isinstance(crypto_key, str):
372 crypto_key = crypto_key.encode(encoding=u"utf-8")
373 if isinstance(integ_key, str):
374 integ_key = integ_key.encode(encoding=u"utf-8")
375 if tunnel_src and tunnel_dst:
376 src_addr = ip_address(tunnel_src)
377 dst_addr = ip_address(tunnel_dst)
382 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
385 if int(n_entries) > 10:
386 tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
388 with open(tmp_filename, 'w') as tmp_file:
389 for i in range(n_entries):
390 integ = f"integ-alg {integ_alg.alg_name} " \
391 f"integ-key {integ_key.hex()}" \
392 if integ_alg else u""
393 tunnel = f"tunnel-src {src_addr + i * addr_incr} " \
394 f"tunnel-dst {dst_addr + i * addr_incr}" \
395 if tunnel_src and tunnel_dst else u""
396 conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
397 f"crypto-alg {crypto_alg.alg_name} " \
398 f"crypto-key {crypto_key.hex()} " \
399 f"{integ} {tunnel}\n"
403 tmp_filename, node, timeout=300, json_out=False,
406 os.remove(tmp_filename)
410 length=len(crypto_key),
414 length=len(integ_key),
415 data=integ_key if integ_key else 0
418 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
419 if tunnel_src and tunnel_dst:
420 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
421 if src_addr.version == 6:
423 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
426 cmd = u"ipsec_sad_entry_add_del"
427 err_msg = f"Failed to add Security Association Database entry " \
428 f"on host {node[u'host']}"
433 crypto_algorithm=crypto_alg.alg_int_repr,
435 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
438 tunnel_src=str(src_addr),
439 tunnel_dst=str(dst_addr),
440 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP)
446 with PapiSocketExecutor(node) as papi_exec:
447 for i in range(n_entries):
448 args[u"entry"][u"sad_id"] = int(sad_id) + i
449 args[u"entry"][u"spi"] = int(spi) + i
450 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
451 if tunnel_src and tunnel_dst else src_addr
452 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
453 if tunnel_src and tunnel_dst else dst_addr
454 history = bool(not 1 < i < n_entries - 2)
455 papi_exec.add(cmd, history=history, **args)
456 papi_exec.get_replies(err_msg)
459 def vpp_ipsec_set_ip_route(
460 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
462 """Set IP address and route on interface.
464 :param node: VPP node to add config on.
465 :param n_tunnels: Number of tunnels to create.
466 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
467 :param traffic_addr: Traffic destination IP address to route.
468 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
469 :param interface: Interface key on node 1.
470 :param raddr_range: Mask specifying range of Policy selector Remote IP
471 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
475 :type tunnel_src: str
476 :type traffic_addr: str
477 :type tunnel_dst: str
479 :type raddr_range: int
481 tunnel_src = ip_address(tunnel_src)
482 tunnel_dst = ip_address(tunnel_dst)
483 traffic_addr = ip_address(traffic_addr)
484 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
485 else 1 << (32 - raddr_range)
487 if int(n_tunnels) > 10:
488 tmp_filename = u"/tmp/ipsec_set_ip.script"
490 with open(tmp_filename, 'w') as tmp_file:
491 if_name = Topology.get_interface_name(node, interface)
492 for i in range(n_tunnels):
493 conf = f"exec set interface ip address {if_name} " \
494 f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
495 f"exec ip route add {traffic_addr + i}/" \
496 f"{128 if traffic_addr.version == 6 else 32} " \
497 f"via {tunnel_dst + i * addr_incr} {if_name}\n"
499 VatExecutor().execute_script(
500 tmp_filename, node, timeout=300, json_out=False,
503 os.remove(tmp_filename)
506 cmd1 = u"sw_interface_add_del_address"
508 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
513 cmd2 = u"ip_route_add_del"
519 err_msg = f"Failed to configure IP addresses and IP routes " \
520 f"on interface {interface} on host {node[u'host']}"
522 with PapiSocketExecutor(node) as papi_exec:
523 for i in range(n_tunnels):
524 args1[u"prefix"] = IPUtil.create_prefix_object(
525 tunnel_src + i * addr_incr, raddr_range
527 args2[u"route"] = IPUtil.compose_vpp_route_structure(
528 node, traffic_addr + i,
529 prefix_len=128 if traffic_addr.version == 6 else 32,
530 interface=interface, gateway=tunnel_dst + i * addr_incr
532 history = bool(not 1 < i < n_tunnels - 2)
533 papi_exec.add(cmd1, history=history, **args1).\
534 add(cmd2, history=history, **args2)
535 papi_exec.get_replies(err_msg)
538 def vpp_ipsec_add_spd(node, spd_id):
539 """Create Security Policy Database on the VPP node.
541 :param node: VPP node to add SPD on.
542 :param spd_id: SPD ID.
546 cmd = u"ipsec_spd_add_del"
547 err_msg = f"Failed to add Security Policy Database " \
548 f"on host {node[u'host']}"
553 with PapiSocketExecutor(node) as papi_exec:
554 papi_exec.add(cmd, **args).get_reply(err_msg)
557 def vpp_ipsec_spd_add_if(node, spd_id, interface):
558 """Add interface to the Security Policy Database.
560 :param node: VPP node.
561 :param spd_id: SPD ID to add interface on.
562 :param interface: Interface name or sw_if_index.
565 :type interface: str or int
567 cmd = u"ipsec_interface_add_del_spd"
568 err_msg = f"Failed to add interface {interface} to Security Policy " \
569 f"Database {spd_id} on host {node[u'host']}"
572 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
575 with PapiSocketExecutor(node) as papi_exec:
576 papi_exec.add(cmd, **args).get_reply(err_msg)
579 def vpp_ipsec_policy_add(
580 node, spd_id, priority, action, inbound=True, sa_id=None,
581 laddr_range=None, raddr_range=None, proto=None, lport_range=None,
582 rport_range=None, is_ipv6=False):
583 """Create Security Policy Database entry on the VPP node.
585 :param node: VPP node to add SPD entry on.
586 :param spd_id: SPD ID to add entry on.
587 :param priority: SPD entry priority, higher number = higher priority.
588 :param action: Policy action.
589 :param inbound: If True policy is for inbound traffic, otherwise
591 :param sa_id: SAD entry ID for protect action.
592 :param laddr_range: Policy selector local IPv4 or IPv6 address range in
593 format IP/prefix or IP/mask. If no mask is provided,
594 it's considered to be /32.
595 :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
596 format IP/prefix or IP/mask. If no mask is provided,
597 it's considered to be /32.
598 :param proto: Policy selector next layer protocol number.
599 :param lport_range: Policy selector local TCP/UDP port range in format
600 <port_start>-<port_end>.
601 :param rport_range: Policy selector remote TCP/UDP port range in format
602 <port_start>-<port_end>.
603 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
604 not defined so it will default to address ::/0, otherwise False.
608 :type action: PolicyAction
611 :type laddr_range: string
612 :type raddr_range: string
614 :type lport_range: string
615 :type rport_range: string
618 if laddr_range is None:
619 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
621 if raddr_range is None:
622 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
624 cmd = u"ipsec_spd_entry_add_del"
625 err_msg = f"Failed to add entry to Security Policy Database {spd_id} " \
626 f"on host {node[u'host']}"
630 priority=int(priority),
631 is_outbound=not inbound,
632 sa_id=int(sa_id) if sa_id else 0,
633 policy=action.policy_int_repr,
634 protocol=int(proto) if proto else 0,
635 remote_address_start=IPAddress.create_ip_address_object(
636 ip_network(raddr_range, strict=False).network_address
638 remote_address_stop=IPAddress.create_ip_address_object(
639 ip_network(raddr_range, strict=False).broadcast_address
641 local_address_start=IPAddress.create_ip_address_object(
642 ip_network(laddr_range, strict=False).network_address
644 local_address_stop=IPAddress.create_ip_address_object(
645 ip_network(laddr_range, strict=False).broadcast_address
647 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
649 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
651 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
653 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
660 with PapiSocketExecutor(node) as papi_exec:
661 papi_exec.add(cmd, **args).get_reply(err_msg)
664 def vpp_ipsec_spd_add_entries(
665 node, n_entries, spd_id, priority, inbound, sa_id, raddr_ip,
667 """Create multiple Security Policy Database entries on the VPP node.
669 :param node: VPP node to add SPD entries on.
670 :param n_entries: Number of SPD entries to be added.
671 :param spd_id: SPD ID to add entries on.
672 :param priority: SPD entries priority, higher number = higher priority.
673 :param inbound: If True policy is for inbound traffic, otherwise
675 :param sa_id: SAD entry ID for first entry. Each subsequent entry will
676 SAD entry ID incremented by 1.
677 :param raddr_ip: Policy selector remote IPv4 start address for the first
678 entry. Remote IPv4 end address will be calculated depending on
679 raddr_range parameter. Each subsequent entry will have start address
680 next after IPv4 end address of previous entry.
681 :param raddr_range: Required IP addres range.
689 :type raddr_range: int
691 raddr_ip = ip_address(raddr_ip)
692 if int(n_entries) > 10:
693 tmp_filename = f"/tmp/ipsec_spd_{sa_id}_add_del_entry.script"
695 with open(tmp_filename, 'w') as tmp_file:
696 for i in range(n_entries):
697 direction = u'inbound' if inbound else u'outbound'
698 tunnel = f"exec ipsec policy add spd {spd_id} " \
699 f"priority {priority} {direction} " \
700 f"action protect sa {sa_id+i} " \
701 f"remote-ip-range {raddr_ip + i * (raddr_range + 1)} " \
702 f"- {raddr_ip + (i + 1) * raddr_range + i} " \
703 f"local-ip-range 0.0.0.0 - 255.255.255.255\n"
704 tmp_file.write(tunnel)
705 VatExecutor().execute_script(
706 tmp_filename, node, timeout=300, json_out=False,
709 os.remove(tmp_filename)
712 laddr_range = u"::/0" if raddr_ip.version == 6 else u"0.0.0.0/0"
714 cmd = u"ipsec_spd_entry_add_del"
715 err_msg = f"ailed to add entry to Security Policy Database '{spd_id} " \
716 f"on host {node[u'host']}"
720 priority=int(priority),
721 is_outbound=not inbound,
722 sa_id=int(sa_id) if sa_id else 0,
723 policy=getattr(PolicyAction.PROTECT, u"policy_int_repr"),
725 remote_address_start=IPAddress.create_ip_address_object(raddr_ip),
726 remote_address_stop=IPAddress.create_ip_address_object(raddr_ip),
727 local_address_start=IPAddress.create_ip_address_object(
728 ip_network(laddr_range, strict=False).network_address
730 local_address_stop=IPAddress.create_ip_address_object(
731 ip_network(laddr_range, strict=False).broadcast_address
734 remote_port_stop=65535,
736 local_port_stop=65535
743 with PapiSocketExecutor(node) as papi_exec:
744 for i in range(n_entries):
745 args[u"entry"][u"remote_address_start"][u"un"] = \
746 IPAddress.union_addr(raddr_ip + i)
747 args[u"entry"][u"remote_address_stop"][u"un"] = \
748 IPAddress.union_addr(raddr_ip + i)
749 history = bool(not 1 < i < n_entries - 2)
750 papi_exec.add(cmd, history=history, **args)
751 papi_exec.get_replies(err_msg)
754 def _ipsec_create_tunnel_interfaces_dut1_vat(
755 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
756 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
757 """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
759 :param nodes: VPP nodes to create tunnel interfaces.
760 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
761 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
762 IPv4/IPv6 address (ip2).
763 :param if1_key: VPP node 1 interface key from topology file.
764 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
765 interface key from topology file.
766 :param n_tunnels: Number of tunnel interfaces to be there at the end.
767 :param crypto_alg: The encryption algorithm name.
768 :param integ_alg: The integrity algorithm name.
769 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
770 first tunnel in direction node2->node1.
771 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
772 :param addr_incr: IP / IPv6 address incremental step.
773 :param existing_tunnels: Number of tunnel interfaces before creation.
774 Useful mainly for reconf tests. Default 0.
780 :type crypto_alg: CryptoAlg
781 :type integ_alg: IntegAlg
782 :type raddr_ip2: IPv4Address or IPv6Address
785 :type existing_tunnels: int
787 tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
788 if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
790 ckeys = [bytes()] * existing_tunnels
791 ikeys = [bytes()] * existing_tunnels
794 with open(tmp_fn1, u"w") as tmp_f1:
795 rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
796 if u"DUT2" in nodes.keys() \
797 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
798 if not existing_tunnels:
800 f"exec create loopback interface\n"
801 f"exec set interface state loop0 up\n"
802 f"exec set interface ip address {if1_n} "
803 f"{tun_ips[u'ip2'] - 1}/"
804 f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
805 f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
808 for i in range(existing_tunnels, n_tunnels):
810 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
814 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
816 integ = f"integ_alg {integ_alg.alg_name} " \
817 f"local_integ_key {ikeys[i].hex()} " \
818 f"remote_integ_key {ikeys[i].hex()} "
822 f"exec set interface ip address loop0 "
823 f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
824 f"ipsec_tunnel_if_add_del "
825 f"local_spi {spi_d[u'spi_1'] + i} "
826 f"remote_spi {spi_d[u'spi_2'] + i} "
827 f"crypto_alg {crypto_alg.alg_name} "
828 f"local_crypto_key {ckeys[i].hex()} "
829 f"remote_crypto_key {ckeys[i].hex()} "
831 f"local_ip {tun_ips[u'ip1'] + i * addr_incr} "
832 f"remote_ip {tun_ips[u'ip2']} "
836 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
837 copy_on_execute=True,
838 history=bool(n_tunnels < 100)
842 with open(tmp_fn1, 'w') as tmp_f1:
843 for i in range(existing_tunnels, n_tunnels):
845 f"exec set interface unnumbered ipip{i} use {if1_n}\n"
846 f"exec set interface state ipip{i} up\n"
847 f"exec ip route add "
848 f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
852 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
853 copy_on_execute=True,
854 history=bool(n_tunnels < 100)
861 def _ipsec_create_tunnel_interfaces_dut2_vat(
862 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
863 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
864 """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
866 :param nodes: VPP nodes to create tunnel interfaces.
867 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
868 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
869 IPv4/IPv6 address (ip2).
870 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
871 interface key from topology file.
872 :param n_tunnels: Number of tunnel interfaces to be there at the end.
873 :param crypto_alg: The encryption algorithm name.
874 :param ckeys: List of encryption keys.
875 :param integ_alg: The integrity algorithm name.
876 :param ikeys: List of integrity keys.
877 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
878 :param addr_incr: IP / IPv6 address incremental step.
879 :param existing_tunnels: Number of tunnel interfaces before creation.
880 Useful mainly for reconf tests. Default 0.
885 :type crypto_alg: CryptoAlg
887 :type integ_alg: IntegAlg
891 :type existing_tunnels: int
893 tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
894 if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
897 with open(tmp_fn2, 'w') as tmp_f2:
898 if not existing_tunnels:
900 f"exec set interface ip address {if2_n}"
901 f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
903 for i in range(existing_tunnels, n_tunnels):
905 integ = f"integ_alg {integ_alg.alg_name} " \
906 f"local_integ_key {ikeys[i].hex()} " \
907 f"remote_integ_key {ikeys[i].hex()} "
911 f"ipsec_tunnel_if_add_del "
912 f"local_spi {spi_d[u'spi_2'] + i} "
913 f"remote_spi {spi_d[u'spi_1'] + i} "
914 f"crypto_alg {crypto_alg.alg_name} "
915 f"local_crypto_key {ckeys[i].hex()} "
916 f"remote_crypto_key {ckeys[i].hex()} "
918 f"local_ip {tun_ips[u'ip2']} "
919 f"remote_ip {tun_ips[u'ip1'] + i * addr_incr} "
923 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
924 copy_on_execute=True,
925 history=bool(n_tunnels < 100)
929 with open(tmp_fn2, 'w') as tmp_f2:
930 if not existing_tunnels:
932 f"exec ip route add {tun_ips[u'ip1']}/8 "
933 f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
935 for i in range(existing_tunnels, n_tunnels):
937 f"exec set interface unnumbered ipip{i} use {if2_n}\n"
938 f"exec set interface state ipip{i} up\n"
939 f"exec ip route add "
940 f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
944 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
945 copy_on_execute=True,
946 history=bool(n_tunnels < 100)
951 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
952 """Create loopback interface and set IP address on VPP node 1 interface
955 :param nodes: VPP nodes to create tunnel interfaces.
956 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
957 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
958 IPv4/IPv6 address (ip2).
959 :param if1_key: VPP node 1 interface key from topology file.
960 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
961 interface key from topology file.
967 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
968 # Create loopback interface on DUT1, set it to up state
969 cmd = u"create_loopback"
973 err_msg = f"Failed to create loopback interface " \
974 f"on host {nodes[u'DUT1'][u'host']}"
975 loop_sw_if_idx = papi_exec.add(cmd, **args). \
976 get_sw_if_index(err_msg)
977 cmd = u"sw_interface_set_flags"
979 sw_if_index=loop_sw_if_idx,
980 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
982 err_msg = f"Failed to set loopback interface state up " \
983 f"on host {nodes[u'DUT1'][u'host']}"
984 papi_exec.add(cmd, **args).get_reply(err_msg)
985 # Set IP address on VPP node 1 interface
986 cmd = u"sw_interface_add_del_address"
988 sw_if_index=InterfaceUtil.get_interface_index(
989 nodes[u"DUT1"], if1_key
993 prefix=IPUtil.create_prefix_object(
994 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
998 err_msg = f"Failed to set IP address on interface {if1_key} " \
999 f"on host {nodes[u'DUT1'][u'host']}"
1000 papi_exec.add(cmd, **args).get_reply(err_msg)
1001 cmd2 = u"ip_neighbor_add_del"
1005 sw_if_index=Topology.get_interface_sw_index(
1006 nodes[u"DUT1"], if1_key
1010 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1011 if u"DUT2" in nodes.keys()
1012 else Topology.get_interface_mac(
1013 nodes[u"TG"], if2_key
1016 ip_address=tun_ips[u"ip2"].compressed
1019 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1020 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1022 return loop_sw_if_idx
1025 def _ipsec_create_tunnel_interfaces_dut1_papi(
1026 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1027 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1028 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1030 :param nodes: VPP nodes to create tunnel interfaces.
1031 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1032 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1033 IPv4/IPv6 address (ip2).
1034 :param if1_key: VPP node 1 interface key from topology file.
1035 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1036 interface key from topology file.
1037 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1038 :param crypto_alg: The encryption algorithm name.
1039 :param integ_alg: The integrity algorithm name.
1040 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1041 first tunnel in direction node2->node1.
1042 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1043 :param addr_incr: IP / IPv6 address incremental step.
1044 :param existing_tunnels: Number of tunnel interfaces before creation.
1045 Useful mainly for reconf tests. Default 0.
1050 :type n_tunnels: int
1051 :type crypto_alg: CryptoAlg
1052 :type integ_alg: IntegAlg
1053 :type raddr_ip2: IPv4Address or IPv6Address
1054 :type addr_incr: int
1056 :type existing_tunnels: int
1058 if not existing_tunnels:
1059 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1060 nodes, tun_ips, if1_key, if2_key
1063 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1064 nodes[u"DUT1"], u"loop0"
1066 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1067 # Configure IP addresses on loop0 interface
1068 cmd = u"sw_interface_add_del_address"
1070 sw_if_index=loop_sw_if_idx,
1075 for i in range(existing_tunnels, n_tunnels):
1076 args[u"prefix"] = IPUtil.create_prefix_object(
1077 tun_ips[u"ip1"] + i * addr_incr,
1078 128 if tun_ips[u"ip1"].version == 6 else 32
1081 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1083 # Configure IPsec tunnel interfaces
1084 cmd = u"ipsec_tunnel_if_add_del"
1091 crypto_alg=crypto_alg.alg_int_repr,
1092 local_crypto_key_len=0,
1093 local_crypto_key=None,
1094 remote_crypto_key_len=0,
1095 remote_crypto_key=None,
1096 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1097 local_integ_key_len=0,
1098 local_integ_key=None,
1099 remote_integ_key_len=0,
1100 remote_integ_key=None,
1103 ipsec_tunnels = [None] * existing_tunnels
1104 ckeys = [bytes()] * existing_tunnels
1105 ikeys = [bytes()] * existing_tunnels
1106 for i in range(existing_tunnels, n_tunnels):
1108 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1112 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1114 args[u"local_spi"] = spi_d[u"spi_1"] + i
1115 args[u"remote_spi"] = spi_d[u"spi_2"] + i
1116 args[u"local_ip"] = IPAddress.create_ip_address_object(
1117 tun_ips[u"ip1"] + i * addr_incr
1119 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1122 args[u"local_crypto_key_len"] = len(ckeys[i])
1123 args[u"local_crypto_key"] = ckeys[i]
1124 args[u"remote_crypto_key_len"] = len(ckeys[i])
1125 args[u"remote_crypto_key"] = ckeys[i]
1127 args[u"local_integ_key_len"] = len(ikeys[i])
1128 args[u"local_integ_key"] = ikeys[i]
1129 args[u"remote_integ_key_len"] = len(ikeys[i])
1130 args[u"remote_integ_key"] = ikeys[i]
1132 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1134 err_msg = f"Failed to add IPsec tunnel interfaces on host" \
1135 f" {nodes[u'DUT1'][u'host']}"
1136 ipsec_tunnels.extend(
1138 reply[u"sw_if_index"]
1139 for reply in papi_exec.get_replies(err_msg)
1140 if u"sw_if_index" in reply
1143 # Configure unnumbered interfaces
1144 cmd = u"sw_interface_set_unnumbered"
1147 sw_if_index=InterfaceUtil.get_interface_index(
1148 nodes[u"DUT1"], if1_key
1150 unnumbered_sw_if_index=0
1152 for i in range(existing_tunnels, n_tunnels):
1153 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1155 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1158 cmd = u"sw_interface_set_flags"
1161 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1163 for i in range(existing_tunnels, n_tunnels):
1164 args[u"sw_if_index"] = ipsec_tunnels[i]
1166 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1168 # Configure IP routes
1169 cmd = u"ip_route_add_del"
1175 for i in range(existing_tunnels, n_tunnels):
1176 args[u"route"] = IPUtil.compose_vpp_route_structure(
1177 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1178 prefix_len=128 if raddr_ip2.version == 6 else 32,
1179 interface=ipsec_tunnels[i]
1182 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1184 err_msg = f"Failed to add IP routes on host " \
1185 f"{nodes[u'DUT1'][u'host']}"
1186 papi_exec.get_replies(err_msg)
1191 def _ipsec_create_tunnel_interfaces_dut2_papi(
1192 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1193 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1194 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1196 :param nodes: VPP nodes to create tunnel interfaces.
1197 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1198 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1199 IPv4/IPv6 address (ip2).
1200 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1201 interface key from topology file.
1202 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1203 :param crypto_alg: The encryption algorithm name.
1204 :param ckeys: List of encryption keys.
1205 :param integ_alg: The integrity algorithm name.
1206 :param ikeys: List of integrity keys.
1207 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1208 :param addr_incr: IP / IPv6 address incremental step.
1209 :param existing_tunnels: Number of tunnel interfaces before creation.
1210 Useful mainly for reconf tests. Default 0.
1214 :type n_tunnels: int
1215 :type crypto_alg: CryptoAlg
1217 :type integ_alg: IntegAlg
1219 :type addr_incr: int
1221 :type existing_tunnels: int
1223 with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1224 if not existing_tunnels:
1225 # Set IP address on VPP node 2 interface
1226 cmd = u"sw_interface_add_del_address"
1228 sw_if_index=InterfaceUtil.get_interface_index(
1229 nodes[u"DUT2"], if2_key
1233 prefix=IPUtil.create_prefix_object(
1234 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1238 err_msg = f"Failed to set IP address on interface {if2_key} " \
1239 f"on host {nodes[u'DUT2'][u'host']}"
1240 papi_exec.add(cmd, **args).get_reply(err_msg)
1241 # Configure IPsec tunnel interfaces
1242 cmd = u"ipsec_tunnel_if_add_del"
1245 local_ip=IPAddress.create_ip_address_object(tun_ips[u"ip2"]),
1249 crypto_alg=crypto_alg.alg_int_repr,
1250 local_crypto_key_len=0,
1251 local_crypto_key=None,
1252 remote_crypto_key_len=0,
1253 remote_crypto_key=None,
1254 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1255 local_integ_key_len=0,
1256 local_integ_key=None,
1257 remote_integ_key_len=0,
1258 remote_integ_key=None,
1261 ipsec_tunnels = [None] * existing_tunnels
1262 for i in range(existing_tunnels, n_tunnels):
1263 args[u"local_spi"] = spi_d[u"spi_2"] + i
1264 args[u"remote_spi"] = spi_d[u"spi_1"] + i
1265 args[u"local_ip"] = IPAddress.create_ip_address_object(
1268 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1269 tun_ips[u"ip1"] + i * addr_incr
1271 args[u"local_crypto_key_len"] = len(ckeys[i])
1272 args[u"local_crypto_key"] = ckeys[i]
1273 args[u"remote_crypto_key_len"] = len(ckeys[i])
1274 args[u"remote_crypto_key"] = ckeys[i]
1276 args[u"local_integ_key_len"] = len(ikeys[i])
1277 args[u"local_integ_key"] = ikeys[i]
1278 args[u"remote_integ_key_len"] = len(ikeys[i])
1279 args[u"remote_integ_key"] = ikeys[i]
1281 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1283 err_msg = f"Failed to add IPsec tunnel interfaces " \
1284 f"on host {nodes[u'DUT2'][u'host']}"
1285 ipsec_tunnels.extend(
1287 reply[u"sw_if_index"]
1288 for reply in papi_exec.get_replies(err_msg)
1289 if u"sw_if_index" in reply
1292 if not existing_tunnels:
1293 # Configure IP route
1294 cmd = u"ip_route_add_del"
1295 route = IPUtil.compose_vpp_route_structure(
1296 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1297 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1299 gateway=(tun_ips[u"ip2"] - 1).compressed
1306 papi_exec.add(cmd, **args)
1307 # Configure unnumbered interfaces
1308 cmd = u"sw_interface_set_unnumbered"
1311 sw_if_index=InterfaceUtil.get_interface_index(
1312 nodes[u"DUT2"], if2_key
1314 unnumbered_sw_if_index=0
1316 for i in range(existing_tunnels, n_tunnels):
1317 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1319 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1322 cmd = u"sw_interface_set_flags"
1325 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1327 for i in range(existing_tunnels, n_tunnels):
1328 args[u"sw_if_index"] = ipsec_tunnels[i]
1330 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1332 # Configure IP routes
1333 cmd = u"ip_route_add_del"
1339 for i in range(existing_tunnels, n_tunnels):
1340 args[u"route"] = IPUtil.compose_vpp_route_structure(
1341 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1342 prefix_len=128 if raddr_ip1.version == 6 else 32,
1343 interface=ipsec_tunnels[i]
1346 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1348 err_msg = f"Failed to add IP routes " \
1349 f"on host {nodes[u'DUT2'][u'host']}"
1350 papi_exec.get_replies(err_msg)
1353 def vpp_ipsec_create_tunnel_interfaces(
1354 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1355 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1356 existing_tunnels=0):
1357 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1359 :param nodes: VPP nodes to create tunnel interfaces.
1360 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1362 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1364 :param if1_key: VPP node 1 interface key from topology file.
1365 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1366 interface key from topology file.
1367 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1368 :param crypto_alg: The encryption algorithm name.
1369 :param integ_alg: The integrity algorithm name.
1370 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1371 first tunnel in direction node1->node2.
1372 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1373 first tunnel in direction node2->node1.
1374 :param raddr_range: Mask specifying range of Policy selector Remote
1375 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1376 and to 128 in case of IPv6.
1377 :param existing_tunnels: Number of tunnel interfaces before creation.
1378 Useful mainly for reconf tests. Default 0.
1380 :type tun_if1_ip_addr: str
1381 :type tun_if2_ip_addr: str
1384 :type n_tunnels: int
1385 :type crypto_alg: CryptoAlg
1386 :type integ_alg: IntegAlg
1387 :type raddr_ip1: string
1388 :type raddr_ip2: string
1389 :type raddr_range: int
1390 :type existing_tunnels: int
1392 n_tunnels = int(n_tunnels)
1393 existing_tunnels = int(existing_tunnels)
1399 ip1=ip_address(tun_if1_ip_addr),
1400 ip2=ip_address(tun_if2_ip_addr)
1402 raddr_ip1 = ip_address(raddr_ip1)
1403 raddr_ip2 = ip_address(raddr_ip2)
1404 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1405 else 1 << (32 - raddr_range)
1407 if n_tunnels - existing_tunnels > 10:
1408 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1409 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1410 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1412 if u"DUT2" not in nodes.keys():
1413 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1414 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1415 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1416 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1419 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1420 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1421 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1423 if u"DUT2" not in nodes.keys():
1424 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1425 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1426 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1427 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1430 return None, None, None, None
1433 def _create_ipsec_script_files(dut, instances):
1434 """Create script files for configuring IPsec in containers
1436 :param dut: DUT node on which to create the script files
1437 :param instances: number of containers on DUT node
1439 :type instances: int
1442 for cnf in range(0, instances):
1444 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1446 scripts.append(open(script_filename, 'w'))
1450 def _close_and_copy_ipsec_script_files(
1451 dut, nodes, instances, scripts):
1452 """Close created scripts and copy them to containers
1454 :param dut: DUT node on which to create the script files
1455 :param nodes: VPP nodes
1456 :param instances: number of containers on DUT node
1457 :param scripts: dictionary holding the script files
1460 :type instances: int
1463 for cnf in range(0, instances):
1464 scripts[cnf].close()
1466 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1468 scp_node(nodes[dut], script_filename, script_filename)
1472 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1473 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1474 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1475 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1477 :param nodes: VPP nodes to create tunnel interfaces.
1478 :param if1_ip_addr: VPP node 1 interface IP4 address.
1479 :param if2_ip_addr: VPP node 2 interface IP4 address.
1480 :param n_tunnels: Number of tunnell interfaces to create.
1481 :param crypto_alg: The encryption algorithm name.
1482 :param integ_alg: The integrity algorithm name.
1483 :param raddr_ip1: Policy selector remote IPv4 start address for the
1484 first tunnel in direction node1->node2.
1485 :param raddr_ip2: Policy selector remote IPv4 start address for the
1486 first tunnel in direction node2->node1.
1487 :param raddr_range: Mask specifying range of Policy selector Remote
1488 IPv4 addresses. Valid values are from 1 to 32.
1489 :param n_instances: Number of containers.
1491 :type if1_ip_addr: str
1492 :type if2_ip_addr: str
1493 :type n_tunnels: int
1494 :type crypto_alg: CryptoAlg
1495 :type integ_alg: IntegAlg
1496 :type raddr_ip1: string
1497 :type raddr_ip2: string
1498 :type raddr_range: int
1499 :type n_instances: int
1503 addr_incr = 1 << (32 - raddr_range)
1505 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1506 u"DUT1", n_instances
1508 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1509 u"DUT2", n_instances
1512 for cnf in range(0, n_instances):
1513 dut1_scripts[cnf].write(
1514 u"create loopback interface\n"
1515 u"set interface state loop0 up\n\n"
1517 dut2_scripts[cnf].write(
1518 f"ip route add {if1_ip_addr}/8 via "
1519 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1522 for tnl in range(0, n_tunnels):
1523 cnf = tnl % n_instances
1525 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1530 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1533 f"integ-alg {integ_alg.alg_name} "
1534 f"local-integ-key {ikey} "
1535 f"remote-integ-key {ikey} "
1537 # Configure tunnel end point(s) on left side
1538 dut1_scripts[cnf].write(
1539 u"set interface ip address loop0 "
1540 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1541 f"create ipsec tunnel "
1542 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1543 f"local-spi {spi_1 + tnl} "
1544 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1545 f"remote-spi {spi_2 + tnl} "
1546 f"crypto-alg {crypto_alg.alg_name} "
1547 f"local-crypto-key {ckey} "
1548 f"remote-crypto-key {ckey} "
1549 f"instance {tnl // n_instances} "
1552 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1553 f"set interface state ipip{tnl // n_instances} up\n"
1554 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1555 f"via ipip{tnl // n_instances}\n\n"
1557 # Configure tunnel end point(s) on right side
1558 dut2_scripts[cnf].write(
1559 f"set ip neighbor memif1/{cnf + 1} "
1560 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1561 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1562 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1563 f"local-spi {spi_2 + tnl} "
1564 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1565 f"remote-spi {spi_1 + tnl} "
1566 f"crypto-alg {crypto_alg.alg_name} "
1567 f"local-crypto-key {ckey} "
1568 f"remote-crypto-key {ckey} "
1569 f"instance {tnl // n_instances} "
1572 f"set interface unnumbered ipip{tnl // n_instances} "
1573 f"use memif1/{cnf + 1}\n"
1574 f"set interface state ipip{tnl // n_instances} up\n"
1575 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1576 f"via ipip{tnl // n_instances}\n\n"
1579 IPsecUtil._close_and_copy_ipsec_script_files(
1580 u"DUT1", nodes, n_instances, dut1_scripts)
1581 IPsecUtil._close_and_copy_ipsec_script_files(
1582 u"DUT2", nodes, n_instances, dut2_scripts)
1585 def vpp_ipsec_add_multiple_tunnels(
1586 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1587 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
1588 """Create multiple IPsec tunnels between two VPP nodes.
1590 :param nodes: VPP nodes to create tunnels.
1591 :param interface1: Interface name or sw_if_index on node 1.
1592 :param interface2: Interface name or sw_if_index on node 2.
1593 :param n_tunnels: Number of tunnels to create.
1594 :param crypto_alg: The encryption algorithm name.
1595 :param integ_alg: The integrity algorithm name.
1596 :param tunnel_ip1: Tunnel node1 IPv4 address.
1597 :param tunnel_ip2: Tunnel node2 IPv4 address.
1598 :param raddr_ip1: Policy selector remote IPv4 start address for the
1599 first tunnel in direction node1->node2.
1600 :param raddr_ip2: Policy selector remote IPv4 start address for the
1601 first tunnel in direction node2->node1.
1602 :param raddr_range: Mask specifying range of Policy selector Remote
1603 IPv4 addresses. Valid values are from 1 to 32.
1605 :type interface1: str or int
1606 :type interface2: str or int
1607 :type n_tunnels: int
1608 :type crypto_alg: CryptoAlg
1609 :type integ_alg: IntegAlg
1610 :type tunnel_ip1: str
1611 :type tunnel_ip2: str
1612 :type raddr_ip1: string
1613 :type raddr_ip2: string
1614 :type raddr_range: int
1624 crypto_key = gen_key(
1625 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1627 integ_key = gen_key(
1628 IPsecUtil.get_integ_alg_key_len(integ_alg)
1629 ).decode() if integ_alg else u""
1631 IPsecUtil.vpp_ipsec_set_ip_route(
1632 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1633 interface1, raddr_range)
1634 IPsecUtil.vpp_ipsec_set_ip_route(
1635 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1636 interface2, raddr_range)
1638 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1639 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1640 IPsecUtil.vpp_ipsec_policy_add(
1641 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1642 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1644 IPsecUtil.vpp_ipsec_policy_add(
1645 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1646 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1649 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1650 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1651 IPsecUtil.vpp_ipsec_policy_add(
1652 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1653 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1655 IPsecUtil.vpp_ipsec_policy_add(
1656 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1657 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1660 IPsecUtil.vpp_ipsec_add_sad_entries(
1661 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1662 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1664 IPsecUtil.vpp_ipsec_spd_add_entries(
1665 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, False, sa_id_1, raddr_ip2
1668 IPsecUtil.vpp_ipsec_add_sad_entries(
1669 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1670 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1672 IPsecUtil.vpp_ipsec_spd_add_entries(
1673 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, True, sa_id_1, raddr_ip2
1676 IPsecUtil.vpp_ipsec_add_sad_entries(
1677 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1678 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1681 IPsecUtil.vpp_ipsec_spd_add_entries(
1682 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, False, sa_id_2, raddr_ip1
1685 IPsecUtil.vpp_ipsec_add_sad_entries(
1686 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1687 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1690 IPsecUtil.vpp_ipsec_spd_add_entries(
1691 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, True, sa_id_2, raddr_ip1
1695 def vpp_ipsec_show(node):
1696 """Run "show ipsec" debug CLI command.
1698 :param node: Node to run command on.
1701 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec")