fix(Pylint): Small fixes
[csit.git] / resources / libraries / python / IPsecUtil.py
1 # Copyright (c) 2021 Cisco and/or its affiliates.
2 # Copyright (c) 2021 PANTHEON.tech s.r.o.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """IPsec utilities library."""
16
17 import os
18
19 from enum import Enum, IntEnum
20 from io import open
21 from ipaddress import ip_network, ip_address
22 from random import choice
23 from string import ascii_letters
24
25 from resources.libraries.python.Constants import Constants
26 from resources.libraries.python.IncrementUtil import ObjIncrement
27 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
28     InterfaceStatusFlags
29 from resources.libraries.python.IPAddress import IPAddress
30 from resources.libraries.python.IPUtil import IPUtil, IpDscp, \
31     MPLS_LABEL_INVALID, NetworkIncrement
32 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
33 from resources.libraries.python.ssh import scp_node
34 from resources.libraries.python.topology import Topology, NodeType
35 from resources.libraries.python.VatExecutor import VatExecutor
36 from resources.libraries.python.VPPUtil import VPPUtil
37
38
39 IPSEC_UDP_PORT_NONE = 0xffff
40
41
42 def gen_key(length):
43     """Generate random string as a key.
44
45     :param length: Length of generated payload.
46     :type length: int
47     :returns: The generated payload.
48     :rtype: bytes
49     """
50     return u"".join(
51         choice(ascii_letters) for _ in range(length)
52     ).encode(encoding=u"utf-8")
53
54
55 class PolicyAction(Enum):
56     """Policy actions."""
57     BYPASS = (u"bypass", 0)
58     DISCARD = (u"discard", 1)
59     PROTECT = (u"protect", 3)
60
61     def __init__(self, policy_name, policy_int_repr):
62         self.policy_name = policy_name
63         self.policy_int_repr = policy_int_repr
64
65     def __str__(self):
66         return self.policy_name
67
68     def __int__(self):
69         return self.policy_int_repr
70
71
72 class CryptoAlg(Enum):
73     """Encryption algorithms."""
74     AES_CBC_128 = (u"aes-cbc-128", 1, u"AES-CBC", 16)
75     AES_CBC_256 = (u"aes-cbc-256", 3, u"AES-CBC", 32)
76     AES_GCM_128 = (u"aes-gcm-128", 7, u"AES-GCM", 16)
77     AES_GCM_256 = (u"aes-gcm-256", 9, u"AES-GCM", 32)
78
79     def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
80         self.alg_name = alg_name
81         self.alg_int_repr = alg_int_repr
82         self.scapy_name = scapy_name
83         self.key_len = key_len
84
85
86 class IntegAlg(Enum):
87     """Integrity algorithm."""
88     SHA_256_128 = (u"sha-256-128", 4, u"SHA2-256-128", 32)
89     SHA_512_256 = (u"sha-512-256", 6, u"SHA2-512-256", 64)
90
91     def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
92         self.alg_name = alg_name
93         self.alg_int_repr = alg_int_repr
94         self.scapy_name = scapy_name
95         self.key_len = key_len
96
97
98 class IPsecProto(IntEnum):
99     """IPsec protocol."""
100     IPSEC_API_PROTO_ESP = 50
101     IPSEC_API_PROTO_AH = 51
102
103
104 class IPsecSadFlags(IntEnum):
105     """IPsec Security Association Database flags."""
106     IPSEC_API_SAD_FLAG_NONE = 0
107     # Enable extended sequence numbers
108     IPSEC_API_SAD_FLAG_USE_ESN = 0x01
109     # Enable Anti - replay
110     IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY = 0x02
111     # IPsec tunnel mode if non-zero, else transport mode
112     IPSEC_API_SAD_FLAG_IS_TUNNEL = 0x04
113     # IPsec tunnel mode is IPv6 if non-zero, else IPv4 tunnel
114     # only valid if is_tunnel is non-zero
115     IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 0x08
116     # Enable UDP encapsulation for NAT traversal
117     IPSEC_API_SAD_FLAG_UDP_ENCAP = 0x10
118     # IPsec SA is or inbound traffic
119     IPSEC_API_SAD_FLAG_IS_INBOUND = 0x40
120
121
122 class TunnelEncpaDecapFlags(IntEnum):
123     """Flags controlling tunnel behaviour."""
124     TUNNEL_API_ENCAP_DECAP_FLAG_NONE = 0
125     # at encap, copy the DF bit of the payload into the tunnel header
126     TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF = 1
127     # at encap, set the DF bit in the tunnel header
128     TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF = 2
129     # at encap, copy the DSCP bits of the payload into the tunnel header
130     TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP = 4
131     # at encap, copy the ECN bit of the payload into the tunnel header
132     TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN = 8
133     # at decap, copy the ECN bit of the tunnel header into the payload
134     TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_ECN = 16
135
136
137 class TunnelMode(IntEnum):
138     """Tunnel modes."""
139     # point-to-point
140     TUNNEL_API_MODE_P2P = 0
141     # multi-point
142     TUNNEL_API_MODE_MP = 1
143
144
145 class IPsecUtil:
146     """IPsec utilities."""
147
148     @staticmethod
149     def policy_action_bypass():
150         """Return policy action bypass.
151
152         :returns: PolicyAction enum BYPASS object.
153         :rtype: PolicyAction
154         """
155         return PolicyAction.BYPASS
156
157     @staticmethod
158     def policy_action_discard():
159         """Return policy action discard.
160
161         :returns: PolicyAction enum DISCARD object.
162         :rtype: PolicyAction
163         """
164         return PolicyAction.DISCARD
165
166     @staticmethod
167     def policy_action_protect():
168         """Return policy action protect.
169
170         :returns: PolicyAction enum PROTECT object.
171         :rtype: PolicyAction
172         """
173         return PolicyAction.PROTECT
174
175     @staticmethod
176     def crypto_alg_aes_cbc_128():
177         """Return encryption algorithm aes-cbc-128.
178
179         :returns: CryptoAlg enum AES_CBC_128 object.
180         :rtype: CryptoAlg
181         """
182         return CryptoAlg.AES_CBC_128
183
184     @staticmethod
185     def crypto_alg_aes_cbc_256():
186         """Return encryption algorithm aes-cbc-256.
187
188         :returns: CryptoAlg enum AES_CBC_256 object.
189         :rtype: CryptoAlg
190         """
191         return CryptoAlg.AES_CBC_256
192
193     @staticmethod
194     def crypto_alg_aes_gcm_128():
195         """Return encryption algorithm aes-gcm-128.
196
197         :returns: CryptoAlg enum AES_GCM_128 object.
198         :rtype: CryptoAlg
199         """
200         return CryptoAlg.AES_GCM_128
201
202     @staticmethod
203     def crypto_alg_aes_gcm_256():
204         """Return encryption algorithm aes-gcm-256.
205
206         :returns: CryptoAlg enum AES_GCM_128 object.
207         :rtype: CryptoAlg
208         """
209         return CryptoAlg.AES_GCM_256
210
211     @staticmethod
212     def get_crypto_alg_key_len(crypto_alg):
213         """Return encryption algorithm key length.
214
215         :param crypto_alg: Encryption algorithm.
216         :type crypto_alg: CryptoAlg
217         :returns: Key length.
218         :rtype: int
219         """
220         return crypto_alg.key_len
221
222     @staticmethod
223     def get_crypto_alg_scapy_name(crypto_alg):
224         """Return encryption algorithm scapy name.
225
226         :param crypto_alg: Encryption algorithm.
227         :type crypto_alg: CryptoAlg
228         :returns: Algorithm scapy name.
229         :rtype: str
230         """
231         return crypto_alg.scapy_name
232
233     @staticmethod
234     def integ_alg_sha_256_128():
235         """Return integrity algorithm SHA-256-128.
236
237         :returns: IntegAlg enum SHA_256_128 object.
238         :rtype: IntegAlg
239         """
240         return IntegAlg.SHA_256_128
241
242     @staticmethod
243     def integ_alg_sha_512_256():
244         """Return integrity algorithm SHA-512-256.
245
246         :returns: IntegAlg enum SHA_512_256 object.
247         :rtype: IntegAlg
248         """
249         return IntegAlg.SHA_512_256
250
251     @staticmethod
252     def get_integ_alg_key_len(integ_alg):
253         """Return integrity algorithm key length.
254
255         None argument is accepted, returning zero.
256
257         :param integ_alg: Integrity algorithm.
258         :type integ_alg: Optional[IntegAlg]
259         :returns: Key length.
260         :rtype: int
261         """
262         return 0 if integ_alg is None else integ_alg.key_len
263
264     @staticmethod
265     def get_integ_alg_scapy_name(integ_alg):
266         """Return integrity algorithm scapy name.
267
268         :param integ_alg: Integrity algorithm.
269         :type integ_alg: IntegAlg
270         :returns: Algorithm scapy name.
271         :rtype: str
272         """
273         return integ_alg.scapy_name
274
275     @staticmethod
276     def ipsec_proto_esp():
277         """Return IPSec protocol ESP.
278
279         :returns: IPsecProto enum ESP object.
280         :rtype: IPsecProto
281         """
282         return int(IPsecProto.IPSEC_API_PROTO_ESP)
283
284     @staticmethod
285     def ipsec_proto_ah():
286         """Return IPSec protocol AH.
287
288         :returns: IPsecProto enum AH object.
289         :rtype: IPsecProto
290         """
291         return int(IPsecProto.IPSEC_API_PROTO_AH)
292
293     @staticmethod
294     def vpp_ipsec_select_backend(node, protocol, index=1):
295         """Select IPsec backend.
296
297         :param node: VPP node to select IPsec backend on.
298         :param protocol: IPsec protocol.
299         :param index: Backend index.
300         :type node: dict
301         :type protocol: IPsecProto
302         :type index: int
303         :raises RuntimeError: If failed to select IPsec backend or if no API
304             reply received.
305         """
306         cmd = u"ipsec_select_backend"
307         err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
308         args = dict(
309             protocol=protocol,
310             index=index
311         )
312         with PapiSocketExecutor(node) as papi_exec:
313             papi_exec.add(cmd, **args).get_reply(err_msg)
314
315     @staticmethod
316     def vpp_ipsec_set_async_mode(node, async_enable=1):
317         """Set IPsec async mode on|off.
318
319         :param node: VPP node to set IPsec async mode.
320         :param async_enable: Async mode on or off.
321         :type node: dict
322         :type async_enable: int
323         :raises RuntimeError: If failed to set IPsec async mode or if no API
324             reply received.
325         """
326         cmd = u"ipsec_set_async_mode"
327         err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
328         args = dict(
329             async_enable=async_enable
330         )
331         with PapiSocketExecutor(node) as papi_exec:
332             papi_exec.add(cmd, **args).get_reply(err_msg)
333
334     @staticmethod
335     def vpp_ipsec_crypto_sw_scheduler_set_worker(
336             node, workers, crypto_enable=False):
337         """Enable or disable crypto on specific vpp worker threads.
338
339         :param node: VPP node to enable or disable crypto for worker threads.
340         :param workers: List of VPP thread numbers.
341         :param crypto_enable: Disable or enable crypto work.
342         :type node: dict
343         :type workers: Iterable[int]
344         :type crypto_enable: bool
345         :raises RuntimeError: If failed to enable or disable crypto for worker
346             thread or if no API reply received.
347         """
348         for worker in workers:
349             cmd = u"crypto_sw_scheduler_set_worker"
350             err_msg = f"Failed to disable/enable crypto for worker thread " \
351                 f"on host {node[u'host']}"
352             args = dict(
353                 worker_index=worker - 1,
354                 crypto_enable=crypto_enable
355             )
356             with PapiSocketExecutor(node) as papi_exec:
357                 papi_exec.add(cmd, **args).get_reply(err_msg)
358
359     @staticmethod
360     def vpp_ipsec_crypto_sw_scheduler_set_worker_on_all_duts(
361             nodes, workers, crypto_enable=False):
362         """Enable or disable crypto on specific vpp worker threads.
363
364         :param node: VPP node to enable or disable crypto for worker threads.
365         :param workers: List of VPP thread numbers.
366         :param crypto_enable: Disable or enable crypto work.
367         :type node: dict
368         :type workers: Iterable[int]
369         :type crypto_enable: bool
370         :raises RuntimeError: If failed to enable or disable crypto for worker
371             thread or if no API reply received.
372         """
373         for node in nodes.values():
374             if node[u"type"] == NodeType.DUT:
375                 thread_data = VPPUtil.vpp_show_threads(node)
376                 worker_cnt = len(thread_data) - 1
377                 if not worker_cnt:
378                     return None
379                 worker_ids = list()
380                 for item in thread_data:
381                     if str(item.cpu_id) in workers.split(u","):
382                         worker_ids.append(item.id)
383
384                 IPsecUtil.vpp_ipsec_crypto_sw_scheduler_set_worker(
385                     node, workers=worker_ids, crypto_enable=crypto_enable
386                 )
387
388     @staticmethod
389     def vpp_ipsec_add_sad_entry(
390             node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
391             integ_key=u"", tunnel_src=None, tunnel_dst=None):
392         """Create Security Association Database entry on the VPP node.
393
394         :param node: VPP node to add SAD entry on.
395         :param sad_id: SAD entry ID.
396         :param spi: Security Parameter Index of this SAD entry.
397         :param crypto_alg: The encryption algorithm name.
398         :param crypto_key: The encryption key string.
399         :param integ_alg: The integrity algorithm name.
400         :param integ_key: The integrity key string.
401         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
402             specified ESP transport mode is used.
403         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
404             not specified ESP transport mode is used.
405         :type node: dict
406         :type sad_id: int
407         :type spi: int
408         :type crypto_alg: CryptoAlg
409         :type crypto_key: str
410         :type integ_alg: Optional[IntegAlg]
411         :type integ_key: str
412         :type tunnel_src: str
413         :type tunnel_dst: str
414         """
415         if isinstance(crypto_key, str):
416             crypto_key = crypto_key.encode(encoding=u"utf-8")
417         if isinstance(integ_key, str):
418             integ_key = integ_key.encode(encoding=u"utf-8")
419         ckey = dict(
420             length=len(crypto_key),
421             data=crypto_key
422         )
423         ikey = dict(
424             length=len(integ_key),
425             data=integ_key if integ_key else 0
426         )
427
428         flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
429         if tunnel_src and tunnel_dst:
430             flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
431             src_addr = ip_address(tunnel_src)
432             dst_addr = ip_address(tunnel_dst)
433             if src_addr.version == 6:
434                 flags = \
435                     flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
436         else:
437             src_addr = u""
438             dst_addr = u""
439
440         cmd = u"ipsec_sad_entry_add_del_v3"
441         err_msg = f"Failed to add Security Association Database entry " \
442             f"on host {node[u'host']}"
443         sad_entry = dict(
444             sad_id=int(sad_id),
445             spi=int(spi),
446             crypto_algorithm=crypto_alg.alg_int_repr,
447             crypto_key=ckey,
448             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
449             integrity_key=ikey,
450             flags=flags,
451             tunnel=dict(
452                 src=str(src_addr),
453                 dst=str(dst_addr),
454                 table_id=0,
455                 encap_decap_flags=int(
456                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
457                 ),
458                 dscp=int(IpDscp.IP_API_DSCP_CS0),
459             ),
460             protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
461             udp_src_port=4500,  # default value in api
462             udp_dst_port=4500  # default value in api
463         )
464         args = dict(
465             is_add=True,
466             entry=sad_entry
467         )
468         with PapiSocketExecutor(node) as papi_exec:
469             papi_exec.add(cmd, **args).get_reply(err_msg)
470
471     @staticmethod
472     def vpp_ipsec_add_sad_entries(
473             node, n_entries, sad_id, spi, crypto_alg, crypto_key,
474             integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
475         """Create multiple Security Association Database entries on VPP node.
476
477         :param node: VPP node to add SAD entry on.
478         :param n_entries: Number of SAD entries to be created.
479         :param sad_id: First SAD entry ID. All subsequent SAD entries will have
480             id incremented by 1.
481         :param spi: Security Parameter Index of first SAD entry. All subsequent
482             SAD entries will have spi incremented by 1.
483         :param crypto_alg: The encryption algorithm name.
484         :param crypto_key: The encryption key string.
485         :param integ_alg: The integrity algorithm name.
486         :param integ_key: The integrity key string.
487         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
488             specified ESP transport mode is used.
489         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
490             not specified ESP transport mode is used.
491         :type node: dict
492         :type n_entries: int
493         :type sad_id: int
494         :type spi: int
495         :type crypto_alg: CryptoAlg
496         :type crypto_key: str
497         :type integ_alg: Optional[IntegAlg]
498         :type integ_key: str
499         :type tunnel_src: str
500         :type tunnel_dst: str
501         """
502         if isinstance(crypto_key, str):
503             crypto_key = crypto_key.encode(encoding=u"utf-8")
504         if isinstance(integ_key, str):
505             integ_key = integ_key.encode(encoding=u"utf-8")
506         if tunnel_src and tunnel_dst:
507             src_addr = ip_address(tunnel_src)
508             dst_addr = ip_address(tunnel_dst)
509         else:
510             src_addr = u""
511             dst_addr = u""
512
513         addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
514             else 1 << (32 - 24)
515
516         if int(n_entries) > 10:
517             tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
518
519             with open(tmp_filename, 'w') as tmp_file:
520                 for i in range(n_entries):
521                     integ = f"integ-alg {integ_alg.alg_name} " \
522                         f"integ-key {integ_key.hex()}" \
523                         if integ_alg else u""
524                     tunnel = f"tunnel src {src_addr + i * addr_incr} " \
525                         f"tunnel dst {dst_addr + i * addr_incr}" \
526                         if tunnel_src and tunnel_dst else u""
527                     conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
528                         f"crypto-alg {crypto_alg.alg_name} " \
529                         f"crypto-key {crypto_key.hex()} " \
530                         f"{integ} {tunnel}\n"
531                     tmp_file.write(conf)
532             vat = VatExecutor()
533             vat.execute_script(
534                 tmp_filename, node, timeout=300, json_out=False,
535                 copy_on_execute=True
536             )
537             os.remove(tmp_filename)
538             return
539
540         ckey = dict(
541             length=len(crypto_key),
542             data=crypto_key
543         )
544         ikey = dict(
545             length=len(integ_key),
546             data=integ_key if integ_key else 0
547         )
548
549         flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
550         if tunnel_src and tunnel_dst:
551             flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
552             if src_addr.version == 6:
553                 flags = flags | int(
554                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
555                 )
556
557         cmd = u"ipsec_sad_entry_add_del_v3"
558         err_msg = f"Failed to add Security Association Database entry " \
559             f"on host {node[u'host']}"
560
561         sad_entry = dict(
562             sad_id=int(sad_id),
563             spi=int(spi),
564             crypto_algorithm=crypto_alg.alg_int_repr,
565             crypto_key=ckey,
566             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
567             integrity_key=ikey,
568             flags=flags,
569             tunnel=dict(
570                 src=str(src_addr),
571                 dst=str(dst_addr),
572                 table_id=0,
573                 encap_decap_flags=int(
574                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
575                 ),
576                 dscp=int(IpDscp.IP_API_DSCP_CS0),
577             ),
578             protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
579             udp_src_port=4500,  # default value in api
580             udp_dst_port=4500  # default value in api
581         )
582         args = dict(
583             is_add=True,
584             entry=sad_entry
585         )
586         with PapiSocketExecutor(node) as papi_exec:
587             for i in range(n_entries):
588                 args[u"entry"][u"sad_id"] = int(sad_id) + i
589                 args[u"entry"][u"spi"] = int(spi) + i
590                 args[u"entry"][u"tunnel"][u"src"] = (
591                     str(src_addr + i * addr_incr)
592                     if tunnel_src and tunnel_dst else src_addr
593                 )
594                 args[u"entry"][u"tunnel"][u"dst"] = (
595                     str(dst_addr + i * addr_incr)
596                     if tunnel_src and tunnel_dst else dst_addr
597                 )
598                 history = bool(not 1 < i < n_entries - 2)
599                 papi_exec.add(cmd, history=history, **args)
600             papi_exec.get_replies(err_msg)
601
602     @staticmethod
603     def vpp_ipsec_set_ip_route(
604             node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
605             raddr_range, dst_mac=None):
606         """Set IP address and route on interface.
607
608         :param node: VPP node to add config on.
609         :param n_tunnels: Number of tunnels to create.
610         :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
611         :param traffic_addr: Traffic destination IP address to route.
612         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
613         :param interface: Interface key on node 1.
614         :param raddr_range: Mask specifying range of Policy selector Remote IP
615             addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
616             in case of IPv6.
617         :param dst_mac: The MAC address of destination tunnels.
618         :type node: dict
619         :type n_tunnels: int
620         :type tunnel_src: str
621         :type traffic_addr: str
622         :type tunnel_dst: str
623         :type interface: str
624         :type raddr_range: int
625         :type dst_mac: str
626         """
627         tunnel_src = ip_address(tunnel_src)
628         tunnel_dst = ip_address(tunnel_dst)
629         traffic_addr = ip_address(traffic_addr)
630         addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
631             else 1 << (32 - raddr_range)
632
633         if int(n_tunnels) > 10:
634             tmp_filename = u"/tmp/ipsec_set_ip.script"
635
636             with open(tmp_filename, 'w') as tmp_file:
637                 if_name = Topology.get_interface_name(node, interface)
638                 for i in range(n_tunnels):
639                     conf = f"exec set interface ip address {if_name} " \
640                         f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
641                         f"exec ip route add {traffic_addr + i}/" \
642                         f"{128 if traffic_addr.version == 6 else 32} " \
643                         f"via {tunnel_dst + i * addr_incr} {if_name}\n"
644                     if dst_mac:
645                         conf = f"{conf}exec set ip neighbor {if_name} " \
646                                f"{tunnel_dst + i * addr_incr} {dst_mac}\n"
647                     tmp_file.write(conf)
648
649             VatExecutor().execute_script(
650                 tmp_filename, node, timeout=300, json_out=False,
651                 copy_on_execute=True
652             )
653             os.remove(tmp_filename)
654             return
655
656         cmd1 = u"sw_interface_add_del_address"
657         args1 = dict(
658             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
659             is_add=True,
660             del_all=False,
661             prefix=None
662         )
663         cmd2 = u"ip_route_add_del"
664         args2 = dict(
665             is_add=1,
666             is_multipath=0,
667             route=None
668         )
669         cmd3 = u"ip_neighbor_add_del"
670         args3 = dict(
671             is_add=True,
672             neighbor=dict(
673                 sw_if_index=Topology.get_interface_sw_index(node, interface),
674                 flags=0,
675                 mac_address=str(dst_mac),
676                 ip_address=None
677             )
678         )
679         err_msg = f"Failed to configure IP addresses, IP routes and " \
680             f"IP neighbor on interface {interface} on host {node[u'host']}" \
681             if dst_mac \
682             else f"Failed to configure IP addresses and IP routes " \
683                  f"on interface {interface} on host {node[u'host']}"
684
685         with PapiSocketExecutor(node) as papi_exec:
686             for i in range(n_tunnels):
687                 args1[u"prefix"] = IPUtil.create_prefix_object(
688                     tunnel_src + i * addr_incr, raddr_range
689                 )
690                 args2[u"route"] = IPUtil.compose_vpp_route_structure(
691                     node, traffic_addr + i,
692                     prefix_len=128 if traffic_addr.version == 6 else 32,
693                     interface=interface, gateway=tunnel_dst + i * addr_incr
694                 )
695                 history = bool(not 1 < i < n_tunnels - 2)
696                 papi_exec.add(cmd1, history=history, **args1).\
697                     add(cmd2, history=history, **args2)
698                 if dst_mac:
699                     args3[u"neighbor"][u"ip_address"] = ip_address(
700                         tunnel_dst + i * addr_incr
701                     )
702                     papi_exec.add(cmd3, history=history, **args3)
703             papi_exec.get_replies(err_msg)
704
705     @staticmethod
706     def vpp_ipsec_add_spd(node, spd_id):
707         """Create Security Policy Database on the VPP node.
708
709         :param node: VPP node to add SPD on.
710         :param spd_id: SPD ID.
711         :type node: dict
712         :type spd_id: int
713         """
714         cmd = u"ipsec_spd_add_del"
715         err_msg = f"Failed to add Security Policy Database " \
716             f"on host {node[u'host']}"
717         args = dict(
718             is_add=True,
719             spd_id=int(spd_id)
720         )
721         with PapiSocketExecutor(node) as papi_exec:
722             papi_exec.add(cmd, **args).get_reply(err_msg)
723
724     @staticmethod
725     def vpp_ipsec_spd_add_if(node, spd_id, interface):
726         """Add interface to the Security Policy Database.
727
728         :param node: VPP node.
729         :param spd_id: SPD ID to add interface on.
730         :param interface: Interface name or sw_if_index.
731         :type node: dict
732         :type spd_id: int
733         :type interface: str or int
734         """
735         cmd = u"ipsec_interface_add_del_spd"
736         err_msg = f"Failed to add interface {interface} to Security Policy " \
737             f"Database {spd_id} on host {node[u'host']}"
738         args = dict(
739             is_add=True,
740             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
741             spd_id=int(spd_id)
742         )
743         with PapiSocketExecutor(node) as papi_exec:
744             papi_exec.add(cmd, **args).get_reply(err_msg)
745
746     @staticmethod
747     def vpp_ipsec_create_spds_match_nth_entry(
748             node, dir1_interface, dir2_interface, entry_amount,
749             local_addr_range, remote_addr_range, action=PolicyAction.BYPASS,
750             inbound=False, bidirectional=True):
751         """Create one matching SPD entry for inbound or outbound traffic on
752         a DUT for each traffic direction and also create entry_amount - 1
753         non-matching SPD entries. Create a Security Policy Database on each
754         outbound interface where these entries will be configured.
755         The matching SPD entry will have the lowest priority, input action and
756         will be configured to match the IP flow. The non-matching entries will
757         be the same, except with higher priority and non-matching IP flows.
758
759         Action Protect is currently not supported.
760
761         :param node: VPP node to configured the SPDs and their entries.
762         :param dir1_interface: The interface in direction 1 where the entries
763             will be checked.
764         :param dir2_interface: The interface in direction 2 where the entries
765             will be checked.
766         :param entry_amount: The number of SPD entries to configure. If
767             entry_amount == 1, no non-matching entries will be configured.
768         :param local_addr_range: Matching local address range in direction 1
769             in format IP/prefix or IP/mask. If no mask is provided, it's
770             considered to be /32.
771         :param remote_addr_range: Matching remote address range in
772             direction 1 in format IP/prefix or IP/mask. If no mask is
773             provided, it's considered to be /32.
774         :param action: Policy action.
775         :param inbound: If True policy is for inbound traffic, otherwise
776             outbound.
777         :param bidirectional: When True, will create SPDs in both directions
778             of traffic. When False, only in one direction.
779         :type node: dict
780         :type dir1_interface: Union[string, int]
781         :type dir2_interface: Union[string, int]
782         :type entry_amount: int
783         :type local_addr_range:
784             Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
785         :type remote_addr_range:
786             Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
787         :type action: IPsecUtil.PolicyAction
788         :type inbound: bool
789         :type bidirectional: bool
790         :raises NotImplementedError: When the action is PolicyAction.PROTECT.
791         """
792
793         if action == PolicyAction.PROTECT:
794             raise NotImplementedError('Policy action PROTECT is not supported.')
795
796         spd_id_dir1 = 1
797         spd_id_dir2 = 2
798         matching_priority = 1
799
800         IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir1)
801         IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir1, dir1_interface)
802         # matching entry direction 1
803         IPsecUtil.vpp_ipsec_add_spd_entry(
804             node, spd_id_dir1, matching_priority, action,
805             inbound=inbound, laddr_range=local_addr_range,
806             raddr_range=remote_addr_range
807         )
808
809         if bidirectional:
810             IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir2)
811             IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir2, dir2_interface)
812
813             # matching entry direction 2, the address ranges are switched
814             IPsecUtil.vpp_ipsec_add_spd_entry(
815                 node, spd_id_dir2, matching_priority, action,
816                 inbound=inbound, laddr_range=remote_addr_range,
817                 raddr_range=local_addr_range
818             )
819
820         # non-matching entries
821         no_match_entry_amount = entry_amount - 1
822         if no_match_entry_amount > 0:
823             # create a NetworkIncrement representation of the network,
824             # then skip the matching network
825             no_match_local_addr_range = NetworkIncrement(
826                 ip_network(local_addr_range)
827             )
828             next(no_match_local_addr_range)
829
830             no_match_remote_addr_range = NetworkIncrement(
831                 ip_network(remote_addr_range)
832             )
833             next(no_match_remote_addr_range)
834
835             # non-matching entries direction 1
836             IPsecUtil.vpp_ipsec_add_spd_entries(
837                 node, no_match_entry_amount, spd_id_dir1,
838                 ObjIncrement(matching_priority + 1, 1), action,
839                 inbound=inbound, laddr_range=no_match_local_addr_range,
840                 raddr_range=no_match_remote_addr_range
841             )
842
843             if bidirectional:
844                 # reset the networks so that we're using a unified config
845                 # the address ranges are switched
846                 no_match_remote_addr_range = NetworkIncrement(
847                     ip_network(local_addr_range)
848                 )
849                 next(no_match_remote_addr_range)
850
851                 no_match_local_addr_range = NetworkIncrement(
852                     ip_network(remote_addr_range)
853                 )
854                 next(no_match_local_addr_range)
855                 # non-matching entries direction 2
856                 IPsecUtil.vpp_ipsec_add_spd_entries(
857                     node, no_match_entry_amount, spd_id_dir2,
858                     ObjIncrement(matching_priority + 1, 1), action,
859                     inbound=inbound, laddr_range=no_match_local_addr_range,
860                     raddr_range=no_match_remote_addr_range
861                 )
862
863         IPsecUtil.vpp_ipsec_show_all(node)
864
865     @staticmethod
866     def vpp_ipsec_add_spd_entry(
867             node, spd_id, priority, action, inbound=True, sa_id=None,
868             proto=None, laddr_range=None, raddr_range=None, lport_range=None,
869             rport_range=None, is_ipv6=False):
870         """Create Security Policy Database entry on the VPP node.
871
872         :param node: VPP node to add SPD entry on.
873         :param spd_id: SPD ID to add entry on.
874         :param priority: SPD entry priority, higher number = higher priority.
875         :param action: Policy action.
876         :param inbound: If True policy is for inbound traffic, otherwise
877             outbound.
878         :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
879         :param proto: Policy selector next layer protocol number.
880         :param laddr_range: Policy selector local IPv4 or IPv6 address range
881             in format IP/prefix or IP/mask. If no mask is provided,
882             it's considered to be /32.
883         :param raddr_range: Policy selector remote IPv4 or IPv6 address range
884             in format IP/prefix or IP/mask. If no mask is provided,
885             it's considered to be /32.
886         :param lport_range: Policy selector local TCP/UDP port range in format
887             <port_start>-<port_end>.
888         :param rport_range: Policy selector remote TCP/UDP port range in format
889             <port_start>-<port_end>.
890         :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
891             not defined so it will default to address ::/0, otherwise False.
892         :type node: dict
893         :type spd_id: int
894         :type priority: int
895         :type action: IPsecUtil.PolicyAction
896         :type inbound: bool
897         :type sa_id: int
898         :type proto: int
899         :type laddr_range: string
900         :type raddr_range: string
901         :type lport_range: string
902         :type rport_range: string
903         :type is_ipv6: bool
904         """
905         if laddr_range is None:
906             laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
907
908         if raddr_range is None:
909             raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
910
911         local_net = ip_network(laddr_range, strict=False)
912         remote_net = ip_network(raddr_range, strict=False)
913
914         cmd = u"ipsec_spd_entry_add_del"
915         err_msg = f"Failed to add entry to Security Policy Database " \
916                   f"{spd_id} on host {node[u'host']}"
917
918         spd_entry = dict(
919             spd_id=int(spd_id),
920             priority=int(priority),
921             is_outbound=not inbound,
922             sa_id=int(sa_id) if sa_id else 0,
923             policy=int(action),
924             protocol=int(proto) if proto else 0,
925             remote_address_start=IPAddress.create_ip_address_object(
926                 remote_net.network_address
927             ),
928             remote_address_stop=IPAddress.create_ip_address_object(
929                 remote_net.broadcast_address
930             ),
931             local_address_start=IPAddress.create_ip_address_object(
932                 local_net.network_address
933             ),
934             local_address_stop=IPAddress.create_ip_address_object(
935                 local_net.broadcast_address
936             ),
937             remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
938             else 0,
939             remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
940             else 65535,
941             local_port_start=int(lport_range.split(u"-")[0]) if lport_range
942             else 0,
943             local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
944             else 65535
945         )
946         args = dict(
947             is_add=True,
948             entry=spd_entry
949         )
950         with PapiSocketExecutor(node) as papi_exec:
951             papi_exec.add(cmd, **args).get_reply(err_msg)
952
953     @staticmethod
954     def vpp_ipsec_add_spd_entries(
955             node, n_entries, spd_id, priority, action, inbound, sa_id=None,
956             proto=None, laddr_range=None, raddr_range=None, lport_range=None,
957             rport_range=None, is_ipv6=False):
958         """Create multiple Security Policy Database entries on the VPP node.
959
960         :param node: VPP node to add SPD entries on.
961         :param n_entries: Number of SPD entries to be added.
962         :param spd_id: SPD ID to add entries on.
963         :param priority: SPD entries priority, higher number = higher priority.
964         :param action: Policy action.
965         :param inbound: If True policy is for inbound traffic, otherwise
966             outbound.
967         :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
968         :param proto: Policy selector next layer protocol number.
969         :param laddr_range: Policy selector local IPv4 or IPv6 address range
970             in format IP/prefix or IP/mask. If no mask is provided,
971             it's considered to be /32.
972         :param raddr_range: Policy selector remote IPv4 or IPv6 address range
973             in format IP/prefix or IP/mask. If no mask is provided,
974             it's considered to be /32.
975         :param lport_range: Policy selector local TCP/UDP port range in format
976             <port_start>-<port_end>.
977         :param rport_range: Policy selector remote TCP/UDP port range in format
978             <port_start>-<port_end>.
979         :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
980             not defined so it will default to address ::/0, otherwise False.
981         :type node: dict
982         :type n_entries: int
983         :type spd_id: int
984         :type priority: IPsecUtil.ObjIncrement
985         :type action: IPsecUtil.PolicyAction
986         :type inbound: bool
987         :type sa_id: IPsecUtil.ObjIncrement
988         :type proto: int
989         :type laddr_range: IPsecUtil.NetworkIncrement
990         :type raddr_range: IPsecUtil.NetworkIncrement
991         :type lport_range: string
992         :type rport_range: string
993         :type is_ipv6: bool
994         """
995         if laddr_range is None:
996             laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
997             laddr_range = NetworkIncrement(ip_network(laddr_range), 0)
998
999         if raddr_range is None:
1000             raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
1001             raddr_range = NetworkIncrement(ip_network(raddr_range), 0)
1002
1003         lport_range_start = 0
1004         lport_range_stop = 65535
1005         if lport_range:
1006             lport_range_start, lport_range_stop = lport_range.split('-')
1007
1008         rport_range_start = 0
1009         rport_range_stop = 65535
1010         if rport_range:
1011             rport_range_start, rport_range_stop = rport_range.split('-')
1012
1013         if int(n_entries) > 10:
1014             tmp_filename = f"/tmp/ipsec_spd_{spd_id}_add_del_entry.script"
1015
1016             with open(tmp_filename, 'w') as tmp_file:
1017                 for _ in range(n_entries):
1018                     direction = u'inbound' if inbound else u'outbound'
1019                     sa = f' sa {sa_id.inc_fmt()}' if sa_id is not None else ''
1020                     protocol = f' protocol {protocol}' if proto else ''
1021                     local_port_range = f' local-port-range ' \
1022                         f'{lport_range_start} - {lport_range_stop}' \
1023                         if lport_range else ''
1024                     remote_port_range = f' remote-port-range ' \
1025                         f'{rport_range_start} - {rport_range_stop}' \
1026                         if rport_range else ''
1027
1028                     spd_cfg = f"exec ipsec policy add spd {spd_id} " \
1029                         f"priority {priority.inc_fmt()} {direction}" \
1030                         f"{protocol} action {action}{sa} " \
1031                         f"local-ip-range {laddr_range.inc_fmt()} " \
1032                         f"remote-ip-range {raddr_range.inc_fmt()}" \
1033                         f"{local_port_range}{remote_port_range}\n"
1034
1035                     tmp_file.write(spd_cfg)
1036
1037             VatExecutor().execute_script(
1038                 tmp_filename, node, timeout=300, json_out=False,
1039                 copy_on_execute=True
1040             )
1041             os.remove(tmp_filename)
1042             return
1043
1044         for _ in range(n_entries):
1045             IPsecUtil.vpp_ipsec_add_spd_entry(
1046                 node, spd_id, next(priority), action, inbound,
1047                 next(sa_id) if sa_id is not None else sa_id,
1048                 proto, next(laddr_range), next(raddr_range), lport_range,
1049                 rport_range, is_ipv6
1050             )
1051
1052     @staticmethod
1053     def _ipsec_create_tunnel_interfaces_dut1_vat(
1054             nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1055             raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1056         """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
1057
1058         Generate random keys and return them (so DUT2 or TG can decrypt).
1059
1060         :param nodes: VPP nodes to create tunnel interfaces.
1061         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1062             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1063             IPv4/IPv6 address (ip2).
1064         :param if1_key: VPP node 1 interface key from topology file.
1065         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1066             interface key from topology file.
1067         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1068         :param crypto_alg: The encryption algorithm name.
1069         :param integ_alg: The integrity algorithm name.
1070         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1071             first tunnel in direction node2->node1.
1072         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1073         :param addr_incr: IP / IPv6 address incremental step.
1074         :param existing_tunnels: Number of tunnel interfaces before creation.
1075             Useful mainly for reconf tests. Default 0.
1076         :type nodes: dict
1077         :type tun_ips: dict
1078         :type if1_key: str
1079         :type if2_key: str
1080         :type n_tunnels: int
1081         :type crypto_alg: CryptoAlg
1082         :type integ_alg: Optional[IntegAlg]
1083         :type raddr_ip2: IPv4Address or IPv6Address
1084         :type addr_incr: int
1085         :type spi_d: dict
1086         :type existing_tunnels: int
1087         :returns: Generated ckeys and ikeys.
1088         :rtype: List[bytes], List[bytes]
1089         """
1090         tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
1091         if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
1092
1093         ckeys = [bytes()] * existing_tunnels
1094         ikeys = [bytes()] * existing_tunnels
1095
1096         vat = VatExecutor()
1097         with open(tmp_fn1, u"w") as tmp_f1:
1098             rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
1099                 if u"DUT2" in nodes.keys() \
1100                 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
1101             if not existing_tunnels:
1102                 tmp_f1.write(
1103                     f"exec create loopback interface\n"
1104                     f"exec set interface state loop0 up\n"
1105                     f"exec set interface ip address {if1_n} "
1106                     f"{tun_ips[u'ip2'] - 1}/"
1107                     f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
1108                     f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
1109                     f"static\n"
1110                 )
1111             for i in range(existing_tunnels, n_tunnels):
1112                 ckeys.append(
1113                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1114                 )
1115                 ikeys.append(
1116                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1117                 )
1118                 if integ_alg:
1119                     integ = f"integ-alg {integ_alg.alg_name} " \
1120                         f"integ-key {ikeys[i].hex()} "
1121                 else:
1122                     integ = u""
1123                 tmp_f1.write(
1124                     f"exec set interface ip address loop0 "
1125                     f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
1126                     f"exec create ipip tunnel "
1127                     f"src {tun_ips[u'ip1'] + i * addr_incr} "
1128                     f"dst {tun_ips[u'ip2']} "
1129                     f"p2p\n"
1130                     f"exec ipsec sa add {i} "
1131                     f"spi {spi_d[u'spi_1'] + i} "
1132                     f"crypto-alg {crypto_alg.alg_name} "
1133                     f"crypto-key {ckeys[i].hex()} "
1134                     f"{integ}"
1135                     f"esp\n"
1136                     f"exec ipsec sa add {100000 + i} "
1137                     f"spi {spi_d[u'spi_2'] + i} "
1138                     f"crypto-alg {crypto_alg.alg_name} "
1139                     f"crypto-key {ckeys[i].hex()} "
1140                     f"{integ}"
1141                     f"esp\n"
1142                     f"exec ipsec tunnel protect ipip{i} "
1143                     f"sa-out {i} "
1144                     f"sa-in {100000 + i} "
1145                     f"add\n"
1146                 )
1147         vat.execute_script(
1148             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
1149             copy_on_execute=True,
1150             history=bool(n_tunnels < 100)
1151         )
1152         os.remove(tmp_fn1)
1153
1154         with open(tmp_fn1, 'w') as tmp_f1:
1155             for i in range(existing_tunnels, n_tunnels):
1156                 tmp_f1.write(
1157                     f"exec set interface unnumbered ipip{i} use {if1_n}\n"
1158                     f"exec set interface state ipip{i} up\n"
1159                     f"exec ip route add "
1160                     f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
1161                     f"via ipip{i}\n"
1162                 )
1163         vat.execute_script(
1164             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
1165             copy_on_execute=True,
1166             history=bool(n_tunnels < 100)
1167         )
1168         os.remove(tmp_fn1)
1169
1170         return ckeys, ikeys
1171
1172     @staticmethod
1173     def _ipsec_create_tunnel_interfaces_dut2_vat(
1174             nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1175             ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1176         """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
1177
1178         This method accesses keys generated by DUT1 method
1179         and does not return anything.
1180
1181         :param nodes: VPP nodes to create tunnel interfaces.
1182         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1183             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1184             IPv4/IPv6 address (ip2).
1185         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1186             interface key from topology file.
1187         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1188         :param crypto_alg: The encryption algorithm name.
1189         :param ckeys: List of encryption keys.
1190         :param integ_alg: The integrity algorithm name.
1191         :param ikeys: List of integrity keys.
1192         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1193         :param addr_incr: IP / IPv6 address incremental step.
1194         :param existing_tunnels: Number of tunnel interfaces before creation.
1195             Useful mainly for reconf tests. Default 0.
1196         :type nodes: dict
1197         :type tun_ips: dict
1198         :type if2_key: str
1199         :type n_tunnels: int
1200         :type crypto_alg: CryptoAlg
1201         :type ckeys: Sequence[bytes]
1202         :type integ_alg: Optional[IntegAlg]
1203         :type ikeys: Sequence[bytes]
1204         :type addr_incr: int
1205         :type spi_d: dict
1206         :type existing_tunnels: int
1207         """
1208         tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
1209         if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
1210
1211         vat = VatExecutor()
1212         with open(tmp_fn2, 'w') as tmp_f2:
1213             if not existing_tunnels:
1214                 tmp_f2.write(
1215                     f"exec set interface ip address {if2_n}"
1216                     f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
1217                 )
1218             for i in range(existing_tunnels, n_tunnels):
1219                 if integ_alg:
1220                     integ = f"integ-alg {integ_alg.alg_name} " \
1221                         f"integ-key {ikeys[i].hex()} "
1222                 else:
1223                     integ = u""
1224                 tmp_f2.write(
1225                     f"exec create ipip tunnel "
1226                     f"src {tun_ips[u'ip2']} "
1227                     f"dst {tun_ips[u'ip1'] + i * addr_incr} "
1228                     f"p2p\n"
1229                     f"exec ipsec sa add {100000 + i} "
1230                     f"spi {spi_d[u'spi_2'] + i} "
1231                     f"crypto-alg {crypto_alg.alg_name} "
1232                     f"crypto-key {ckeys[i].hex()} "
1233                     f"{integ}"
1234                     f"esp\n"
1235                     f"exec ipsec sa add {i} "
1236                     f"spi {spi_d[u'spi_1'] + i} "
1237                     f"crypto-alg {crypto_alg.alg_name} "
1238                     f"crypto-key {ckeys[i].hex()} "
1239                     f"{integ}"
1240                     f"esp\n"
1241                     f"exec ipsec tunnel protect ipip{i} "
1242                     f"sa-out {100000 + i} "
1243                     f"sa-in {i} "
1244                     f"add\n"
1245                 )
1246         vat.execute_script(
1247             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1248             copy_on_execute=True,
1249             history=bool(n_tunnels < 100)
1250         )
1251         os.remove(tmp_fn2)
1252
1253         with open(tmp_fn2, 'w') as tmp_f2:
1254             if not existing_tunnels:
1255                 tmp_f2.write(
1256                     f"exec ip route add {tun_ips[u'ip1']}/8 "
1257                     f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
1258                 )
1259             for i in range(existing_tunnels, n_tunnels):
1260                 tmp_f2.write(
1261                     f"exec set interface unnumbered ipip{i} use {if2_n}\n"
1262                     f"exec set interface state ipip{i} up\n"
1263                     f"exec ip route add "
1264                     f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
1265                     f"via ipip{i}\n"
1266                 )
1267         vat.execute_script(
1268             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1269             copy_on_execute=True,
1270             history=bool(n_tunnels < 100)
1271         )
1272         os.remove(tmp_fn2)
1273
1274     @staticmethod
1275     def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1276         """Create loopback interface and set IP address on VPP node 1 interface
1277         using PAPI.
1278
1279         :param nodes: VPP nodes to create tunnel interfaces.
1280         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1281             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1282             IPv4/IPv6 address (ip2).
1283         :param if1_key: VPP node 1 interface key from topology file.
1284         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1285             interface key from topology file.
1286         :type nodes: dict
1287         :type tun_ips: dict
1288         :type if1_key: str
1289         :type if2_key: str
1290         """
1291         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1292             # Create loopback interface on DUT1, set it to up state
1293             cmd = u"create_loopback_instance"
1294             args = dict(
1295                 mac_address=0,
1296                 is_specified=False,
1297                 user_instance=0,
1298             )
1299             err_msg = f"Failed to create loopback interface " \
1300                 f"on host {nodes[u'DUT1'][u'host']}"
1301             loop_sw_if_idx = papi_exec.add(cmd, **args). \
1302                 get_sw_if_index(err_msg)
1303             cmd = u"sw_interface_set_flags"
1304             args = dict(
1305                 sw_if_index=loop_sw_if_idx,
1306                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1307             )
1308             err_msg = f"Failed to set loopback interface state up " \
1309                 f"on host {nodes[u'DUT1'][u'host']}"
1310             papi_exec.add(cmd, **args).get_reply(err_msg)
1311             # Set IP address on VPP node 1 interface
1312             cmd = u"sw_interface_add_del_address"
1313             args = dict(
1314                 sw_if_index=InterfaceUtil.get_interface_index(
1315                     nodes[u"DUT1"], if1_key
1316                 ),
1317                 is_add=True,
1318                 del_all=False,
1319                 prefix=IPUtil.create_prefix_object(
1320                     tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1321                     else 24
1322                 )
1323             )
1324             err_msg = f"Failed to set IP address on interface {if1_key} " \
1325                 f"on host {nodes[u'DUT1'][u'host']}"
1326             papi_exec.add(cmd, **args).get_reply(err_msg)
1327             cmd2 = u"ip_neighbor_add_del"
1328             args2 = dict(
1329                 is_add=1,
1330                 neighbor=dict(
1331                     sw_if_index=Topology.get_interface_sw_index(
1332                         nodes[u"DUT1"], if1_key
1333                     ),
1334                     flags=1,
1335                     mac_address=str(
1336                         Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1337                         if u"DUT2" in nodes.keys()
1338                         else Topology.get_interface_mac(
1339                             nodes[u"TG"], if2_key
1340                         )
1341                     ),
1342                     ip_address=tun_ips[u"ip2"].compressed
1343                 )
1344             )
1345             err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1346             papi_exec.add(cmd2, **args2).get_reply(err_msg)
1347
1348             return loop_sw_if_idx
1349
1350     @staticmethod
1351     def _ipsec_create_tunnel_interfaces_dut1_papi(
1352             nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1353             raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1354         """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1355
1356         Generate random keys and return them (so DUT2 or TG can decrypt).
1357
1358         :param nodes: VPP nodes to create tunnel interfaces.
1359         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1360             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1361             IPv4/IPv6 address (ip2).
1362         :param if1_key: VPP node 1 interface key from topology file.
1363         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1364             interface key from topology file.
1365         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1366         :param crypto_alg: The encryption algorithm name.
1367         :param integ_alg: The integrity algorithm name.
1368         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1369             first tunnel in direction node2->node1.
1370         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1371         :param addr_incr: IP / IPv6 address incremental step.
1372         :param existing_tunnels: Number of tunnel interfaces before creation.
1373             Useful mainly for reconf tests. Default 0.
1374         :type nodes: dict
1375         :type tun_ips: dict
1376         :type if1_key: str
1377         :type if2_key: str
1378         :type n_tunnels: int
1379         :type crypto_alg: CryptoAlg
1380         :type integ_alg: Optional[IntegAlg]
1381         :type raddr_ip2: IPv4Address or IPv6Address
1382         :type addr_incr: int
1383         :type spi_d: dict
1384         :type existing_tunnels: int
1385         :returns: Generated ckeys and ikeys.
1386         :rtype: List[bytes], List[bytes]
1387         """
1388         if not existing_tunnels:
1389             loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1390                 nodes, tun_ips, if1_key, if2_key
1391             )
1392         else:
1393             loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1394                 nodes[u"DUT1"], u"loop0"
1395             )
1396         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1397             # Configure IP addresses on loop0 interface
1398             cmd = u"sw_interface_add_del_address"
1399             args = dict(
1400                 sw_if_index=loop_sw_if_idx,
1401                 is_add=True,
1402                 del_all=False,
1403                 prefix=None
1404             )
1405             for i in range(existing_tunnels, n_tunnels):
1406                 args[u"prefix"] = IPUtil.create_prefix_object(
1407                     tun_ips[u"ip1"] + i * addr_incr,
1408                     128 if tun_ips[u"ip1"].version == 6 else 32
1409                 )
1410                 papi_exec.add(
1411                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1412                 )
1413             # Configure IPIP tunnel interfaces
1414             cmd = u"ipip_add_tunnel"
1415             ipip_tunnel = dict(
1416                 instance=Constants.BITWISE_NON_ZERO,
1417                 src=None,
1418                 dst=None,
1419                 table_id=0,
1420                 flags=int(
1421                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1422                 ),
1423                 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1424                 dscp=int(IpDscp.IP_API_DSCP_CS0)
1425             )
1426             args = dict(
1427                 tunnel=ipip_tunnel
1428             )
1429             ipip_tunnels = [None] * existing_tunnels
1430             for i in range(existing_tunnels, n_tunnels):
1431                 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1432                     tun_ips[u"ip1"] + i * addr_incr
1433                 )
1434                 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1435                     tun_ips[u"ip2"]
1436                 )
1437                 papi_exec.add(
1438                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1439                 )
1440             err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1441                 f" {nodes[u'DUT1'][u'host']}"
1442             ipip_tunnels.extend(
1443                 [
1444                     reply[u"sw_if_index"]
1445                     for reply in papi_exec.get_replies(err_msg)
1446                     if u"sw_if_index" in reply
1447                 ]
1448             )
1449             # Configure IPSec SAD entries
1450             ckeys = [bytes()] * existing_tunnels
1451             ikeys = [bytes()] * existing_tunnels
1452             cmd = u"ipsec_sad_entry_add_del_v3"
1453             c_key = dict(
1454                 length=0,
1455                 data=None
1456             )
1457             i_key = dict(
1458                 length=0,
1459                 data=None
1460             )
1461             sad_entry = dict(
1462                 sad_id=None,
1463                 spi=None,
1464                 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1465                 crypto_algorithm=crypto_alg.alg_int_repr,
1466                 crypto_key=c_key,
1467                 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1468                 integrity_key=i_key,
1469                 flags=None,
1470                 tunnel=dict(
1471                     src=0,
1472                     dst=0,
1473                     table_id=0,
1474                     encap_decap_flags=int(
1475                         TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1476                     ),
1477                     dscp=int(IpDscp.IP_API_DSCP_CS0),
1478                 ),
1479                 salt=0,
1480                 udp_src_port=IPSEC_UDP_PORT_NONE,
1481                 udp_dst_port=IPSEC_UDP_PORT_NONE,
1482             )
1483             args = dict(
1484                 is_add=True,
1485                 entry=sad_entry
1486             )
1487             for i in range(existing_tunnels, n_tunnels):
1488                 ckeys.append(
1489                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1490                 )
1491                 ikeys.append(
1492                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1493                 )
1494                 # SAD entry for outband / tx path
1495                 args[u"entry"][u"sad_id"] = i
1496                 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1497
1498                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1499                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1500                 if integ_alg:
1501                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1502                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1503                 args[u"entry"][u"flags"] = int(
1504                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1505                 )
1506                 papi_exec.add(
1507                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1508                 )
1509                 # SAD entry for inband / rx path
1510                 args[u"entry"][u"sad_id"] = 100000 + i
1511                 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1512
1513                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1514                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1515                 if integ_alg:
1516                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1517                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1518                 args[u"entry"][u"flags"] = int(
1519                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1520                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1521                 )
1522                 papi_exec.add(
1523                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1524                 )
1525             err_msg = f"Failed to add IPsec SAD entries on host" \
1526                 f" {nodes[u'DUT1'][u'host']}"
1527             papi_exec.get_replies(err_msg)
1528             # Add protection for tunnels with IPSEC
1529             cmd = u"ipsec_tunnel_protect_update"
1530             n_hop = dict(
1531                 address=0,
1532                 via_label=MPLS_LABEL_INVALID,
1533                 obj_id=Constants.BITWISE_NON_ZERO
1534             )
1535             ipsec_tunnel_protect = dict(
1536                 sw_if_index=None,
1537                 nh=n_hop,
1538                 sa_out=None,
1539                 n_sa_in=1,
1540                 sa_in=None
1541             )
1542             args = dict(
1543                 tunnel=ipsec_tunnel_protect
1544             )
1545             for i in range(existing_tunnels, n_tunnels):
1546                 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1547                 args[u"tunnel"][u"sa_out"] = i
1548                 args[u"tunnel"][u"sa_in"] = [100000 + i]
1549                 papi_exec.add(
1550                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1551                 )
1552             err_msg = f"Failed to add protection for tunnels with IPSEC " \
1553                 f"on host {nodes[u'DUT1'][u'host']}"
1554             papi_exec.get_replies(err_msg)
1555
1556             # Configure unnumbered interfaces
1557             cmd = u"sw_interface_set_unnumbered"
1558             args = dict(
1559                 is_add=True,
1560                 sw_if_index=InterfaceUtil.get_interface_index(
1561                     nodes[u"DUT1"], if1_key
1562                 ),
1563                 unnumbered_sw_if_index=0
1564             )
1565             for i in range(existing_tunnels, n_tunnels):
1566                 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1567                 papi_exec.add(
1568                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1569                 )
1570             # Set interfaces up
1571             cmd = u"sw_interface_set_flags"
1572             args = dict(
1573                 sw_if_index=0,
1574                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1575             )
1576             for i in range(existing_tunnels, n_tunnels):
1577                 args[u"sw_if_index"] = ipip_tunnels[i]
1578                 papi_exec.add(
1579                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1580                 )
1581             # Configure IP routes
1582             cmd = u"ip_route_add_del"
1583             args = dict(
1584                 is_add=1,
1585                 is_multipath=0,
1586                 route=None
1587             )
1588             for i in range(existing_tunnels, n_tunnels):
1589                 args[u"route"] = IPUtil.compose_vpp_route_structure(
1590                     nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1591                     prefix_len=128 if raddr_ip2.version == 6 else 32,
1592                     interface=ipip_tunnels[i]
1593                 )
1594                 papi_exec.add(
1595                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1596                 )
1597             err_msg = f"Failed to add IP routes on host " \
1598                 f"{nodes[u'DUT1'][u'host']}"
1599             papi_exec.get_replies(err_msg)
1600
1601         return ckeys, ikeys
1602
1603     @staticmethod
1604     def _ipsec_create_tunnel_interfaces_dut2_papi(
1605             nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1606             ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1607         """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1608
1609         This method accesses keys generated by DUT1 method
1610         and does not return anything.
1611
1612         :param nodes: VPP nodes to create tunnel interfaces.
1613         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1614             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1615             IPv4/IPv6 address (ip2).
1616         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1617             interface key from topology file.
1618         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1619         :param crypto_alg: The encryption algorithm name.
1620         :param ckeys: List of encryption keys.
1621         :param integ_alg: The integrity algorithm name.
1622         :param ikeys: List of integrity keys.
1623         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1624         :param addr_incr: IP / IPv6 address incremental step.
1625         :param existing_tunnels: Number of tunnel interfaces before creation.
1626             Useful mainly for reconf tests. Default 0.
1627         :type nodes: dict
1628         :type tun_ips: dict
1629         :type if2_key: str
1630         :type n_tunnels: int
1631         :type crypto_alg: CryptoAlg
1632         :type ckeys: Sequence[bytes]
1633         :type integ_alg: Optional[IntegAlg]
1634         :type ikeys: Sequence[bytes]
1635         :type addr_incr: int
1636         :type spi_d: dict
1637         :type existing_tunnels: int
1638         """
1639         with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1640             if not existing_tunnels:
1641                 # Set IP address on VPP node 2 interface
1642                 cmd = u"sw_interface_add_del_address"
1643                 args = dict(
1644                     sw_if_index=InterfaceUtil.get_interface_index(
1645                         nodes[u"DUT2"], if2_key
1646                     ),
1647                     is_add=True,
1648                     del_all=False,
1649                     prefix=IPUtil.create_prefix_object(
1650                         tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1651                         else 24
1652                     )
1653                 )
1654                 err_msg = f"Failed to set IP address on interface {if2_key} " \
1655                     f"on host {nodes[u'DUT2'][u'host']}"
1656                 papi_exec.add(cmd, **args).get_reply(err_msg)
1657             # Configure IPIP tunnel interfaces
1658             cmd = u"ipip_add_tunnel"
1659             ipip_tunnel = dict(
1660                 instance=Constants.BITWISE_NON_ZERO,
1661                 src=None,
1662                 dst=None,
1663                 table_id=0,
1664                 flags=int(
1665                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1666                 ),
1667                 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1668                 dscp=int(IpDscp.IP_API_DSCP_CS0)
1669             )
1670             args = dict(
1671                 tunnel=ipip_tunnel
1672             )
1673             ipip_tunnels = [None] * existing_tunnels
1674             for i in range(existing_tunnels, n_tunnels):
1675                 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1676                     tun_ips[u"ip2"]
1677                 )
1678                 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1679                     tun_ips[u"ip1"] + i * addr_incr
1680                 )
1681                 papi_exec.add(
1682                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1683                 )
1684             err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1685                 f" {nodes[u'DUT2'][u'host']}"
1686             ipip_tunnels.extend(
1687                 [
1688                     reply[u"sw_if_index"]
1689                     for reply in papi_exec.get_replies(err_msg)
1690                     if u"sw_if_index" in reply
1691                 ]
1692             )
1693             # Configure IPSec SAD entries
1694             cmd = u"ipsec_sad_entry_add_del_v3"
1695             c_key = dict(
1696                 length=0,
1697                 data=None
1698             )
1699             i_key = dict(
1700                 length=0,
1701                 data=None
1702             )
1703             sad_entry = dict(
1704                 sad_id=None,
1705                 spi=None,
1706                 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1707                 crypto_algorithm=crypto_alg.alg_int_repr,
1708                 crypto_key=c_key,
1709                 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1710                 integrity_key=i_key,
1711                 flags=None,
1712                 tunnel=dict(
1713                     src=0,
1714                     dst=0,
1715                     table_id=0,
1716                     encap_decap_flags=int(
1717                         TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1718                     ),
1719                     dscp=int(IpDscp.IP_API_DSCP_CS0),
1720                 ),
1721                 salt=0,
1722                 udp_src_port=IPSEC_UDP_PORT_NONE,
1723                 udp_dst_port=IPSEC_UDP_PORT_NONE,
1724             )
1725             args = dict(
1726                 is_add=True,
1727                 entry=sad_entry
1728             )
1729             for i in range(existing_tunnels, n_tunnels):
1730                 ckeys.append(
1731                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1732                 )
1733                 ikeys.append(
1734                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1735                 )
1736                 # SAD entry for outband / tx path
1737                 args[u"entry"][u"sad_id"] = 100000 + i
1738                 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1739
1740                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1741                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1742                 if integ_alg:
1743                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1744                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1745                 args[u"entry"][u"flags"] = int(
1746                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1747                 )
1748                 papi_exec.add(
1749                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1750                 )
1751                 # SAD entry for inband / rx path
1752                 args[u"entry"][u"sad_id"] = i
1753                 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1754
1755                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1756                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1757                 if integ_alg:
1758                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1759                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1760                 args[u"entry"][u"flags"] = int(
1761                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1762                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1763                 )
1764                 papi_exec.add(
1765                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1766                 )
1767             err_msg = f"Failed to add IPsec SAD entries on host" \
1768                 f" {nodes[u'DUT2'][u'host']}"
1769             papi_exec.get_replies(err_msg)
1770             # Add protection for tunnels with IPSEC
1771             cmd = u"ipsec_tunnel_protect_update"
1772             n_hop = dict(
1773                 address=0,
1774                 via_label=MPLS_LABEL_INVALID,
1775                 obj_id=Constants.BITWISE_NON_ZERO
1776             )
1777             ipsec_tunnel_protect = dict(
1778                 sw_if_index=None,
1779                 nh=n_hop,
1780                 sa_out=None,
1781                 n_sa_in=1,
1782                 sa_in=None
1783             )
1784             args = dict(
1785                 tunnel=ipsec_tunnel_protect
1786             )
1787             for i in range(existing_tunnels, n_tunnels):
1788                 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1789                 args[u"tunnel"][u"sa_out"] = 100000 + i
1790                 args[u"tunnel"][u"sa_in"] = [i]
1791                 papi_exec.add(
1792                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1793                 )
1794             err_msg = f"Failed to add protection for tunnels with IPSEC " \
1795                 f"on host {nodes[u'DUT2'][u'host']}"
1796             papi_exec.get_replies(err_msg)
1797
1798             if not existing_tunnels:
1799                 # Configure IP route
1800                 cmd = u"ip_route_add_del"
1801                 route = IPUtil.compose_vpp_route_structure(
1802                     nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1803                     prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1804                     interface=if2_key,
1805                     gateway=(tun_ips[u"ip2"] - 1).compressed
1806                 )
1807                 args = dict(
1808                     is_add=1,
1809                     is_multipath=0,
1810                     route=route
1811                 )
1812                 papi_exec.add(cmd, **args)
1813             # Configure unnumbered interfaces
1814             cmd = u"sw_interface_set_unnumbered"
1815             args = dict(
1816                 is_add=True,
1817                 sw_if_index=InterfaceUtil.get_interface_index(
1818                     nodes[u"DUT2"], if2_key
1819                 ),
1820                 unnumbered_sw_if_index=0
1821             )
1822             for i in range(existing_tunnels, n_tunnels):
1823                 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1824                 papi_exec.add(
1825                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1826                 )
1827             # Set interfaces up
1828             cmd = u"sw_interface_set_flags"
1829             args = dict(
1830                 sw_if_index=0,
1831                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1832             )
1833             for i in range(existing_tunnels, n_tunnels):
1834                 args[u"sw_if_index"] = ipip_tunnels[i]
1835                 papi_exec.add(
1836                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1837                 )
1838             # Configure IP routes
1839             cmd = u"ip_route_add_del"
1840             args = dict(
1841                 is_add=1,
1842                 is_multipath=0,
1843                 route=None
1844             )
1845             for i in range(existing_tunnels, n_tunnels):
1846                 args[u"route"] = IPUtil.compose_vpp_route_structure(
1847                     nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1848                     prefix_len=128 if raddr_ip1.version == 6 else 32,
1849                     interface=ipip_tunnels[i]
1850                 )
1851                 papi_exec.add(
1852                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1853                 )
1854             err_msg = f"Failed to add IP routes " \
1855                 f"on host {nodes[u'DUT2'][u'host']}"
1856             papi_exec.get_replies(err_msg)
1857
1858     @staticmethod
1859     def vpp_ipsec_create_tunnel_interfaces(
1860             nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1861             n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1862             existing_tunnels=0, return_keys=False):
1863         """Create multiple IPsec tunnel interfaces between two VPP nodes.
1864
1865         Some deployments (e.g. devicetest) need to know the generated keys.
1866         But other deployments (e.g. scale perf test) would get spammed
1867         if we returned keys every time.
1868
1869         :param nodes: VPP nodes to create tunnel interfaces.
1870         :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1871             address.
1872         :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1873             address.
1874         :param if1_key: VPP node 1 interface key from topology file.
1875         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1876             interface key from topology file.
1877         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1878         :param crypto_alg: The encryption algorithm name.
1879         :param integ_alg: The integrity algorithm name.
1880         :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1881             first tunnel in direction node1->node2.
1882         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1883             first tunnel in direction node2->node1.
1884         :param raddr_range: Mask specifying range of Policy selector Remote
1885             IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1886             and to 128 in case of IPv6.
1887         :param existing_tunnels: Number of tunnel interfaces before creation.
1888             Useful mainly for reconf tests. Default 0.
1889         :param return_keys: Whether generated keys should be returned.
1890         :type nodes: dict
1891         :type tun_if1_ip_addr: str
1892         :type tun_if2_ip_addr: str
1893         :type if1_key: str
1894         :type if2_key: str
1895         :type n_tunnels: int
1896         :type crypto_alg: CryptoAlg
1897         :type integ_alg: Optonal[IntegAlg]
1898         :type raddr_ip1: string
1899         :type raddr_ip2: string
1900         :type raddr_range: int
1901         :type existing_tunnels: int
1902         :type return_keys: bool
1903         :returns: Ckeys, ikeys, spi_1, spi_2.
1904         :rtype: Optional[List[bytes], List[bytes], int, int]
1905         """
1906         n_tunnels = int(n_tunnels)
1907         existing_tunnels = int(existing_tunnels)
1908         spi_d = dict(
1909             spi_1=100000,
1910             spi_2=200000
1911         )
1912         tun_ips = dict(
1913             ip1=ip_address(tun_if1_ip_addr),
1914             ip2=ip_address(tun_if2_ip_addr)
1915         )
1916         raddr_ip1 = ip_address(raddr_ip1)
1917         raddr_ip2 = ip_address(raddr_ip2)
1918         addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1919             else 1 << (32 - raddr_range)
1920
1921         if n_tunnels - existing_tunnels > 10:
1922             ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1923                 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1924                 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1925             )
1926             if u"DUT2" in nodes.keys():
1927                 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1928                     nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1929                     integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1930                     existing_tunnels
1931                 )
1932         else:
1933             ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1934                 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1935                 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1936             )
1937             if u"DUT2" in nodes.keys():
1938                 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1939                     nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1940                     integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1941                     existing_tunnels
1942                 )
1943
1944         if return_keys:
1945             return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1946         return None
1947
1948     @staticmethod
1949     def _create_ipsec_script_files(dut, instances):
1950         """Create script files for configuring IPsec in containers
1951
1952         :param dut: DUT node on which to create the script files
1953         :param instances: number of containers on DUT node
1954         :type dut: string
1955         :type instances: int
1956         """
1957         scripts = []
1958         for cnf in range(0, instances):
1959             script_filename = (
1960                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1961             )
1962             scripts.append(open(script_filename, 'w'))
1963         return scripts
1964
1965     @staticmethod
1966     def _close_and_copy_ipsec_script_files(
1967             dut, nodes, instances, scripts):
1968         """Close created scripts and copy them to containers
1969
1970         :param dut: DUT node on which to create the script files
1971         :param nodes: VPP nodes
1972         :param instances: number of containers on DUT node
1973         :param scripts: dictionary holding the script files
1974         :type dut: string
1975         :type nodes: dict
1976         :type instances: int
1977         :type scripts: dict
1978         """
1979         for cnf in range(0, instances):
1980             scripts[cnf].close()
1981             script_filename = (
1982                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1983             )
1984             scp_node(nodes[dut], script_filename, script_filename)
1985
1986
1987     @staticmethod
1988     def vpp_ipsec_create_tunnel_interfaces_in_containers(
1989             nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1990             raddr_ip1, raddr_ip2, raddr_range, n_instances):
1991         """Create multiple IPsec tunnel interfaces between two VPP nodes.
1992
1993         :param nodes: VPP nodes to create tunnel interfaces.
1994         :param if1_ip_addr: VPP node 1 interface IP4 address.
1995         :param if2_ip_addr: VPP node 2 interface IP4 address.
1996         :param n_tunnels: Number of tunnell interfaces to create.
1997         :param crypto_alg: The encryption algorithm name.
1998         :param integ_alg: The integrity algorithm name.
1999         :param raddr_ip1: Policy selector remote IPv4 start address for the
2000             first tunnel in direction node1->node2.
2001         :param raddr_ip2: Policy selector remote IPv4 start address for the
2002             first tunnel in direction node2->node1.
2003         :param raddr_range: Mask specifying range of Policy selector Remote
2004             IPv4 addresses. Valid values are from 1 to 32.
2005         :param n_instances: Number of containers.
2006         :type nodes: dict
2007         :type if1_ip_addr: str
2008         :type if2_ip_addr: str
2009         :type n_tunnels: int
2010         :type crypto_alg: CryptoAlg
2011         :type integ_alg: Optional[IntegAlg]
2012         :type raddr_ip1: string
2013         :type raddr_ip2: string
2014         :type raddr_range: int
2015         :type n_instances: int
2016         """
2017         spi_1 = 100000
2018         spi_2 = 200000
2019         addr_incr = 1 << (32 - raddr_range)
2020
2021         dut1_scripts = IPsecUtil._create_ipsec_script_files(
2022             u"DUT1", n_instances
2023         )
2024         dut2_scripts = IPsecUtil._create_ipsec_script_files(
2025             u"DUT2", n_instances
2026         )
2027
2028         for cnf in range(0, n_instances):
2029             dut1_scripts[cnf].write(
2030                 u"create loopback interface\n"
2031                 u"set interface state loop0 up\n\n"
2032             )
2033             dut2_scripts[cnf].write(
2034                 f"ip route add {if1_ip_addr}/8 via "
2035                 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
2036             )
2037
2038         for tnl in range(0, n_tunnels):
2039             cnf = tnl % n_instances
2040             ckey = getattr(
2041                 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
2042             )
2043             integ = u""
2044             ikey = getattr(
2045                 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
2046             )
2047             if integ_alg:
2048                 integ = (
2049                     f"integ-alg {integ_alg.alg_name} "
2050                     f"local-integ-key {ikey} "
2051                     f"remote-integ-key {ikey} "
2052                 )
2053             # Configure tunnel end point(s) on left side
2054             dut1_scripts[cnf].write(
2055                 u"set interface ip address loop0 "
2056                 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
2057                 f"create ipsec tunnel "
2058                 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
2059                 f"local-spi {spi_1 + tnl} "
2060                 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
2061                 f"remote-spi {spi_2 + tnl} "
2062                 f"crypto-alg {crypto_alg.alg_name} "
2063                 f"local-crypto-key {ckey} "
2064                 f"remote-crypto-key {ckey} "
2065                 f"instance {tnl // n_instances} "
2066                 f"salt 0x0 "
2067                 f"{integ} \n"
2068                 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
2069                 f"set interface state ipip{tnl // n_instances} up\n"
2070                 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
2071                 f"via ipip{tnl // n_instances}\n\n"
2072             )
2073             # Configure tunnel end point(s) on right side
2074             dut2_scripts[cnf].write(
2075                 f"set ip neighbor memif1/{cnf + 1} "
2076                 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
2077                 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
2078                 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
2079                 f"local-spi {spi_2 + tnl} "
2080                 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
2081                 f"remote-spi {spi_1 + tnl} "
2082                 f"crypto-alg {crypto_alg.alg_name} "
2083                 f"local-crypto-key {ckey} "
2084                 f"remote-crypto-key {ckey} "
2085                 f"instance {tnl // n_instances} "
2086                 f"salt 0x0 "
2087                 f"{integ}\n"
2088                 f"set interface unnumbered ipip{tnl // n_instances} "
2089                 f"use memif1/{cnf + 1}\n"
2090                 f"set interface state ipip{tnl // n_instances} up\n"
2091                 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
2092                 f"via ipip{tnl // n_instances}\n\n"
2093             )
2094
2095         IPsecUtil._close_and_copy_ipsec_script_files(
2096             u"DUT1", nodes, n_instances, dut1_scripts)
2097         IPsecUtil._close_and_copy_ipsec_script_files(
2098             u"DUT2", nodes, n_instances, dut2_scripts)
2099
2100     @staticmethod
2101     def vpp_ipsec_add_multiple_tunnels(
2102             nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
2103             tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
2104         """Create multiple IPsec tunnels between two VPP nodes.
2105
2106         :param nodes: VPP nodes to create tunnels.
2107         :param interface1: Interface name or sw_if_index on node 1.
2108         :param interface2: Interface name or sw_if_index on node 2.
2109         :param n_tunnels: Number of tunnels to create.
2110         :param crypto_alg: The encryption algorithm name.
2111         :param integ_alg: The integrity algorithm name.
2112         :param tunnel_ip1: Tunnel node1 IPv4 address.
2113         :param tunnel_ip2: Tunnel node2 IPv4 address.
2114         :param raddr_ip1: Policy selector remote IPv4 start address for the
2115             first tunnel in direction node1->node2.
2116         :param raddr_ip2: Policy selector remote IPv4 start address for the
2117             first tunnel in direction node2->node1.
2118         :param raddr_range: Mask specifying range of Policy selector Remote
2119             IPv4 addresses. Valid values are from 1 to 32.
2120         :type nodes: dict
2121         :type interface1: str or int
2122         :type interface2: str or int
2123         :type n_tunnels: int
2124         :type crypto_alg: CryptoAlg
2125         :type integ_alg: Optional[IntegAlg]
2126         :type tunnel_ip1: str
2127         :type tunnel_ip2: str
2128         :type raddr_ip1: string
2129         :type raddr_ip2: string
2130         :type raddr_range: int
2131         """
2132         spd_id = 1
2133         p_hi = 100
2134         p_lo = 10
2135         sa_id_1 = 100000
2136         sa_id_2 = 200000
2137         spi_1 = 300000
2138         spi_2 = 400000
2139
2140         crypto_key = gen_key(
2141             IPsecUtil.get_crypto_alg_key_len(crypto_alg)
2142         ).decode()
2143         integ_key = gen_key(
2144             IPsecUtil.get_integ_alg_key_len(integ_alg)
2145         ).decode() if integ_alg else u""
2146
2147         rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
2148             if u"DUT2" in nodes.keys() \
2149             else Topology.get_interface_mac(nodes[u"TG"], interface2)
2150         IPsecUtil.vpp_ipsec_set_ip_route(
2151             nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
2152             interface1, raddr_range, rmac)
2153
2154         IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
2155         IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
2156         IPsecUtil.vpp_ipsec_add_spd_entry(
2157             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
2158             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
2159         )
2160         IPsecUtil.vpp_ipsec_add_spd_entry(
2161             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
2162             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
2163         )
2164
2165         IPsecUtil.vpp_ipsec_add_sad_entries(
2166             nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
2167             integ_alg, integ_key, tunnel_ip1, tunnel_ip2
2168         )
2169
2170         IPsecUtil.vpp_ipsec_add_spd_entries(
2171             nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2172             action=PolicyAction.PROTECT, inbound=False,
2173             sa_id=ObjIncrement(sa_id_1, 1),
2174             raddr_range=NetworkIncrement(ip_network(raddr_ip2))
2175         )
2176
2177         IPsecUtil.vpp_ipsec_add_sad_entries(
2178             nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
2179             integ_alg, integ_key, tunnel_ip2, tunnel_ip1
2180         )
2181         IPsecUtil.vpp_ipsec_add_spd_entries(
2182             nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2183             action=PolicyAction.PROTECT, inbound=True,
2184             sa_id=ObjIncrement(sa_id_2, 1),
2185             raddr_range=NetworkIncrement(ip_network(raddr_ip1))
2186         )
2187
2188         if u"DUT2" in nodes.keys():
2189             IPsecUtil.vpp_ipsec_set_ip_route(
2190                 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
2191                 interface2, raddr_range)
2192
2193             IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
2194             IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
2195             IPsecUtil.vpp_ipsec_add_spd_entry(
2196                 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2197                 inbound=False, proto=50, laddr_range=u"100.0.0.0/8",
2198                 raddr_range=u"100.0.0.0/8"
2199             )
2200             IPsecUtil.vpp_ipsec_add_spd_entry(
2201                 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2202                 inbound=True, proto=50, laddr_range=u"100.0.0.0/8",
2203                 raddr_range=u"100.0.0.0/8"
2204             )
2205
2206             IPsecUtil.vpp_ipsec_add_sad_entries(
2207                 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
2208                 crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2
2209             )
2210             IPsecUtil.vpp_ipsec_add_spd_entries(
2211                 nodes[u"DUT2"], n_tunnels, spd_id,
2212                 priority=ObjIncrement(p_lo, 0),
2213                 action=PolicyAction.PROTECT, inbound=True,
2214                 sa_id=ObjIncrement(sa_id_1, 1),
2215                 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
2216             )
2217
2218             IPsecUtil.vpp_ipsec_add_sad_entries(
2219                 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
2220                 crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1
2221             )
2222             IPsecUtil.vpp_ipsec_add_spd_entries(
2223                 nodes[u"DUT2"], n_tunnels, spd_id,
2224                 priority=ObjIncrement(p_lo, 0),
2225                 action=PolicyAction.PROTECT, inbound=False,
2226                 sa_id=ObjIncrement(sa_id_2, 1),
2227                 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
2228             )
2229
2230     @staticmethod
2231     def vpp_ipsec_show_all(node):
2232         """Run "show ipsec all" debug CLI command.
2233
2234         :param node: Node to run command on.
2235         :type node: dict
2236         """
2237         PapiSocketExecutor.run_cli_cmd(node, u"show ipsec all")
2238
2239     @staticmethod
2240     def show_ipsec_security_association(node):
2241         """Show IPSec security association.
2242
2243         :param node: DUT node.
2244         :type node: dict
2245         """
2246         cmds = [
2247             u"ipsec_sa_v3_dump"
2248         ]
2249         PapiSocketExecutor.dump_and_log(node, cmds)