Separate files needing GPL license
[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         )
333         args = dict(
334             is_add=True,
335             entry=sad_entry
336         )
337         with PapiSocketExecutor(node) as papi_exec:
338             papi_exec.add(cmd, **args).get_reply(err_msg)
339
340     @staticmethod
341     def vpp_ipsec_add_sad_entries(
342             node, n_entries, sad_id, spi, crypto_alg, crypto_key,
343             integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
344         """Create multiple Security Association Database entries on VPP node.
345
346         :param node: VPP node to add SAD entry on.
347         :param n_entries: Number of SAD entries to be created.
348         :param sad_id: First SAD entry ID. All subsequent SAD entries will have
349             id incremented by 1.
350         :param spi: Security Parameter Index of first SAD entry. All subsequent
351             SAD entries will have spi incremented by 1.
352         :param crypto_alg: The encryption algorithm name.
353         :param crypto_key: The encryption key string.
354         :param integ_alg: The integrity algorithm name.
355         :param integ_key: The integrity key string.
356         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
357             specified ESP transport mode is used.
358         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
359             not specified ESP transport mode is used.
360         :type node: dict
361         :type n_entries: int
362         :type sad_id: int
363         :type spi: int
364         :type crypto_alg: CryptoAlg
365         :type crypto_key: str
366         :type integ_alg: IntegAlg
367         :type integ_key: str
368         :type tunnel_src: str
369         :type tunnel_dst: str
370         """
371         if isinstance(crypto_key, str):
372             crypto_key = crypto_key.encode(encoding=u"utf-8")
373         if isinstance(integ_key, str):
374             integ_key = integ_key.encode(encoding=u"utf-8")
375         if tunnel_src and tunnel_dst:
376             src_addr = ip_address(tunnel_src)
377             dst_addr = ip_address(tunnel_dst)
378         else:
379             src_addr = u""
380             dst_addr = u""
381
382         addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
383             else 1 << (32 - 24)
384
385         if int(n_entries) > 10:
386             tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
387
388             with open(tmp_filename, 'w') as tmp_file:
389                 for i in range(n_entries):
390                     integ = f"integ-alg {integ_alg.alg_name} " \
391                         f"integ-key {integ_key.hex()}" \
392                         if integ_alg else u""
393                     tunnel = f"tunnel-src {src_addr + i * addr_incr} " \
394                         f"tunnel-dst {dst_addr + i * addr_incr}" \
395                         if tunnel_src and tunnel_dst else u""
396                     conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
397                         f"crypto-alg {crypto_alg.alg_name} " \
398                         f"crypto-key {crypto_key.hex()} " \
399                         f"{integ} {tunnel}\n"
400                     tmp_file.write(conf)
401             vat = VatExecutor()
402             vat.execute_script(
403                 tmp_filename, node, timeout=300, json_out=False,
404                 copy_on_execute=True
405             )
406             os.remove(tmp_filename)
407             return
408
409         ckey = dict(
410             length=len(crypto_key),
411             data=crypto_key
412         )
413         ikey = dict(
414             length=len(integ_key),
415             data=integ_key if integ_key else 0
416         )
417
418         flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
419         if tunnel_src and tunnel_dst:
420             flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
421             if src_addr.version == 6:
422                 flags = flags | int(
423                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
424                 )
425
426         cmd = u"ipsec_sad_entry_add_del"
427         err_msg = f"Failed to add Security Association Database entry " \
428             f"on host {node[u'host']}"
429
430         sad_entry = dict(
431             sad_id=int(sad_id),
432             spi=int(spi),
433             crypto_algorithm=crypto_alg.alg_int_repr,
434             crypto_key=ckey,
435             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
436             integrity_key=ikey,
437             flags=flags,
438             tunnel_src=str(src_addr),
439             tunnel_dst=str(dst_addr),
440             protocol=int(IPsecProto.IPSEC_API_PROTO_ESP)
441         )
442         args = dict(
443             is_add=True,
444             entry=sad_entry
445         )
446         with PapiSocketExecutor(node) as papi_exec:
447             for i in range(n_entries):
448                 args[u"entry"][u"sad_id"] = int(sad_id) + i
449                 args[u"entry"][u"spi"] = int(spi) + i
450                 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
451                     if tunnel_src and tunnel_dst else src_addr
452                 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
453                     if tunnel_src and tunnel_dst else dst_addr
454                 history = bool(not 1 < i < n_entries - 2)
455                 papi_exec.add(cmd, history=history, **args)
456             papi_exec.get_replies(err_msg)
457
458     @staticmethod
459     def vpp_ipsec_set_ip_route(
460             node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
461             raddr_range):
462         """Set IP address and route on interface.
463
464         :param node: VPP node to add config on.
465         :param n_tunnels: Number of tunnels to create.
466         :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
467         :param traffic_addr: Traffic destination IP address to route.
468         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
469         :param interface: Interface key on node 1.
470         :param raddr_range: Mask specifying range of Policy selector Remote IP
471             addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
472             in case of IPv6.
473         :type node: dict
474         :type n_tunnels: int
475         :type tunnel_src: str
476         :type traffic_addr: str
477         :type tunnel_dst: str
478         :type interface: str
479         :type raddr_range: int
480         """
481         tunnel_src = ip_address(tunnel_src)
482         tunnel_dst = ip_address(tunnel_dst)
483         traffic_addr = ip_address(traffic_addr)
484         addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
485             else 1 << (32 - raddr_range)
486
487         if int(n_tunnels) > 10:
488             tmp_filename = u"/tmp/ipsec_set_ip.script"
489
490             with open(tmp_filename, 'w') as tmp_file:
491                 if_name = Topology.get_interface_name(node, interface)
492                 for i in range(n_tunnels):
493                     conf = f"exec set interface ip address {if_name} " \
494                         f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
495                         f"exec ip route add {traffic_addr + i}/" \
496                         f"{128 if traffic_addr.version == 6 else 32} " \
497                         f"via {tunnel_dst + i * addr_incr} {if_name}\n"
498                     tmp_file.write(conf)
499             VatExecutor().execute_script(
500                 tmp_filename, node, timeout=300, json_out=False,
501                 copy_on_execute=True
502             )
503             os.remove(tmp_filename)
504             return
505
506         cmd1 = u"sw_interface_add_del_address"
507         args1 = dict(
508             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
509             is_add=True,
510             del_all=False,
511             prefix=None
512         )
513         cmd2 = u"ip_route_add_del"
514         args2 = dict(
515             is_add=1,
516             is_multipath=0,
517             route=None
518         )
519         err_msg = f"Failed to configure IP addresses and IP routes " \
520             f"on interface {interface} on host {node[u'host']}"
521
522         with PapiSocketExecutor(node) as papi_exec:
523             for i in range(n_tunnels):
524                 args1[u"prefix"] = IPUtil.create_prefix_object(
525                     tunnel_src + i * addr_incr, raddr_range
526                 )
527                 args2[u"route"] = IPUtil.compose_vpp_route_structure(
528                     node, traffic_addr + i,
529                     prefix_len=128 if traffic_addr.version == 6 else 32,
530                     interface=interface, gateway=tunnel_dst + i * addr_incr
531                 )
532                 history = bool(not 1 < i < n_tunnels - 2)
533                 papi_exec.add(cmd1, history=history, **args1).\
534                     add(cmd2, history=history, **args2)
535             papi_exec.get_replies(err_msg)
536
537     @staticmethod
538     def vpp_ipsec_add_spd(node, spd_id):
539         """Create Security Policy Database on the VPP node.
540
541         :param node: VPP node to add SPD on.
542         :param spd_id: SPD ID.
543         :type node: dict
544         :type spd_id: int
545         """
546         cmd = u"ipsec_spd_add_del"
547         err_msg = f"Failed to add Security Policy Database " \
548             f"on host {node[u'host']}"
549         args = dict(
550             is_add=True,
551             spd_id=int(spd_id)
552         )
553         with PapiSocketExecutor(node) as papi_exec:
554             papi_exec.add(cmd, **args).get_reply(err_msg)
555
556     @staticmethod
557     def vpp_ipsec_spd_add_if(node, spd_id, interface):
558         """Add interface to the Security Policy Database.
559
560         :param node: VPP node.
561         :param spd_id: SPD ID to add interface on.
562         :param interface: Interface name or sw_if_index.
563         :type node: dict
564         :type spd_id: int
565         :type interface: str or int
566         """
567         cmd = u"ipsec_interface_add_del_spd"
568         err_msg = f"Failed to add interface {interface} to Security Policy " \
569             f"Database {spd_id} on host {node[u'host']}"
570         args = dict(
571             is_add=True,
572             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
573             spd_id=int(spd_id)
574         )
575         with PapiSocketExecutor(node) as papi_exec:
576             papi_exec.add(cmd, **args).get_reply(err_msg)
577
578     @staticmethod
579     def vpp_ipsec_policy_add(
580             node, spd_id, priority, action, inbound=True, sa_id=None,
581             laddr_range=None, raddr_range=None, proto=None, lport_range=None,
582             rport_range=None, is_ipv6=False):
583         """Create Security Policy Database entry on the VPP node.
584
585         :param node: VPP node to add SPD entry on.
586         :param spd_id: SPD ID to add entry on.
587         :param priority: SPD entry priority, higher number = higher priority.
588         :param action: Policy action.
589         :param inbound: If True policy is for inbound traffic, otherwise
590             outbound.
591         :param sa_id: SAD entry ID for protect action.
592         :param laddr_range: Policy selector local IPv4 or IPv6 address range in
593             format IP/prefix or IP/mask. If no mask is provided,
594             it's considered to be /32.
595         :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
596             format IP/prefix or IP/mask. If no mask is provided,
597             it's considered to be /32.
598         :param proto: Policy selector next layer protocol number.
599         :param lport_range: Policy selector local TCP/UDP port range in format
600             <port_start>-<port_end>.
601         :param rport_range: Policy selector remote TCP/UDP port range in format
602             <port_start>-<port_end>.
603         :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
604             not defined so it will default to address ::/0, otherwise False.
605         :type node: dict
606         :type spd_id: int
607         :type priority: int
608         :type action: PolicyAction
609         :type inbound: bool
610         :type sa_id: int
611         :type laddr_range: string
612         :type raddr_range: string
613         :type proto: int
614         :type lport_range: string
615         :type rport_range: string
616         :type is_ipv6: bool
617         """
618         if laddr_range is None:
619             laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
620
621         if raddr_range is None:
622             raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
623
624         cmd = u"ipsec_spd_entry_add_del"
625         err_msg = f"Failed to add entry to Security Policy Database {spd_id} " \
626             f"on host {node[u'host']}"
627
628         spd_entry = dict(
629             spd_id=int(spd_id),
630             priority=int(priority),
631             is_outbound=not inbound,
632             sa_id=int(sa_id) if sa_id else 0,
633             policy=action.policy_int_repr,
634             protocol=int(proto) if proto else 0,
635             remote_address_start=IPAddress.create_ip_address_object(
636                 ip_network(raddr_range, strict=False).network_address
637             ),
638             remote_address_stop=IPAddress.create_ip_address_object(
639                 ip_network(raddr_range, strict=False).broadcast_address
640             ),
641             local_address_start=IPAddress.create_ip_address_object(
642                 ip_network(laddr_range, strict=False).network_address
643             ),
644             local_address_stop=IPAddress.create_ip_address_object(
645                 ip_network(laddr_range, strict=False).broadcast_address
646             ),
647             remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
648             else 0,
649             remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
650             else 65535,
651             local_port_start=int(lport_range.split(u"-")[0]) if lport_range
652             else 0,
653             local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
654             else 65535
655         )
656         args = dict(
657             is_add=True,
658             entry=spd_entry
659         )
660         with PapiSocketExecutor(node) as papi_exec:
661             papi_exec.add(cmd, **args).get_reply(err_msg)
662
663     @staticmethod
664     def vpp_ipsec_spd_add_entries(
665             node, n_entries, spd_id, priority, inbound, sa_id, raddr_ip,
666             raddr_range=0):
667         """Create multiple Security Policy Database entries on the VPP node.
668
669         :param node: VPP node to add SPD entries on.
670         :param n_entries: Number of SPD entries to be added.
671         :param spd_id: SPD ID to add entries on.
672         :param priority: SPD entries priority, higher number = higher priority.
673         :param inbound: If True policy is for inbound traffic, otherwise
674             outbound.
675         :param sa_id: SAD entry ID for first entry. Each subsequent entry will
676             SAD entry ID incremented by 1.
677         :param raddr_ip: Policy selector remote IPv4 start address for the first
678             entry. Remote IPv4 end address will be calculated depending on
679             raddr_range parameter. Each subsequent entry will have start address
680             next after IPv4 end address of previous entry.
681         :param raddr_range: Required IP addres range.
682         :type node: dict
683         :type n_entries: int
684         :type spd_id: int
685         :type priority: int
686         :type inbound: bool
687         :type sa_id: int
688         :type raddr_ip: str
689         :type raddr_range: int
690         """
691         raddr_ip = ip_address(raddr_ip)
692         if int(n_entries) > 10:
693             tmp_filename = f"/tmp/ipsec_spd_{sa_id}_add_del_entry.script"
694
695             with open(tmp_filename, 'w') as tmp_file:
696                 for i in range(n_entries):
697                     direction = u'inbound' if inbound else u'outbound'
698                     tunnel = f"exec ipsec policy add spd {spd_id} " \
699                         f"priority {priority} {direction} " \
700                         f"action protect sa {sa_id+i} " \
701                         f"remote-ip-range {raddr_ip + i * (raddr_range + 1)} " \
702                         f"- {raddr_ip + (i  + 1) * raddr_range + i} " \
703                         f"local-ip-range 0.0.0.0 - 255.255.255.255\n"
704                     tmp_file.write(tunnel)
705             VatExecutor().execute_script(
706                 tmp_filename, node, timeout=300, json_out=False,
707                 copy_on_execute=True
708             )
709             os.remove(tmp_filename)
710             return
711
712         laddr_range = u"::/0" if raddr_ip.version == 6 else u"0.0.0.0/0"
713
714         cmd = u"ipsec_spd_entry_add_del"
715         err_msg = f"ailed to add entry to Security Policy Database '{spd_id} " \
716             f"on host {node[u'host']}"
717
718         spd_entry = dict(
719             spd_id=int(spd_id),
720             priority=int(priority),
721             is_outbound=not inbound,
722             sa_id=int(sa_id) if sa_id else 0,
723             policy=getattr(PolicyAction.PROTECT, u"policy_int_repr"),
724             protocol=0,
725             remote_address_start=IPAddress.create_ip_address_object(raddr_ip),
726             remote_address_stop=IPAddress.create_ip_address_object(raddr_ip),
727             local_address_start=IPAddress.create_ip_address_object(
728                 ip_network(laddr_range, strict=False).network_address
729             ),
730             local_address_stop=IPAddress.create_ip_address_object(
731                 ip_network(laddr_range, strict=False).broadcast_address
732             ),
733             remote_port_start=0,
734             remote_port_stop=65535,
735             local_port_start=0,
736             local_port_stop=65535
737         )
738         args = dict(
739             is_add=True,
740             entry=spd_entry
741         )
742
743         with PapiSocketExecutor(node) as papi_exec:
744             for i in range(n_entries):
745                 args[u"entry"][u"remote_address_start"][u"un"] = \
746                     IPAddress.union_addr(raddr_ip + i)
747                 args[u"entry"][u"remote_address_stop"][u"un"] = \
748                     IPAddress.union_addr(raddr_ip + i)
749                 history = bool(not 1 < i < n_entries - 2)
750                 papi_exec.add(cmd, history=history, **args)
751             papi_exec.get_replies(err_msg)
752
753     @staticmethod
754     def _ipsec_create_tunnel_interfaces_dut1_vat(
755             nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
756             raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
757         """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
758
759         :param nodes: VPP nodes to create tunnel interfaces.
760         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
761             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
762             IPv4/IPv6 address (ip2).
763         :param if1_key: VPP node 1 interface key from topology file.
764         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
765             interface key from topology file.
766         :param n_tunnels: Number of tunnel interfaces to be there at the end.
767         :param crypto_alg: The encryption algorithm name.
768         :param integ_alg: The integrity algorithm name.
769         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
770             first tunnel in direction node2->node1.
771         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
772         :param addr_incr: IP / IPv6 address incremental step.
773         :param existing_tunnels: Number of tunnel interfaces before creation.
774             Useful mainly for reconf tests. Default 0.
775         :type nodes: dict
776         :type tun_ips: dict
777         :type if1_key: str
778         :type if2_key: str
779         :type n_tunnels: int
780         :type crypto_alg: CryptoAlg
781         :type integ_alg: IntegAlg
782         :type raddr_ip2: IPv4Address or IPv6Address
783         :type addr_incr: int
784         :type spi_d: dict
785         :type existing_tunnels: int
786         """
787         tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
788         if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
789
790         ckeys = [bytes()] * existing_tunnels
791         ikeys = [bytes()] * existing_tunnels
792
793         vat = VatExecutor()
794         with open(tmp_fn1, u"w") as tmp_f1:
795             rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
796                 if u"DUT2" in nodes.keys() \
797                 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
798             if not existing_tunnels:
799                 tmp_f1.write(
800                     f"exec create loopback interface\n"
801                     f"exec set interface state loop0 up\n"
802                     f"exec set interface ip address {if1_n} "
803                     f"{tun_ips[u'ip2'] - 1}/"
804                     f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
805                     f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
806                     f"static\n"
807                 )
808             for i in range(existing_tunnels, n_tunnels):
809                 ckeys.append(
810                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
811                 )
812                 if integ_alg:
813                     ikeys.append(
814                         gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
815                     )
816                     integ = f"integ_alg {integ_alg.alg_name} " \
817                         f"local_integ_key {ikeys[i].hex()} " \
818                         f"remote_integ_key {ikeys[i].hex()} "
819                 else:
820                     integ = u""
821                 tmp_f1.write(
822                     f"exec set interface ip address loop0 "
823                     f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
824                     f"ipsec_tunnel_if_add_del "
825                     f"local_spi {spi_d[u'spi_1'] + i} "
826                     f"remote_spi {spi_d[u'spi_2'] + i} "
827                     f"crypto_alg {crypto_alg.alg_name} "
828                     f"local_crypto_key {ckeys[i].hex()} "
829                     f"remote_crypto_key {ckeys[i].hex()} "
830                     f"{integ} "
831                     f"local_ip {tun_ips[u'ip1'] + i * addr_incr} "
832                     f"remote_ip {tun_ips[u'ip2']} "
833                     f"instance {i}\n"
834                 )
835         vat.execute_script(
836             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
837             copy_on_execute=True,
838             history=bool(n_tunnels < 100)
839         )
840         os.remove(tmp_fn1)
841
842         with open(tmp_fn1, 'w') as tmp_f1:
843             for i in range(existing_tunnels, n_tunnels):
844                 tmp_f1.write(
845                     f"exec set interface unnumbered ipip{i} use {if1_n}\n"
846                     f"exec set interface state ipip{i} up\n"
847                     f"exec ip route add "
848                     f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
849                     f"via ipip{i}\n"
850                 )
851         vat.execute_script(
852             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
853             copy_on_execute=True,
854             history=bool(n_tunnels < 100)
855         )
856         os.remove(tmp_fn1)
857
858         return ckeys, ikeys
859
860     @staticmethod
861     def _ipsec_create_tunnel_interfaces_dut2_vat(
862             nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
863             ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
864         """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
865
866         :param nodes: VPP nodes to create tunnel interfaces.
867         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
868             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
869             IPv4/IPv6 address (ip2).
870         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
871             interface key from topology file.
872         :param n_tunnels: Number of tunnel interfaces to be there at the end.
873         :param crypto_alg: The encryption algorithm name.
874         :param ckeys: List of encryption keys.
875         :param integ_alg: The integrity algorithm name.
876         :param ikeys: List of integrity keys.
877         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
878         :param addr_incr: IP / IPv6 address incremental step.
879         :param existing_tunnels: Number of tunnel interfaces before creation.
880             Useful mainly for reconf tests. Default 0.
881         :type nodes: dict
882         :type tun_ips: dict
883         :type if2_key: str
884         :type n_tunnels: int
885         :type crypto_alg: CryptoAlg
886         :type ckeys: list
887         :type integ_alg: IntegAlg
888         :type ikeys: list
889         :type addr_incr: int
890         :type spi_d: dict
891         :type existing_tunnels: int
892         """
893         tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
894         if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
895
896         vat = VatExecutor()
897         with open(tmp_fn2, 'w') as tmp_f2:
898             if not existing_tunnels:
899                 tmp_f2.write(
900                     f"exec set interface ip address {if2_n}"
901                     f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
902                 )
903             for i in range(existing_tunnels, n_tunnels):
904                 if integ_alg:
905                     integ = f"integ_alg {integ_alg.alg_name} " \
906                         f"local_integ_key {ikeys[i].hex()} " \
907                         f"remote_integ_key {ikeys[i].hex()} "
908                 else:
909                     integ = u""
910                 tmp_f2.write(
911                     f"ipsec_tunnel_if_add_del "
912                     f"local_spi {spi_d[u'spi_2'] + i} "
913                     f"remote_spi {spi_d[u'spi_1'] + i} "
914                     f"crypto_alg {crypto_alg.alg_name} "
915                     f"local_crypto_key {ckeys[i].hex()} "
916                     f"remote_crypto_key {ckeys[i].hex()} "
917                     f"{integ} "
918                     f"local_ip {tun_ips[u'ip2']} "
919                     f"remote_ip {tun_ips[u'ip1'] + i * addr_incr} "
920                     f"instance {i}\n"
921                 )
922         vat.execute_script(
923             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
924             copy_on_execute=True,
925             history=bool(n_tunnels < 100)
926         )
927         os.remove(tmp_fn2)
928
929         with open(tmp_fn2, 'w') as tmp_f2:
930             if not existing_tunnels:
931                 tmp_f2.write(
932                     f"exec ip route add {tun_ips[u'ip1']}/8 "
933                     f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
934                 )
935             for i in range(existing_tunnels, n_tunnels):
936                 tmp_f2.write(
937                     f"exec set interface unnumbered ipip{i} use {if2_n}\n"
938                     f"exec set interface state ipip{i} up\n"
939                     f"exec ip route add "
940                     f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
941                     f"via ipip{i}\n"
942                 )
943         vat.execute_script(
944             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
945             copy_on_execute=True,
946             history=bool(n_tunnels < 100)
947         )
948         os.remove(tmp_fn2)
949
950     @staticmethod
951     def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
952         """Create loopback interface and set IP address on VPP node 1 interface
953         using PAPI.
954
955         :param nodes: VPP nodes to create tunnel interfaces.
956         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
957             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
958             IPv4/IPv6 address (ip2).
959         :param if1_key: VPP node 1 interface key from topology file.
960         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
961             interface key from topology file.
962         :type nodes: dict
963         :type tun_ips: dict
964         :type if1_key: str
965         :type if2_key: str
966         """
967         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
968             # Create loopback interface on DUT1, set it to up state
969             cmd = u"create_loopback"
970             args = dict(
971                 mac_address=0
972             )
973             err_msg = f"Failed to create loopback interface " \
974                 f"on host {nodes[u'DUT1'][u'host']}"
975             loop_sw_if_idx = papi_exec.add(cmd, **args). \
976                 get_sw_if_index(err_msg)
977             cmd = u"sw_interface_set_flags"
978             args = dict(
979                 sw_if_index=loop_sw_if_idx,
980                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
981             )
982             err_msg = f"Failed to set loopback interface state up " \
983                 f"on host {nodes[u'DUT1'][u'host']}"
984             papi_exec.add(cmd, **args).get_reply(err_msg)
985             # Set IP address on VPP node 1 interface
986             cmd = u"sw_interface_add_del_address"
987             args = dict(
988                 sw_if_index=InterfaceUtil.get_interface_index(
989                     nodes[u"DUT1"], if1_key
990                 ),
991                 is_add=True,
992                 del_all=False,
993                 prefix=IPUtil.create_prefix_object(
994                     tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
995                     else 24
996                 )
997             )
998             err_msg = f"Failed to set IP address on interface {if1_key} " \
999                 f"on host {nodes[u'DUT1'][u'host']}"
1000             papi_exec.add(cmd, **args).get_reply(err_msg)
1001             cmd2 = u"ip_neighbor_add_del"
1002             args2 = dict(
1003                 is_add=1,
1004                 neighbor=dict(
1005                     sw_if_index=Topology.get_interface_sw_index(
1006                         nodes[u"DUT1"], if1_key
1007                     ),
1008                     flags=1,
1009                     mac_address=str(
1010                         Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1011                         if u"DUT2" in nodes.keys()
1012                         else Topology.get_interface_mac(
1013                             nodes[u"TG"], if2_key
1014                         )
1015                     ),
1016                     ip_address=tun_ips[u"ip2"].compressed
1017                 )
1018             )
1019             err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1020             papi_exec.add(cmd2, **args2).get_reply(err_msg)
1021
1022             return loop_sw_if_idx
1023
1024     @staticmethod
1025     def _ipsec_create_tunnel_interfaces_dut1_papi(
1026             nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1027             raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1028         """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1029
1030         :param nodes: VPP nodes to create tunnel interfaces.
1031         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1032             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1033             IPv4/IPv6 address (ip2).
1034         :param if1_key: VPP node 1 interface key from topology file.
1035         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1036             interface key from topology file.
1037         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1038         :param crypto_alg: The encryption algorithm name.
1039         :param integ_alg: The integrity algorithm name.
1040         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1041             first tunnel in direction node2->node1.
1042         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1043         :param addr_incr: IP / IPv6 address incremental step.
1044         :param existing_tunnels: Number of tunnel interfaces before creation.
1045             Useful mainly for reconf tests. Default 0.
1046         :type nodes: dict
1047         :type tun_ips: dict
1048         :type if1_key: str
1049         :type if2_key: str
1050         :type n_tunnels: int
1051         :type crypto_alg: CryptoAlg
1052         :type integ_alg: IntegAlg
1053         :type raddr_ip2: IPv4Address or IPv6Address
1054         :type addr_incr: int
1055         :type spi_d: dict
1056         :type existing_tunnels: int
1057         """
1058         if not existing_tunnels:
1059             loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1060                 nodes, tun_ips, if1_key, if2_key
1061             )
1062         else:
1063             loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1064                 nodes[u"DUT1"], u"loop0"
1065             )
1066         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1067             # Configure IP addresses on loop0 interface
1068             cmd = u"sw_interface_add_del_address"
1069             args = dict(
1070                 sw_if_index=loop_sw_if_idx,
1071                 is_add=True,
1072                 del_all=False,
1073                 prefix=None
1074             )
1075             for i in range(existing_tunnels, n_tunnels):
1076                 args[u"prefix"] = IPUtil.create_prefix_object(
1077                     tun_ips[u"ip1"] + i * addr_incr,
1078                     128 if tun_ips[u"ip1"].version == 6 else 32
1079                 )
1080                 papi_exec.add(
1081                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1082                 )
1083             # Configure IPsec tunnel interfaces
1084             cmd = u"ipsec_tunnel_if_add_del"
1085             args = dict(
1086                 is_add=True,
1087                 local_ip=None,
1088                 remote_ip=None,
1089                 local_spi=0,
1090                 remote_spi=0,
1091                 crypto_alg=crypto_alg.alg_int_repr,
1092                 local_crypto_key_len=0,
1093                 local_crypto_key=None,
1094                 remote_crypto_key_len=0,
1095                 remote_crypto_key=None,
1096                 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1097                 local_integ_key_len=0,
1098                 local_integ_key=None,
1099                 remote_integ_key_len=0,
1100                 remote_integ_key=None,
1101                 tx_table_id=0
1102             )
1103             ipsec_tunnels = [None] * existing_tunnels
1104             ckeys = [bytes()] * existing_tunnels
1105             ikeys = [bytes()] * existing_tunnels
1106             for i in range(existing_tunnels, n_tunnels):
1107                 ckeys.append(
1108                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1109                 )
1110                 if integ_alg:
1111                     ikeys.append(
1112                         gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1113                     )
1114                 args[u"local_spi"] = spi_d[u"spi_1"] + i
1115                 args[u"remote_spi"] = spi_d[u"spi_2"] + i
1116                 args[u"local_ip"] = IPAddress.create_ip_address_object(
1117                     tun_ips[u"ip1"] + i * addr_incr
1118                 )
1119                 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1120                     tun_ips[u"ip2"]
1121                 )
1122                 args[u"local_crypto_key_len"] = len(ckeys[i])
1123                 args[u"local_crypto_key"] = ckeys[i]
1124                 args[u"remote_crypto_key_len"] = len(ckeys[i])
1125                 args[u"remote_crypto_key"] = ckeys[i]
1126                 if integ_alg:
1127                     args[u"local_integ_key_len"] = len(ikeys[i])
1128                     args[u"local_integ_key"] = ikeys[i]
1129                     args[u"remote_integ_key_len"] = len(ikeys[i])
1130                     args[u"remote_integ_key"] = ikeys[i]
1131                 papi_exec.add(
1132                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1133                 )
1134             err_msg = f"Failed to add IPsec tunnel interfaces on host" \
1135                 f" {nodes[u'DUT1'][u'host']}"
1136             ipsec_tunnels.extend(
1137                 [
1138                     reply[u"sw_if_index"]
1139                     for reply in papi_exec.get_replies(err_msg)
1140                     if u"sw_if_index" in reply
1141                 ]
1142             )
1143             # Configure unnumbered interfaces
1144             cmd = u"sw_interface_set_unnumbered"
1145             args = dict(
1146                 is_add=True,
1147                 sw_if_index=InterfaceUtil.get_interface_index(
1148                     nodes[u"DUT1"], if1_key
1149                 ),
1150                 unnumbered_sw_if_index=0
1151             )
1152             for i in range(existing_tunnels, n_tunnels):
1153                 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1154                 papi_exec.add(
1155                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1156                 )
1157             # Set interfaces up
1158             cmd = u"sw_interface_set_flags"
1159             args = dict(
1160                 sw_if_index=0,
1161                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1162             )
1163             for i in range(existing_tunnels, n_tunnels):
1164                 args[u"sw_if_index"] = ipsec_tunnels[i]
1165                 papi_exec.add(
1166                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1167                 )
1168             # Configure IP routes
1169             cmd = u"ip_route_add_del"
1170             args = dict(
1171                 is_add=1,
1172                 is_multipath=0,
1173                 route=None
1174             )
1175             for i in range(existing_tunnels, n_tunnels):
1176                 args[u"route"] = IPUtil.compose_vpp_route_structure(
1177                     nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1178                     prefix_len=128 if raddr_ip2.version == 6 else 32,
1179                     interface=ipsec_tunnels[i]
1180                 )
1181                 papi_exec.add(
1182                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1183                 )
1184             err_msg = f"Failed to add IP routes on host " \
1185                 f"{nodes[u'DUT1'][u'host']}"
1186             papi_exec.get_replies(err_msg)
1187
1188         return ckeys, ikeys
1189
1190     @staticmethod
1191     def _ipsec_create_tunnel_interfaces_dut2_papi(
1192             nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1193             ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1194         """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1195
1196         :param nodes: VPP nodes to create tunnel interfaces.
1197         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1198             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1199             IPv4/IPv6 address (ip2).
1200         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1201             interface key from topology file.
1202         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1203         :param crypto_alg: The encryption algorithm name.
1204         :param ckeys: List of encryption keys.
1205         :param integ_alg: The integrity algorithm name.
1206         :param ikeys: List of integrity keys.
1207         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1208         :param addr_incr: IP / IPv6 address incremental step.
1209         :param existing_tunnels: Number of tunnel interfaces before creation.
1210             Useful mainly for reconf tests. Default 0.
1211         :type nodes: dict
1212         :type tun_ips: dict
1213         :type if2_key: str
1214         :type n_tunnels: int
1215         :type crypto_alg: CryptoAlg
1216         :type ckeys: list
1217         :type integ_alg: IntegAlg
1218         :type ikeys: list
1219         :type addr_incr: int
1220         :type spi_d: dict
1221         :type existing_tunnels: int
1222         """
1223         with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1224             if not existing_tunnels:
1225                 # Set IP address on VPP node 2 interface
1226                 cmd = u"sw_interface_add_del_address"
1227                 args = dict(
1228                     sw_if_index=InterfaceUtil.get_interface_index(
1229                         nodes[u"DUT2"], if2_key
1230                     ),
1231                     is_add=True,
1232                     del_all=False,
1233                     prefix=IPUtil.create_prefix_object(
1234                         tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1235                         else 24
1236                     )
1237                 )
1238                 err_msg = f"Failed to set IP address on interface {if2_key} " \
1239                     f"on host {nodes[u'DUT2'][u'host']}"
1240                 papi_exec.add(cmd, **args).get_reply(err_msg)
1241             # Configure IPsec tunnel interfaces
1242             cmd = u"ipsec_tunnel_if_add_del"
1243             args = dict(
1244                 is_add=True,
1245                 local_ip=IPAddress.create_ip_address_object(tun_ips[u"ip2"]),
1246                 remote_ip=None,
1247                 local_spi=0,
1248                 remote_spi=0,
1249                 crypto_alg=crypto_alg.alg_int_repr,
1250                 local_crypto_key_len=0,
1251                 local_crypto_key=None,
1252                 remote_crypto_key_len=0,
1253                 remote_crypto_key=None,
1254                 integ_alg=integ_alg.alg_int_repr if integ_alg else 0,
1255                 local_integ_key_len=0,
1256                 local_integ_key=None,
1257                 remote_integ_key_len=0,
1258                 remote_integ_key=None,
1259                 tx_table_id=0
1260             )
1261             ipsec_tunnels = [None] * existing_tunnels
1262             for i in range(existing_tunnels, n_tunnels):
1263                 args[u"local_spi"] = spi_d[u"spi_2"] + i
1264                 args[u"remote_spi"] = spi_d[u"spi_1"] + i
1265                 args[u"local_ip"] = IPAddress.create_ip_address_object(
1266                     tun_ips[u"ip2"]
1267                 )
1268                 args[u"remote_ip"] = IPAddress.create_ip_address_object(
1269                     tun_ips[u"ip1"] + i * addr_incr
1270                 )
1271                 args[u"local_crypto_key_len"] = len(ckeys[i])
1272                 args[u"local_crypto_key"] = ckeys[i]
1273                 args[u"remote_crypto_key_len"] = len(ckeys[i])
1274                 args[u"remote_crypto_key"] = ckeys[i]
1275                 if integ_alg:
1276                     args[u"local_integ_key_len"] = len(ikeys[i])
1277                     args[u"local_integ_key"] = ikeys[i]
1278                     args[u"remote_integ_key_len"] = len(ikeys[i])
1279                     args[u"remote_integ_key"] = ikeys[i]
1280                 papi_exec.add(
1281                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1282                 )
1283             err_msg = f"Failed to add IPsec tunnel interfaces " \
1284                 f"on host {nodes[u'DUT2'][u'host']}"
1285             ipsec_tunnels.extend(
1286                 [
1287                     reply[u"sw_if_index"]
1288                     for reply in papi_exec.get_replies(err_msg)
1289                     if u"sw_if_index" in reply
1290                 ]
1291             )
1292             if not existing_tunnels:
1293                 # Configure IP route
1294                 cmd = u"ip_route_add_del"
1295                 route = IPUtil.compose_vpp_route_structure(
1296                     nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1297                     prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1298                     interface=if2_key,
1299                     gateway=(tun_ips[u"ip2"] - 1).compressed
1300                 )
1301                 args = dict(
1302                     is_add=1,
1303                     is_multipath=0,
1304                     route=route
1305                 )
1306                 papi_exec.add(cmd, **args)
1307             # Configure unnumbered interfaces
1308             cmd = u"sw_interface_set_unnumbered"
1309             args = dict(
1310                 is_add=True,
1311                 sw_if_index=InterfaceUtil.get_interface_index(
1312                     nodes[u"DUT2"], if2_key
1313                 ),
1314                 unnumbered_sw_if_index=0
1315             )
1316             for i in range(existing_tunnels, n_tunnels):
1317                 args[u"unnumbered_sw_if_index"] = ipsec_tunnels[i]
1318                 papi_exec.add(
1319                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1320                 )
1321             # Set interfaces up
1322             cmd = u"sw_interface_set_flags"
1323             args = dict(
1324                 sw_if_index=0,
1325                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1326             )
1327             for i in range(existing_tunnels, n_tunnels):
1328                 args[u"sw_if_index"] = ipsec_tunnels[i]
1329                 papi_exec.add(
1330                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1331                 )
1332             # Configure IP routes
1333             cmd = u"ip_route_add_del"
1334             args = dict(
1335                 is_add=1,
1336                 is_multipath=0,
1337                 route=None
1338             )
1339             for i in range(existing_tunnels, n_tunnels):
1340                 args[u"route"] = IPUtil.compose_vpp_route_structure(
1341                     nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1342                     prefix_len=128 if raddr_ip1.version == 6 else 32,
1343                     interface=ipsec_tunnels[i]
1344                 )
1345                 papi_exec.add(
1346                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1347                 )
1348             err_msg = f"Failed to add IP routes " \
1349                 f"on host {nodes[u'DUT2'][u'host']}"
1350             papi_exec.get_replies(err_msg)
1351
1352     @staticmethod
1353     def vpp_ipsec_create_tunnel_interfaces(
1354             nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1355             n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1356             existing_tunnels=0):
1357         """Create multiple IPsec tunnel interfaces between two VPP nodes.
1358
1359         :param nodes: VPP nodes to create tunnel interfaces.
1360         :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1361             address.
1362         :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1363             address.
1364         :param if1_key: VPP node 1 interface key from topology file.
1365         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1366             interface key from topology file.
1367         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1368         :param crypto_alg: The encryption algorithm name.
1369         :param integ_alg: The integrity algorithm name.
1370         :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1371             first tunnel in direction node1->node2.
1372         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1373             first tunnel in direction node2->node1.
1374         :param raddr_range: Mask specifying range of Policy selector Remote
1375             IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1376             and to 128 in case of IPv6.
1377         :param existing_tunnels: Number of tunnel interfaces before creation.
1378             Useful mainly for reconf tests. Default 0.
1379         :type nodes: dict
1380         :type tun_if1_ip_addr: str
1381         :type tun_if2_ip_addr: str
1382         :type if1_key: str
1383         :type if2_key: str
1384         :type n_tunnels: int
1385         :type crypto_alg: CryptoAlg
1386         :type integ_alg: IntegAlg
1387         :type raddr_ip1: string
1388         :type raddr_ip2: string
1389         :type raddr_range: int
1390         :type existing_tunnels: int
1391         """
1392         n_tunnels = int(n_tunnels)
1393         existing_tunnels = int(existing_tunnels)
1394         spi_d = dict(
1395             spi_1=100000,
1396             spi_2=200000
1397         )
1398         tun_ips = dict(
1399             ip1=ip_address(tun_if1_ip_addr),
1400             ip2=ip_address(tun_if2_ip_addr)
1401         )
1402         raddr_ip1 = ip_address(raddr_ip1)
1403         raddr_ip2 = ip_address(raddr_ip2)
1404         addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1405             else 1 << (32 - raddr_range)
1406
1407         if n_tunnels - existing_tunnels > 10:
1408             ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1409                 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1410                 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1411             )
1412             if u"DUT2" not in nodes.keys():
1413                 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1414             IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1415                 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1416                 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1417             )
1418         else:
1419             ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1420                 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1421                 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1422             )
1423             if u"DUT2" not in nodes.keys():
1424                 return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
1425             IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1426                 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1427                 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
1428             )
1429
1430         return None, None, None, None
1431
1432     @staticmethod
1433     def _create_ipsec_script_files(dut, instances):
1434         """Create script files for configuring IPsec in containers
1435
1436         :param dut: DUT node on which to create the script files
1437         :param instances: number of containers on DUT node
1438         :type dut: string
1439         :type instances: int
1440         """
1441         scripts = []
1442         for cnf in range(0, instances):
1443             script_filename = (
1444                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1445             )
1446             scripts.append(open(script_filename, 'w'))
1447         return scripts
1448
1449     @staticmethod
1450     def _close_and_copy_ipsec_script_files(
1451             dut, nodes, instances, scripts):
1452         """Close created scripts and copy them to containers
1453
1454         :param dut: DUT node on which to create the script files
1455         :param nodes: VPP nodes
1456         :param instances: number of containers on DUT node
1457         :param scripts: dictionary holding the script files
1458         :type dut: string
1459         :type nodes: dict
1460         :type instances: int
1461         :type scripts: dict
1462         """
1463         for cnf in range(0, instances):
1464             scripts[cnf].close()
1465             script_filename = (
1466                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1467             )
1468             scp_node(nodes[dut], script_filename, script_filename)
1469
1470
1471     @staticmethod
1472     def vpp_ipsec_create_tunnel_interfaces_in_containers(
1473             nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1474             raddr_ip1, raddr_ip2, raddr_range, n_instances):
1475         """Create multiple IPsec tunnel interfaces between two VPP nodes.
1476
1477         :param nodes: VPP nodes to create tunnel interfaces.
1478         :param if1_ip_addr: VPP node 1 interface IP4 address.
1479         :param if2_ip_addr: VPP node 2 interface IP4 address.
1480         :param n_tunnels: Number of tunnell interfaces to create.
1481         :param crypto_alg: The encryption algorithm name.
1482         :param integ_alg: The integrity algorithm name.
1483         :param raddr_ip1: Policy selector remote IPv4 start address for the
1484             first tunnel in direction node1->node2.
1485         :param raddr_ip2: Policy selector remote IPv4 start address for the
1486             first tunnel in direction node2->node1.
1487         :param raddr_range: Mask specifying range of Policy selector Remote
1488             IPv4 addresses. Valid values are from 1 to 32.
1489         :param n_instances: Number of containers.
1490         :type nodes: dict
1491         :type if1_ip_addr: str
1492         :type if2_ip_addr: str
1493         :type n_tunnels: int
1494         :type crypto_alg: CryptoAlg
1495         :type integ_alg: IntegAlg
1496         :type raddr_ip1: string
1497         :type raddr_ip2: string
1498         :type raddr_range: int
1499         :type n_instances: int
1500         """
1501         spi_1 = 100000
1502         spi_2 = 200000
1503         addr_incr = 1 << (32 - raddr_range)
1504
1505         dut1_scripts = IPsecUtil._create_ipsec_script_files(
1506             u"DUT1", n_instances
1507         )
1508         dut2_scripts = IPsecUtil._create_ipsec_script_files(
1509             u"DUT2", n_instances
1510         )
1511
1512         for cnf in range(0, n_instances):
1513             dut1_scripts[cnf].write(
1514                 u"create loopback interface\n"
1515                 u"set interface state loop0 up\n\n"
1516             )
1517             dut2_scripts[cnf].write(
1518                 f"ip route add {if1_ip_addr}/8 via "
1519                 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1520             )
1521
1522         for tnl in range(0, n_tunnels):
1523             cnf = tnl % n_instances
1524             ckey = getattr(
1525                 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1526             )
1527             integ = u""
1528             if integ_alg:
1529                 ikey = getattr(
1530                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1531                 )
1532                 integ = (
1533                     f"integ-alg {integ_alg.alg_name} "
1534                     f"local-integ-key {ikey} "
1535                     f"remote-integ-key {ikey} "
1536                 )
1537             # Configure tunnel end point(s) on left side
1538             dut1_scripts[cnf].write(
1539                 u"set interface ip address loop0 "
1540                 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1541                 f"create ipsec tunnel "
1542                 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1543                 f"local-spi {spi_1 + tnl} "
1544                 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1545                 f"remote-spi {spi_2 + tnl} "
1546                 f"crypto-alg {crypto_alg.alg_name} "
1547                 f"local-crypto-key {ckey} "
1548                 f"remote-crypto-key {ckey} "
1549                 f"instance {tnl // n_instances} "
1550                 f"salt 0x0 "
1551                 f"{integ} \n"
1552                 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1553                 f"set interface state ipip{tnl // n_instances} up\n"
1554                 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1555                 f"via ipip{tnl // n_instances}\n\n"
1556             )
1557             # Configure tunnel end point(s) on right side
1558             dut2_scripts[cnf].write(
1559                 f"set ip neighbor memif1/{cnf + 1} "
1560                 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1561                 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1562                 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1563                 f"local-spi {spi_2 + tnl} "
1564                 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1565                 f"remote-spi {spi_1 + tnl} "
1566                 f"crypto-alg {crypto_alg.alg_name} "
1567                 f"local-crypto-key {ckey} "
1568                 f"remote-crypto-key {ckey} "
1569                 f"instance {tnl // n_instances} "
1570                 f"salt 0x0 "
1571                 f"{integ}\n"
1572                 f"set interface unnumbered ipip{tnl // n_instances} "
1573                 f"use memif1/{cnf + 1}\n"
1574                 f"set interface state ipip{tnl // n_instances} up\n"
1575                 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1576                 f"via ipip{tnl // n_instances}\n\n"
1577             )
1578
1579         IPsecUtil._close_and_copy_ipsec_script_files(
1580             u"DUT1", nodes, n_instances, dut1_scripts)
1581         IPsecUtil._close_and_copy_ipsec_script_files(
1582             u"DUT2", nodes, n_instances, dut2_scripts)
1583
1584     @staticmethod
1585     def vpp_ipsec_add_multiple_tunnels(
1586             nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1587             tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
1588         """Create multiple IPsec tunnels between two VPP nodes.
1589
1590         :param nodes: VPP nodes to create tunnels.
1591         :param interface1: Interface name or sw_if_index on node 1.
1592         :param interface2: Interface name or sw_if_index on node 2.
1593         :param n_tunnels: Number of tunnels to create.
1594         :param crypto_alg: The encryption algorithm name.
1595         :param integ_alg: The integrity algorithm name.
1596         :param tunnel_ip1: Tunnel node1 IPv4 address.
1597         :param tunnel_ip2: Tunnel node2 IPv4 address.
1598         :param raddr_ip1: Policy selector remote IPv4 start address for the
1599             first tunnel in direction node1->node2.
1600         :param raddr_ip2: Policy selector remote IPv4 start address for the
1601             first tunnel in direction node2->node1.
1602         :param raddr_range: Mask specifying range of Policy selector Remote
1603             IPv4 addresses. Valid values are from 1 to 32.
1604         :type nodes: dict
1605         :type interface1: str or int
1606         :type interface2: str or int
1607         :type n_tunnels: int
1608         :type crypto_alg: CryptoAlg
1609         :type integ_alg: IntegAlg
1610         :type tunnel_ip1: str
1611         :type tunnel_ip2: str
1612         :type raddr_ip1: string
1613         :type raddr_ip2: string
1614         :type raddr_range: int
1615         """
1616         spd_id = 1
1617         p_hi = 100
1618         p_lo = 10
1619         sa_id_1 = 100000
1620         sa_id_2 = 200000
1621         spi_1 = 300000
1622         spi_2 = 400000
1623
1624         crypto_key = gen_key(
1625             IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1626         ).decode()
1627         integ_key = gen_key(
1628             IPsecUtil.get_integ_alg_key_len(integ_alg)
1629         ).decode() if integ_alg else u""
1630
1631         IPsecUtil.vpp_ipsec_set_ip_route(
1632             nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1633             interface1, raddr_range)
1634         IPsecUtil.vpp_ipsec_set_ip_route(
1635             nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
1636             interface2, raddr_range)
1637
1638         IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1639         IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1640         IPsecUtil.vpp_ipsec_policy_add(
1641             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1642             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1643         )
1644         IPsecUtil.vpp_ipsec_policy_add(
1645             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1646             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1647         )
1648
1649         IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
1650         IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
1651         IPsecUtil.vpp_ipsec_policy_add(
1652             nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1653             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1654         )
1655         IPsecUtil.vpp_ipsec_policy_add(
1656             nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1657             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1658         )
1659
1660         IPsecUtil.vpp_ipsec_add_sad_entries(
1661             nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1662             integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1663         )
1664         IPsecUtil.vpp_ipsec_spd_add_entries(
1665             nodes[u"DUT1"], n_tunnels, spd_id, p_lo, False, sa_id_1, raddr_ip2
1666         )
1667
1668         IPsecUtil.vpp_ipsec_add_sad_entries(
1669             nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1670             integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1671         )
1672         IPsecUtil.vpp_ipsec_spd_add_entries(
1673             nodes[u"DUT2"], n_tunnels, spd_id, p_lo, True, sa_id_1, raddr_ip2
1674         )
1675
1676         IPsecUtil.vpp_ipsec_add_sad_entries(
1677             nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1678             integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1679         )
1680
1681         IPsecUtil.vpp_ipsec_spd_add_entries(
1682             nodes[u"DUT2"], n_tunnels, spd_id, p_lo, False, sa_id_2, raddr_ip1
1683         )
1684
1685         IPsecUtil.vpp_ipsec_add_sad_entries(
1686             nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1687             integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1688         )
1689
1690         IPsecUtil.vpp_ipsec_spd_add_entries(
1691             nodes[u"DUT1"], n_tunnels, spd_id, p_lo, True, sa_id_2, raddr_ip1
1692         )
1693
1694     @staticmethod
1695     def vpp_ipsec_show(node):
1696         """Run "show ipsec" debug CLI command.
1697
1698         :param node: Node to run command on.
1699         :type node: dict
1700         """
1701         PapiSocketExecutor.run_cli_cmd(node, u"show ipsec")