T-Rex: 2.82, core pin, 8 workers
[csit.git] / resources / libraries / python / IPsecUtil.py
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:
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.InterfaceUtil import InterfaceUtil, \
26     InterfaceStatusFlags
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
33
34
35 def gen_key(length):
36     """Generate random string as a key.
37
38     :param length: Length of generated payload.
39     :type length: int
40     :returns: The generated payload.
41     :rtype: bytes
42     """
43     return u"".join(
44         choice(ascii_letters) for _ in range(length)
45     ).encode(encoding=u"utf-8")
46
47
48 class PolicyAction(Enum):
49     """Policy actions."""
50     BYPASS = (u"bypass", 0)
51     DISCARD = (u"discard", 1)
52     PROTECT = (u"protect", 3)
53
54     def __init__(self, policy_name, policy_int_repr):
55         self.policy_name = policy_name
56         self.policy_int_repr = policy_int_repr
57
58
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)
65
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
71
72
73 class IntegAlg(Enum):
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)
77
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
83
84
85 class IPsecProto(IntEnum):
86     """IPsec protocol."""
87     IPSEC_API_PROTO_ESP = 50
88     IPSEC_API_PROTO_AH = 51
89
90
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
96
97
98 class IPsecUtil:
99     """IPsec utilities."""
100
101     @staticmethod
102     def policy_action_bypass():
103         """Return policy action bypass.
104
105         :returns: PolicyAction enum BYPASS object.
106         :rtype: PolicyAction
107         """
108         return PolicyAction.BYPASS
109
110     @staticmethod
111     def policy_action_discard():
112         """Return policy action discard.
113
114         :returns: PolicyAction enum DISCARD object.
115         :rtype: PolicyAction
116         """
117         return PolicyAction.DISCARD
118
119     @staticmethod
120     def policy_action_protect():
121         """Return policy action protect.
122
123         :returns: PolicyAction enum PROTECT object.
124         :rtype: PolicyAction
125         """
126         return PolicyAction.PROTECT
127
128     @staticmethod
129     def crypto_alg_aes_cbc_128():
130         """Return encryption algorithm aes-cbc-128.
131
132         :returns: CryptoAlg enum AES_CBC_128 object.
133         :rtype: CryptoAlg
134         """
135         return CryptoAlg.AES_CBC_128
136
137     @staticmethod
138     def crypto_alg_aes_cbc_256():
139         """Return encryption algorithm aes-cbc-256.
140
141         :returns: CryptoAlg enum AES_CBC_256 object.
142         :rtype: CryptoAlg
143         """
144         return CryptoAlg.AES_CBC_256
145
146     @staticmethod
147     def crypto_alg_aes_gcm_128():
148         """Return encryption algorithm aes-gcm-128.
149
150         :returns: CryptoAlg enum AES_GCM_128 object.
151         :rtype: CryptoAlg
152         """
153         return CryptoAlg.AES_GCM_128
154
155     @staticmethod
156     def crypto_alg_aes_gcm_256():
157         """Return encryption algorithm aes-gcm-256.
158
159         :returns: CryptoAlg enum AES_GCM_128 object.
160         :rtype: CryptoAlg
161         """
162         return CryptoAlg.AES_GCM_256
163
164     @staticmethod
165     def get_crypto_alg_key_len(crypto_alg):
166         """Return encryption algorithm key length.
167
168         :param crypto_alg: Encryption algorithm.
169         :type crypto_alg: CryptoAlg
170         :returns: Key length.
171         :rtype: int
172         """
173         return crypto_alg.key_len
174
175     @staticmethod
176     def get_crypto_alg_scapy_name(crypto_alg):
177         """Return encryption algorithm scapy name.
178
179         :param crypto_alg: Encryption algorithm.
180         :type crypto_alg: CryptoAlg
181         :returns: Algorithm scapy name.
182         :rtype: str
183         """
184         return crypto_alg.scapy_name
185
186     @staticmethod
187     def integ_alg_sha_256_128():
188         """Return integrity algorithm SHA-256-128.
189
190         :returns: IntegAlg enum SHA_256_128 object.
191         :rtype: IntegAlg
192         """
193         return IntegAlg.SHA_256_128
194
195     @staticmethod
196     def integ_alg_sha_512_256():
197         """Return integrity algorithm SHA-512-256.
198
199         :returns: IntegAlg enum SHA_512_256 object.
200         :rtype: IntegAlg
201         """
202         return IntegAlg.SHA_512_256
203
204     @staticmethod
205     def get_integ_alg_key_len(integ_alg):
206         """Return integrity algorithm key length.
207
208         :param integ_alg: Integrity algorithm.
209         :type integ_alg: IntegAlg
210         :returns: Key length.
211         :rtype: int
212         """
213         return integ_alg.key_len
214
215     @staticmethod
216     def get_integ_alg_scapy_name(integ_alg):
217         """Return integrity algorithm scapy name.
218
219         :param integ_alg: Integrity algorithm.
220         :type integ_alg: IntegAlg
221         :returns: Algorithm scapy name.
222         :rtype: str
223         """
224         return integ_alg.scapy_name
225
226     @staticmethod
227     def ipsec_proto_esp():
228         """Return IPSec protocol ESP.
229
230         :returns: IPsecProto enum ESP object.
231         :rtype: IPsecProto
232         """
233         return int(IPsecProto.IPSEC_API_PROTO_ESP)
234
235     @staticmethod
236     def ipsec_proto_ah():
237         """Return IPSec protocol AH.
238
239         :returns: IPsecProto enum AH object.
240         :rtype: IPsecProto
241         """
242         return int(IPsecProto.IPSEC_API_PROTO_AH)
243
244     @staticmethod
245     def vpp_ipsec_select_backend(node, protocol, index=1):
246         """Select IPsec backend.
247
248         :param node: VPP node to select IPsec backend on.
249         :param protocol: IPsec protocol.
250         :param index: Backend index.
251         :type node: dict
252         :type protocol: IPsecProto
253         :type index: int
254         :raises RuntimeError: If failed to select IPsec backend or if no API
255             reply received.
256         """
257         cmd = u"ipsec_select_backend"
258         err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
259         args = dict(
260             protocol=protocol,
261             index=index
262         )
263         with PapiSocketExecutor(node) as papi_exec:
264             papi_exec.add(cmd, **args).get_reply(err_msg)
265
266     @staticmethod
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.
271
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.
283         :type node: dict
284         :type sad_id: int
285         :type spi: int
286         :type crypto_alg: CryptoAlg
287         :type crypto_key: str
288         :type integ_alg: IntegAlg
289         :type integ_key: str
290         :type tunnel_src: str
291         :type tunnel_dst: str
292         """
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")
297         ckey = dict(
298             length=len(crypto_key),
299             data=crypto_key
300         )
301         ikey = dict(
302             length=len(integ_key),
303             data=integ_key if integ_key else 0
304         )
305
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:
312                 flags = \
313                     flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
314         else:
315             src_addr = u""
316             dst_addr = u""
317
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']}"
321         sad_entry = dict(
322             sad_id=int(sad_id),
323             spi=int(spi),
324             crypto_algorithm=crypto_alg.alg_int_repr,
325             crypto_key=ckey,
326             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
327             integrity_key=ikey,
328             flags=flags,
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
334         )
335         args = dict(
336             is_add=True,
337             entry=sad_entry
338         )
339         with PapiSocketExecutor(node) as papi_exec:
340             papi_exec.add(cmd, **args).get_reply(err_msg)
341
342     @staticmethod
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.
347
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
351             id incremented by 1.
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.
362         :type node: dict
363         :type n_entries: int
364         :type sad_id: int
365         :type spi: int
366         :type crypto_alg: CryptoAlg
367         :type crypto_key: str
368         :type integ_alg: IntegAlg
369         :type integ_key: str
370         :type tunnel_src: str
371         :type tunnel_dst: str
372         """
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)
380         else:
381             src_addr = u""
382             dst_addr = u""
383
384         addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
385             else 1 << (32 - 24)
386
387         if int(n_entries) > 10:
388             tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
389
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"
402                     tmp_file.write(conf)
403             vat = VatExecutor()
404             vat.execute_script(
405                 tmp_filename, node, timeout=300, json_out=False,
406                 copy_on_execute=True
407             )
408             os.remove(tmp_filename)
409             return
410
411         ckey = dict(
412             length=len(crypto_key),
413             data=crypto_key
414         )
415         ikey = dict(
416             length=len(integ_key),
417             data=integ_key if integ_key else 0
418         )
419
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:
424                 flags = flags | int(
425                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
426                 )
427
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']}"
431
432         sad_entry = dict(
433             sad_id=int(sad_id),
434             spi=int(spi),
435             crypto_algorithm=crypto_alg.alg_int_repr,
436             crypto_key=ckey,
437             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
438             integrity_key=ikey,
439             flags=flags,
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
445         )
446         args = dict(
447             is_add=True,
448             entry=sad_entry
449         )
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)
461
462     @staticmethod
463     def vpp_ipsec_set_ip_route(
464             node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
465             raddr_range):
466         """Set IP address and route on interface.
467
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
476             in case of IPv6.
477         :type node: dict
478         :type n_tunnels: int
479         :type tunnel_src: str
480         :type traffic_addr: str
481         :type tunnel_dst: str
482         :type interface: str
483         :type raddr_range: int
484         """
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)
490
491         if int(n_tunnels) > 10:
492             tmp_filename = u"/tmp/ipsec_set_ip.script"
493
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"
502                     tmp_file.write(conf)
503             VatExecutor().execute_script(
504                 tmp_filename, node, timeout=300, json_out=False,
505                 copy_on_execute=True
506             )
507             os.remove(tmp_filename)
508             return
509
510         cmd1 = u"sw_interface_add_del_address"
511         args1 = dict(
512             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
513             is_add=True,
514             del_all=False,
515             prefix=None
516         )
517         cmd2 = u"ip_route_add_del"
518         args2 = dict(
519             is_add=1,
520             is_multipath=0,
521             route=None
522         )
523         err_msg = f"Failed to configure IP addresses and IP routes " \
524             f"on interface {interface} on host {node[u'host']}"
525
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
530                 )
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
535                 )
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)
540
541     @staticmethod
542     def vpp_ipsec_add_spd(node, spd_id):
543         """Create Security Policy Database on the VPP node.
544
545         :param node: VPP node to add SPD on.
546         :param spd_id: SPD ID.
547         :type node: dict
548         :type spd_id: int
549         """
550         cmd = u"ipsec_spd_add_del"
551         err_msg = f"Failed to add Security Policy Database " \
552             f"on host {node[u'host']}"
553         args = dict(
554             is_add=True,
555             spd_id=int(spd_id)
556         )
557         with PapiSocketExecutor(node) as papi_exec:
558             papi_exec.add(cmd, **args).get_reply(err_msg)
559
560     @staticmethod
561     def vpp_ipsec_spd_add_if(node, spd_id, interface):
562         """Add interface to the Security Policy Database.
563
564         :param node: VPP node.
565         :param spd_id: SPD ID to add interface on.
566         :param interface: Interface name or sw_if_index.
567         :type node: dict
568         :type spd_id: int
569         :type interface: str or int
570         """
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']}"
574         args = dict(
575             is_add=True,
576             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
577             spd_id=int(spd_id)
578         )
579         with PapiSocketExecutor(node) as papi_exec:
580             papi_exec.add(cmd, **args).get_reply(err_msg)
581
582     @staticmethod
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.
588
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
594             outbound.
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.
609         :type node: dict
610         :type spd_id: int
611         :type priority: int
612         :type action: PolicyAction
613         :type inbound: bool
614         :type sa_id: int
615         :type laddr_range: string
616         :type raddr_range: string
617         :type proto: int
618         :type lport_range: string
619         :type rport_range: string
620         :type is_ipv6: bool
621         """
622         if laddr_range is None:
623             laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
624
625         if raddr_range is None:
626             raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
627
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']}"
631
632         spd_entry = dict(
633             spd_id=int(spd_id),
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
641             ),
642             remote_address_stop=IPAddress.create_ip_address_object(
643                 ip_network(raddr_range, strict=False).broadcast_address
644             ),
645             local_address_start=IPAddress.create_ip_address_object(
646                 ip_network(laddr_range, strict=False).network_address
647             ),
648             local_address_stop=IPAddress.create_ip_address_object(
649                 ip_network(laddr_range, strict=False).broadcast_address
650             ),
651             remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
652             else 0,
653             remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
654             else 65535,
655             local_port_start=int(lport_range.split(u"-")[0]) if lport_range
656             else 0,
657             local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
658             else 65535
659         )
660         args = dict(
661             is_add=True,
662             entry=spd_entry
663         )
664         with PapiSocketExecutor(node) as papi_exec:
665             papi_exec.add(cmd, **args).get_reply(err_msg)
666
667     @staticmethod
668     def vpp_ipsec_spd_add_entries(
669             node, n_entries, spd_id, priority, inbound, sa_id, raddr_ip,
670             raddr_range=0):
671         """Create multiple Security Policy Database entries on the VPP node.
672
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
678             outbound.
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.
686         :type node: dict
687         :type n_entries: int
688         :type spd_id: int
689         :type priority: int
690         :type inbound: bool
691         :type sa_id: int
692         :type raddr_ip: str
693         :type raddr_range: int
694         """
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"
698
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,
711                 copy_on_execute=True
712             )
713             os.remove(tmp_filename)
714             return
715
716         laddr_range = u"::/0" if raddr_ip.version == 6 else u"0.0.0.0/0"
717
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']}"
721
722         spd_entry = dict(
723             spd_id=int(spd_id),
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"),
728             protocol=0,
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
733             ),
734             local_address_stop=IPAddress.create_ip_address_object(
735                 ip_network(laddr_range, strict=False).broadcast_address
736             ),
737             remote_port_start=0,
738             remote_port_stop=65535,
739             local_port_start=0,
740             local_port_stop=65535
741         )
742         args = dict(
743             is_add=True,
744             entry=spd_entry
745         )
746
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)
756
757     @staticmethod
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.
762
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.
779         :type nodes: dict
780         :type tun_ips: dict
781         :type if1_key: str
782         :type if2_key: str
783         :type n_tunnels: int
784         :type crypto_alg: CryptoAlg
785         :type integ_alg: IntegAlg
786         :type raddr_ip2: IPv4Address or IPv6Address
787         :type addr_incr: int
788         :type spi_d: dict
789         :type existing_tunnels: int
790         """
791         tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
792         if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
793
794         ckeys = [bytes()] * existing_tunnels
795         ikeys = [bytes()] * existing_tunnels
796
797         vat = VatExecutor()
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:
803                 tmp_f1.write(
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} "
810                     f"static\n"
811                 )
812             for i in range(existing_tunnels, n_tunnels):
813                 ckeys.append(
814                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
815                 )
816                 if integ_alg:
817                     ikeys.append(
818                         gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
819                     )
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()} "
823                 else:
824                     integ = u""
825                 tmp_f1.write(
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()} "
834                     f"{integ} "
835                     f"local_ip {tun_ips[u'ip1'] + i * addr_incr} "
836                     f"remote_ip {tun_ips[u'ip2']} "
837                     f"instance {i}\n"
838                 )
839         vat.execute_script(
840             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
841             copy_on_execute=True,
842             history=bool(n_tunnels < 100)
843         )
844         os.remove(tmp_fn1)
845
846         with open(tmp_fn1, 'w') as tmp_f1:
847             for i in range(existing_tunnels, n_tunnels):
848                 tmp_f1.write(
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} "
853                     f"via ipip{i}\n"
854                 )
855         vat.execute_script(
856             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
857             copy_on_execute=True,
858             history=bool(n_tunnels < 100)
859         )
860         os.remove(tmp_fn1)
861
862         return ckeys, ikeys
863
864     @staticmethod
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.
869
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.
885         :type nodes: dict
886         :type tun_ips: dict
887         :type if2_key: str
888         :type n_tunnels: int
889         :type crypto_alg: CryptoAlg
890         :type ckeys: list
891         :type integ_alg: IntegAlg
892         :type ikeys: list
893         :type addr_incr: int
894         :type spi_d: dict
895         :type existing_tunnels: int
896         """
897         tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
898         if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
899
900         vat = VatExecutor()
901         with open(tmp_fn2, 'w') as tmp_f2:
902             if not existing_tunnels:
903                 tmp_f2.write(
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"
906                 )
907             for i in range(existing_tunnels, n_tunnels):
908                 if integ_alg:
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()} "
912                 else:
913                     integ = u""
914                 tmp_f2.write(
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()} "
921                     f"{integ} "
922                     f"local_ip {tun_ips[u'ip2']} "
923                     f"remote_ip {tun_ips[u'ip1'] + i * addr_incr} "
924                     f"instance {i}\n"
925                 )
926         vat.execute_script(
927             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
928             copy_on_execute=True,
929             history=bool(n_tunnels < 100)
930         )
931         os.remove(tmp_fn2)
932
933         with open(tmp_fn2, 'w') as tmp_f2:
934             if not existing_tunnels:
935                 tmp_f2.write(
936                     f"exec ip route add {tun_ips[u'ip1']}/8 "
937                     f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
938                 )
939             for i in range(existing_tunnels, n_tunnels):
940                 tmp_f2.write(
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} "
945                     f"via ipip{i}\n"
946                 )
947         vat.execute_script(
948             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
949             copy_on_execute=True,
950             history=bool(n_tunnels < 100)
951         )
952         os.remove(tmp_fn2)
953
954     @staticmethod
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
957         using PAPI.
958
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.
966         :type nodes: dict
967         :type tun_ips: dict
968         :type if1_key: str
969         :type if2_key: str
970         """
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"
974             args = dict(
975                 mac_address=0
976             )
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"
982             args = dict(
983                 sw_if_index=loop_sw_if_idx,
984                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
985             )
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"
991             args = dict(
992                 sw_if_index=InterfaceUtil.get_interface_index(
993                     nodes[u"DUT1"], if1_key
994                 ),
995                 is_add=True,
996                 del_all=False,
997                 prefix=IPUtil.create_prefix_object(
998                     tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
999                     else 24
1000                 )
1001             )
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"
1006             args2 = dict(
1007                 is_add=1,
1008                 neighbor=dict(
1009                     sw_if_index=Topology.get_interface_sw_index(
1010                         nodes[u"DUT1"], if1_key
1011                     ),
1012                     flags=1,
1013                     mac_address=str(
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
1018                         )
1019                     ),
1020                     ip_address=tun_ips[u"ip2"].compressed
1021                 )
1022             )
1023             err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1024             papi_exec.add(cmd2, **args2).get_reply(err_msg)
1025
1026             return loop_sw_if_idx
1027
1028     @staticmethod
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.
1033
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.
1050         :type nodes: dict
1051         :type tun_ips: dict
1052         :type if1_key: str
1053         :type if2_key: str
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
1059         :type spi_d: dict
1060         :type existing_tunnels: int
1061         """
1062         if not existing_tunnels:
1063             loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1064                 nodes, tun_ips, if1_key, if2_key
1065             )
1066         else:
1067             loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1068                 nodes[u"DUT1"], u"loop0"
1069             )
1070         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1071             # Configure IP addresses on loop0 interface
1072             cmd = u"sw_interface_add_del_address"
1073             args = dict(
1074                 sw_if_index=loop_sw_if_idx,
1075                 is_add=True,
1076                 del_all=False,
1077                 prefix=None
1078             )
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
1083                 )
1084                 papi_exec.add(
1085                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1086                 )
1087             # Configure IPsec tunnel interfaces
1088             cmd = u"ipsec_tunnel_if_add_del"
1089             args = dict(
1090                 is_add=True,
1091                 local_ip=None,
1092                 remote_ip=None,
1093                 local_spi=0,
1094                 remote_spi=0,
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,
1105                 tx_table_id=0
1106             )
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):
1111                 ckeys.append(
1112                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1113                 )
1114                 if integ_alg:
1115                     ikeys.append(
1116                         gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1117                     )
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
1122                 )
1123                 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1124                     tun_ips[u"ip2"]
1125                 )
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]
1130                 if integ_alg:
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]
1135                 papi_exec.add(
1136                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1137                 )
1138             err_msg = f"Failed to add IPsec tunnel interfaces on host" \
1139                 f" {nodes[u'DUT1'][u'host']}"
1140             ipsec_tunnels.extend(
1141                 [
1142                     reply[u"sw_if_index"]
1143                     for reply in papi_exec.get_replies(err_msg)
1144                     if u"sw_if_index" in reply
1145                 ]
1146             )
1147             # Configure unnumbered interfaces
1148             cmd = u"sw_interface_set_unnumbered"
1149             args = dict(
1150                 is_add=True,
1151                 sw_if_index=InterfaceUtil.get_interface_index(
1152                     nodes[u"DUT1"], if1_key
1153                 ),
1154                 unnumbered_sw_if_index=0
1155             )
1156             for i in range(existing_tunnels, n_tunnels):
1157                 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1158                 papi_exec.add(
1159                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1160                 )
1161             # Set interfaces up
1162             cmd = u"sw_interface_set_flags"
1163             args = dict(
1164                 sw_if_index=0,
1165                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1166             )
1167             for i in range(existing_tunnels, n_tunnels):
1168                 args[u"sw_if_index"] = ipsec_tunnels[i]
1169                 papi_exec.add(
1170                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1171                 )
1172             # Configure IP routes
1173             cmd = u"ip_route_add_del"
1174             args = dict(
1175                 is_add=1,
1176                 is_multipath=0,
1177                 route=None
1178             )
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]
1184                 )
1185                 papi_exec.add(
1186                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1187                 )
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)
1191
1192         return ckeys, ikeys
1193
1194     @staticmethod
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.
1199
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.
1215         :type nodes: dict
1216         :type tun_ips: dict
1217         :type if2_key: str
1218         :type n_tunnels: int
1219         :type crypto_alg: CryptoAlg
1220         :type ckeys: list
1221         :type integ_alg: IntegAlg
1222         :type ikeys: list
1223         :type addr_incr: int
1224         :type spi_d: dict
1225         :type existing_tunnels: int
1226         """
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"
1231                 args = dict(
1232                     sw_if_index=InterfaceUtil.get_interface_index(
1233                         nodes[u"DUT2"], if2_key
1234                     ),
1235                     is_add=True,
1236                     del_all=False,
1237                     prefix=IPUtil.create_prefix_object(
1238                         tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1239                         else 24
1240                     )
1241                 )
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"
1247             args = dict(
1248                 is_add=True,
1249                 local_ip=IPAddress.create_ip_address_object(tun_ips[u"ip2"]),
1250                 remote_ip=None,
1251                 local_spi=0,
1252                 remote_spi=0,
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,
1263                 tx_table_id=0
1264             )
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(
1270                     tun_ips[u"ip2"]
1271                 )
1272                 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1273                     tun_ips[u"ip1"] + i * addr_incr
1274                 )
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]
1279                 if integ_alg:
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]
1284                 papi_exec.add(
1285                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1286                 )
1287             err_msg = f"Failed to add IPsec tunnel interfaces " \
1288                 f"on host {nodes[u'DUT2'][u'host']}"
1289             ipsec_tunnels.extend(
1290                 [
1291                     reply[u"sw_if_index"]
1292                     for reply in papi_exec.get_replies(err_msg)
1293                     if u"sw_if_index" in reply
1294                 ]
1295             )
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,
1302                     interface=if2_key,
1303                     gateway=(tun_ips[u"ip2"] - 1).compressed
1304                 )
1305                 args = dict(
1306                     is_add=1,
1307                     is_multipath=0,
1308                     route=route
1309                 )
1310                 papi_exec.add(cmd, **args)
1311             # Configure unnumbered interfaces
1312             cmd = u"sw_interface_set_unnumbered"
1313             args = dict(
1314                 is_add=True,
1315                 sw_if_index=InterfaceUtil.get_interface_index(
1316                     nodes[u"DUT2"], if2_key
1317                 ),
1318                 unnumbered_sw_if_index=0
1319             )
1320             for i in range(existing_tunnels, n_tunnels):
1321                 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1322                 papi_exec.add(
1323                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1324                 )
1325             # Set interfaces up
1326             cmd = u"sw_interface_set_flags"
1327             args = dict(
1328                 sw_if_index=0,
1329                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1330             )
1331             for i in range(existing_tunnels, n_tunnels):
1332                 args[u"sw_if_index"] = ipsec_tunnels[i]
1333                 papi_exec.add(
1334                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1335                 )
1336             # Configure IP routes
1337             cmd = u"ip_route_add_del"
1338             args = dict(
1339                 is_add=1,
1340                 is_multipath=0,
1341                 route=None
1342             )
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]
1348                 )
1349                 papi_exec.add(
1350                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1351                 )
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)
1355
1356     @staticmethod
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.
1362
1363         :param nodes: VPP nodes to create tunnel interfaces.
1364         :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1365             address.
1366         :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1367             address.
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.
1383         :type nodes: dict
1384         :type tun_if1_ip_addr: str
1385         :type tun_if2_ip_addr: str
1386         :type if1_key: str
1387         :type if2_key: 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
1395         """
1396         n_tunnels = int(n_tunnels)
1397         existing_tunnels = int(existing_tunnels)
1398         spi_d = dict(
1399             spi_1=100000,
1400             spi_2=200000
1401         )
1402         tun_ips = dict(
1403             ip1=ip_address(tun_if1_ip_addr),
1404             ip2=ip_address(tun_if2_ip_addr)
1405         )
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)
1410
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
1415             )
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
1421             )
1422         else:
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
1426             )
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
1432             )
1433
1434         return None, None, None, None
1435
1436     @staticmethod
1437     def _create_ipsec_script_files(dut, instances):
1438         """Create script files for configuring IPsec in containers
1439
1440         :param dut: DUT node on which to create the script files
1441         :param instances: number of containers on DUT node
1442         :type dut: string
1443         :type instances: int
1444         """
1445         scripts = []
1446         for cnf in range(0, instances):
1447             script_filename = (
1448                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1449             )
1450             scripts.append(open(script_filename, 'w'))
1451         return scripts
1452
1453     @staticmethod
1454     def _close_and_copy_ipsec_script_files(
1455             dut, nodes, instances, scripts):
1456         """Close created scripts and copy them to containers
1457
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
1462         :type dut: string
1463         :type nodes: dict
1464         :type instances: int
1465         :type scripts: dict
1466         """
1467         for cnf in range(0, instances):
1468             scripts[cnf].close()
1469             script_filename = (
1470                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1471             )
1472             scp_node(nodes[dut], script_filename, script_filename)
1473
1474
1475     @staticmethod
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.
1480
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.
1494         :type nodes: dict
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
1504         """
1505         spi_1 = 100000
1506         spi_2 = 200000
1507         addr_incr = 1 << (32 - raddr_range)
1508
1509         dut1_scripts = IPsecUtil._create_ipsec_script_files(
1510             u"DUT1", n_instances
1511         )
1512         dut2_scripts = IPsecUtil._create_ipsec_script_files(
1513             u"DUT2", n_instances
1514         )
1515
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"
1520             )
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"
1524             )
1525
1526         for tnl in range(0, n_tunnels):
1527             cnf = tnl % n_instances
1528             ckey = getattr(
1529                 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1530             )
1531             integ = u""
1532             if integ_alg:
1533                 ikey = getattr(
1534                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1535                 )
1536                 integ = (
1537                     f"integ-alg {integ_alg.alg_name} "
1538                     f"local-integ-key {ikey} "
1539                     f"remote-integ-key {ikey} "
1540                 )
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} "
1554                 f"salt 0x0 "
1555                 f"{integ} \n"
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"
1560             )
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} "
1574                 f"salt 0x0 "
1575                 f"{integ}\n"
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"
1581             )
1582
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)
1587
1588     @staticmethod
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.
1593
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.
1608         :type nodes: dict
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
1619         """
1620         spd_id = 1
1621         p_hi = 100
1622         p_lo = 10
1623         sa_id_1 = 100000
1624         sa_id_2 = 200000
1625         spi_1 = 300000
1626         spi_2 = 400000
1627
1628         crypto_key = gen_key(
1629             IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1630         ).decode()
1631         integ_key = gen_key(
1632             IPsecUtil.get_integ_alg_key_len(integ_alg)
1633         ).decode() if integ_alg else u""
1634
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)
1641
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"
1647         )
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"
1651         )
1652
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"
1658         )
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"
1662         )
1663
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
1667         )
1668         IPsecUtil.vpp_ipsec_spd_add_entries(
1669             nodes[u"DUT1"], n_tunnels, spd_id, p_lo, False, sa_id_1, raddr_ip2
1670         )
1671
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
1675         )
1676         IPsecUtil.vpp_ipsec_spd_add_entries(
1677             nodes[u"DUT2"], n_tunnels, spd_id, p_lo, True, sa_id_1, raddr_ip2
1678         )
1679
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
1683         )
1684
1685         IPsecUtil.vpp_ipsec_spd_add_entries(
1686             nodes[u"DUT2"], n_tunnels, spd_id, p_lo, False, sa_id_2, raddr_ip1
1687         )
1688
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
1692         )
1693
1694         IPsecUtil.vpp_ipsec_spd_add_entries(
1695             nodes[u"DUT1"], n_tunnels, spd_id, p_lo, True, sa_id_2, raddr_ip1
1696         )
1697
1698     @staticmethod
1699     def vpp_ipsec_show(node):
1700         """Run "show ipsec" debug CLI command.
1701
1702         :param node: Node to run command on.
1703         :type node: dict
1704         """
1705         PapiSocketExecutor.run_cli_cmd(node, u"show ipsec")