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),
332 udp_src_port=4500, # default value in api
333 udp_dst_port=4500 # default value in api
339 with PapiSocketExecutor(node) as papi_exec:
340 papi_exec.add(cmd, **args).get_reply(err_msg)
343 def vpp_ipsec_add_sad_entries(
344 node, n_entries, sad_id, spi, crypto_alg, crypto_key,
345 integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
346 """Create multiple Security Association Database entries on VPP node.
348 :param node: VPP node to add SAD entry on.
349 :param n_entries: Number of SAD entries to be created.
350 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
352 :param spi: Security Parameter Index of first SAD entry. All subsequent
353 SAD entries will have spi incremented by 1.
354 :param crypto_alg: The encryption algorithm name.
355 :param crypto_key: The encryption key string.
356 :param integ_alg: The integrity algorithm name.
357 :param integ_key: The integrity key string.
358 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
359 specified ESP transport mode is used.
360 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
361 not specified ESP transport mode is used.
366 :type crypto_alg: CryptoAlg
367 :type crypto_key: str
368 :type integ_alg: IntegAlg
370 :type tunnel_src: str
371 :type tunnel_dst: str
373 if isinstance(crypto_key, str):
374 crypto_key = crypto_key.encode(encoding=u"utf-8")
375 if isinstance(integ_key, str):
376 integ_key = integ_key.encode(encoding=u"utf-8")
377 if tunnel_src and tunnel_dst:
378 src_addr = ip_address(tunnel_src)
379 dst_addr = ip_address(tunnel_dst)
384 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
387 if int(n_entries) > 10:
388 tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
390 with open(tmp_filename, 'w') as tmp_file:
391 for i in range(n_entries):
392 integ = f"integ-alg {integ_alg.alg_name} " \
393 f"integ-key {integ_key.hex()}" \
394 if integ_alg else u""
395 tunnel = f"tunnel-src {src_addr + i * addr_incr} " \
396 f"tunnel-dst {dst_addr + i * addr_incr}" \
397 if tunnel_src and tunnel_dst else u""
398 conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
399 f"crypto-alg {crypto_alg.alg_name} " \
400 f"crypto-key {crypto_key.hex()} " \
401 f"{integ} {tunnel}\n"
405 tmp_filename, node, timeout=300, json_out=False,
408 os.remove(tmp_filename)
412 length=len(crypto_key),
416 length=len(integ_key),
417 data=integ_key if integ_key else 0
420 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
421 if tunnel_src and tunnel_dst:
422 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
423 if src_addr.version == 6:
425 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
428 cmd = u"ipsec_sad_entry_add_del"
429 err_msg = f"Failed to add Security Association Database entry " \
430 f"on host {node[u'host']}"
435 crypto_algorithm=crypto_alg.alg_int_repr,
437 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
440 tunnel_src=str(src_addr),
441 tunnel_dst=str(dst_addr),
442 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
443 udp_src_port=4500, # default value in api
444 udp_dst_port=4500 # default value in api
450 with PapiSocketExecutor(node) as papi_exec:
451 for i in range(n_entries):
452 args[u"entry"][u"sad_id"] = int(sad_id) + i
453 args[u"entry"][u"spi"] = int(spi) + i
454 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
455 if tunnel_src and tunnel_dst else src_addr
456 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
457 if tunnel_src and tunnel_dst else dst_addr
458 history = bool(not 1 < i < n_entries - 2)
459 papi_exec.add(cmd, history=history, **args)
460 papi_exec.get_replies(err_msg)
463 def vpp_ipsec_set_ip_route(
464 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
466 """Set IP address and route on interface.
468 :param node: VPP node to add config on.
469 :param n_tunnels: Number of tunnels to create.
470 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
471 :param traffic_addr: Traffic destination IP address to route.
472 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
473 :param interface: Interface key on node 1.
474 :param raddr_range: Mask specifying range of Policy selector Remote IP
475 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
479 :type tunnel_src: str
480 :type traffic_addr: str
481 :type tunnel_dst: str
483 :type raddr_range: int
485 tunnel_src = ip_address(tunnel_src)
486 tunnel_dst = ip_address(tunnel_dst)
487 traffic_addr = ip_address(traffic_addr)
488 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
489 else 1 << (32 - raddr_range)
491 if int(n_tunnels) > 10:
492 tmp_filename = u"/tmp/ipsec_set_ip.script"
494 with open(tmp_filename, 'w') as tmp_file:
495 if_name = Topology.get_interface_name(node, interface)
496 for i in range(n_tunnels):
497 conf = f"exec set interface ip address {if_name} " \
498 f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
499 f"exec ip route add {traffic_addr + i}/" \
500 f"{128 if traffic_addr.version == 6 else 32} " \
501 f"via {tunnel_dst + i * addr_incr} {if_name}\n"
503 VatExecutor().execute_script(
504 tmp_filename, node, timeout=300, json_out=False,
507 os.remove(tmp_filename)
510 cmd1 = u"sw_interface_add_del_address"
512 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
517 cmd2 = u"ip_route_add_del"
523 err_msg = f"Failed to configure IP addresses and IP routes " \
524 f"on interface {interface} on host {node[u'host']}"
526 with PapiSocketExecutor(node) as papi_exec:
527 for i in range(n_tunnels):
528 args1[u"prefix"] = IPUtil.create_prefix_object(
529 tunnel_src + i * addr_incr, raddr_range
531 args2[u"route"] = IPUtil.compose_vpp_route_structure(
532 node, traffic_addr + i,
533 prefix_len=128 if traffic_addr.version == 6 else 32,
534 interface=interface, gateway=tunnel_dst + i * addr_incr
536 history = bool(not 1 < i < n_tunnels - 2)
537 papi_exec.add(cmd1, history=history, **args1).\
538 add(cmd2, history=history, **args2)
539 papi_exec.get_replies(err_msg)
542 def vpp_ipsec_add_spd(node, spd_id):
543 """Create Security Policy Database on the VPP node.
545 :param node: VPP node to add SPD on.
546 :param spd_id: SPD ID.
550 cmd = u"ipsec_spd_add_del"
551 err_msg = f"Failed to add Security Policy Database " \
552 f"on host {node[u'host']}"
557 with PapiSocketExecutor(node) as papi_exec:
558 papi_exec.add(cmd, **args).get_reply(err_msg)
561 def vpp_ipsec_spd_add_if(node, spd_id, interface):
562 """Add interface to the Security Policy Database.
564 :param node: VPP node.
565 :param spd_id: SPD ID to add interface on.
566 :param interface: Interface name or sw_if_index.
569 :type interface: str or int
571 cmd = u"ipsec_interface_add_del_spd"
572 err_msg = f"Failed to add interface {interface} to Security Policy " \
573 f"Database {spd_id} on host {node[u'host']}"
576 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
579 with PapiSocketExecutor(node) as papi_exec:
580 papi_exec.add(cmd, **args).get_reply(err_msg)
583 def vpp_ipsec_policy_add(
584 node, spd_id, priority, action, inbound=True, sa_id=None,
585 laddr_range=None, raddr_range=None, proto=None, lport_range=None,
586 rport_range=None, is_ipv6=False):
587 """Create Security Policy Database entry on the VPP node.
589 :param node: VPP node to add SPD entry on.
590 :param spd_id: SPD ID to add entry on.
591 :param priority: SPD entry priority, higher number = higher priority.
592 :param action: Policy action.
593 :param inbound: If True policy is for inbound traffic, otherwise
595 :param sa_id: SAD entry ID for protect action.
596 :param laddr_range: Policy selector local IPv4 or IPv6 address range in
597 format IP/prefix or IP/mask. If no mask is provided,
598 it's considered to be /32.
599 :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
600 format IP/prefix or IP/mask. If no mask is provided,
601 it's considered to be /32.
602 :param proto: Policy selector next layer protocol number.
603 :param lport_range: Policy selector local TCP/UDP port range in format
604 <port_start>-<port_end>.
605 :param rport_range: Policy selector remote TCP/UDP port range in format
606 <port_start>-<port_end>.
607 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
608 not defined so it will default to address ::/0, otherwise False.
612 :type action: PolicyAction
615 :type laddr_range: string
616 :type raddr_range: string
618 :type lport_range: string
619 :type rport_range: string
622 if laddr_range is None:
623 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
625 if raddr_range is None:
626 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
628 cmd = u"ipsec_spd_entry_add_del"
629 err_msg = f"Failed to add entry to Security Policy Database {spd_id} " \
630 f"on host {node[u'host']}"
634 priority=int(priority),
635 is_outbound=not inbound,
636 sa_id=int(sa_id) if sa_id else 0,
637 policy=action.policy_int_repr,
638 protocol=int(proto) if proto else 0,
639 remote_address_start=IPAddress.create_ip_address_object(
640 ip_network(raddr_range, strict=False).network_address
642 remote_address_stop=IPAddress.create_ip_address_object(
643 ip_network(raddr_range, strict=False).broadcast_address
645 local_address_start=IPAddress.create_ip_address_object(
646 ip_network(laddr_range, strict=False).network_address
648 local_address_stop=IPAddress.create_ip_address_object(
649 ip_network(laddr_range, strict=False).broadcast_address
651 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
653 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
655 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
657 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
664 with PapiSocketExecutor(node) as papi_exec:
665 papi_exec.add(cmd, **args).get_reply(err_msg)
668 def vpp_ipsec_spd_add_entries(
669 node, n_entries, spd_id, priority, inbound, sa_id, raddr_ip,
671 """Create multiple Security Policy Database entries on the VPP node.
673 :param node: VPP node to add SPD entries on.
674 :param n_entries: Number of SPD entries to be added.
675 :param spd_id: SPD ID to add entries on.
676 :param priority: SPD entries priority, higher number = higher priority.
677 :param inbound: If True policy is for inbound traffic, otherwise
679 :param sa_id: SAD entry ID for first entry. Each subsequent entry will
680 SAD entry ID incremented by 1.
681 :param raddr_ip: Policy selector remote IPv4 start address for the first
682 entry. Remote IPv4 end address will be calculated depending on
683 raddr_range parameter. Each subsequent entry will have start address
684 next after IPv4 end address of previous entry.
685 :param raddr_range: Required IP addres range.
693 :type raddr_range: int
695 raddr_ip = ip_address(raddr_ip)
696 if int(n_entries) > 10:
697 tmp_filename = f"/tmp/ipsec_spd_{sa_id}_add_del_entry.script"
699 with open(tmp_filename, 'w') as tmp_file:
700 for i in range(n_entries):
701 direction = u'inbound' if inbound else u'outbound'
702 tunnel = f"exec ipsec policy add spd {spd_id} " \
703 f"priority {priority} {direction} " \
704 f"action protect sa {sa_id+i} " \
705 f"remote-ip-range {raddr_ip + i * (raddr_range + 1)} " \
706 f"- {raddr_ip + (i + 1) * raddr_range + i} " \
707 f"local-ip-range 0.0.0.0 - 255.255.255.255\n"
708 tmp_file.write(tunnel)
709 VatExecutor().execute_script(
710 tmp_filename, node, timeout=300, json_out=False,
713 os.remove(tmp_filename)
716 laddr_range = u"::/0" if raddr_ip.version == 6 else u"0.0.0.0/0"
718 cmd = u"ipsec_spd_entry_add_del"
719 err_msg = f"ailed to add entry to Security Policy Database '{spd_id} " \
720 f"on host {node[u'host']}"
724 priority=int(priority),
725 is_outbound=not inbound,
726 sa_id=int(sa_id) if sa_id else 0,
727 policy=getattr(PolicyAction.PROTECT, u"policy_int_repr"),
729 remote_address_start=IPAddress.create_ip_address_object(raddr_ip),
730 remote_address_stop=IPAddress.create_ip_address_object(raddr_ip),
731 local_address_start=IPAddress.create_ip_address_object(
732 ip_network(laddr_range, strict=False).network_address
734 local_address_stop=IPAddress.create_ip_address_object(
735 ip_network(laddr_range, strict=False).broadcast_address
738 remote_port_stop=65535,
740 local_port_stop=65535
747 with PapiSocketExecutor(node) as papi_exec:
748 for i in range(n_entries):
749 args[u"entry"][u"remote_address_start"][u"un"] = \
750 IPAddress.union_addr(raddr_ip + i)
751 args[u"entry"][u"remote_address_stop"][u"un"] = \
752 IPAddress.union_addr(raddr_ip + i)
753 history = bool(not 1 < i < n_entries - 2)
754 papi_exec.add(cmd, history=history, **args)
755 papi_exec.get_replies(err_msg)
758 def _ipsec_create_tunnel_interfaces_dut1_vat(
759 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
760 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
761 """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
763 :param nodes: VPP nodes to create tunnel interfaces.
764 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
765 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
766 IPv4/IPv6 address (ip2).
767 :param if1_key: VPP node 1 interface key from topology file.
768 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
769 interface key from topology file.
770 :param n_tunnels: Number of tunnel interfaces to be there at the end.
771 :param crypto_alg: The encryption algorithm name.
772 :param integ_alg: The integrity algorithm name.
773 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
774 first tunnel in direction node2->node1.
775 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
776 :param addr_incr: IP / IPv6 address incremental step.
777 :param existing_tunnels: Number of tunnel interfaces before creation.
778 Useful mainly for reconf tests. Default 0.
784 :type crypto_alg: CryptoAlg
785 :type integ_alg: IntegAlg
786 :type raddr_ip2: IPv4Address or IPv6Address
789 :type existing_tunnels: int
791 tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
792 if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
794 ckeys = [bytes()] * existing_tunnels
795 ikeys = [bytes()] * existing_tunnels
798 with open(tmp_fn1, u"w") as tmp_f1:
799 rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
800 if u"DUT2" in nodes.keys() \
801 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
802 if not existing_tunnels:
804 f"exec create loopback interface\n"
805 f"exec set interface state loop0 up\n"
806 f"exec set interface ip address {if1_n} "
807 f"{tun_ips[u'ip2'] - 1}/"
808 f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
809 f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
812 for i in range(existing_tunnels, n_tunnels):
814 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
818 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
820 integ = f"integ_alg {integ_alg.alg_name} " \
821 f"local_integ_key {ikeys[i].hex()} " \
822 f"remote_integ_key {ikeys[i].hex()} "
826 f"exec set interface ip address loop0 "
827 f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
828 f"ipsec_tunnel_if_add_del "
829 f"local_spi {spi_d[u'spi_1'] + i} "
830 f"remote_spi {spi_d[u'spi_2'] + i} "
831 f"crypto_alg {crypto_alg.alg_name} "
832 f"local_crypto_key {ckeys[i].hex()} "
833 f"remote_crypto_key {ckeys[i].hex()} "
835 f"local_ip {tun_ips[u'ip1'] + i * addr_incr} "
836 f"remote_ip {tun_ips[u'ip2']} "
840 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
841 copy_on_execute=True,
842 history=bool(n_tunnels < 100)
846 with open(tmp_fn1, 'w') as tmp_f1:
847 for i in range(existing_tunnels, n_tunnels):
849 f"exec set interface unnumbered ipip{i} use {if1_n}\n"
850 f"exec set interface state ipip{i} up\n"
851 f"exec ip route add "
852 f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
856 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
857 copy_on_execute=True,
858 history=bool(n_tunnels < 100)
865 def _ipsec_create_tunnel_interfaces_dut2_vat(
866 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
867 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
868 """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
870 :param nodes: VPP nodes to create tunnel interfaces.
871 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
872 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
873 IPv4/IPv6 address (ip2).
874 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
875 interface key from topology file.
876 :param n_tunnels: Number of tunnel interfaces to be there at the end.
877 :param crypto_alg: The encryption algorithm name.
878 :param ckeys: List of encryption keys.
879 :param integ_alg: The integrity algorithm name.
880 :param ikeys: List of integrity keys.
881 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
882 :param addr_incr: IP / IPv6 address incremental step.
883 :param existing_tunnels: Number of tunnel interfaces before creation.
884 Useful mainly for reconf tests. Default 0.
889 :type crypto_alg: CryptoAlg
891 :type integ_alg: IntegAlg
895 :type existing_tunnels: int
897 tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
898 if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
901 with open(tmp_fn2, 'w') as tmp_f2:
902 if not existing_tunnels:
904 f"exec set interface ip address {if2_n}"
905 f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
907 for i in range(existing_tunnels, n_tunnels):
909 integ = f"integ_alg {integ_alg.alg_name} " \
910 f"local_integ_key {ikeys[i].hex()} " \
911 f"remote_integ_key {ikeys[i].hex()} "
915 f"ipsec_tunnel_if_add_del "
916 f"local_spi {spi_d[u'spi_2'] + i} "
917 f"remote_spi {spi_d[u'spi_1'] + i} "
918 f"crypto_alg {crypto_alg.alg_name} "
919 f"local_crypto_key {ckeys[i].hex()} "
920 f"remote_crypto_key {ckeys[i].hex()} "
922 f"local_ip {tun_ips[u'ip2']} "
923 f"remote_ip {tun_ips[u'ip1'] + i * addr_incr} "
927 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
928 copy_on_execute=True,
929 history=bool(n_tunnels < 100)
933 with open(tmp_fn2, 'w') as tmp_f2:
934 if not existing_tunnels:
936 f"exec ip route add {tun_ips[u'ip1']}/8 "
937 f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
939 for i in range(existing_tunnels, n_tunnels):
941 f"exec set interface unnumbered ipip{i} use {if2_n}\n"
942 f"exec set interface state ipip{i} up\n"
943 f"exec ip route add "
944 f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
948 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
949 copy_on_execute=True,
950 history=bool(n_tunnels < 100)
955 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
956 """Create loopback interface and set IP address on VPP node 1 interface
959 :param nodes: VPP nodes to create tunnel interfaces.
960 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
961 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
962 IPv4/IPv6 address (ip2).
963 :param if1_key: VPP node 1 interface key from topology file.
964 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
965 interface key from topology file.
971 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
972 # Create loopback interface on DUT1, set it to up state
973 cmd = u"create_loopback"
977 err_msg = f"Failed to create loopback interface " \
978 f"on host {nodes[u'DUT1'][u'host']}"
979 loop_sw_if_idx = papi_exec.add(cmd, **args). \
980 get_sw_if_index(err_msg)
981 cmd = u"sw_interface_set_flags"
983 sw_if_index=loop_sw_if_idx,
984 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
986 err_msg = f"Failed to set loopback interface state up " \
987 f"on host {nodes[u'DUT1'][u'host']}"
988 papi_exec.add(cmd, **args).get_reply(err_msg)
989 # Set IP address on VPP node 1 interface
990 cmd = u"sw_interface_add_del_address"
992 sw_if_index=InterfaceUtil.get_interface_index(
993 nodes[u"DUT1"], if1_key
997 prefix=IPUtil.create_prefix_object(
998 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1002 err_msg = f"Failed to set IP address on interface {if1_key} " \
1003 f"on host {nodes[u'DUT1'][u'host']}"
1004 papi_exec.add(cmd, **args).get_reply(err_msg)
1005 cmd2 = u"ip_neighbor_add_del"
1009 sw_if_index=Topology.get_interface_sw_index(
1010 nodes[u"DUT1"], if1_key
1014 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1015 if u"DUT2" in nodes.keys()
1016 else Topology.get_interface_mac(
1017 nodes[u"TG"], if2_key
1020 ip_address=tun_ips[u"ip2"].compressed
1023 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1024 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1026 return loop_sw_if_idx
1029 def _ipsec_create_tunnel_interfaces_dut1_papi(
1030 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1031 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1032 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1034 :param nodes: VPP nodes to create tunnel interfaces.
1035 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1036 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1037 IPv4/IPv6 address (ip2).
1038 :param if1_key: VPP node 1 interface key from topology file.
1039 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1040 interface key from topology file.
1041 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1042 :param crypto_alg: The encryption algorithm name.
1043 :param integ_alg: The integrity algorithm name.
1044 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1045 first tunnel in direction node2->node1.
1046 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1047 :param addr_incr: IP / IPv6 address incremental step.
1048 :param existing_tunnels: Number of tunnel interfaces before creation.
1049 Useful mainly for reconf tests. Default 0.
1054 :type n_tunnels: int
1055 :type crypto_alg: CryptoAlg
1056 :type integ_alg: IntegAlg
1057 :type raddr_ip2: IPv4Address or IPv6Address
1058 :type addr_incr: int
1060 :type existing_tunnels: int
1062 if not existing_tunnels:
1063 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1064 nodes, tun_ips, if1_key, if2_key
1067 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1068 nodes[u"DUT1"], u"loop0"
1070 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1071 # Configure IP addresses on loop0 interface
1072 cmd = u"sw_interface_add_del_address"
1074 sw_if_index=loop_sw_if_idx,
1079 for i in range(existing_tunnels, n_tunnels):
1080 args[u"prefix"] = IPUtil.create_prefix_object(
1081 tun_ips[u"ip1"] + i * addr_incr,
1082 128 if tun_ips[u"ip1"].version == 6 else 32
1085 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1087 # Configure IPsec tunnel interfaces
1088 cmd = u"ipsec_tunnel_if_add_del"
1095 crypto_alg=crypto_alg.alg_int_repr,
1096 local_crypto_key_len=0,
1097 local_crypto_key=None,
1098 remote_crypto_key_len=0,
1099 remote_crypto_key=None,
1100 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1101 local_integ_key_len=0,
1102 local_integ_key=None,
1103 remote_integ_key_len=0,
1104 remote_integ_key=None,
1107 ipsec_tunnels = [None] * existing_tunnels
1108 ckeys = [bytes()] * existing_tunnels
1109 ikeys = [bytes()] * existing_tunnels
1110 for i in range(existing_tunnels, n_tunnels):
1112 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1116 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1118 args[u"local_spi"] = spi_d[u"spi_1"] + i
1119 args[u"remote_spi"] = spi_d[u"spi_2"] + i
1120 args[u"local_ip"] = IPAddress.create_ip_address_object(
1121 tun_ips[u"ip1"] + i * addr_incr
1123 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1126 args[u"local_crypto_key_len"] = len(ckeys[i])
1127 args[u"local_crypto_key"] = ckeys[i]
1128 args[u"remote_crypto_key_len"] = len(ckeys[i])
1129 args[u"remote_crypto_key"] = ckeys[i]
1131 args[u"local_integ_key_len"] = len(ikeys[i])
1132 args[u"local_integ_key"] = ikeys[i]
1133 args[u"remote_integ_key_len"] = len(ikeys[i])
1134 args[u"remote_integ_key"] = ikeys[i]
1136 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1138 err_msg = f"Failed to add IPsec tunnel interfaces on host" \
1139 f" {nodes[u'DUT1'][u'host']}"
1140 ipsec_tunnels.extend(
1142 reply[u"sw_if_index"]
1143 for reply in papi_exec.get_replies(err_msg)
1144 if u"sw_if_index" in reply
1147 # Configure unnumbered interfaces
1148 cmd = u"sw_interface_set_unnumbered"
1151 sw_if_index=InterfaceUtil.get_interface_index(
1152 nodes[u"DUT1"], if1_key
1154 unnumbered_sw_if_index=0
1156 for i in range(existing_tunnels, n_tunnels):
1157 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1159 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1162 cmd = u"sw_interface_set_flags"
1165 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1167 for i in range(existing_tunnels, n_tunnels):
1168 args[u"sw_if_index"] = ipsec_tunnels[i]
1170 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1172 # Configure IP routes
1173 cmd = u"ip_route_add_del"
1179 for i in range(existing_tunnels, n_tunnels):
1180 args[u"route"] = IPUtil.compose_vpp_route_structure(
1181 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1182 prefix_len=128 if raddr_ip2.version == 6 else 32,
1183 interface=ipsec_tunnels[i]
1186 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1188 err_msg = f"Failed to add IP routes on host " \
1189 f"{nodes[u'DUT1'][u'host']}"
1190 papi_exec.get_replies(err_msg)
1195 def _ipsec_create_tunnel_interfaces_dut2_papi(
1196 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1197 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1198 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1200 :param nodes: VPP nodes to create tunnel interfaces.
1201 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1202 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1203 IPv4/IPv6 address (ip2).
1204 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1205 interface key from topology file.
1206 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1207 :param crypto_alg: The encryption algorithm name.
1208 :param ckeys: List of encryption keys.
1209 :param integ_alg: The integrity algorithm name.
1210 :param ikeys: List of integrity keys.
1211 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1212 :param addr_incr: IP / IPv6 address incremental step.
1213 :param existing_tunnels: Number of tunnel interfaces before creation.
1214 Useful mainly for reconf tests. Default 0.
1218 :type n_tunnels: int
1219 :type crypto_alg: CryptoAlg
1221 :type integ_alg: IntegAlg
1223 :type addr_incr: int
1225 :type existing_tunnels: int
1227 with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1228 if not existing_tunnels:
1229 # Set IP address on VPP node 2 interface
1230 cmd = u"sw_interface_add_del_address"
1232 sw_if_index=InterfaceUtil.get_interface_index(
1233 nodes[u"DUT2"], if2_key
1237 prefix=IPUtil.create_prefix_object(
1238 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1242 err_msg = f"Failed to set IP address on interface {if2_key} " \
1243 f"on host {nodes[u'DUT2'][u'host']}"
1244 papi_exec.add(cmd, **args).get_reply(err_msg)
1245 # Configure IPsec tunnel interfaces
1246 cmd = u"ipsec_tunnel_if_add_del"
1249 local_ip=IPAddress.create_ip_address_object(tun_ips[u"ip2"]),
1253 crypto_alg=crypto_alg.alg_int_repr,
1254 local_crypto_key_len=0,
1255 local_crypto_key=None,
1256 remote_crypto_key_len=0,
1257 remote_crypto_key=None,
1258 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1259 local_integ_key_len=0,
1260 local_integ_key=None,
1261 remote_integ_key_len=0,
1262 remote_integ_key=None,
1265 ipsec_tunnels = [None] * existing_tunnels
1266 for i in range(existing_tunnels, n_tunnels):
1267 args[u"local_spi"] = spi_d[u"spi_2"] + i
1268 args[u"remote_spi"] = spi_d[u"spi_1"] + i
1269 args[u"local_ip"] = IPAddress.create_ip_address_object(
1272 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1273 tun_ips[u"ip1"] + i * addr_incr
1275 args[u"local_crypto_key_len"] = len(ckeys[i])
1276 args[u"local_crypto_key"] = ckeys[i]
1277 args[u"remote_crypto_key_len"] = len(ckeys[i])
1278 args[u"remote_crypto_key"] = ckeys[i]
1280 args[u"local_integ_key_len"] = len(ikeys[i])
1281 args[u"local_integ_key"] = ikeys[i]
1282 args[u"remote_integ_key_len"] = len(ikeys[i])
1283 args[u"remote_integ_key"] = ikeys[i]
1285 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1287 err_msg = f"Failed to add IPsec tunnel interfaces " \
1288 f"on host {nodes[u'DUT2'][u'host']}"
1289 ipsec_tunnels.extend(
1291 reply[u"sw_if_index"]
1292 for reply in papi_exec.get_replies(err_msg)
1293 if u"sw_if_index" in reply
1296 if not existing_tunnels:
1297 # Configure IP route
1298 cmd = u"ip_route_add_del"
1299 route = IPUtil.compose_vpp_route_structure(
1300 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1301 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1303 gateway=(tun_ips[u"ip2"] - 1).compressed
1310 papi_exec.add(cmd, **args)
1311 # Configure unnumbered interfaces
1312 cmd = u"sw_interface_set_unnumbered"
1315 sw_if_index=InterfaceUtil.get_interface_index(
1316 nodes[u"DUT2"], if2_key
1318 unnumbered_sw_if_index=0
1320 for i in range(existing_tunnels, n_tunnels):
1321 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1323 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1326 cmd = u"sw_interface_set_flags"
1329 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1331 for i in range(existing_tunnels, n_tunnels):
1332 args[u"sw_if_index"] = ipsec_tunnels[i]
1334 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1336 # Configure IP routes
1337 cmd = u"ip_route_add_del"
1343 for i in range(existing_tunnels, n_tunnels):
1344 args[u"route"] = IPUtil.compose_vpp_route_structure(
1345 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1346 prefix_len=128 if raddr_ip1.version == 6 else 32,
1347 interface=ipsec_tunnels[i]
1350 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1352 err_msg = f"Failed to add IP routes " \
1353 f"on host {nodes[u'DUT2'][u'host']}"
1354 papi_exec.get_replies(err_msg)
1357 def vpp_ipsec_create_tunnel_interfaces(
1358 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1359 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1360 existing_tunnels=0):
1361 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1363 :param nodes: VPP nodes to create tunnel interfaces.
1364 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1366 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1368 :param if1_key: VPP node 1 interface key from topology file.
1369 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1370 interface key from topology file.
1371 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1372 :param crypto_alg: The encryption algorithm name.
1373 :param integ_alg: The integrity algorithm name.
1374 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1375 first tunnel in direction node1->node2.
1376 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1377 first tunnel in direction node2->node1.
1378 :param raddr_range: Mask specifying range of Policy selector Remote
1379 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1380 and to 128 in case of IPv6.
1381 :param existing_tunnels: Number of tunnel interfaces before creation.
1382 Useful mainly for reconf tests. Default 0.
1384 :type tun_if1_ip_addr: str
1385 :type tun_if2_ip_addr: str
1388 :type n_tunnels: int
1389 :type crypto_alg: CryptoAlg
1390 :type integ_alg: IntegAlg
1391 :type raddr_ip1: string
1392 :type raddr_ip2: string
1393 :type raddr_range: int
1394 :type existing_tunnels: int
1396 n_tunnels = int(n_tunnels)
1397 existing_tunnels = int(existing_tunnels)
1403 ip1=ip_address(tun_if1_ip_addr),
1404 ip2=ip_address(tun_if2_ip_addr)
1406 raddr_ip1 = ip_address(raddr_ip1)
1407 raddr_ip2 = ip_address(raddr_ip2)
1408 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1409 else 1 << (32 - raddr_range)
1411 if n_tunnels - existing_tunnels > 10:
1412 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1413 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1414 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1416 if u"DUT2" not in nodes.keys():
1417 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1418 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1419 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1420 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1423 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1424 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1425 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1427 if u"DUT2" not in nodes.keys():
1428 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1429 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1430 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1431 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1434 return None, None, None, None
1437 def _create_ipsec_script_files(dut, instances):
1438 """Create script files for configuring IPsec in containers
1440 :param dut: DUT node on which to create the script files
1441 :param instances: number of containers on DUT node
1443 :type instances: int
1446 for cnf in range(0, instances):
1448 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1450 scripts.append(open(script_filename, 'w'))
1454 def _close_and_copy_ipsec_script_files(
1455 dut, nodes, instances, scripts):
1456 """Close created scripts and copy them to containers
1458 :param dut: DUT node on which to create the script files
1459 :param nodes: VPP nodes
1460 :param instances: number of containers on DUT node
1461 :param scripts: dictionary holding the script files
1464 :type instances: int
1467 for cnf in range(0, instances):
1468 scripts[cnf].close()
1470 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1472 scp_node(nodes[dut], script_filename, script_filename)
1476 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1477 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1478 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1479 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1481 :param nodes: VPP nodes to create tunnel interfaces.
1482 :param if1_ip_addr: VPP node 1 interface IP4 address.
1483 :param if2_ip_addr: VPP node 2 interface IP4 address.
1484 :param n_tunnels: Number of tunnell interfaces to create.
1485 :param crypto_alg: The encryption algorithm name.
1486 :param integ_alg: The integrity algorithm name.
1487 :param raddr_ip1: Policy selector remote IPv4 start address for the
1488 first tunnel in direction node1->node2.
1489 :param raddr_ip2: Policy selector remote IPv4 start address for the
1490 first tunnel in direction node2->node1.
1491 :param raddr_range: Mask specifying range of Policy selector Remote
1492 IPv4 addresses. Valid values are from 1 to 32.
1493 :param n_instances: Number of containers.
1495 :type if1_ip_addr: str
1496 :type if2_ip_addr: str
1497 :type n_tunnels: int
1498 :type crypto_alg: CryptoAlg
1499 :type integ_alg: IntegAlg
1500 :type raddr_ip1: string
1501 :type raddr_ip2: string
1502 :type raddr_range: int
1503 :type n_instances: int
1507 addr_incr = 1 << (32 - raddr_range)
1509 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1510 u"DUT1", n_instances
1512 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1513 u"DUT2", n_instances
1516 for cnf in range(0, n_instances):
1517 dut1_scripts[cnf].write(
1518 u"create loopback interface\n"
1519 u"set interface state loop0 up\n\n"
1521 dut2_scripts[cnf].write(
1522 f"ip route add {if1_ip_addr}/8 via "
1523 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1526 for tnl in range(0, n_tunnels):
1527 cnf = tnl % n_instances
1529 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1534 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1537 f"integ-alg {integ_alg.alg_name} "
1538 f"local-integ-key {ikey} "
1539 f"remote-integ-key {ikey} "
1541 # Configure tunnel end point(s) on left side
1542 dut1_scripts[cnf].write(
1543 u"set interface ip address loop0 "
1544 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1545 f"create ipsec tunnel "
1546 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1547 f"local-spi {spi_1 + tnl} "
1548 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1549 f"remote-spi {spi_2 + tnl} "
1550 f"crypto-alg {crypto_alg.alg_name} "
1551 f"local-crypto-key {ckey} "
1552 f"remote-crypto-key {ckey} "
1553 f"instance {tnl // n_instances} "
1556 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1557 f"set interface state ipip{tnl // n_instances} up\n"
1558 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1559 f"via ipip{tnl // n_instances}\n\n"
1561 # Configure tunnel end point(s) on right side
1562 dut2_scripts[cnf].write(
1563 f"set ip neighbor memif1/{cnf + 1} "
1564 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1565 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1566 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1567 f"local-spi {spi_2 + tnl} "
1568 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1569 f"remote-spi {spi_1 + tnl} "
1570 f"crypto-alg {crypto_alg.alg_name} "
1571 f"local-crypto-key {ckey} "
1572 f"remote-crypto-key {ckey} "
1573 f"instance {tnl // n_instances} "
1576 f"set interface unnumbered ipip{tnl // n_instances} "
1577 f"use memif1/{cnf + 1}\n"
1578 f"set interface state ipip{tnl // n_instances} up\n"
1579 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1580 f"via ipip{tnl // n_instances}\n\n"
1583 IPsecUtil._close_and_copy_ipsec_script_files(
1584 u"DUT1", nodes, n_instances, dut1_scripts)
1585 IPsecUtil._close_and_copy_ipsec_script_files(
1586 u"DUT2", nodes, n_instances, dut2_scripts)
1589 def vpp_ipsec_add_multiple_tunnels(
1590 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1591 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
1592 """Create multiple IPsec tunnels between two VPP nodes.
1594 :param nodes: VPP nodes to create tunnels.
1595 :param interface1: Interface name or sw_if_index on node 1.
1596 :param interface2: Interface name or sw_if_index on node 2.
1597 :param n_tunnels: Number of tunnels to create.
1598 :param crypto_alg: The encryption algorithm name.
1599 :param integ_alg: The integrity algorithm name.
1600 :param tunnel_ip1: Tunnel node1 IPv4 address.
1601 :param tunnel_ip2: Tunnel node2 IPv4 address.
1602 :param raddr_ip1: Policy selector remote IPv4 start address for the
1603 first tunnel in direction node1->node2.
1604 :param raddr_ip2: Policy selector remote IPv4 start address for the
1605 first tunnel in direction node2->node1.
1606 :param raddr_range: Mask specifying range of Policy selector Remote
1607 IPv4 addresses. Valid values are from 1 to 32.
1609 :type interface1: str or int
1610 :type interface2: str or int
1611 :type n_tunnels: int
1612 :type crypto_alg: CryptoAlg
1613 :type integ_alg: IntegAlg
1614 :type tunnel_ip1: str
1615 :type tunnel_ip2: str
1616 :type raddr_ip1: string
1617 :type raddr_ip2: string
1618 :type raddr_range: int
1628 crypto_key = gen_key(
1629 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1631 integ_key = gen_key(
1632 IPsecUtil.get_integ_alg_key_len(integ_alg)
1633 ).decode() if integ_alg else u""
1635 IPsecUtil.vpp_ipsec_set_ip_route(
1636 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1637 interface1, raddr_range)
1638 IPsecUtil.vpp_ipsec_set_ip_route(
1639 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1640 interface2, raddr_range)
1642 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1643 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1644 IPsecUtil.vpp_ipsec_policy_add(
1645 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1646 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1648 IPsecUtil.vpp_ipsec_policy_add(
1649 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1650 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1653 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1654 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1655 IPsecUtil.vpp_ipsec_policy_add(
1656 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1657 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1659 IPsecUtil.vpp_ipsec_policy_add(
1660 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1661 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1664 IPsecUtil.vpp_ipsec_add_sad_entries(
1665 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1666 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1668 IPsecUtil.vpp_ipsec_spd_add_entries(
1669 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, False, sa_id_1, raddr_ip2
1672 IPsecUtil.vpp_ipsec_add_sad_entries(
1673 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1674 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1676 IPsecUtil.vpp_ipsec_spd_add_entries(
1677 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, True, sa_id_1, raddr_ip2
1680 IPsecUtil.vpp_ipsec_add_sad_entries(
1681 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1682 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1685 IPsecUtil.vpp_ipsec_spd_add_entries(
1686 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, False, sa_id_2, raddr_ip1
1689 IPsecUtil.vpp_ipsec_add_sad_entries(
1690 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1691 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1694 IPsecUtil.vpp_ipsec_spd_add_entries(
1695 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, True, sa_id_2, raddr_ip1
1699 def vpp_ipsec_show(node):
1700 """Run "show ipsec" debug CLI command.
1702 :param node: Node to run command on.
1705 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec")