FIX: IPsec naming creation
[csit.git] / resources / libraries / python / IPsecUtil.py
1 # Copyright (c) 2019 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:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
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.
13
14 """IPsec utilities library."""
15
16 import os
17
18 from enum import Enum, IntEnum
19 from io import open
20 from random import choice
21 from string import ascii_letters
22
23 from ipaddress import ip_network, ip_address
24
25 from resources.libraries.python.IPUtil import IPUtil
26 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
27     InterfaceStatusFlags
28 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
29 from resources.libraries.python.topology import Topology
30 from resources.libraries.python.VatExecutor import VatExecutor
31
32
33 def gen_key(length):
34     """Generate random string as a key.
35
36     :param length: Length of generated payload.
37     :type length: int
38     :returns: The generated payload.
39     :rtype: bytes
40     """
41     return u"".join(
42         choice(ascii_letters) for _ in range(length)
43     ).encode(encoding=u"utf-8")
44
45
46 class PolicyAction(Enum):
47     """Policy actions."""
48     BYPASS = (u"bypass", 0)
49     DISCARD = (u"discard", 1)
50     PROTECT = (u"protect", 3)
51
52     def __init__(self, policy_name, policy_int_repr):
53         self.policy_name = policy_name
54         self.policy_int_repr = policy_int_repr
55
56
57 class CryptoAlg(Enum):
58     """Encryption algorithms."""
59     AES_CBC_128 = (u"aes-cbc-128", 1, u"AES-CBC", 16)
60     AES_CBC_256 = (u"aes-cbc-256", 3, u"AES-CBC", 32)
61     AES_GCM_128 = (u"aes-gcm-128", 7, u"AES-GCM", 16)
62     AES_GCM_256 = (u"aes-gcm-256", 9, u"AES-GCM", 32)
63
64     def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
65         self.alg_name = alg_name
66         self.alg_int_repr = alg_int_repr
67         self.scapy_name = scapy_name
68         self.key_len = key_len
69
70
71 class IntegAlg(Enum):
72     """Integrity algorithm."""
73     SHA_256_128 = (u"sha-256-128", 4, u"SHA2-256-128", 32)
74     SHA_512_256 = (u"sha-512-256", 6, u"SHA2-512-256", 64)
75
76     def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
77         self.alg_name = alg_name
78         self.alg_int_repr = alg_int_repr
79         self.scapy_name = scapy_name
80         self.key_len = key_len
81
82
83 class IPsecProto(IntEnum):
84     """IPsec protocol."""
85     ESP = 1
86     SEC_AH = 0
87
88
89 class IPsecSadFlags(IntEnum):
90     """IPsec Security Association Database flags."""
91     IPSEC_API_SAD_FLAG_NONE = 0
92     IPSEC_API_SAD_FLAG_IS_TUNNEL = 4
93     IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 8
94
95
96 class IPsecUtil:
97     """IPsec utilities."""
98
99     @staticmethod
100     def policy_action_bypass():
101         """Return policy action bypass.
102
103         :returns: PolicyAction enum BYPASS object.
104         :rtype: PolicyAction
105         """
106         return PolicyAction.BYPASS
107
108     @staticmethod
109     def policy_action_discard():
110         """Return policy action discard.
111
112         :returns: PolicyAction enum DISCARD object.
113         :rtype: PolicyAction
114         """
115         return PolicyAction.DISCARD
116
117     @staticmethod
118     def policy_action_protect():
119         """Return policy action protect.
120
121         :returns: PolicyAction enum PROTECT object.
122         :rtype: PolicyAction
123         """
124         return PolicyAction.PROTECT
125
126     @staticmethod
127     def crypto_alg_aes_cbc_128():
128         """Return encryption algorithm aes-cbc-128.
129
130         :returns: CryptoAlg enum AES_CBC_128 object.
131         :rtype: CryptoAlg
132         """
133         return CryptoAlg.AES_CBC_128
134
135     @staticmethod
136     def crypto_alg_aes_cbc_256():
137         """Return encryption algorithm aes-cbc-256.
138
139         :returns: CryptoAlg enum AES_CBC_256 object.
140         :rtype: CryptoAlg
141         """
142         return CryptoAlg.AES_CBC_256
143
144     @staticmethod
145     def crypto_alg_aes_gcm_128():
146         """Return encryption algorithm aes-gcm-128.
147
148         :returns: CryptoAlg enum AES_GCM_128 object.
149         :rtype: CryptoAlg
150         """
151         return CryptoAlg.AES_GCM_128
152
153     @staticmethod
154     def crypto_alg_aes_gcm_256():
155         """Return encryption algorithm aes-gcm-256.
156
157         :returns: CryptoAlg enum AES_GCM_128 object.
158         :rtype: CryptoAlg
159         """
160         return CryptoAlg.AES_GCM_256
161
162     @staticmethod
163     def get_crypto_alg_key_len(crypto_alg):
164         """Return encryption algorithm key length.
165
166         :param crypto_alg: Encryption algorithm.
167         :type crypto_alg: CryptoAlg
168         :returns: Key length.
169         :rtype: int
170         """
171         return crypto_alg.key_len
172
173     @staticmethod
174     def get_crypto_alg_scapy_name(crypto_alg):
175         """Return encryption algorithm scapy name.
176
177         :param crypto_alg: Encryption algorithm.
178         :type crypto_alg: CryptoAlg
179         :returns: Algorithm scapy name.
180         :rtype: str
181         """
182         return crypto_alg.scapy_name
183
184     @staticmethod
185     def integ_alg_sha_256_128():
186         """Return integrity algorithm SHA-256-128.
187
188         :returns: IntegAlg enum SHA_256_128 object.
189         :rtype: IntegAlg
190         """
191         return IntegAlg.SHA_256_128
192
193     @staticmethod
194     def integ_alg_sha_512_256():
195         """Return integrity algorithm SHA-512-256.
196
197         :returns: IntegAlg enum SHA_512_256 object.
198         :rtype: IntegAlg
199         """
200         return IntegAlg.SHA_512_256
201
202     @staticmethod
203     def get_integ_alg_key_len(integ_alg):
204         """Return integrity algorithm key length.
205
206         :param integ_alg: Integrity algorithm.
207         :type integ_alg: IntegAlg
208         :returns: Key length.
209         :rtype: int
210         """
211         return integ_alg.key_len
212
213     @staticmethod
214     def get_integ_alg_scapy_name(integ_alg):
215         """Return integrity algorithm scapy name.
216
217         :param integ_alg: Integrity algorithm.
218         :type integ_alg: IntegAlg
219         :returns: Algorithm scapy name.
220         :rtype: str
221         """
222         return integ_alg.scapy_name
223
224     @staticmethod
225     def ipsec_proto_esp():
226         """Return IPSec protocol ESP.
227
228         :returns: IPsecProto enum ESP object.
229         :rtype: IPsecProto
230         """
231         return int(IPsecProto.ESP)
232
233     @staticmethod
234     def ipsec_proto_ah():
235         """Return IPSec protocol AH.
236
237         :returns: IPsecProto enum AH object.
238         :rtype: IPsecProto
239         """
240         return int(IPsecProto.SEC_AH)
241
242     @staticmethod
243     def vpp_ipsec_select_backend(node, protocol, index=1):
244         """Select IPsec backend.
245
246         :param node: VPP node to select IPsec backend on.
247         :param protocol: IPsec protocol.
248         :param index: Backend index.
249         :type node: dict
250         :type protocol: IPsecProto
251         :type index: int
252         :raises RuntimeError: If failed to select IPsec backend or if no API
253             reply received.
254         """
255         cmd = u"ipsec_select_backend"
256         err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
257         args = dict(
258             protocol=protocol,
259             index=index
260         )
261         with PapiSocketExecutor(node) as papi_exec:
262             papi_exec.add(cmd, **args).get_reply(err_msg)
263
264     @staticmethod
265     def vpp_ipsec_backend_dump(node):
266         """Dump IPsec backends.
267
268         :param node: VPP node to dump IPsec backend on.
269         :type node: dict
270         """
271         err_msg = f"Failed to dump IPsec backends on host {node[u'host']}"
272         with PapiSocketExecutor(node) as papi_exec:
273             papi_exec.add(u"ipsec_backend_dump").get_details(err_msg)
274
275     @staticmethod
276     def vpp_ipsec_add_sad_entry(
277             node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
278             integ_key=u"", tunnel_src=None, tunnel_dst=None):
279         """Create Security Association Database entry on the VPP node.
280
281         :param node: VPP node to add SAD entry on.
282         :param sad_id: SAD entry ID.
283         :param spi: Security Parameter Index of this SAD entry.
284         :param crypto_alg: The encryption algorithm name.
285         :param crypto_key: The encryption key string.
286         :param integ_alg: The integrity algorithm name.
287         :param integ_key: The integrity key string.
288         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
289             specified ESP transport mode is used.
290         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
291             not specified ESP transport mode is used.
292         :type node: dict
293         :type sad_id: int
294         :type spi: int
295         :type crypto_alg: CryptoAlg
296         :type crypto_key: str
297         :type integ_alg: IntegAlg
298         :type integ_key: str
299         :type tunnel_src: str
300         :type tunnel_dst: str
301         """
302         if isinstance(crypto_key, str):
303             crypto_key = crypto_key.encode(encoding=u"utf-8")
304         if isinstance(integ_key, str):
305             integ_key = integ_key.encode(encoding=u"utf-8")
306         ckey = dict(
307             length=len(crypto_key),
308             data=crypto_key
309         )
310         ikey = dict(
311             length=len(integ_key),
312             data=integ_key if integ_key else 0
313         )
314
315         flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
316         if tunnel_src and tunnel_dst:
317             flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
318             src_addr = ip_address(tunnel_src)
319             dst_addr = ip_address(tunnel_dst)
320             if src_addr.version == 6:
321                 flags = \
322                     flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
323         else:
324             src_addr = u""
325             dst_addr = u""
326
327         cmd = u"ipsec_sad_entry_add_del"
328         err_msg = f"Failed to add Security Association Database entry " \
329             f"on host {node[u'host']}"
330         sad_entry = dict(
331             sad_id=int(sad_id),
332             spi=int(spi),
333             crypto_algorithm=crypto_alg.alg_int_repr,
334             crypto_key=ckey,
335             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
336             integrity_key=ikey,
337             flags=flags,
338             tunnel_src=str(src_addr),
339             tunnel_dst=str(dst_addr),
340             protocol=int(IPsecProto.ESP)
341         )
342         args = dict(
343             is_add=1,
344             entry=sad_entry
345         )
346         with PapiSocketExecutor(node) as papi_exec:
347             papi_exec.add(cmd, **args).get_reply(err_msg)
348
349     @staticmethod
350     def vpp_ipsec_add_sad_entries(
351             node, n_entries, sad_id, spi, crypto_alg, crypto_key,
352             integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
353         """Create multiple Security Association Database entries on VPP node.
354
355         :param node: VPP node to add SAD entry on.
356         :param n_entries: Number of SAD entries to be created.
357         :param sad_id: First SAD entry ID. All subsequent SAD entries will have
358             id incremented by 1.
359         :param spi: Security Parameter Index of first SAD entry. All subsequent
360             SAD entries will have spi incremented by 1.
361         :param crypto_alg: The encryption algorithm name.
362         :param crypto_key: The encryption key string.
363         :param integ_alg: The integrity algorithm name.
364         :param integ_key: The integrity key string.
365         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
366             specified ESP transport mode is used.
367         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
368             not specified ESP transport mode is used.
369         :type node: dict
370         :type n_entries: int
371         :type sad_id: int
372         :type spi: int
373         :type crypto_alg: CryptoAlg
374         :type crypto_key: str
375         :type integ_alg: IntegAlg
376         :type integ_key: str
377         :type tunnel_src: str
378         :type tunnel_dst: str
379         """
380         if isinstance(crypto_key, str):
381             crypto_key = crypto_key.encode(encoding=u"utf-8")
382         if isinstance(integ_key, str):
383             integ_key = integ_key.encode(encoding=u"utf-8")
384         if tunnel_src and tunnel_dst:
385             src_addr = ip_address(tunnel_src)
386             dst_addr = ip_address(tunnel_dst)
387         else:
388             src_addr = u""
389             dst_addr = u""
390
391         addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
392             else 1 << (32 - 24)
393
394         if int(n_entries) > 10:
395             tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
396
397             with open(tmp_filename, 'w') as tmp_file:
398                 for i in range(n_entries):
399                     integ = f"integ-alg {integ_alg.alg_name} " \
400                         f"integ-key {integ_key.hex()}" \
401                         if integ_alg else u""
402                     tunnel = f"tunnel-src {src_addr + i * addr_incr} " \
403                         f"tunnel-dst {dst_addr + i * addr_incr}" \
404                         if tunnel_src and tunnel_dst else u""
405                     conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
406                         f"crypto-alg {crypto_alg.alg_name} " \
407                         f"crypto-key {crypto_key.hex()} " \
408                         f"{integ} {tunnel}\n"
409                     tmp_file.write(conf)
410             vat = VatExecutor()
411             vat.execute_script(
412                 tmp_filename, node, timeout=300, json_out=False,
413                 copy_on_execute=True
414             )
415             os.remove(tmp_filename)
416             return
417
418         ckey = dict(
419             length=len(crypto_key),
420             data=crypto_key
421         )
422         ikey = dict(
423             length=len(integ_key),
424             data=integ_key if integ_key else 0
425         )
426
427         flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
428         if tunnel_src and tunnel_dst:
429             flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
430             if src_addr.version == 6:
431                 flags = flags | int(
432                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
433                 )
434
435         cmd = u"ipsec_sad_entry_add_del"
436         err_msg = f"Failed to add Security Association Database entry " \
437             f"on host {node[u'host']}"
438
439         sad_entry = dict(
440             sad_id=int(sad_id),
441             spi=int(spi),
442             crypto_algorithm=crypto_alg.alg_int_repr,
443             crypto_key=ckey,
444             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
445             integrity_key=ikey,
446             flags=flags,
447             tunnel_src=str(src_addr),
448             tunnel_dst=str(dst_addr),
449             protocol=int(IPsecProto.ESP)
450         )
451         args = dict(
452             is_add=1,
453             entry=sad_entry
454         )
455         with PapiSocketExecutor(node) as papi_exec:
456             for i in range(n_entries):
457                 args[u"entry"][u"sad_id"] = int(sad_id) + i
458                 args[u"entry"][u"spi"] = int(spi) + i
459                 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
460                     if tunnel_src and tunnel_dst else src_addr
461                 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
462                     if tunnel_src and tunnel_dst else dst_addr
463                 history = bool(not 1 < i < n_entries - 2)
464                 papi_exec.add(cmd, history=history, **args)
465             papi_exec.get_replies(err_msg)
466
467     @staticmethod
468     def vpp_ipsec_set_ip_route(
469             node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
470             raddr_range):
471         """Set IP address and route on interface.
472
473         :param node: VPP node to add config on.
474         :param n_tunnels: Number of tunnels to create.
475         :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
476         :param traffic_addr: Traffic destination IP address to route.
477         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
478         :param interface: Interface key on node 1.
479         :param raddr_range: Mask specifying range of Policy selector Remote IP
480             addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
481             in case of IPv6.
482         :type node: dict
483         :type n_tunnels: int
484         :type tunnel_src: str
485         :type traffic_addr: str
486         :type tunnel_dst: str
487         :type interface: str
488         :type raddr_range: int
489         """
490         laddr = ip_address(tunnel_src)
491         raddr = ip_address(tunnel_dst)
492         taddr = ip_address(traffic_addr)
493         addr_incr = 1 << (128 - raddr_range) if laddr.version == 6 \
494             else 1 << (32 - raddr_range)
495
496         if int(n_tunnels) > 10:
497             tmp_filename = u"/tmp/ipsec_set_ip.script"
498
499             with open(tmp_filename, 'w') as tmp_file:
500                 if_name = Topology.get_interface_name(node, interface)
501                 for i in range(n_tunnels):
502                     conf = f"exec set interface ip address {if_name} " \
503                         f"{laddr + i * addr_incr}/{raddr_range}\n" \
504                         f"exec ip route add {taddr + i}/" \
505                         f"{128 if taddr.version == 6 else 32} " \
506                         f"via {raddr + i * addr_incr} {if_name}\n"
507                     tmp_file.write(conf)
508             vat = VatExecutor()
509             vat.execute_script(
510                 tmp_filename, node, timeout=300, json_out=False,
511                 copy_on_execute=True
512             )
513             os.remove(tmp_filename)
514             return
515
516         cmd1 = u"sw_interface_add_del_address"
517         args1 = dict(
518             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
519             is_add=True,
520             del_all=False,
521             prefix=None
522         )
523         cmd2 = u"ip_route_add_del"
524         args2 = dict(
525             is_add=1,
526             is_multipath=0,
527             route=None
528         )
529         err_msg = f"Failed to configure IP addresses and IP routes " \
530             f"on interface {interface} on host {node[u'host']}"
531
532         with PapiSocketExecutor(node) as papi_exec:
533             for i in range(n_tunnels):
534                 args1[u"prefix"] = IPUtil.create_prefix_object(
535                     laddr + i * addr_incr, raddr_range
536                 )
537                 args2[u"route"] = IPUtil.compose_vpp_route_structure(
538                     node, taddr + i,
539                     prefix_len=128 if taddr.version == 6 else 32,
540                     interface=interface, gateway=raddr + i * addr_incr
541                 )
542                 history = bool(not 1 < i < n_tunnels - 2)
543                 papi_exec.add(cmd1, history=history, **args1).\
544                     add(cmd2, history=history, **args2)
545             papi_exec.get_replies(err_msg)
546
547     @staticmethod
548     def vpp_ipsec_add_spd(node, spd_id):
549         """Create Security Policy Database on the VPP node.
550
551         :param node: VPP node to add SPD on.
552         :param spd_id: SPD ID.
553         :type node: dict
554         :type spd_id: int
555         """
556         cmd = u"ipsec_spd_add_del"
557         err_msg = f"Failed to add Security Policy Database " \
558             f"on host {node[u'host']}"
559         args = dict(
560             is_add=1,
561             spd_id=int(spd_id)
562         )
563         with PapiSocketExecutor(node) as papi_exec:
564             papi_exec.add(cmd, **args).get_reply(err_msg)
565
566     @staticmethod
567     def vpp_ipsec_spd_add_if(node, spd_id, interface):
568         """Add interface to the Security Policy Database.
569
570         :param node: VPP node.
571         :param spd_id: SPD ID to add interface on.
572         :param interface: Interface name or sw_if_index.
573         :type node: dict
574         :type spd_id: int
575         :type interface: str or int
576         """
577         cmd = u"ipsec_interface_add_del_spd"
578         err_msg = f"Failed to add interface {interface} to Security Policy " \
579             f"Database {spd_id} on host {node[u'host']}"
580         args = dict(
581             is_add=1,
582             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
583             spd_id=int(spd_id)
584         )
585         with PapiSocketExecutor(node) as papi_exec:
586             papi_exec.add(cmd, **args).get_reply(err_msg)
587
588     @staticmethod
589     def vpp_ipsec_policy_add(
590             node, spd_id, priority, action, inbound=True, sa_id=None,
591             laddr_range=None, raddr_range=None, proto=None, lport_range=None,
592             rport_range=None, is_ipv6=False):
593         """Create Security Policy Database entry on the VPP node.
594
595         :param node: VPP node to add SPD entry on.
596         :param spd_id: SPD ID to add entry on.
597         :param priority: SPD entry priority, higher number = higher priority.
598         :param action: Policy action.
599         :param inbound: If True policy is for inbound traffic, otherwise
600             outbound.
601         :param sa_id: SAD entry ID for protect action.
602         :param laddr_range: Policy selector local IPv4 or IPv6 address range in
603             format IP/prefix or IP/mask. If no mask is provided,
604             it's considered to be /32.
605         :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
606             format IP/prefix or IP/mask. If no mask is provided,
607             it's considered to be /32.
608         :param proto: Policy selector next layer protocol number.
609         :param lport_range: Policy selector local TCP/UDP port range in format
610             <port_start>-<port_end>.
611         :param rport_range: Policy selector remote TCP/UDP port range in format
612             <port_start>-<port_end>.
613         :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
614             not defined so it will default to address ::/0, otherwise False.
615         :type node: dict
616         :type spd_id: int
617         :type priority: int
618         :type action: PolicyAction
619         :type inbound: bool
620         :type sa_id: int
621         :type laddr_range: string
622         :type raddr_range: string
623         :type proto: int
624         :type lport_range: string
625         :type rport_range: string
626         :type is_ipv6: bool
627         """
628         if laddr_range is None:
629             laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
630
631         if raddr_range is None:
632             raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
633
634         cmd = u"ipsec_spd_entry_add_del"
635         err_msg = f"Failed to add entry to Security Policy Database {spd_id} " \
636             f"on host {node[u'host']}"
637
638         spd_entry = dict(
639             spd_id=int(spd_id),
640             priority=int(priority),
641             is_outbound=0 if inbound else 1,
642             sa_id=int(sa_id) if sa_id else 0,
643             policy=action.policy_int_repr,
644             protocol=int(proto) if proto else 0,
645             remote_address_start=IPUtil.create_ip_address_object(
646                 ip_network(raddr_range, strict=False).network_address
647             ),
648             remote_address_stop=IPUtil.create_ip_address_object(
649                 ip_network(raddr_range, strict=False).broadcast_address
650             ),
651             local_address_start=IPUtil.create_ip_address_object(
652                 ip_network(laddr_range, strict=False).network_address
653             ),
654             local_address_stop=IPUtil.create_ip_address_object(
655                 ip_network(laddr_range, strict=False).broadcast_address
656             ),
657             remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
658             else 0,
659             remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
660             else 65535,
661             local_port_start=int(lport_range.split(u"-")[0]) if lport_range
662             else 0,
663             local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
664             else 65535
665         )
666         args = dict(
667             is_add=1,
668             entry=spd_entry
669         )
670         with PapiSocketExecutor(node) as papi_exec:
671             papi_exec.add(cmd, **args).get_reply(err_msg)
672
673     @staticmethod
674     def vpp_ipsec_spd_add_entries(
675             node, n_entries, spd_id, priority, inbound, sa_id, raddr_ip,
676             raddr_range=0):
677         """Create multiple Security Policy Database entries on the VPP node.
678
679         :param node: VPP node to add SPD entries on.
680         :param n_entries: Number of SPD entries to be added.
681         :param spd_id: SPD ID to add entries on.
682         :param priority: SPD entries priority, higher number = higher priority.
683         :param inbound: If True policy is for inbound traffic, otherwise
684             outbound.
685         :param sa_id: SAD entry ID for first entry. Each subsequent entry will
686             SAD entry ID incremented by 1.
687         :param raddr_ip: Policy selector remote IPv4 start address for the first
688             entry. Remote IPv4 end address will be calculated depending on
689             raddr_range parameter. Each subsequent entry will have start address
690             next after IPv4 end address of previous entry.
691         :param raddr_range: Required IP addres range.
692         :type node: dict
693         :type n_entries: int
694         :type spd_id: int
695         :type priority: int
696         :type inbound: bool
697         :type sa_id: int
698         :type raddr_ip: str
699         :type raddr_range: int
700         """
701         raddr_ip = ip_address(raddr_ip)
702         if int(n_entries) > 10:
703             tmp_filename = f"/tmp/ipsec_spd_{sa_id}_add_del_entry.script"
704
705             with open(tmp_filename, 'w') as tmp_file:
706                 for i in range(n_entries):
707                     direction = u'inbound' if inbound else u'outbound'
708                     tunnel = f"exec ipsec policy add spd {spd_id} " \
709                         f"priority {priority} {direction} " \
710                         f"action protect sa {sa_id+i} " \
711                         f"remote-ip-range {raddr_ip + i * (raddr_range + 1)} " \
712                         f"- {raddr_ip + (i  + 1) * raddr_range + i} " \
713                         f"local-ip-range 0.0.0.0 - 255.255.255.255\n"
714                     tmp_file.write(tunnel)
715             VatExecutor().execute_script(
716                 tmp_filename, node, timeout=300, json_out=False,
717                 copy_on_execute=True
718             )
719             os.remove(tmp_filename)
720             return
721
722         laddr_range = u"::/0" if raddr_ip.version == 6 else u"0.0.0.0/0"
723
724         cmd = u"ipsec_spd_entry_add_del"
725         err_msg = f"ailed to add entry to Security Policy Database '{spd_id} " \
726             f"on host {node[u'host']}"
727
728         spd_entry = dict(
729             spd_id=int(spd_id),
730             priority=int(priority),
731             is_outbound=0 if inbound else 1,
732             sa_id=int(sa_id) if sa_id else 0,
733             policy=IPsecUtil.policy_action_protect().policy_int_repr,
734             protocol=0,
735             remote_address_start=IPUtil.create_ip_address_object(raddr_ip),
736             remote_address_stop=IPUtil.create_ip_address_object(raddr_ip),
737             local_address_start=IPUtil.create_ip_address_object(
738                 ip_network(laddr_range, strict=False).network_address
739             ),
740             local_address_stop=IPUtil.create_ip_address_object(
741                 ip_network(laddr_range, strict=False).broadcast_address
742             ),
743             remote_port_start=0,
744             remote_port_stop=65535,
745             local_port_start=0,
746             local_port_stop=65535
747         )
748         args = dict(
749             is_add=1,
750             entry=spd_entry
751         )
752
753         with PapiSocketExecutor(node) as papi_exec:
754             for i in range(n_entries):
755                 args[u"entry"][u"remote_address_start"][u"un"] = \
756                     IPUtil.union_addr(raddr_ip + i)
757                 args[u"entry"][u"remote_address_stop"][u"un"] = \
758                     IPUtil.union_addr(raddr_ip + i)
759                 history = bool(not 1 < i < n_entries - 2)
760                 papi_exec.add(cmd, history=history, **args)
761             papi_exec.get_replies(err_msg)
762
763     @staticmethod
764     def vpp_ipsec_create_tunnel_interfaces(
765             nodes, if1_ip_addr, if2_ip_addr, if1_key, if2_key, n_tunnels,
766             crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range):
767         """Create multiple IPsec tunnel interfaces between two VPP nodes.
768
769         :param nodes: VPP nodes to create tunnel interfaces.
770         :param if1_ip_addr: VPP node 1 interface IPv4/IPv6 address.
771         :param if2_ip_addr: VPP node 2 interface IPv4/IPv6 address.
772         :param if1_key: VPP node 1 interface key from topology file.
773         :param if2_key: VPP node 2 interface key from topology file.
774         :param n_tunnels: Number of tunnel interfaces to create.
775         :param crypto_alg: The encryption algorithm name.
776         :param integ_alg: The integrity algorithm name.
777         :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
778             first tunnel in direction node1->node2.
779         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
780             first tunnel in direction node2->node1.
781         :param raddr_range: Mask specifying range of Policy selector Remote
782             IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
783             and to 128 in case of IPv6.
784         :type nodes: dict
785         :type if1_ip_addr: str
786         :type if2_ip_addr: str
787         :type if1_key: str
788         :type if2_key: str
789         :type n_tunnels: int
790         :type crypto_alg: CryptoAlg
791         :type integ_alg: IntegAlg
792         :type raddr_ip1: string
793         :type raddr_ip2: string
794         :type raddr_range: int
795         """
796         n_tunnels = int(n_tunnels)
797         spi_1 = 100000
798         spi_2 = 200000
799         if1_ip = ip_address(if1_ip_addr)
800         if2_ip = ip_address(if2_ip_addr)
801         raddr_ip1 = ip_address(raddr_ip1)
802         raddr_ip2 = ip_address(raddr_ip2)
803         addr_incr = 1 << (128 - raddr_range) if if1_ip.version == 6 \
804             else 1 << (32 - raddr_range)
805
806         if n_tunnels > 10:
807             tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
808             tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
809             if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
810             if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
811             mask = 96 if if2_ip.version == 6 else 24
812             mask2 = 128 if if2_ip.version == 6 else 32
813             vat = VatExecutor()
814             with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
815                 rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
816                 tmp_f1.write(
817                     f"exec create loopback interface\n"
818                     f"exec set interface state loop0 up\n"
819                     f"exec set interface ip address "
820                     f"{if1_n} {if2_ip - 1}/{mask}\n"
821                     f"exec set ip arp {if1_n} {if2_ip}/{mask2} {rmac} static\n"
822                 )
823                 tmp_f2.write(
824                     f"exec set interface ip address {if2_n} {if2_ip}/{mask}\n"
825                 )
826                 for i in range(n_tunnels):
827                     ckey = gen_key(
828                         IPsecUtil.get_crypto_alg_key_len(crypto_alg)
829                     ).hex()
830                     if integ_alg:
831                         ikey = gen_key(
832                             IPsecUtil.get_integ_alg_key_len(integ_alg)
833                         ).hex()
834                         integ = f"integ_alg {integ_alg.alg_name} " \
835                             f"local_integ_key {ikey} remote_integ_key {ikey} "
836                     else:
837                         integ = u""
838                     tmp_f1.write(
839                         f"exec set interface ip address loop0 "
840                         f"{if1_ip + i * addr_incr}/32\n"
841                         f"ipsec_tunnel_if_add_del "
842                         f"local_spi {spi_1 + i} remote_spi {spi_2 + i} "
843                         f"crypto_alg {crypto_alg.alg_name} "
844                         f"local_crypto_key {ckey} remote_crypto_key {ckey} "
845                         f"{integ} "
846                         f"local_ip {if1_ip + i * addr_incr} "
847                         f"remote_ip {if2_ip} "
848                         f"instance {i}\n"
849                     )
850                     tmp_f2.write(
851                         f"ipsec_tunnel_if_add_del "
852                         f"local_spi {spi_2 + i} remote_spi {spi_1 + i} "
853                         f"crypto_alg {crypto_alg.alg_name} "
854                         f"local_crypto_key {ckey} remote_crypto_key {ckey} "
855                         f"{integ} "
856                         f"local_ip {if2_ip} "
857                         f"remote_ip {if1_ip + i * addr_incr} "
858                         f"instance {i}\n"
859                     )
860             vat.execute_script(
861                 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
862                 copy_on_execute=True,
863                 history=bool(n_tunnels < 100)
864             )
865             vat.execute_script(
866                 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
867                 copy_on_execute=True,
868                 history=bool(n_tunnels < 100)
869             )
870             os.remove(tmp_fn1)
871             os.remove(tmp_fn2)
872
873             with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
874                 raddr = ip_network(if1_ip_addr + u"/8", False)
875                 tmp_f2.write(
876                     f"exec ip route add {raddr} via {if2_n} {if2_ip - 1}\n"
877                 )
878                 for i in range(n_tunnels):
879                     tmp_f1.write(
880                         f"exec set interface unnumbered ipip{i} use {if1_n}\n"
881                         f"exec set interface state ipip{i} up\n"
882                         f"exec ip route add {raddr_ip2 + i}/{mask2} "
883                         f"via ipip{i}\n"
884                     )
885                     tmp_f2.write(
886                         f"exec set interface unnumbered ipip{i} use {if2_n}\n"
887                         f"exec set interface state ipip{i} up\n"
888                         f"exec ip route add {raddr_ip1 + i}/{mask2} "
889                         f"via ipip{i}\n"
890                     )
891             vat.execute_script(
892                 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
893                 copy_on_execute=True,
894                 history=bool(n_tunnels < 100)
895             )
896             vat.execute_script(
897                 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
898                 copy_on_execute=True,
899                 history=bool(n_tunnels < 100)
900             )
901             os.remove(tmp_fn1)
902             os.remove(tmp_fn2)
903             return
904
905         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
906             # Create loopback interface on DUT1, set it to up state
907             cmd1 = u"create_loopback"
908             args1 = dict(
909                 mac_address=0
910             )
911             err_msg = f"Failed to create loopback interface " \
912                 f"on host {nodes[u'DUT1'][u'host']}"
913             loop_sw_if_idx = papi_exec.add(cmd1, **args1).\
914                 get_sw_if_index(err_msg)
915             cmd1 = u"sw_interface_set_flags"
916             args1 = dict(
917                 sw_if_index=loop_sw_if_idx,
918                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
919             )
920             err_msg = f"Failed to set loopback interface state up " \
921                 f"on host {nodes[u'DUT1'][u'host']}"
922             papi_exec.add(cmd1, **args1).get_reply(err_msg)
923             # Set IP address on VPP node 1 interface
924             cmd1 = u"sw_interface_add_del_address"
925             args1 = dict(
926                 sw_if_index=InterfaceUtil.get_interface_index(
927                     nodes[u"DUT1"], if1_key
928                 ),
929                 is_add=True,
930                 del_all=False,
931                 prefix=IPUtil.create_prefix_object(
932                     if2_ip - 1, 96 if if2_ip.version == 6 else 24
933                 )
934             )
935             err_msg = f"Failed to set IP address on interface {if1_key} " \
936                 f"on host {nodes[u'DUT1'][u'host']}"
937             papi_exec.add(cmd1, **args1).get_reply(err_msg)
938             cmd4 = u"ip_neighbor_add_del"
939             args4 = dict(
940                 is_add=1,
941                 neighbor=dict(
942                     sw_if_index=Topology.get_interface_sw_index(
943                         nodes[u"DUT1"], if1_key
944                     ),
945                     flags=1,
946                     mac_address=str(
947                         Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
948                     ),
949                     ip_address=str(ip_address(if2_ip_addr))
950                 )
951             )
952             err_msg = f"Failed to add IP neighbor on interface {if1_key}"
953             papi_exec.add(cmd4, **args4).get_reply(err_msg)
954             # Configure IPsec tunnel interfaces
955             args1 = dict(
956                 sw_if_index=loop_sw_if_idx,
957                 is_add=True,
958                 del_all=False,
959                 prefix=None
960             )
961             cmd2 = u"ipsec_tunnel_if_add_del"
962             args2 = dict(
963                 is_add=1,
964                 local_ip=None,
965                 remote_ip=None,
966                 local_spi=0,
967                 remote_spi=0,
968                 crypto_alg=crypto_alg.alg_int_repr,
969                 local_crypto_key_len=0,
970                 local_crypto_key=None,
971                 remote_crypto_key_len=0,
972                 remote_crypto_key=None,
973                 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
974                 local_integ_key_len=0,
975                 local_integ_key=None,
976                 remote_integ_key_len=0,
977                 remote_integ_key=None,
978                 tx_table_id=0
979             )
980             err_msg = f"Failed to add IPsec tunnel interfaces " \
981                 f"on host {nodes[u'DUT1'][u'host']}"
982             ipsec_tunnels = list()
983             ckeys = list()
984             ikeys = list()
985             for i in range(n_tunnels):
986                 ckeys.append(
987                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
988                 )
989                 if integ_alg:
990                     ikeys.append(
991                         gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
992                     )
993                 args1[u"prefix"] = IPUtil.create_prefix_object(
994                     if1_ip + i * addr_incr, 128 if if1_ip.version == 6 else 32
995                 )
996                 args2[u"local_spi"] = spi_1 + i
997                 args2[u"remote_spi"] = spi_2 + i
998                 args2[u"local_ip"] = IPUtil.create_ip_address_object(
999                     if1_ip + i * addr_incr
1000                 )
1001                 args2[u"remote_ip"] = IPUtil.create_ip_address_object(if2_ip)
1002                 args2[u"local_crypto_key_len"] = len(ckeys[i])
1003                 args2[u"local_crypto_key"] = ckeys[i]
1004                 args2[u"remote_crypto_key_len"] = len(ckeys[i])
1005                 args2[u"remote_crypto_key"] = ckeys[i]
1006                 if integ_alg:
1007                     args2[u"local_integ_key_len"] = len(ikeys[i])
1008                     args2[u"local_integ_key"] = ikeys[i]
1009                     args2[u"remote_integ_key_len"] = len(ikeys[i])
1010                     args2[u"remote_integ_key"] = ikeys[i]
1011                 history = bool(not 1 < i < n_tunnels - 2)
1012                 papi_exec.add(cmd1, history=history, **args1).\
1013                     add(cmd2, history=history, **args2)
1014             replies = papi_exec.get_replies(err_msg)
1015             for reply in replies:
1016                 if u"sw_if_index" in reply:
1017                     ipsec_tunnels.append(reply[u"sw_if_index"])
1018             # Configure IP routes
1019             cmd1 = u"sw_interface_set_unnumbered"
1020             args1 = dict(
1021                 is_add=True,
1022                 sw_if_index=InterfaceUtil.get_interface_index(
1023                     nodes[u"DUT1"], if1_key
1024                 ),
1025                 unnumbered_sw_if_index=0
1026             )
1027             cmd2 = u"sw_interface_set_flags"
1028             args2 = dict(
1029                 sw_if_index=0,
1030                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1031             )
1032             cmd3 = u"ip_route_add_del"
1033             args3 = dict(
1034                 is_add=1,
1035                 is_multipath=0,
1036                 route=None
1037             )
1038             err_msg = f"Failed to add IP routes " \
1039                 f"on host {nodes[u'DUT1'][u'host']}"
1040             for i in range(n_tunnels):
1041                 args1[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1042                 args2[u"sw_if_index"] = ipsec_tunnels[i]
1043                 args3[u"route"] = IPUtil.compose_vpp_route_structure(
1044                     nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1045                     prefix_len=128 if raddr_ip2.version == 6 else 32,
1046                     interface=ipsec_tunnels[i]
1047                 )
1048                 history = bool(not 1 < i < n_tunnels - 2)
1049                 papi_exec.add(cmd1, history=history, **args1).\
1050                     add(cmd2, history=history, **args2).\
1051                     add(cmd3, history=history, **args3)
1052             papi_exec.get_replies(err_msg)
1053
1054         with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1055             # Set IP address on VPP node 2 interface
1056             cmd1 = u"sw_interface_add_del_address"
1057             args1 = dict(
1058                 sw_if_index=InterfaceUtil.get_interface_index(
1059                     nodes[u"DUT2"], if2_key
1060                 ),
1061                 is_add=True,
1062                 del_all=False,
1063                 prefix=IPUtil.create_prefix_object(
1064                     if2_ip, 96 if if2_ip.version == 6 else 24
1065                 )
1066             )
1067             err_msg = f"Failed to set IP address on interface {if2_key} " \
1068                 f"on host {nodes[u'DUT2'][u'host']}"
1069             papi_exec.add(cmd1, **args1).get_reply(err_msg)
1070             # Configure IPsec tunnel interfaces
1071             cmd2 = u"ipsec_tunnel_if_add_del"
1072             args2 = dict(
1073                 is_add=1,
1074                 local_ip=IPUtil.create_ip_address_object(if2_ip),
1075                 remote_ip=None,
1076                 local_spi=0,
1077                 remote_spi=0,
1078                 crypto_alg=crypto_alg.alg_int_repr,
1079                 local_crypto_key_len=0,
1080                 local_crypto_key=None,
1081                 remote_crypto_key_len=0,
1082                 remote_crypto_key=None,
1083                 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1084                 local_integ_key_len=0,
1085                 local_integ_key=None,
1086                 remote_integ_key_len=0,
1087                 remote_integ_key=None,
1088                 tx_table_id=0
1089             )
1090             err_msg = f"Failed to add IPsec tunnel interfaces " \
1091                 f"on host {nodes[u'DUT2'][u'host']}"
1092             ipsec_tunnels = list()
1093             for i in range(n_tunnels):
1094                 args2[u"local_spi"] = spi_2 + i
1095                 args2[u"remote_spi"] = spi_1 + i
1096                 args2[u"local_ip"] = IPUtil.create_ip_address_object(if2_ip)
1097                 args2[u"remote_ip"] = IPUtil.create_ip_address_object(
1098                     if1_ip + i * addr_incr)
1099                 args2[u"local_crypto_key_len"] = len(ckeys[i])
1100                 args2[u"local_crypto_key"] = ckeys[i]
1101                 args2[u"remote_crypto_key_len"] = len(ckeys[i])
1102                 args2[u"remote_crypto_key"] = ckeys[i]
1103                 if integ_alg:
1104                     args2[u"local_integ_key_len"] = len(ikeys[i])
1105                     args2[u"local_integ_key"] = ikeys[i]
1106                     args2[u"remote_integ_key_len"] = len(ikeys[i])
1107                     args2[u"remote_integ_key"] = ikeys[i]
1108                 history = bool(not 1 < i < n_tunnels - 2)
1109                 papi_exec.add(cmd2, history=history, **args2)
1110             replies = papi_exec.get_replies(err_msg)
1111             for reply in replies:
1112                 if u"sw_if_index" in reply:
1113                     ipsec_tunnels.append(reply[u"sw_if_index"])
1114             # Configure IP routes
1115             cmd1 = u"ip_route_add_del"
1116             route = IPUtil.compose_vpp_route_structure(
1117                 nodes[u"DUT2"], if1_ip.compressed,
1118                 prefix_len=32 if if1_ip.version == 6 else 8,
1119                 interface=if2_key,
1120                 gateway=(if2_ip - 1).compressed
1121             )
1122             args1 = dict(
1123                 is_add=1,
1124                 is_multipath=0,
1125                 route=route
1126             )
1127             papi_exec.add(cmd1, **args1)
1128             cmd1 = u"sw_interface_set_unnumbered"
1129             args1 = dict(
1130                 is_add=True,
1131                 sw_if_index=InterfaceUtil.get_interface_index(
1132                     nodes[u"DUT2"], if2_key
1133                 ),
1134                 unnumbered_sw_if_index=0
1135             )
1136             cmd2 = u"sw_interface_set_flags"
1137             args2 = dict(
1138                 sw_if_index=0,
1139                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1140             )
1141             cmd3 = u"ip_route_add_del"
1142             args3 = dict(
1143                 is_add=1,
1144                 is_multipath=0,
1145                 route=None
1146             )
1147             err_msg = f"Failed to add IP routes " \
1148                 f"on host {nodes[u'DUT2'][u'host']}"
1149             for i in range(n_tunnels):
1150                 args1[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1151                 args2[u"sw_if_index"] = ipsec_tunnels[i]
1152                 args3[u"route"] = IPUtil.compose_vpp_route_structure(
1153                     nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1154                     prefix_len=128 if raddr_ip1.version == 6 else 32,
1155                     interface=ipsec_tunnels[i]
1156                 )
1157                 history = bool(not 1 < i < n_tunnels - 2)
1158                 papi_exec.add(cmd1, history=history, **args1). \
1159                     add(cmd2, history=history, **args2). \
1160                     add(cmd3, history=history, **args3)
1161             papi_exec.get_replies(err_msg)
1162
1163     @staticmethod
1164     def vpp_ipsec_add_multiple_tunnels(
1165             nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1166             tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
1167         """Create multiple IPsec tunnels between two VPP nodes.
1168
1169         :param nodes: VPP nodes to create tunnels.
1170         :param interface1: Interface name or sw_if_index on node 1.
1171         :param interface2: Interface name or sw_if_index on node 2.
1172         :param n_tunnels: Number of tunnels to create.
1173         :param crypto_alg: The encryption algorithm name.
1174         :param integ_alg: The integrity algorithm name.
1175         :param tunnel_ip1: Tunnel node1 IPv4 address.
1176         :param tunnel_ip2: Tunnel node2 IPv4 address.
1177         :param raddr_ip1: Policy selector remote IPv4 start address for the
1178             first tunnel in direction node1->node2.
1179         :param raddr_ip2: Policy selector remote IPv4 start address for the
1180             first tunnel in direction node2->node1.
1181         :param raddr_range: Mask specifying range of Policy selector Remote IPv4
1182             addresses. Valid values are from 1 to 32.
1183         :type nodes: dict
1184         :type interface1: str or int
1185         :type interface2: str or int
1186         :type n_tunnels: int
1187         :type crypto_alg: CryptoAlg
1188         :type integ_alg: IntegAlg
1189         :type tunnel_ip1: str
1190         :type tunnel_ip2: str
1191         :type raddr_ip1: string
1192         :type raddr_ip2: string
1193         :type raddr_range: int
1194         """
1195         spd_id = 1
1196         p_hi = 100
1197         p_lo = 10
1198         sa_id_1 = 100000
1199         sa_id_2 = 200000
1200         spi_1 = 300000
1201         spi_2 = 400000
1202
1203         crypto_key = gen_key(
1204             IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1205         ).decode()
1206         integ_key = gen_key(
1207             IPsecUtil.get_integ_alg_key_len(integ_alg)
1208         ).decode() if integ_alg else u""
1209
1210         IPsecUtil.vpp_ipsec_set_ip_route(
1211             nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1212             interface1, raddr_range)
1213         IPsecUtil.vpp_ipsec_set_ip_route(
1214             nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1215             interface2, raddr_range)
1216
1217         IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1218         IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1219         IPsecUtil.vpp_ipsec_policy_add(
1220             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1221             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1222         )
1223         IPsecUtil.vpp_ipsec_policy_add(
1224             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1225             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1226         )
1227
1228         IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1229         IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1230         IPsecUtil.vpp_ipsec_policy_add(
1231             nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1232             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1233         )
1234         IPsecUtil.vpp_ipsec_policy_add(
1235             nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1236             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1237         )
1238
1239         IPsecUtil.vpp_ipsec_add_sad_entries(
1240             nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1241             integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1242         )
1243         IPsecUtil.vpp_ipsec_spd_add_entries(
1244             nodes[u"DUT1"], n_tunnels, spd_id, p_lo, False, sa_id_1, raddr_ip2
1245         )
1246
1247         IPsecUtil.vpp_ipsec_add_sad_entries(
1248             nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1249             integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1250         )
1251         IPsecUtil.vpp_ipsec_spd_add_entries(
1252             nodes[u"DUT2"], n_tunnels, spd_id, p_lo, True, sa_id_1, raddr_ip2
1253         )
1254
1255         IPsecUtil.vpp_ipsec_add_sad_entries(
1256             nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1257             integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1258         )
1259
1260         IPsecUtil.vpp_ipsec_spd_add_entries(
1261             nodes[u"DUT2"], n_tunnels, spd_id, p_lo, False, sa_id_2, raddr_ip1
1262         )
1263
1264         IPsecUtil.vpp_ipsec_add_sad_entries(
1265             nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1266             integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1267         )
1268
1269         IPsecUtil.vpp_ipsec_spd_add_entries(
1270             nodes[u"DUT1"], n_tunnels, spd_id, p_lo, True, sa_id_2, raddr_ip1
1271         )
1272
1273     @staticmethod
1274     def vpp_ipsec_show(node):
1275         """Run "show ipsec" debug CLI command.
1276
1277         :param node: Node to run command on.
1278         :type node: dict
1279         """
1280         PapiSocketExecutor.run_cli_cmd(node, u"show ipsec")