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