2efc70eab65d7172943a6acc0ec7dcec165689a2
[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_v2"
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_src=str(src_addr),
452             tunnel_dst=str(dst_addr),
453             tunnel_flags=int(
454                 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
455             ),
456             dscp=int(IpDscp.IP_API_DSCP_CS0),
457             protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
458             udp_src_port=4500,  # default value in api
459             udp_dst_port=4500  # default value in api
460         )
461         args = dict(
462             is_add=True,
463             entry=sad_entry
464         )
465         with PapiSocketExecutor(node) as papi_exec:
466             papi_exec.add(cmd, **args).get_reply(err_msg)
467
468     @staticmethod
469     def vpp_ipsec_add_sad_entries(
470             node, n_entries, sad_id, spi, crypto_alg, crypto_key,
471             integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
472         """Create multiple Security Association Database entries on VPP node.
473
474         :param node: VPP node to add SAD entry on.
475         :param n_entries: Number of SAD entries to be created.
476         :param sad_id: First SAD entry ID. All subsequent SAD entries will have
477             id incremented by 1.
478         :param spi: Security Parameter Index of first SAD entry. All subsequent
479             SAD entries will have spi incremented by 1.
480         :param crypto_alg: The encryption algorithm name.
481         :param crypto_key: The encryption key string.
482         :param integ_alg: The integrity algorithm name.
483         :param integ_key: The integrity key string.
484         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
485             specified ESP transport mode is used.
486         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
487             not specified ESP transport mode is used.
488         :type node: dict
489         :type n_entries: int
490         :type sad_id: int
491         :type spi: int
492         :type crypto_alg: CryptoAlg
493         :type crypto_key: str
494         :type integ_alg: Optional[IntegAlg]
495         :type integ_key: str
496         :type tunnel_src: str
497         :type tunnel_dst: str
498         """
499         if isinstance(crypto_key, str):
500             crypto_key = crypto_key.encode(encoding=u"utf-8")
501         if isinstance(integ_key, str):
502             integ_key = integ_key.encode(encoding=u"utf-8")
503         if tunnel_src and tunnel_dst:
504             src_addr = ip_address(tunnel_src)
505             dst_addr = ip_address(tunnel_dst)
506         else:
507             src_addr = u""
508             dst_addr = u""
509
510         addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
511             else 1 << (32 - 24)
512
513         if int(n_entries) > 10:
514             tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
515
516             with open(tmp_filename, 'w') as tmp_file:
517                 for i in range(n_entries):
518                     integ = f"integ-alg {integ_alg.alg_name} " \
519                         f"integ-key {integ_key.hex()}" \
520                         if integ_alg else u""
521                     tunnel = f"tunnel src {src_addr + i * addr_incr} " \
522                         f"tunnel dst {dst_addr + i * addr_incr}" \
523                         if tunnel_src and tunnel_dst else u""
524                     conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
525                         f"crypto-alg {crypto_alg.alg_name} " \
526                         f"crypto-key {crypto_key.hex()} " \
527                         f"{integ} {tunnel}\n"
528                     tmp_file.write(conf)
529             vat = VatExecutor()
530             vat.execute_script(
531                 tmp_filename, node, timeout=300, json_out=False,
532                 copy_on_execute=True
533             )
534             os.remove(tmp_filename)
535             return
536
537         ckey = dict(
538             length=len(crypto_key),
539             data=crypto_key
540         )
541         ikey = dict(
542             length=len(integ_key),
543             data=integ_key if integ_key else 0
544         )
545
546         flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
547         if tunnel_src and tunnel_dst:
548             flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
549             if src_addr.version == 6:
550                 flags = flags | int(
551                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
552                 )
553
554         cmd = u"ipsec_sad_entry_add_del_v2"
555         err_msg = f"Failed to add Security Association Database entry " \
556             f"on host {node[u'host']}"
557
558         sad_entry = dict(
559             sad_id=int(sad_id),
560             spi=int(spi),
561             crypto_algorithm=crypto_alg.alg_int_repr,
562             crypto_key=ckey,
563             integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
564             integrity_key=ikey,
565             flags=flags,
566             tunnel_src=str(src_addr),
567             tunnel_dst=str(dst_addr),
568             tunnel_flags=int(
569                 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
570             ),
571             dscp=int(IpDscp.IP_API_DSCP_CS0),
572             protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
573             udp_src_port=4500,  # default value in api
574             udp_dst_port=4500  # default value in api
575         )
576         args = dict(
577             is_add=True,
578             entry=sad_entry
579         )
580         with PapiSocketExecutor(node) as papi_exec:
581             for i in range(n_entries):
582                 args[u"entry"][u"sad_id"] = int(sad_id) + i
583                 args[u"entry"][u"spi"] = int(spi) + i
584                 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
585                     if tunnel_src and tunnel_dst else src_addr
586                 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
587                     if tunnel_src and tunnel_dst else dst_addr
588                 history = bool(not 1 < i < n_entries - 2)
589                 papi_exec.add(cmd, history=history, **args)
590             papi_exec.get_replies(err_msg)
591
592     @staticmethod
593     def vpp_ipsec_set_ip_route(
594             node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
595             raddr_range, dst_mac=None):
596         """Set IP address and route on interface.
597
598         :param node: VPP node to add config on.
599         :param n_tunnels: Number of tunnels to create.
600         :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
601         :param traffic_addr: Traffic destination IP address to route.
602         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
603         :param interface: Interface key on node 1.
604         :param raddr_range: Mask specifying range of Policy selector Remote IP
605             addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
606             in case of IPv6.
607         :param dst_mac: The MAC address of destination tunnels.
608         :type node: dict
609         :type n_tunnels: int
610         :type tunnel_src: str
611         :type traffic_addr: str
612         :type tunnel_dst: str
613         :type interface: str
614         :type raddr_range: int
615         :type dst_mac: str
616         """
617         tunnel_src = ip_address(tunnel_src)
618         tunnel_dst = ip_address(tunnel_dst)
619         traffic_addr = ip_address(traffic_addr)
620         addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
621             else 1 << (32 - raddr_range)
622
623         if int(n_tunnels) > 10:
624             tmp_filename = u"/tmp/ipsec_set_ip.script"
625
626             with open(tmp_filename, 'w') as tmp_file:
627                 if_name = Topology.get_interface_name(node, interface)
628                 for i in range(n_tunnels):
629                     conf = f"exec set interface ip address {if_name} " \
630                         f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
631                         f"exec ip route add {traffic_addr + i}/" \
632                         f"{128 if traffic_addr.version == 6 else 32} " \
633                         f"via {tunnel_dst + i * addr_incr} {if_name}\n"
634                     if dst_mac:
635                         conf = f"{conf}exec set ip neighbor {if_name} " \
636                                f"{tunnel_dst + i * addr_incr} {dst_mac}\n"
637                     tmp_file.write(conf)
638
639             VatExecutor().execute_script(
640                 tmp_filename, node, timeout=300, json_out=False,
641                 copy_on_execute=True
642             )
643             os.remove(tmp_filename)
644             return
645
646         cmd1 = u"sw_interface_add_del_address"
647         args1 = dict(
648             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
649             is_add=True,
650             del_all=False,
651             prefix=None
652         )
653         cmd2 = u"ip_route_add_del"
654         args2 = dict(
655             is_add=1,
656             is_multipath=0,
657             route=None
658         )
659         cmd3 = u"ip_neighbor_add_del"
660         args3 = dict(
661             is_add=True,
662             neighbor=dict(
663                 sw_if_index=Topology.get_interface_sw_index(node, interface),
664                 flags=0,
665                 mac_address=str(dst_mac),
666                 ip_address=None
667             )
668         )
669         err_msg = f"Failed to configure IP addresses, IP routes and " \
670             f"IP neighbor on interface {interface} on host {node[u'host']}" \
671             if dst_mac \
672             else f"Failed to configure IP addresses and IP routes " \
673                  f"on interface {interface} on host {node[u'host']}"
674
675         with PapiSocketExecutor(node) as papi_exec:
676             for i in range(n_tunnels):
677                 args1[u"prefix"] = IPUtil.create_prefix_object(
678                     tunnel_src + i * addr_incr, raddr_range
679                 )
680                 args2[u"route"] = IPUtil.compose_vpp_route_structure(
681                     node, traffic_addr + i,
682                     prefix_len=128 if traffic_addr.version == 6 else 32,
683                     interface=interface, gateway=tunnel_dst + i * addr_incr
684                 )
685                 history = bool(not 1 < i < n_tunnels - 2)
686                 papi_exec.add(cmd1, history=history, **args1).\
687                     add(cmd2, history=history, **args2)
688                 if dst_mac:
689                     args3[u"neighbor"][u"ip_address"] = ip_address(
690                         tunnel_dst + i * addr_incr
691                     )
692                     papi_exec.add(cmd3, history=history, **args3)
693             papi_exec.get_replies(err_msg)
694
695     @staticmethod
696     def vpp_ipsec_add_spd(node, spd_id):
697         """Create Security Policy Database on the VPP node.
698
699         :param node: VPP node to add SPD on.
700         :param spd_id: SPD ID.
701         :type node: dict
702         :type spd_id: int
703         """
704         cmd = u"ipsec_spd_add_del"
705         err_msg = f"Failed to add Security Policy Database " \
706             f"on host {node[u'host']}"
707         args = dict(
708             is_add=True,
709             spd_id=int(spd_id)
710         )
711         with PapiSocketExecutor(node) as papi_exec:
712             papi_exec.add(cmd, **args).get_reply(err_msg)
713
714     @staticmethod
715     def vpp_ipsec_spd_add_if(node, spd_id, interface):
716         """Add interface to the Security Policy Database.
717
718         :param node: VPP node.
719         :param spd_id: SPD ID to add interface on.
720         :param interface: Interface name or sw_if_index.
721         :type node: dict
722         :type spd_id: int
723         :type interface: str or int
724         """
725         cmd = u"ipsec_interface_add_del_spd"
726         err_msg = f"Failed to add interface {interface} to Security Policy " \
727             f"Database {spd_id} on host {node[u'host']}"
728         args = dict(
729             is_add=True,
730             sw_if_index=InterfaceUtil.get_interface_index(node, interface),
731             spd_id=int(spd_id)
732         )
733         with PapiSocketExecutor(node) as papi_exec:
734             papi_exec.add(cmd, **args).get_reply(err_msg)
735
736     @staticmethod
737     def vpp_ipsec_create_spds_match_nth_entry(
738             node, dir1_interface, dir2_interface, entry_amount,
739             local_addr_range, remote_addr_range, action=PolicyAction.BYPASS,
740             inbound=False, bidirectional=True):
741         """Create one matching SPD entry for inbound or outbound traffic on
742         a DUT for each traffic direction and also create entry_amount - 1
743         non-matching SPD entries. Create a Security Policy Database on each
744         outbound interface where these entries will be configured.
745         The matching SPD entry will have the lowest priority, input action and
746         will be configured to match the IP flow. The non-matching entries will
747         be the same, except with higher priority and non-matching IP flows.
748
749         Action Protect is currently not supported.
750
751         :param node: VPP node to configured the SPDs and their entries.
752         :param dir1_interface: The interface in direction 1 where the entries
753             will be checked.
754         :param dir2_interface: The interface in direction 2 where the entries
755             will be checked.
756         :param entry_amount: The number of SPD entries to configure. If
757             entry_amount == 1, no non-matching entries will be configured.
758         :param local_addr_range: Matching local address range in direction 1
759             in format IP/prefix or IP/mask. If no mask is provided, it's
760             considered to be /32.
761         :param remote_addr_range: Matching remote address range in
762             direction 1 in format IP/prefix or IP/mask. If no mask is
763             provided, it's considered to be /32.
764         :param action: Policy action.
765         :param inbound: If True policy is for inbound traffic, otherwise
766             outbound.
767         :param bidirectional: When True, will create SPDs in both directions
768             of traffic. When False, only in one direction.
769         :type node: dict
770         :type dir1_interface: Union[string, int]
771         :type dir2_interface: Union[string, int]
772         :type entry_amount: int
773         :type local_addr_range:
774             Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
775         :type remote_addr_range:
776             Union[string, ipaddress.IPv4Address, ipaddress.IPv6Address]
777         :type action: IPsecUtil.PolicyAction
778         :type inbound: bool
779         :type bidirectional: bool
780         :raises NotImplemented: When the action is PolicyAction.PROTECT.
781         """
782
783         if action == PolicyAction.PROTECT:
784             raise NotImplemented('Policy action PROTECT is not supported.')
785
786         spd_id_dir1 = 1
787         spd_id_dir2 = 2
788         matching_priority = 1
789
790         IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir1)
791         IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir1, dir1_interface)
792         # matching entry direction 1
793         IPsecUtil.vpp_ipsec_add_spd_entry(
794             node, spd_id_dir1, matching_priority, action,
795             inbound=inbound, laddr_range=local_addr_range,
796             raddr_range=remote_addr_range
797         )
798
799         if bidirectional:
800             IPsecUtil.vpp_ipsec_add_spd(node, spd_id_dir2)
801             IPsecUtil.vpp_ipsec_spd_add_if(node, spd_id_dir2, dir2_interface)
802
803             # matching entry direction 2, the address ranges are switched
804             IPsecUtil.vpp_ipsec_add_spd_entry(
805                 node, spd_id_dir2, matching_priority, action,
806                 inbound=inbound, laddr_range=remote_addr_range,
807                 raddr_range=local_addr_range
808             )
809
810         # non-matching entries
811         no_match_entry_amount = entry_amount - 1
812         if no_match_entry_amount > 0:
813             # create a NetworkIncrement representation of the network,
814             # then skip the matching network
815             no_match_local_addr_range = NetworkIncrement(
816                 ip_network(local_addr_range)
817             )
818             next(no_match_local_addr_range)
819
820             no_match_remote_addr_range = NetworkIncrement(
821                 ip_network(remote_addr_range)
822             )
823             next(no_match_remote_addr_range)
824
825             # non-matching entries direction 1
826             IPsecUtil.vpp_ipsec_add_spd_entries(
827                 node, no_match_entry_amount, spd_id_dir1,
828                 ObjIncrement(matching_priority + 1, 1), action,
829                 inbound=inbound, laddr_range=no_match_local_addr_range,
830                 raddr_range=no_match_remote_addr_range
831             )
832
833             if bidirectional:
834                 # reset the networks so that we're using a unified config
835                 # the address ranges are switched
836                 no_match_remote_addr_range = NetworkIncrement(
837                     ip_network(local_addr_range)
838                 )
839                 next(no_match_remote_addr_range)
840
841                 no_match_local_addr_range = NetworkIncrement(
842                     ip_network(remote_addr_range)
843                 )
844                 next(no_match_local_addr_range)
845                 # non-matching entries direction 2
846                 IPsecUtil.vpp_ipsec_add_spd_entries(
847                     node, no_match_entry_amount, spd_id_dir2,
848                     ObjIncrement(matching_priority + 1, 1), action,
849                     inbound=inbound, laddr_range=no_match_local_addr_range,
850                     raddr_range=no_match_remote_addr_range
851                 )
852
853         IPsecUtil.vpp_ipsec_show_all(node)
854
855     @staticmethod
856     def vpp_ipsec_add_spd_entry(
857             node, spd_id, priority, action, inbound=True, sa_id=None,
858             proto=None, laddr_range=None, raddr_range=None, lport_range=None,
859             rport_range=None, is_ipv6=False):
860         """Create Security Policy Database entry on the VPP node.
861
862         :param node: VPP node to add SPD entry on.
863         :param spd_id: SPD ID to add entry on.
864         :param priority: SPD entry priority, higher number = higher priority.
865         :param action: Policy action.
866         :param inbound: If True policy is for inbound traffic, otherwise
867             outbound.
868         :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
869         :param proto: Policy selector next layer protocol number.
870         :param laddr_range: Policy selector local IPv4 or IPv6 address range
871             in format IP/prefix or IP/mask. If no mask is provided,
872             it's considered to be /32.
873         :param raddr_range: Policy selector remote IPv4 or IPv6 address range
874             in format IP/prefix or IP/mask. If no mask is provided,
875             it's considered to be /32.
876         :param lport_range: Policy selector local TCP/UDP port range in format
877             <port_start>-<port_end>.
878         :param rport_range: Policy selector remote TCP/UDP port range in format
879             <port_start>-<port_end>.
880         :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
881             not defined so it will default to address ::/0, otherwise False.
882         :type node: dict
883         :type spd_id: int
884         :type priority: int
885         :type action: IPsecUtil.PolicyAction
886         :type inbound: bool
887         :type sa_id: int
888         :type proto: int
889         :type laddr_range: string
890         :type raddr_range: string
891         :type lport_range: string
892         :type rport_range: string
893         :type is_ipv6: bool
894         """
895         if laddr_range is None:
896             laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
897
898         if raddr_range is None:
899             raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
900
901         local_net = ip_network(laddr_range, strict=False)
902         remote_net = ip_network(raddr_range, strict=False)
903
904         cmd = u"ipsec_spd_entry_add_del"
905         err_msg = f"Failed to add entry to Security Policy Database " \
906                   f"{spd_id} on host {node[u'host']}"
907
908         spd_entry = dict(
909             spd_id=int(spd_id),
910             priority=int(priority),
911             is_outbound=not inbound,
912             sa_id=int(sa_id) if sa_id else 0,
913             policy=int(action),
914             protocol=int(proto) if proto else 0,
915             remote_address_start=IPAddress.create_ip_address_object(
916                 remote_net.network_address
917             ),
918             remote_address_stop=IPAddress.create_ip_address_object(
919                 remote_net.broadcast_address
920             ),
921             local_address_start=IPAddress.create_ip_address_object(
922                 local_net.network_address
923             ),
924             local_address_stop=IPAddress.create_ip_address_object(
925                 local_net.broadcast_address
926             ),
927             remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
928             else 0,
929             remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
930             else 65535,
931             local_port_start=int(lport_range.split(u"-")[0]) if lport_range
932             else 0,
933             local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
934             else 65535
935         )
936         args = dict(
937             is_add=True,
938             entry=spd_entry
939         )
940         with PapiSocketExecutor(node) as papi_exec:
941             papi_exec.add(cmd, **args).get_reply(err_msg)
942
943     @staticmethod
944     def vpp_ipsec_add_spd_entries(
945             node, n_entries, spd_id, priority, action, inbound, sa_id=None,
946             proto=None, laddr_range=None, raddr_range=None, lport_range=None,
947             rport_range=None, is_ipv6=False):
948         """Create multiple Security Policy Database entries on the VPP node.
949
950         :param node: VPP node to add SPD entries on.
951         :param n_entries: Number of SPD entries to be added.
952         :param spd_id: SPD ID to add entries on.
953         :param priority: SPD entries priority, higher number = higher priority.
954         :param action: Policy action.
955         :param inbound: If True policy is for inbound traffic, otherwise
956             outbound.
957         :param sa_id: SAD entry ID for action PolicyAction.PROTECT.
958         :param proto: Policy selector next layer protocol number.
959         :param laddr_range: Policy selector local IPv4 or IPv6 address range
960             in format IP/prefix or IP/mask. If no mask is provided,
961             it's considered to be /32.
962         :param raddr_range: Policy selector remote IPv4 or IPv6 address range
963             in format IP/prefix or IP/mask. If no mask is provided,
964             it's considered to be /32.
965         :param lport_range: Policy selector local TCP/UDP port range in format
966             <port_start>-<port_end>.
967         :param rport_range: Policy selector remote TCP/UDP port range in format
968             <port_start>-<port_end>.
969         :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
970             not defined so it will default to address ::/0, otherwise False.
971         :type node: dict
972         :type n_entries: int
973         :type spd_id: int
974         :type priority: IPsecUtil.ObjIncrement
975         :type action: IPsecUtil.PolicyAction
976         :type inbound: bool
977         :type sa_id: IPsecUtil.ObjIncrement
978         :type proto: int
979         :type laddr_range: IPsecUtil.NetworkIncrement
980         :type raddr_range: IPsecUtil.NetworkIncrement
981         :type lport_range: string
982         :type rport_range: string
983         :type is_ipv6: bool
984         """
985         if laddr_range is None:
986             laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
987             laddr_range = NetworkIncrement(ip_network(laddr_range), 0)
988
989         if raddr_range is None:
990             raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
991             raddr_range = NetworkIncrement(ip_network(raddr_range), 0)
992
993         lport_range_start = 0
994         lport_range_stop = 65535
995         if lport_range:
996             lport_range_start, lport_range_stop = lport_range.split('-')
997
998         rport_range_start = 0
999         rport_range_stop = 65535
1000         if rport_range:
1001             rport_range_start, rport_range_stop = rport_range.split('-')
1002
1003         if int(n_entries) > 10:
1004             tmp_filename = f"/tmp/ipsec_spd_{spd_id}_add_del_entry.script"
1005
1006             with open(tmp_filename, 'w') as tmp_file:
1007                 for i in range(n_entries):
1008                     direction = u'inbound' if inbound else u'outbound'
1009                     sa = f' sa {sa_id.inc_fmt()}' if sa_id is not None else ''
1010                     protocol = f' protocol {protocol}' if proto else ''
1011                     local_port_range = f' local-port-range ' \
1012                         f'{lport_range_start} - {lport_range_stop}' \
1013                         if lport_range else ''
1014                     remote_port_range = f' remote-port-range ' \
1015                         f'{rport_range_start} - {rport_range_stop}' \
1016                         if rport_range else ''
1017
1018                     spd_cfg = f"exec ipsec policy add spd {spd_id} " \
1019                         f"priority {priority.inc_fmt()} {direction}" \
1020                         f"{protocol} action {action}{sa} " \
1021                         f"local-ip-range {laddr_range.inc_fmt()} " \
1022                         f"remote-ip-range {raddr_range.inc_fmt()}" \
1023                         f"{local_port_range}{remote_port_range}\n"
1024
1025                     tmp_file.write(spd_cfg)
1026
1027             VatExecutor().execute_script(
1028                 tmp_filename, node, timeout=300, json_out=False,
1029                 copy_on_execute=True
1030             )
1031             os.remove(tmp_filename)
1032             return
1033
1034         for i in range(n_entries):
1035             IPsecUtil.vpp_ipsec_add_spd_entry(
1036                 node, spd_id, next(priority), action, inbound,
1037                 next(sa_id) if sa_id is not None else sa_id,
1038                 proto, next(laddr_range), next(raddr_range), lport_range,
1039                 rport_range, is_ipv6
1040             )
1041
1042     @staticmethod
1043     def _ipsec_create_tunnel_interfaces_dut1_vat(
1044             nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1045             raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1046         """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
1047
1048         Generate random keys and return them (so DUT2 or TG can decrypt).
1049
1050         :param nodes: VPP nodes to create tunnel interfaces.
1051         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1052             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1053             IPv4/IPv6 address (ip2).
1054         :param if1_key: VPP node 1 interface key from topology file.
1055         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1056             interface key from topology file.
1057         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1058         :param crypto_alg: The encryption algorithm name.
1059         :param integ_alg: The integrity algorithm name.
1060         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1061             first tunnel in direction node2->node1.
1062         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1063         :param addr_incr: IP / IPv6 address incremental step.
1064         :param existing_tunnels: Number of tunnel interfaces before creation.
1065             Useful mainly for reconf tests. Default 0.
1066         :type nodes: dict
1067         :type tun_ips: dict
1068         :type if1_key: str
1069         :type if2_key: str
1070         :type n_tunnels: int
1071         :type crypto_alg: CryptoAlg
1072         :type integ_alg: Optional[IntegAlg]
1073         :type raddr_ip2: IPv4Address or IPv6Address
1074         :type addr_incr: int
1075         :type spi_d: dict
1076         :type existing_tunnels: int
1077         :returns: Generated ckeys and ikeys.
1078         :rtype: List[bytes], List[bytes]
1079         """
1080         tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
1081         if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
1082
1083         ckeys = [bytes()] * existing_tunnels
1084         ikeys = [bytes()] * existing_tunnels
1085
1086         vat = VatExecutor()
1087         with open(tmp_fn1, u"w") as tmp_f1:
1088             rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
1089                 if u"DUT2" in nodes.keys() \
1090                 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
1091             if not existing_tunnels:
1092                 tmp_f1.write(
1093                     f"exec create loopback interface\n"
1094                     f"exec set interface state loop0 up\n"
1095                     f"exec set interface ip address {if1_n} "
1096                     f"{tun_ips[u'ip2'] - 1}/"
1097                     f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
1098                     f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
1099                     f"static\n"
1100                 )
1101             for i in range(existing_tunnels, n_tunnels):
1102                 ckeys.append(
1103                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1104                 )
1105                 ikeys.append(
1106                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1107                 )
1108                 if integ_alg:
1109                     integ = f"integ-alg {integ_alg.alg_name} " \
1110                         f"integ-key {ikeys[i].hex()} "
1111                 else:
1112                     integ = u""
1113                 tmp_f1.write(
1114                     f"exec set interface ip address loop0 "
1115                     f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
1116                     f"exec create ipip tunnel "
1117                     f"src {tun_ips[u'ip1'] + i * addr_incr} "
1118                     f"dst {tun_ips[u'ip2']} "
1119                     f"p2p\n"
1120                     f"exec ipsec sa add {i} "
1121                     f"spi {spi_d[u'spi_1'] + i} "
1122                     f"crypto-alg {crypto_alg.alg_name} "
1123                     f"crypto-key {ckeys[i].hex()} "
1124                     f"{integ}"
1125                     f"esp\n"
1126                     f"exec ipsec sa add {100000 + i} "
1127                     f"spi {spi_d[u'spi_2'] + i} "
1128                     f"crypto-alg {crypto_alg.alg_name} "
1129                     f"crypto-key {ckeys[i].hex()} "
1130                     f"{integ}"
1131                     f"esp\n"
1132                     f"exec ipsec tunnel protect ipip{i} "
1133                     f"sa-out {i} "
1134                     f"sa-in {100000 + i} "
1135                     f"add\n"
1136                 )
1137         vat.execute_script(
1138             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
1139             copy_on_execute=True,
1140             history=bool(n_tunnels < 100)
1141         )
1142         os.remove(tmp_fn1)
1143
1144         with open(tmp_fn1, 'w') as tmp_f1:
1145             for i in range(existing_tunnels, n_tunnels):
1146                 tmp_f1.write(
1147                     f"exec set interface unnumbered ipip{i} use {if1_n}\n"
1148                     f"exec set interface state ipip{i} up\n"
1149                     f"exec ip route add "
1150                     f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
1151                     f"via ipip{i}\n"
1152                 )
1153         vat.execute_script(
1154             tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
1155             copy_on_execute=True,
1156             history=bool(n_tunnels < 100)
1157         )
1158         os.remove(tmp_fn1)
1159
1160         return ckeys, ikeys
1161
1162     @staticmethod
1163     def _ipsec_create_tunnel_interfaces_dut2_vat(
1164             nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1165             ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1166         """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
1167
1168         This method accesses keys generated by DUT1 method
1169         and does not return anything.
1170
1171         :param nodes: VPP nodes to create tunnel interfaces.
1172         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1173             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1174             IPv4/IPv6 address (ip2).
1175         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1176             interface key from topology file.
1177         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1178         :param crypto_alg: The encryption algorithm name.
1179         :param ckeys: List of encryption keys.
1180         :param integ_alg: The integrity algorithm name.
1181         :param ikeys: List of integrity keys.
1182         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1183         :param addr_incr: IP / IPv6 address incremental step.
1184         :param existing_tunnels: Number of tunnel interfaces before creation.
1185             Useful mainly for reconf tests. Default 0.
1186         :type nodes: dict
1187         :type tun_ips: dict
1188         :type if2_key: str
1189         :type n_tunnels: int
1190         :type crypto_alg: CryptoAlg
1191         :type ckeys: Sequence[bytes]
1192         :type integ_alg: Optional[IntegAlg]
1193         :type ikeys: Sequence[bytes]
1194         :type addr_incr: int
1195         :type spi_d: dict
1196         :type existing_tunnels: int
1197         """
1198         tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
1199         if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
1200
1201         vat = VatExecutor()
1202         with open(tmp_fn2, 'w') as tmp_f2:
1203             if not existing_tunnels:
1204                 tmp_f2.write(
1205                     f"exec set interface ip address {if2_n}"
1206                     f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
1207                 )
1208             for i in range(existing_tunnels, n_tunnels):
1209                 if integ_alg:
1210                     integ = f"integ-alg {integ_alg.alg_name} " \
1211                         f"integ-key {ikeys[i].hex()} "
1212                 else:
1213                     integ = u""
1214                 tmp_f2.write(
1215                     f"exec create ipip tunnel "
1216                     f"src {tun_ips[u'ip2']} "
1217                     f"dst {tun_ips[u'ip1'] + i * addr_incr} "
1218                     f"p2p\n"
1219                     f"exec ipsec sa add {100000 + i} "
1220                     f"spi {spi_d[u'spi_2'] + i} "
1221                     f"crypto-alg {crypto_alg.alg_name} "
1222                     f"crypto-key {ckeys[i].hex()} "
1223                     f"{integ}"
1224                     f"esp\n"
1225                     f"exec ipsec sa add {i} "
1226                     f"spi {spi_d[u'spi_1'] + i} "
1227                     f"crypto-alg {crypto_alg.alg_name} "
1228                     f"crypto-key {ckeys[i].hex()} "
1229                     f"{integ}"
1230                     f"esp\n"
1231                     f"exec ipsec tunnel protect ipip{i} "
1232                     f"sa-out {100000 + i} "
1233                     f"sa-in {i} "
1234                     f"add\n"
1235                 )
1236         vat.execute_script(
1237             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1238             copy_on_execute=True,
1239             history=bool(n_tunnels < 100)
1240         )
1241         os.remove(tmp_fn2)
1242
1243         with open(tmp_fn2, 'w') as tmp_f2:
1244             if not existing_tunnels:
1245                 tmp_f2.write(
1246                     f"exec ip route add {tun_ips[u'ip1']}/8 "
1247                     f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
1248                 )
1249             for i in range(existing_tunnels, n_tunnels):
1250                 tmp_f2.write(
1251                     f"exec set interface unnumbered ipip{i} use {if2_n}\n"
1252                     f"exec set interface state ipip{i} up\n"
1253                     f"exec ip route add "
1254                     f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
1255                     f"via ipip{i}\n"
1256                 )
1257         vat.execute_script(
1258             tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1259             copy_on_execute=True,
1260             history=bool(n_tunnels < 100)
1261         )
1262         os.remove(tmp_fn2)
1263
1264     @staticmethod
1265     def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1266         """Create loopback interface and set IP address on VPP node 1 interface
1267         using PAPI.
1268
1269         :param nodes: VPP nodes to create tunnel interfaces.
1270         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1271             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1272             IPv4/IPv6 address (ip2).
1273         :param if1_key: VPP node 1 interface key from topology file.
1274         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1275             interface key from topology file.
1276         :type nodes: dict
1277         :type tun_ips: dict
1278         :type if1_key: str
1279         :type if2_key: str
1280         """
1281         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1282             # Create loopback interface on DUT1, set it to up state
1283             cmd = u"create_loopback_instance"
1284             args = dict(
1285                 mac_address=0,
1286                 is_specified=False,
1287                 user_instance=0,
1288             )
1289             err_msg = f"Failed to create loopback interface " \
1290                 f"on host {nodes[u'DUT1'][u'host']}"
1291             loop_sw_if_idx = papi_exec.add(cmd, **args). \
1292                 get_sw_if_index(err_msg)
1293             cmd = u"sw_interface_set_flags"
1294             args = dict(
1295                 sw_if_index=loop_sw_if_idx,
1296                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1297             )
1298             err_msg = f"Failed to set loopback interface state up " \
1299                 f"on host {nodes[u'DUT1'][u'host']}"
1300             papi_exec.add(cmd, **args).get_reply(err_msg)
1301             # Set IP address on VPP node 1 interface
1302             cmd = u"sw_interface_add_del_address"
1303             args = dict(
1304                 sw_if_index=InterfaceUtil.get_interface_index(
1305                     nodes[u"DUT1"], if1_key
1306                 ),
1307                 is_add=True,
1308                 del_all=False,
1309                 prefix=IPUtil.create_prefix_object(
1310                     tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1311                     else 24
1312                 )
1313             )
1314             err_msg = f"Failed to set IP address on interface {if1_key} " \
1315                 f"on host {nodes[u'DUT1'][u'host']}"
1316             papi_exec.add(cmd, **args).get_reply(err_msg)
1317             cmd2 = u"ip_neighbor_add_del"
1318             args2 = dict(
1319                 is_add=1,
1320                 neighbor=dict(
1321                     sw_if_index=Topology.get_interface_sw_index(
1322                         nodes[u"DUT1"], if1_key
1323                     ),
1324                     flags=1,
1325                     mac_address=str(
1326                         Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1327                         if u"DUT2" in nodes.keys()
1328                         else Topology.get_interface_mac(
1329                             nodes[u"TG"], if2_key
1330                         )
1331                     ),
1332                     ip_address=tun_ips[u"ip2"].compressed
1333                 )
1334             )
1335             err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1336             papi_exec.add(cmd2, **args2).get_reply(err_msg)
1337
1338             return loop_sw_if_idx
1339
1340     @staticmethod
1341     def _ipsec_create_tunnel_interfaces_dut1_papi(
1342             nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1343             raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1344         """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1345
1346         Generate random keys and return them (so DUT2 or TG can decrypt).
1347
1348         :param nodes: VPP nodes to create tunnel interfaces.
1349         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1350             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1351             IPv4/IPv6 address (ip2).
1352         :param if1_key: VPP node 1 interface key from topology file.
1353         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1354             interface key from topology file.
1355         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1356         :param crypto_alg: The encryption algorithm name.
1357         :param integ_alg: The integrity algorithm name.
1358         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1359             first tunnel in direction node2->node1.
1360         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1361         :param addr_incr: IP / IPv6 address incremental step.
1362         :param existing_tunnels: Number of tunnel interfaces before creation.
1363             Useful mainly for reconf tests. Default 0.
1364         :type nodes: dict
1365         :type tun_ips: dict
1366         :type if1_key: str
1367         :type if2_key: str
1368         :type n_tunnels: int
1369         :type crypto_alg: CryptoAlg
1370         :type integ_alg: Optional[IntegAlg]
1371         :type raddr_ip2: IPv4Address or IPv6Address
1372         :type addr_incr: int
1373         :type spi_d: dict
1374         :type existing_tunnels: int
1375         :returns: Generated ckeys and ikeys.
1376         :rtype: List[bytes], List[bytes]
1377         """
1378         if not existing_tunnels:
1379             loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1380                 nodes, tun_ips, if1_key, if2_key
1381             )
1382         else:
1383             loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1384                 nodes[u"DUT1"], u"loop0"
1385             )
1386         with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1387             # Configure IP addresses on loop0 interface
1388             cmd = u"sw_interface_add_del_address"
1389             args = dict(
1390                 sw_if_index=loop_sw_if_idx,
1391                 is_add=True,
1392                 del_all=False,
1393                 prefix=None
1394             )
1395             for i in range(existing_tunnels, n_tunnels):
1396                 args[u"prefix"] = IPUtil.create_prefix_object(
1397                     tun_ips[u"ip1"] + i * addr_incr,
1398                     128 if tun_ips[u"ip1"].version == 6 else 32
1399                 )
1400                 papi_exec.add(
1401                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1402                 )
1403             # Configure IPIP tunnel interfaces
1404             cmd = u"ipip_add_tunnel"
1405             ipip_tunnel = dict(
1406                 instance=Constants.BITWISE_NON_ZERO,
1407                 src=None,
1408                 dst=None,
1409                 table_id=0,
1410                 flags=int(
1411                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1412                 ),
1413                 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1414                 dscp=int(IpDscp.IP_API_DSCP_CS0)
1415             )
1416             args = dict(
1417                 tunnel=ipip_tunnel
1418             )
1419             ipip_tunnels = [None] * existing_tunnels
1420             for i in range(existing_tunnels, n_tunnels):
1421                 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1422                     tun_ips[u"ip1"] + i * addr_incr
1423                 )
1424                 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1425                     tun_ips[u"ip2"]
1426                 )
1427                 papi_exec.add(
1428                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1429                 )
1430             err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1431                 f" {nodes[u'DUT1'][u'host']}"
1432             ipip_tunnels.extend(
1433                 [
1434                     reply[u"sw_if_index"]
1435                     for reply in papi_exec.get_replies(err_msg)
1436                     if u"sw_if_index" in reply
1437                 ]
1438             )
1439             # Configure IPSec SAD entries
1440             ckeys = [bytes()] * existing_tunnels
1441             ikeys = [bytes()] * existing_tunnels
1442             cmd = u"ipsec_sad_entry_add_del_v2"
1443             c_key = dict(
1444                 length=0,
1445                 data=None
1446             )
1447             i_key = dict(
1448                 length=0,
1449                 data=None
1450             )
1451             sad_entry = dict(
1452                 sad_id=None,
1453                 spi=None,
1454                 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1455                 crypto_algorithm=crypto_alg.alg_int_repr,
1456                 crypto_key=c_key,
1457                 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1458                 integrity_key=i_key,
1459                 flags=None,
1460                 tunnel_src=0,
1461                 tunnel_dst=0,
1462                 tunnel_flags=int(
1463                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1464                 ),
1465                 dscp=int(IpDscp.IP_API_DSCP_CS0),
1466                 table_id=0,
1467                 salt=0,
1468                 udp_src_port=IPSEC_UDP_PORT_NONE,
1469                 udp_dst_port=IPSEC_UDP_PORT_NONE
1470             )
1471             args = dict(
1472                 is_add=True,
1473                 entry=sad_entry
1474             )
1475             for i in range(existing_tunnels, n_tunnels):
1476                 ckeys.append(
1477                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1478                 )
1479                 ikeys.append(
1480                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1481                 )
1482                 # SAD entry for outband / tx path
1483                 args[u"entry"][u"sad_id"] = i
1484                 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1485
1486                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1487                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1488                 if integ_alg:
1489                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1490                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1491                 args[u"entry"][u"flags"] = int(
1492                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1493                 )
1494                 papi_exec.add(
1495                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1496                 )
1497                 # SAD entry for inband / rx path
1498                 args[u"entry"][u"sad_id"] = 100000 + i
1499                 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1500
1501                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1502                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1503                 if integ_alg:
1504                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1505                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1506                 args[u"entry"][u"flags"] = int(
1507                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1508                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1509                 )
1510                 papi_exec.add(
1511                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1512                 )
1513             err_msg = f"Failed to add IPsec SAD entries on host" \
1514                 f" {nodes[u'DUT1'][u'host']}"
1515             papi_exec.get_replies(err_msg)
1516             # Add protection for tunnels with IPSEC
1517             cmd = u"ipsec_tunnel_protect_update"
1518             n_hop = dict(
1519                 address=0,
1520                 via_label=MPLS_LABEL_INVALID,
1521                 obj_id=Constants.BITWISE_NON_ZERO
1522             )
1523             ipsec_tunnel_protect = dict(
1524                 sw_if_index=None,
1525                 nh=n_hop,
1526                 sa_out=None,
1527                 n_sa_in=1,
1528                 sa_in=None
1529             )
1530             args = dict(
1531                 tunnel=ipsec_tunnel_protect
1532             )
1533             for i in range(existing_tunnels, n_tunnels):
1534                 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1535                 args[u"tunnel"][u"sa_out"] = i
1536                 args[u"tunnel"][u"sa_in"] = [100000 + i]
1537                 papi_exec.add(
1538                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1539                 )
1540             err_msg = f"Failed to add protection for tunnels with IPSEC " \
1541                 f"on host {nodes[u'DUT1'][u'host']}"
1542             papi_exec.get_replies(err_msg)
1543
1544             # Configure unnumbered interfaces
1545             cmd = u"sw_interface_set_unnumbered"
1546             args = dict(
1547                 is_add=True,
1548                 sw_if_index=InterfaceUtil.get_interface_index(
1549                     nodes[u"DUT1"], if1_key
1550                 ),
1551                 unnumbered_sw_if_index=0
1552             )
1553             for i in range(existing_tunnels, n_tunnels):
1554                 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1555                 papi_exec.add(
1556                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1557                 )
1558             # Set interfaces up
1559             cmd = u"sw_interface_set_flags"
1560             args = dict(
1561                 sw_if_index=0,
1562                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1563             )
1564             for i in range(existing_tunnels, n_tunnels):
1565                 args[u"sw_if_index"] = ipip_tunnels[i]
1566                 papi_exec.add(
1567                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1568                 )
1569             # Configure IP routes
1570             cmd = u"ip_route_add_del"
1571             args = dict(
1572                 is_add=1,
1573                 is_multipath=0,
1574                 route=None
1575             )
1576             for i in range(existing_tunnels, n_tunnels):
1577                 args[u"route"] = IPUtil.compose_vpp_route_structure(
1578                     nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1579                     prefix_len=128 if raddr_ip2.version == 6 else 32,
1580                     interface=ipip_tunnels[i]
1581                 )
1582                 papi_exec.add(
1583                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1584                 )
1585             err_msg = f"Failed to add IP routes on host " \
1586                 f"{nodes[u'DUT1'][u'host']}"
1587             papi_exec.get_replies(err_msg)
1588
1589         return ckeys, ikeys
1590
1591     @staticmethod
1592     def _ipsec_create_tunnel_interfaces_dut2_papi(
1593             nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1594             ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1595         """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1596
1597         This method accesses keys generated by DUT1 method
1598         and does not return anything.
1599
1600         :param nodes: VPP nodes to create tunnel interfaces.
1601         :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1602             IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1603             IPv4/IPv6 address (ip2).
1604         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1605             interface key from topology file.
1606         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1607         :param crypto_alg: The encryption algorithm name.
1608         :param ckeys: List of encryption keys.
1609         :param integ_alg: The integrity algorithm name.
1610         :param ikeys: List of integrity keys.
1611         :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1612         :param addr_incr: IP / IPv6 address incremental step.
1613         :param existing_tunnels: Number of tunnel interfaces before creation.
1614             Useful mainly for reconf tests. Default 0.
1615         :type nodes: dict
1616         :type tun_ips: dict
1617         :type if2_key: str
1618         :type n_tunnels: int
1619         :type crypto_alg: CryptoAlg
1620         :type ckeys: Sequence[bytes]
1621         :type integ_alg: Optional[IntegAlg]
1622         :type ikeys: Sequence[bytes]
1623         :type addr_incr: int
1624         :type spi_d: dict
1625         :type existing_tunnels: int
1626         """
1627         with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1628             if not existing_tunnels:
1629                 # Set IP address on VPP node 2 interface
1630                 cmd = u"sw_interface_add_del_address"
1631                 args = dict(
1632                     sw_if_index=InterfaceUtil.get_interface_index(
1633                         nodes[u"DUT2"], if2_key
1634                     ),
1635                     is_add=True,
1636                     del_all=False,
1637                     prefix=IPUtil.create_prefix_object(
1638                         tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1639                         else 24
1640                     )
1641                 )
1642                 err_msg = f"Failed to set IP address on interface {if2_key} " \
1643                     f"on host {nodes[u'DUT2'][u'host']}"
1644                 papi_exec.add(cmd, **args).get_reply(err_msg)
1645             # Configure IPIP tunnel interfaces
1646             cmd = u"ipip_add_tunnel"
1647             ipip_tunnel = dict(
1648                 instance=Constants.BITWISE_NON_ZERO,
1649                 src=None,
1650                 dst=None,
1651                 table_id=0,
1652                 flags=int(
1653                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1654                 ),
1655                 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1656                 dscp=int(IpDscp.IP_API_DSCP_CS0)
1657             )
1658             args = dict(
1659                 tunnel=ipip_tunnel
1660             )
1661             ipip_tunnels = [None] * existing_tunnels
1662             for i in range(existing_tunnels, n_tunnels):
1663                 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1664                     tun_ips[u"ip2"]
1665                 )
1666                 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1667                     tun_ips[u"ip1"] + i * addr_incr
1668                 )
1669                 papi_exec.add(
1670                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1671                 )
1672             err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1673                 f" {nodes[u'DUT2'][u'host']}"
1674             ipip_tunnels.extend(
1675                 [
1676                     reply[u"sw_if_index"]
1677                     for reply in papi_exec.get_replies(err_msg)
1678                     if u"sw_if_index" in reply
1679                 ]
1680             )
1681             # Configure IPSec SAD entries
1682             cmd = u"ipsec_sad_entry_add_del_v2"
1683             c_key = dict(
1684                 length=0,
1685                 data=None
1686             )
1687             i_key = dict(
1688                 length=0,
1689                 data=None
1690             )
1691             sad_entry = dict(
1692                 sad_id=None,
1693                 spi=None,
1694                 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1695
1696                 crypto_algorithm=crypto_alg.alg_int_repr,
1697                 crypto_key=c_key,
1698                 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1699                 integrity_key=i_key,
1700
1701                 flags=None,
1702                 tunnel_src=0,
1703                 tunnel_dst=0,
1704                 tunnel_flags=int(
1705                     TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1706                 ),
1707                 dscp=int(IpDscp.IP_API_DSCP_CS0),
1708                 table_id=0,
1709                 salt=0,
1710                 udp_src_port=IPSEC_UDP_PORT_NONE,
1711                 udp_dst_port=IPSEC_UDP_PORT_NONE
1712             )
1713             args = dict(
1714                 is_add=True,
1715                 entry=sad_entry
1716             )
1717             for i in range(existing_tunnels, n_tunnels):
1718                 ckeys.append(
1719                     gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1720                 )
1721                 ikeys.append(
1722                     gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1723                 )
1724                 # SAD entry for outband / tx path
1725                 args[u"entry"][u"sad_id"] = 100000 + i
1726                 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1727
1728                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1729                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1730                 if integ_alg:
1731                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1732                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1733                 args[u"entry"][u"flags"] = int(
1734                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1735                 )
1736                 papi_exec.add(
1737                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1738                 )
1739                 # SAD entry for inband / rx path
1740                 args[u"entry"][u"sad_id"] = i
1741                 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1742
1743                 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1744                 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1745                 if integ_alg:
1746                     args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1747                     args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1748                 args[u"entry"][u"flags"] = int(
1749                     IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1750                     IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1751                 )
1752                 papi_exec.add(
1753                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1754                 )
1755             err_msg = f"Failed to add IPsec SAD entries on host" \
1756                 f" {nodes[u'DUT2'][u'host']}"
1757             papi_exec.get_replies(err_msg)
1758             # Add protection for tunnels with IPSEC
1759             cmd = u"ipsec_tunnel_protect_update"
1760             n_hop = dict(
1761                 address=0,
1762                 via_label=MPLS_LABEL_INVALID,
1763                 obj_id=Constants.BITWISE_NON_ZERO
1764             )
1765             ipsec_tunnel_protect = dict(
1766                 sw_if_index=None,
1767                 nh=n_hop,
1768                 sa_out=None,
1769                 n_sa_in=1,
1770                 sa_in=None
1771             )
1772             args = dict(
1773                 tunnel=ipsec_tunnel_protect
1774             )
1775             for i in range(existing_tunnels, n_tunnels):
1776                 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1777                 args[u"tunnel"][u"sa_out"] = 100000 + i
1778                 args[u"tunnel"][u"sa_in"] = [i]
1779                 papi_exec.add(
1780                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1781                 )
1782             err_msg = f"Failed to add protection for tunnels with IPSEC " \
1783                 f"on host {nodes[u'DUT2'][u'host']}"
1784             papi_exec.get_replies(err_msg)
1785
1786             if not existing_tunnels:
1787                 # Configure IP route
1788                 cmd = u"ip_route_add_del"
1789                 route = IPUtil.compose_vpp_route_structure(
1790                     nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1791                     prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1792                     interface=if2_key,
1793                     gateway=(tun_ips[u"ip2"] - 1).compressed
1794                 )
1795                 args = dict(
1796                     is_add=1,
1797                     is_multipath=0,
1798                     route=route
1799                 )
1800                 papi_exec.add(cmd, **args)
1801             # Configure unnumbered interfaces
1802             cmd = u"sw_interface_set_unnumbered"
1803             args = dict(
1804                 is_add=True,
1805                 sw_if_index=InterfaceUtil.get_interface_index(
1806                     nodes[u"DUT2"], if2_key
1807                 ),
1808                 unnumbered_sw_if_index=0
1809             )
1810             for i in range(existing_tunnels, n_tunnels):
1811                 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1812                 papi_exec.add(
1813                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1814                 )
1815             # Set interfaces up
1816             cmd = u"sw_interface_set_flags"
1817             args = dict(
1818                 sw_if_index=0,
1819                 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1820             )
1821             for i in range(existing_tunnels, n_tunnels):
1822                 args[u"sw_if_index"] = ipip_tunnels[i]
1823                 papi_exec.add(
1824                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1825                 )
1826             # Configure IP routes
1827             cmd = u"ip_route_add_del"
1828             args = dict(
1829                 is_add=1,
1830                 is_multipath=0,
1831                 route=None
1832             )
1833             for i in range(existing_tunnels, n_tunnels):
1834                 args[u"route"] = IPUtil.compose_vpp_route_structure(
1835                     nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1836                     prefix_len=128 if raddr_ip1.version == 6 else 32,
1837                     interface=ipip_tunnels[i]
1838                 )
1839                 papi_exec.add(
1840                     cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1841                 )
1842             err_msg = f"Failed to add IP routes " \
1843                 f"on host {nodes[u'DUT2'][u'host']}"
1844             papi_exec.get_replies(err_msg)
1845
1846     @staticmethod
1847     def vpp_ipsec_create_tunnel_interfaces(
1848             nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1849             n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1850             existing_tunnels=0, return_keys=False):
1851         """Create multiple IPsec tunnel interfaces between two VPP nodes.
1852
1853         Some deployments (e.g. devicetest) need to know the generated keys.
1854         But other deployments (e.g. scale perf test) would get spammed
1855         if we returned keys every time.
1856
1857         :param nodes: VPP nodes to create tunnel interfaces.
1858         :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1859             address.
1860         :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1861             address.
1862         :param if1_key: VPP node 1 interface key from topology file.
1863         :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1864             interface key from topology file.
1865         :param n_tunnels: Number of tunnel interfaces to be there at the end.
1866         :param crypto_alg: The encryption algorithm name.
1867         :param integ_alg: The integrity algorithm name.
1868         :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1869             first tunnel in direction node1->node2.
1870         :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1871             first tunnel in direction node2->node1.
1872         :param raddr_range: Mask specifying range of Policy selector Remote
1873             IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1874             and to 128 in case of IPv6.
1875         :param existing_tunnels: Number of tunnel interfaces before creation.
1876             Useful mainly for reconf tests. Default 0.
1877         :param return_keys: Whether generated keys should be returned.
1878         :type nodes: dict
1879         :type tun_if1_ip_addr: str
1880         :type tun_if2_ip_addr: str
1881         :type if1_key: str
1882         :type if2_key: str
1883         :type n_tunnels: int
1884         :type crypto_alg: CryptoAlg
1885         :type integ_alg: Optonal[IntegAlg]
1886         :type raddr_ip1: string
1887         :type raddr_ip2: string
1888         :type raddr_range: int
1889         :type existing_tunnels: int
1890         :type return_keys: bool
1891         :returns: Ckeys, ikeys, spi_1, spi_2.
1892         :rtype: Optional[List[bytes], List[bytes], int, int]
1893         """
1894         n_tunnels = int(n_tunnels)
1895         existing_tunnels = int(existing_tunnels)
1896         spi_d = dict(
1897             spi_1=100000,
1898             spi_2=200000
1899         )
1900         tun_ips = dict(
1901             ip1=ip_address(tun_if1_ip_addr),
1902             ip2=ip_address(tun_if2_ip_addr)
1903         )
1904         raddr_ip1 = ip_address(raddr_ip1)
1905         raddr_ip2 = ip_address(raddr_ip2)
1906         addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1907             else 1 << (32 - raddr_range)
1908
1909         if n_tunnels - existing_tunnels > 10:
1910             ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1911                 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1912                 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1913             )
1914             if u"DUT2" in nodes.keys():
1915                 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1916                     nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1917                     integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1918                     existing_tunnels
1919                 )
1920         else:
1921             ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1922                 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1923                 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1924             )
1925             if u"DUT2" in nodes.keys():
1926                 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1927                     nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1928                     integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1929                     existing_tunnels
1930                 )
1931
1932         if return_keys:
1933             return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1934         return None
1935
1936     @staticmethod
1937     def _create_ipsec_script_files(dut, instances):
1938         """Create script files for configuring IPsec in containers
1939
1940         :param dut: DUT node on which to create the script files
1941         :param instances: number of containers on DUT node
1942         :type dut: string
1943         :type instances: int
1944         """
1945         scripts = []
1946         for cnf in range(0, instances):
1947             script_filename = (
1948                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1949             )
1950             scripts.append(open(script_filename, 'w'))
1951         return scripts
1952
1953     @staticmethod
1954     def _close_and_copy_ipsec_script_files(
1955             dut, nodes, instances, scripts):
1956         """Close created scripts and copy them to containers
1957
1958         :param dut: DUT node on which to create the script files
1959         :param nodes: VPP nodes
1960         :param instances: number of containers on DUT node
1961         :param scripts: dictionary holding the script files
1962         :type dut: string
1963         :type nodes: dict
1964         :type instances: int
1965         :type scripts: dict
1966         """
1967         for cnf in range(0, instances):
1968             scripts[cnf].close()
1969             script_filename = (
1970                 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1971             )
1972             scp_node(nodes[dut], script_filename, script_filename)
1973
1974
1975     @staticmethod
1976     def vpp_ipsec_create_tunnel_interfaces_in_containers(
1977             nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1978             raddr_ip1, raddr_ip2, raddr_range, n_instances):
1979         """Create multiple IPsec tunnel interfaces between two VPP nodes.
1980
1981         :param nodes: VPP nodes to create tunnel interfaces.
1982         :param if1_ip_addr: VPP node 1 interface IP4 address.
1983         :param if2_ip_addr: VPP node 2 interface IP4 address.
1984         :param n_tunnels: Number of tunnell interfaces to create.
1985         :param crypto_alg: The encryption algorithm name.
1986         :param integ_alg: The integrity algorithm name.
1987         :param raddr_ip1: Policy selector remote IPv4 start address for the
1988             first tunnel in direction node1->node2.
1989         :param raddr_ip2: Policy selector remote IPv4 start address for the
1990             first tunnel in direction node2->node1.
1991         :param raddr_range: Mask specifying range of Policy selector Remote
1992             IPv4 addresses. Valid values are from 1 to 32.
1993         :param n_instances: Number of containers.
1994         :type nodes: dict
1995         :type if1_ip_addr: str
1996         :type if2_ip_addr: str
1997         :type n_tunnels: int
1998         :type crypto_alg: CryptoAlg
1999         :type integ_alg: Optional[IntegAlg]
2000         :type raddr_ip1: string
2001         :type raddr_ip2: string
2002         :type raddr_range: int
2003         :type n_instances: int
2004         """
2005         spi_1 = 100000
2006         spi_2 = 200000
2007         addr_incr = 1 << (32 - raddr_range)
2008
2009         dut1_scripts = IPsecUtil._create_ipsec_script_files(
2010             u"DUT1", n_instances
2011         )
2012         dut2_scripts = IPsecUtil._create_ipsec_script_files(
2013             u"DUT2", n_instances
2014         )
2015
2016         for cnf in range(0, n_instances):
2017             dut1_scripts[cnf].write(
2018                 u"create loopback interface\n"
2019                 u"set interface state loop0 up\n\n"
2020             )
2021             dut2_scripts[cnf].write(
2022                 f"ip route add {if1_ip_addr}/8 via "
2023                 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
2024             )
2025
2026         for tnl in range(0, n_tunnels):
2027             cnf = tnl % n_instances
2028             ckey = getattr(
2029                 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
2030             )
2031             integ = u""
2032             ikey = getattr(
2033                 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
2034             )
2035             if integ_alg:
2036                 integ = (
2037                     f"integ-alg {integ_alg.alg_name} "
2038                     f"local-integ-key {ikey} "
2039                     f"remote-integ-key {ikey} "
2040                 )
2041             # Configure tunnel end point(s) on left side
2042             dut1_scripts[cnf].write(
2043                 u"set interface ip address loop0 "
2044                 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
2045                 f"create ipsec tunnel "
2046                 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
2047                 f"local-spi {spi_1 + tnl} "
2048                 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
2049                 f"remote-spi {spi_2 + tnl} "
2050                 f"crypto-alg {crypto_alg.alg_name} "
2051                 f"local-crypto-key {ckey} "
2052                 f"remote-crypto-key {ckey} "
2053                 f"instance {tnl // n_instances} "
2054                 f"salt 0x0 "
2055                 f"{integ} \n"
2056                 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
2057                 f"set interface state ipip{tnl // n_instances} up\n"
2058                 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
2059                 f"via ipip{tnl // n_instances}\n\n"
2060             )
2061             # Configure tunnel end point(s) on right side
2062             dut2_scripts[cnf].write(
2063                 f"set ip neighbor memif1/{cnf + 1} "
2064                 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
2065                 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
2066                 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
2067                 f"local-spi {spi_2 + tnl} "
2068                 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
2069                 f"remote-spi {spi_1 + tnl} "
2070                 f"crypto-alg {crypto_alg.alg_name} "
2071                 f"local-crypto-key {ckey} "
2072                 f"remote-crypto-key {ckey} "
2073                 f"instance {tnl // n_instances} "
2074                 f"salt 0x0 "
2075                 f"{integ}\n"
2076                 f"set interface unnumbered ipip{tnl // n_instances} "
2077                 f"use memif1/{cnf + 1}\n"
2078                 f"set interface state ipip{tnl // n_instances} up\n"
2079                 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
2080                 f"via ipip{tnl // n_instances}\n\n"
2081             )
2082
2083         IPsecUtil._close_and_copy_ipsec_script_files(
2084             u"DUT1", nodes, n_instances, dut1_scripts)
2085         IPsecUtil._close_and_copy_ipsec_script_files(
2086             u"DUT2", nodes, n_instances, dut2_scripts)
2087
2088     @staticmethod
2089     def vpp_ipsec_add_multiple_tunnels(
2090             nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
2091             tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
2092         """Create multiple IPsec tunnels between two VPP nodes.
2093
2094         :param nodes: VPP nodes to create tunnels.
2095         :param interface1: Interface name or sw_if_index on node 1.
2096         :param interface2: Interface name or sw_if_index on node 2.
2097         :param n_tunnels: Number of tunnels to create.
2098         :param crypto_alg: The encryption algorithm name.
2099         :param integ_alg: The integrity algorithm name.
2100         :param tunnel_ip1: Tunnel node1 IPv4 address.
2101         :param tunnel_ip2: Tunnel node2 IPv4 address.
2102         :param raddr_ip1: Policy selector remote IPv4 start address for the
2103             first tunnel in direction node1->node2.
2104         :param raddr_ip2: Policy selector remote IPv4 start address for the
2105             first tunnel in direction node2->node1.
2106         :param raddr_range: Mask specifying range of Policy selector Remote
2107             IPv4 addresses. Valid values are from 1 to 32.
2108         :type nodes: dict
2109         :type interface1: str or int
2110         :type interface2: str or int
2111         :type n_tunnels: int
2112         :type crypto_alg: CryptoAlg
2113         :type integ_alg: Optional[IntegAlg]
2114         :type tunnel_ip1: str
2115         :type tunnel_ip2: str
2116         :type raddr_ip1: string
2117         :type raddr_ip2: string
2118         :type raddr_range: int
2119         """
2120         spd_id = 1
2121         p_hi = 100
2122         p_lo = 10
2123         sa_id_1 = 100000
2124         sa_id_2 = 200000
2125         spi_1 = 300000
2126         spi_2 = 400000
2127
2128         crypto_key = gen_key(
2129             IPsecUtil.get_crypto_alg_key_len(crypto_alg)
2130         ).decode()
2131         integ_key = gen_key(
2132             IPsecUtil.get_integ_alg_key_len(integ_alg)
2133         ).decode() if integ_alg else u""
2134
2135         rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
2136             if u"DUT2" in nodes.keys() \
2137             else Topology.get_interface_mac(nodes[u"TG"], interface2)
2138         IPsecUtil.vpp_ipsec_set_ip_route(
2139             nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
2140             interface1, raddr_range, rmac)
2141
2142         IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
2143         IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
2144         IPsecUtil.vpp_ipsec_add_spd_entry(
2145             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
2146             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
2147         )
2148         IPsecUtil.vpp_ipsec_add_spd_entry(
2149             nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
2150             proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
2151         )
2152
2153         IPsecUtil.vpp_ipsec_add_sad_entries(
2154             nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
2155             integ_alg, integ_key, tunnel_ip1, tunnel_ip2
2156         )
2157
2158         IPsecUtil.vpp_ipsec_add_spd_entries(
2159             nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2160             action=PolicyAction.PROTECT, inbound=False,
2161             sa_id=ObjIncrement(sa_id_1, 1),
2162             raddr_range=NetworkIncrement(ip_network(raddr_ip2))
2163         )
2164
2165         IPsecUtil.vpp_ipsec_add_sad_entries(
2166             nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
2167             integ_alg, integ_key, tunnel_ip2, tunnel_ip1
2168         )
2169         IPsecUtil.vpp_ipsec_add_spd_entries(
2170             nodes[u"DUT1"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2171             action=PolicyAction.PROTECT, inbound=True,
2172             sa_id=ObjIncrement(sa_id_2, 1),
2173             raddr_range=NetworkIncrement(ip_network(raddr_ip1))
2174         )
2175
2176         if u"DUT2" in nodes.keys():
2177             IPsecUtil.vpp_ipsec_set_ip_route(
2178                 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
2179                 interface2, raddr_range)
2180
2181             IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
2182             IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
2183             IPsecUtil.vpp_ipsec_add_spd_entry(
2184                 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2185                 inbound=False, proto=50, laddr_range=u"100.0.0.0/8",
2186                 raddr_range=u"100.0.0.0/8"
2187             )
2188             IPsecUtil.vpp_ipsec_add_spd_entry(
2189                 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2190                 inbound=True, proto=50, laddr_range=u"100.0.0.0/8",
2191                 raddr_range=u"100.0.0.0/8"
2192             )
2193
2194             IPsecUtil.vpp_ipsec_add_sad_entries(
2195                 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
2196                 crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2
2197             )
2198             IPsecUtil.vpp_ipsec_add_spd_entries(
2199                 nodes[u"DUT2"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2200                 action=PolicyAction.PROTECT, inbound=True,
2201                 sa_id=ObjIncrement(sa_id_1, 1),
2202                 raddr_range=NetworkIncrement(ip_network(raddr_ip2))
2203             )
2204
2205             IPsecUtil.vpp_ipsec_add_sad_entries(
2206                 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
2207                 crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1
2208             )
2209             IPsecUtil.vpp_ipsec_add_spd_entries(
2210                 nodes[u"DUT2"], n_tunnels, spd_id, priority=ObjIncrement(p_lo, 0),
2211                 action=PolicyAction.PROTECT, inbound=False,
2212                 sa_id=ObjIncrement(sa_id_2, 1),
2213                 raddr_range=NetworkIncrement(ip_network(raddr_ip1))
2214             )
2215
2216     @staticmethod
2217     def vpp_ipsec_show_all(node):
2218         """Run "show ipsec all" debug CLI command.
2219
2220         :param node: Node to run command on.
2221         :type node: dict
2222         """
2223         PapiSocketExecutor.run_cli_cmd(node, u"show ipsec all")
2224
2225     @staticmethod
2226     def show_ipsec_security_association(node):
2227         """Show IPSec security association.
2228
2229         :param node: DUT node.
2230         :type node: dict
2231         """
2232         cmds = [
2233             u"ipsec_sa_v2_dump"
2234         ]
2235         PapiSocketExecutor.dump_and_log(node, cmds)