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