b08c2a6e48748752efa5235c7c00c06c09725ac3
[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 from ipaddress import ip_network, ip_address
18
19 from enum import Enum, IntEnum
20
21 from resources.libraries.python.PapiExecutor import PapiExecutor
22 from resources.libraries.python.topology import Topology
23 from resources.libraries.python.VatExecutor import VatExecutor
24 from resources.libraries.python.VatJsonUtil import VatJsonUtil
25
26
27 class PolicyAction(Enum):
28     """Policy actions."""
29     BYPASS = 'bypass'
30     DISCARD = 'discard'
31     PROTECT = 'protect'
32
33     def __init__(self, string):
34         self.string = string
35
36
37 class CryptoAlg(Enum):
38     """Encryption algorithms."""
39     AES_CBC_128 = ('aes-cbc-128', 'AES-CBC', 16)
40     AES_CBC_192 = ('aes-cbc-192', 'AES-CBC', 24)
41     AES_CBC_256 = ('aes-cbc-256', 'AES-CBC', 32)
42     AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
43     AES_GCM_256 = ('aes-gcm-256', 'AES-GCM', 40)
44
45     def __init__(self, alg_name, scapy_name, key_len):
46         self.alg_name = alg_name
47         self.scapy_name = scapy_name
48         self.key_len = key_len
49
50
51 class IntegAlg(Enum):
52     """Integrity algorithm."""
53     SHA1_96 = ('sha1-96', 'HMAC-SHA1-96', 20)
54     SHA_256_128 = ('sha-256-128', 'SHA2-256-128', 32)
55     SHA_384_192 = ('sha-384-192', 'SHA2-384-192', 48)
56     SHA_512_256 = ('sha-512-256', 'SHA2-512-256', 64)
57     AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
58     AES_GCM_256 = ('aes-gcm-256', 'AES-GCM', 40)
59
60     def __init__(self, alg_name, scapy_name, key_len):
61         self.alg_name = alg_name
62         self.scapy_name = scapy_name
63         self.key_len = key_len
64
65
66 class IPsecProto(IntEnum):
67     """IPsec protocol."""
68     ESP = 1
69     SEC_AH = 0
70
71
72 class IPsecUtil(object):
73     """IPsec utilities."""
74
75     @staticmethod
76     def policy_action_bypass():
77         """Return policy action bypass.
78
79         :returns: PolicyAction enum BYPASS object.
80         :rtype: PolicyAction
81         """
82         return PolicyAction.BYPASS
83
84     @staticmethod
85     def policy_action_discard():
86         """Return policy action discard.
87
88         :returns: PolicyAction enum DISCARD object.
89         :rtype: PolicyAction
90         """
91         return PolicyAction.DISCARD
92
93     @staticmethod
94     def policy_action_protect():
95         """Return policy action protect.
96
97         :returns: PolicyAction enum PROTECT object.
98         :rtype: PolicyAction
99         """
100         return PolicyAction.PROTECT
101
102     @staticmethod
103     def crypto_alg_aes_cbc_128():
104         """Return encryption algorithm aes-cbc-128.
105
106         :returns: CryptoAlg enum AES_CBC_128 object.
107         :rtype: CryptoAlg
108         """
109         return CryptoAlg.AES_CBC_128
110
111     @staticmethod
112     def crypto_alg_aes_cbc_192():
113         """Return encryption algorithm aes-cbc-192.
114
115         :returns: CryptoAlg enum AES_CBC_192 objec.
116         :rtype: CryptoAlg
117         """
118         return CryptoAlg.AES_CBC_192
119
120     @staticmethod
121     def crypto_alg_aes_cbc_256():
122         """Return encryption algorithm aes-cbc-256.
123
124         :returns: CryptoAlg enum AES_CBC_256 object.
125         :rtype: CryptoAlg
126         """
127         return CryptoAlg.AES_CBC_256
128
129     @staticmethod
130     def crypto_alg_aes_gcm_128():
131         """Return encryption algorithm aes-gcm-128.
132
133         :returns: CryptoAlg enum AES_GCM_128 object.
134         :rtype: CryptoAlg
135         """
136         return CryptoAlg.AES_GCM_128
137
138     @staticmethod
139     def crypto_alg_aes_gcm_256():
140         """Return encryption algorithm aes-gcm-256.
141
142         :returns: CryptoAlg enum AES_GCM_128 object.
143         :rtype: CryptoAlg
144         """
145         return CryptoAlg.AES_GCM_256
146
147     @staticmethod
148     def get_crypto_alg_key_len(crypto_alg):
149         """Return encryption algorithm key length.
150
151         :param crypto_alg: Encryption algorithm.
152         :type crypto_alg: CryptoAlg
153         :returns: Key length.
154         :rtype: int
155         """
156         return crypto_alg.key_len
157
158     @staticmethod
159     def get_crypto_alg_scapy_name(crypto_alg):
160         """Return encryption algorithm scapy name.
161
162         :param crypto_alg: Encryption algorithm.
163         :type crypto_alg: CryptoAlg
164         :returns: Algorithm scapy name.
165         :rtype: str
166         """
167         return crypto_alg.scapy_name
168
169     @staticmethod
170     def integ_alg_sha1_96():
171         """Return integrity algorithm SHA1-96.
172
173         :returns: IntegAlg enum SHA1_96 object.
174         :rtype: IntegAlg
175         """
176         return IntegAlg.SHA1_96
177
178     @staticmethod
179     def integ_alg_sha_256_128():
180         """Return integrity algorithm SHA-256-128.
181
182         :returns: IntegAlg enum SHA_256_128 object.
183         :rtype: IntegAlg
184         """
185         return IntegAlg.SHA_256_128
186
187     @staticmethod
188     def integ_alg_sha_384_192():
189         """Return integrity algorithm SHA-384-192.
190
191         :returns: IntegAlg enum SHA_384_192 object.
192         :rtype: IntegAlg
193         """
194         return IntegAlg.SHA_384_192
195
196     @staticmethod
197     def integ_alg_sha_512_256():
198         """Return integrity algorithm SHA-512-256.
199
200         :returns: IntegAlg enum SHA_512_256 object.
201         :rtype: IntegAlg
202         """
203         return IntegAlg.SHA_512_256
204
205     @staticmethod
206     def integ_alg_aes_gcm_128():
207         """Return integrity algorithm AES-GCM-128.
208
209         :returns: IntegAlg enum AES_GCM_128 object.
210         :rtype: IntegAlg
211         """
212         return IntegAlg.AES_GCM_128
213
214     @staticmethod
215     def integ_alg_aes_gcm_256():
216         """Return integrity algorithm AES-GCM-256.
217
218         :returns: IntegAlg enum AES_GCM_256 object.
219         :rtype: IntegAlg
220         """
221         return IntegAlg.AES_GCM_256
222
223     @staticmethod
224     def get_integ_alg_key_len(integ_alg):
225         """Return integrity algorithm key length.
226
227         :param integ_alg: Integrity algorithm.
228         :type integ_alg: IntegAlg
229         :returns: Key length.
230         :rtype: int
231         """
232         return integ_alg.key_len
233
234     @staticmethod
235     def get_integ_alg_scapy_name(integ_alg):
236         """Return integrity algorithm scapy name.
237
238         :param integ_alg: Integrity algorithm.
239         :type integ_alg: IntegAlg
240         :returns: Algorithm scapy name.
241         :rtype: str
242         """
243         return integ_alg.scapy_name
244
245     @staticmethod
246     def ipsec_proto_esp():
247         """Return IPSec protocol ESP.
248
249         :returns: IPsecProto enum ESP object.
250         :rtype: IPsecProto
251         """
252         return int(IPsecProto.ESP)
253
254     @staticmethod
255     def ipsec_proto_ah():
256         """Return IPSec protocol AH.
257
258         :returns: IPsecProto enum AH object.
259         :rtype: IPsecProto
260         """
261         return int(IPsecProto.SEC_AH)
262
263     @staticmethod
264     def vpp_ipsec_select_backend(node, protocol, index=1):
265         """Select IPsec backend.
266
267         :param node: VPP node to select IPsec backend on.
268         :param protocol: IPsec protocol.
269         :param index: Backend index.
270         :type node: dict
271         :type protocol: IPsecProto
272         :type index: int
273         :raises RuntimeError: If failed to select IPsec backend or if no API
274             reply received.
275         """
276
277         cmd = 'ipsec_select_backend'
278         cmd_reply = 'ipsec_select_backend_reply'
279         err_msg = 'Failed to select IPsec backend on host {host}'.format(
280             host=node['host'])
281         args = dict(protocol=protocol, index=index)
282         with PapiExecutor(node) as papi_exec:
283             papi_resp = papi_exec.add(cmd, **args).execute_should_pass(err_msg)
284         data = papi_resp.reply[0]['api_reply'][cmd_reply]
285         if data['retval'] != 0:
286             raise RuntimeError('Failed to select IPsec backend on host {host}'.
287                                format(host=node['host']))
288
289     @staticmethod
290     def vpp_ipsec_backend_dump(node):
291         """Dump IPsec backends.
292
293         :param node: VPP node to dump IPsec backend on.
294         :type node: dict
295         """
296
297         err_msg = 'Failed to dump IPsec backends on host {host}'.format(
298             host=node['host'])
299         with PapiExecutor(node) as papi_exec:
300             papi_exec.add('ipsec_backend_dump').execute_should_pass(
301                 err_msg, process_reply=False)
302
303     @staticmethod
304     def vpp_ipsec_add_sad_entry(node, sad_id, spi, crypto_alg, crypto_key,
305                                 integ_alg, integ_key, tunnel_src=None,
306                                 tunnel_dst=None):
307         """Create Security Association Database entry on the VPP node.
308
309         :param node: VPP node to add SAD entry on.
310         :param sad_id: SAD entry ID.
311         :param spi: Security Parameter Index of this SAD entry.
312         :param crypto_alg: The encryption algorithm name.
313         :param crypto_key: The encryption key string.
314         :param integ_alg: The integrity algorithm name.
315         :param integ_key: The integrity key string.
316         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
317             specified ESP transport mode is used.
318         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
319             not specified ESP transport mode is used.
320         :type node: dict
321         :type sad_id: int
322         :type spi: int
323         :type crypto_alg: CryptoAlg
324         :type crypto_key: str
325         :type integ_alg: IntegAlg
326         :type integ_key: str
327         :type tunnel_src: str
328         :type tunnel_dst: str
329         """
330         ckey = crypto_key.encode('hex')
331         ikey = integ_key.encode('hex')
332         tunnel = 'tunnel-src {0} tunnel-dst {1}'.format(tunnel_src, tunnel_dst)\
333             if tunnel_src is not None and tunnel_dst is not None else ''
334
335         out = VatExecutor.cmd_from_template(node,
336                                             'ipsec/ipsec_sad_add_entry.vat',
337                                             sad_id=sad_id, spi=spi,
338                                             calg=crypto_alg.alg_name, ckey=ckey,
339                                             ialg=integ_alg.alg_name, ikey=ikey,
340                                             tunnel=tunnel)
341         VatJsonUtil.verify_vat_retval(
342             out[0],
343             err_msg='Add SAD entry failed on {0}'.format(node['host']))
344
345     @staticmethod
346     def vpp_ipsec_add_sad_entries(node, n_entries, sad_id, spi, crypto_alg,
347                                   crypto_key, integ_alg, integ_key,
348                                   tunnel_src=None, tunnel_dst=None):
349         """Create multiple Security Association Database entries on VPP node.
350
351         :param node: VPP node to add SAD entry on.
352         :param n_entries: Number of SAD entries to be created.
353         :param sad_id: First SAD entry ID. All subsequent SAD entries will have
354             id incremented by 1.
355         :param spi: Security Parameter Index of first SAD entry. All subsequent
356             SAD entries will have spi incremented by 1.
357         :param crypto_alg: The encryption algorithm name.
358         :param crypto_key: The encryption key string.
359         :param integ_alg: The integrity algorithm name.
360         :param integ_key: The integrity key string.
361         :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
362             specified ESP transport mode is used.
363         :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
364             not specified ESP transport mode is used.
365         :type node: dict
366         :type n_entries: int
367         :type sad_id: int
368         :type spi: int
369         :type crypto_alg: CryptoAlg
370         :type crypto_key: str
371         :type integ_alg: IntegAlg
372         :type integ_key: str
373         :type tunnel_src: str
374         :type tunnel_dst: str
375         """
376         tmp_filename = '/tmp/ipsec_sad_{0}_add_del_entry.script'.format(sad_id)
377         ckey = crypto_key.encode('hex')
378         ikey = integ_key.encode('hex')
379         tunnel = 'tunnel-src {0} tunnel-dst {1}'.format(tunnel_src, tunnel_dst)\
380             if tunnel_src is not None and tunnel_dst is not None else ''
381
382         integ = 'integ-alg {0} integ-key {1}'.format(integ_alg.alg_name, ikey)\
383             if crypto_alg.alg_name != 'aes-gcm-128' and \
384                crypto_alg.alg_name != 'aes-gcm-256' else ''
385
386         with open(tmp_filename, 'w') as tmp_file:
387             for i in range(0, n_entries):
388                 buf_str = 'exec ipsec sa add {0} esp spi {1} ' \
389                           'crypto-alg {2} crypto-key {3} {4} {5}\n'.format(
390                               sad_id+i, spi+i, crypto_alg.alg_name, ckey, integ,
391                               tunnel)
392                 tmp_file.write(buf_str)
393         vat = VatExecutor()
394         vat.execute_script(tmp_filename, node, timeout=300, json_out=False,
395                            copy_on_execute=True)
396         os.remove(tmp_filename)
397
398     @staticmethod
399     def vpp_ipsec_sa_set_key(node, sa_id, crypto_key, integ_key):
400         """Update Security Association (SA) keys.
401
402         :param node: VPP node to update SA keys.
403         :param sa_id: SAD entry ID.
404         :param crypto_key: The encryption key string.
405         :param integ_key: The integrity key string.
406         :type node: dict
407         :type sa_id: int
408         :type crypto_key: str
409         :type integ_key: str
410         """
411         ckey = crypto_key.encode('hex')
412         ikey = integ_key.encode('hex')
413
414         out = VatExecutor.cmd_from_template(
415             node, 'ipsec/ipsec_sa_set_key.vat', json_param=False, sa_id=sa_id,
416             ckey=ckey, ikey=ikey)
417         VatJsonUtil.verify_vat_retval(
418             out[0],
419             err_msg='Update SA key failed on {0}'.format(node['host']))
420
421     @staticmethod
422     def vpp_ipsec_add_spd(node, spd_id):
423         """Create Security Policy Database on the VPP node.
424
425         :param node: VPP node to add SPD on.
426         :param spd_id: SPD ID.
427         :type node: dict
428         :type spd_id: int
429         """
430         out = VatExecutor.cmd_from_template(node, 'ipsec/ipsec_spd_add.vat',
431                                             spd_id=spd_id)
432         VatJsonUtil.verify_vat_retval(
433             out[0],
434             err_msg='Add SPD {0} failed on {1}'.format(spd_id, node['host']))
435
436     @staticmethod
437     def vpp_ipsec_spd_add_if(node, spd_id, interface):
438         """Add interface to the Security Policy Database.
439
440         :param node: VPP node.
441         :param spd_id: SPD ID to add interface on.
442         :param interface: Interface name or sw_if_index.
443         :type node: dict
444         :type spd_id: int
445         :type interface: str or int
446         """
447         sw_if_index = Topology.get_interface_sw_index(node, interface)\
448             if isinstance(interface, basestring) else interface
449
450         out = VatExecutor.cmd_from_template(node,
451                                             'ipsec/ipsec_interface_add_spd.vat',
452                                             spd_id=spd_id, sw_if_id=sw_if_index)
453         VatJsonUtil.verify_vat_retval(
454             out[0],
455             err_msg='Add interface {0} to SPD {1} failed on {2}'.format(
456                 interface, spd_id, node['host']))
457
458     @staticmethod
459     def vpp_ipsec_policy_add(node, spd_id, priority, action, inbound=True,
460                              sa_id=None, laddr_range=None, raddr_range=None,
461                              proto=None, lport_range=None, rport_range=None,
462                              is_ipv6=False):
463         """Create Security Policy Database entry on the VPP node.
464
465         :param node: VPP node to add SPD entry on.
466         :param spd_id: SPD ID to add entry on.
467         :param priority: SPD entry priority, higher number = higher priority.
468         :param action: Policy action.
469         :param inbound: If True policy is for inbound traffic, otherwise
470             outbound.
471         :param sa_id: SAD entry ID for protect action.
472         :param laddr_range: Policy selector local IPv4 or IPv6 address range in
473             format IP/prefix or IP/mask. If no mask is provided,
474             it's considered to be /32.
475         :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
476             format IP/prefix or IP/mask. If no mask is provided,
477             it's considered to be /32.
478         :param proto: Policy selector next layer protocol number.
479         :param lport_range: Policy selector local TCP/UDP port range in format
480             <port_start>-<port_end>.
481         :param rport_range: Policy selector remote TCP/UDP port range in format
482             <port_start>-<port_end>.
483         :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
484             not defined so it will default to address ::/0, otherwise False.
485         :type node: dict
486         :type spd_id: int
487         :type priority: int
488         :type action: PolicyAction
489         :type inbound: bool
490         :type sa_id: int
491         :type laddr_range: string
492         :type raddr_range: string
493         :type proto: int
494         :type lport_range: string
495         :type rport_range: string
496         :type is_ipv6: bool
497         """
498         direction = 'inbound' if inbound else 'outbound'
499
500         if laddr_range is None and is_ipv6:
501             laddr_range = '::/0'
502
503         if raddr_range is None and is_ipv6:
504             raddr_range = '::/0'
505
506         act_str = action.value
507         if PolicyAction.PROTECT == action and sa_id is not None:
508             act_str += ' sa {0}'.format(sa_id)
509
510         selector = ''
511         if laddr_range is not None:
512             net = ip_network(unicode(laddr_range), strict=False)
513             selector += 'local-ip-range {0} - {1} '.format(
514                 net.network_address, net.broadcast_address)
515         if raddr_range is not None:
516             net = ip_network(unicode(raddr_range), strict=False)
517             selector += 'remote-ip-range {0} - {1} '.format(
518                 net.network_address, net.broadcast_address)
519         if proto is not None:
520             selector += 'protocol {0} '.format(proto)
521         if lport_range is not None:
522             selector += 'local-port-range {0} '.format(lport_range)
523         if rport_range is not None:
524             selector += 'remote-port-range {0} '.format(rport_range)
525
526         out = VatExecutor.cmd_from_template(
527             node, 'ipsec/ipsec_policy_add.vat', json_param=False, spd_id=spd_id,
528             priority=priority, action=act_str, direction=direction,
529             selector=selector)
530         VatJsonUtil.verify_vat_retval(
531             out[0],
532             err_msg='Add IPsec policy ID {0} failed on {1}'.format(
533                 spd_id, node['host']))
534
535     @staticmethod
536     def vpp_ipsec_spd_add_entries(node, n_entries, spd_id, priority, inbound,
537                                   sa_id, raddr_ip, raddr_range):
538         """Create multiple Security Policy Database entries on the VPP node.
539
540         :param node: VPP node to add SPD entries on.
541         :param n_entries: Number of SPD entries to be added.
542         :param spd_id: SPD ID to add entries on.
543         :param priority: SPD entries priority, higher number = higher priority.
544         :param inbound: If True policy is for inbound traffic, otherwise
545             outbound.
546         :param sa_id: SAD entry ID for first entry. Each subsequent entry will
547             SAD entry ID incremented by 1.
548         :param raddr_ip: Policy selector remote IPv4 start address for the first
549             entry. Remote IPv4 end address will be calculated depending on
550             raddr_range parameter. Each subsequent entry will have start address
551             next after IPv4 end address of previous entry.
552         :param raddr_range: Mask specifying range of Policy selector Remote IPv4
553             addresses. Valid values are from 1 to 32.
554         :type node: dict
555         :type n_entries: int
556         :type spd_id: int
557         :type priority: int
558         :type inbound: bool
559         :type sa_id: int
560         :type raddr_ip: string
561         :type raddr_range: int
562         """
563         tmp_filename = '/tmp/ipsec_spd_{0}_add_del_entry.script'.format(sa_id)
564
565         direction = 'inbound' if inbound else 'outbound'
566         addr_incr = 1 << (32 - raddr_range)
567         addr_ip = int(ip_address(unicode(raddr_ip)))
568         start_str = 'exec ipsec policy add spd {0} priority {1} {2} ' \
569                     'action protect sa'.format(spd_id, priority, direction)
570         with open(tmp_filename, 'w') as tmp_file:
571             for i in range(0, n_entries):
572                 r_ip_s = ip_address(addr_ip + addr_incr * i)
573                 r_ip_e = ip_address(addr_ip + addr_incr * (i+1) - 1)
574                 buf_str = '{0} {1} remote-ip-range {2} - {3}\n'.format(
575                     start_str, sa_id+i, r_ip_s, r_ip_e)
576                 tmp_file.write(buf_str)
577         vat = VatExecutor()
578         vat.execute_script(tmp_filename, node, timeout=300, json_out=False,
579                            copy_on_execute=True)
580         os.remove(tmp_filename)
581
582     @staticmethod
583     def vpp_ipsec_create_tunnel_interfaces(node1, node2, if1_ip_addr,
584                                            if2_ip_addr, if1_key, if2_key,
585                                            n_tunnels, crypto_alg, crypto_key,
586                                            integ_alg, integ_key, raddr_ip1,
587                                            raddr_ip2, raddr_range):
588         """Create multiple IPsec tunnel interfaces between two VPP nodes.
589
590         :param node1: VPP node 1 to create tunnel interfaces.
591         :param node2: VPP node 2 to create tunnel interfaces.
592         :param if1_ip_addr: VPP node 1 interface IP4 address.
593         :param if2_ip_addr: VPP node 2 interface IP4 address.
594         :param if1_key: VPP node 1 interface key from topology file.
595         :param if2_key: VPP node 2 interface key from topology file.
596         :param n_tunnels: Number of tunnell interfaces to create.
597         :param crypto_alg: The encryption algorithm name.
598         :param crypto_key: The encryption key string.
599         :param integ_alg: The integrity algorithm name.
600         :param integ_key: The integrity key string.
601         :param raddr_ip1: Policy selector remote IPv4 start address for the
602             first tunnel in direction node1->node2.
603         :param raddr_ip2: Policy selector remote IPv4 start address for the
604             first tunnel in direction node2->node1.
605         :param raddr_range: Mask specifying range of Policy selector Remote IPv4
606             addresses. Valid values are from 1 to 32.
607         :type node1: dict
608         :type node2: dict
609         :type if1_ip_addr: str
610         :type if2_ip_addr: str
611         :type if1_key: str
612         :type if2_key: str
613         :type n_tunnels: int
614         :type crypto_alg: CryptoAlg
615         :type crypto_key: str
616         :type integ_alg: IntegAlg
617         :type integ_key: str
618         :type raddr_ip1: string
619         :type raddr_ip2: string
620         :type raddr_range: int
621         """
622         spi_1 = 10000
623         spi_2 = 20000
624
625         raddr_ip1_i = int(ip_address(unicode(raddr_ip1)))
626         raddr_ip2_i = int(ip_address(unicode(raddr_ip2)))
627         addr_incr = 1 << (32 - raddr_range)
628
629         tmp_fn1 = '/tmp/ipsec_create_tunnel_dut1.config'
630         tmp_fn2 = '/tmp/ipsec_create_tunnel_dut2.config'
631
632         ckey = crypto_key.encode('hex')
633         ikey = integ_key.encode('hex')
634
635         vat = VatExecutor()
636         with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
637             for i in range(0, n_tunnels):
638                 integ = ''
639                 if not crypto_alg.alg_name.startswith('aes-gcm-'):
640                     integ = 'integ_alg {integ_alg} '\
641                             'local_integ_key {local_integ_key} '\
642                             'remote_integ_key {remote_integ_key} '\
643                             .format(integ_alg=integ_alg.alg_name,
644                                     local_integ_key=ikey,
645                                     remote_integ_key=ikey)
646                 dut1_tunnel = 'ipsec_tunnel_if_add_del '\
647                               'local_spi {local_spi} '\
648                               'remote_spi {remote_spi} '\
649                               'crypto_alg {crypto_alg} '\
650                               'local_crypto_key {local_crypto_key} '\
651                               'remote_crypto_key {remote_crypto_key} '\
652                               '{integ} '\
653                               'local_ip {local_ip} '\
654                               'remote_ip {remote_ip}\n'\
655                               .format(local_spi=spi_1+i,
656                                       remote_spi=spi_2+i,
657                                       crypto_alg=crypto_alg.alg_name,
658                                       local_crypto_key=ckey,
659                                       remote_crypto_key=ckey,
660                                       integ=integ,
661                                       local_ip=if1_ip_addr,
662                                       remote_ip=if2_ip_addr)
663                 dut2_tunnel = 'ipsec_tunnel_if_add_del '\
664                               'local_spi {local_spi} '\
665                               'remote_spi {remote_spi} '\
666                               'crypto_alg {crypto_alg} '\
667                               'local_crypto_key {local_crypto_key} '\
668                               'remote_crypto_key {remote_crypto_key} '\
669                               '{integ} '\
670                               'local_ip {local_ip} '\
671                               'remote_ip {remote_ip}\n'\
672                               .format(local_spi=spi_2+i,
673                                       remote_spi=spi_1+i,
674                                       crypto_alg=crypto_alg.alg_name,
675                                       local_crypto_key=ckey,
676                                       remote_crypto_key=ckey,
677                                       integ=integ,
678                                       local_ip=if2_ip_addr,
679                                       remote_ip=if1_ip_addr)
680                 tmp_f1.write(dut1_tunnel)
681                 tmp_f2.write(dut2_tunnel)
682         vat.execute_script(tmp_fn1, node1, timeout=300, json_out=False,
683                            copy_on_execute=True)
684         vat.execute_script(tmp_fn2, node2, timeout=300, json_out=False,
685                            copy_on_execute=True)
686         os.remove(tmp_fn1)
687         os.remove(tmp_fn2)
688
689         with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
690             for i in range(0, n_tunnels):
691                 raddr_ip1 = ip_address(raddr_ip1_i + addr_incr*i)
692                 raddr_ip2 = ip_address(raddr_ip2_i + addr_incr*i)
693                 dut1_if = Topology.get_interface_name(node1, if1_key)
694                 dut1 = 'exec ip route add {raddr}/{mask} via {addr} ipsec{i}\n'\
695                        'exec set interface unnumbered ipsec{i} use {uifc}\n'\
696                        'exec set interface state ipsec{i} up\n'\
697                        .format(raddr=raddr_ip2, mask=raddr_range,
698                                addr=if2_ip_addr, i=i, uifc=dut1_if)
699                 dut2_if = Topology.get_interface_name(node2, if2_key)
700                 dut2 = 'exec ip route add {raddr}/{mask} via {addr} ipsec{i}\n'\
701                        'exec set interface unnumbered ipsec{i} use {uifc}\n'\
702                        'exec set interface state ipsec{i} up\n'\
703                        .format(raddr=raddr_ip1, mask=raddr_range,
704                                addr=if1_ip_addr, i=i, uifc=dut2_if)
705                 tmp_f1.write(dut1)
706                 tmp_f2.write(dut2)
707
708         vat.execute_script(tmp_fn1, node1, timeout=300, json_out=False,
709                            copy_on_execute=True)
710         vat.execute_script(tmp_fn2, node2, timeout=300, json_out=False,
711                            copy_on_execute=True)
712         os.remove(tmp_fn1)
713         os.remove(tmp_fn2)
714
715     @staticmethod
716     def vpp_ipsec_add_multiple_tunnels(node1, node2, interface1, interface2,
717                                        n_tunnels, crypto_alg, crypto_key,
718                                        integ_alg, integ_key, tunnel_ip1,
719                                        tunnel_ip2, raddr_ip1, raddr_ip2,
720                                        raddr_range):
721         """Create multiple IPsec tunnels between two VPP nodes.
722
723         :param node1: VPP node 1 to create tunnels.
724         :param node2: VPP node 2 to create tunnels.
725         :param interface1: Interface name or sw_if_index on node 1.
726         :param interface2: Interface name or sw_if_index on node 2.
727         :param n_tunnels: Number of tunnels to create.
728         :param crypto_alg: The encryption algorithm name.
729         :param crypto_key: The encryption key string.
730         :param integ_alg: The integrity algorithm name.
731         :param integ_key: The integrity key string.
732         :param tunnel_ip1: Tunnel node1 IPv4 address.
733         :param tunnel_ip2: Tunnel node2 IPv4 address.
734         :param raddr_ip1: Policy selector remote IPv4 start address for the
735             first tunnel in direction node1->node2.
736         :param raddr_ip2: Policy selector remote IPv4 start address for the
737             first tunnel in direction node2->node1.
738         :param raddr_range: Mask specifying range of Policy selector Remote IPv4
739             addresses. Valid values are from 1 to 32.
740         :type node1: dict
741         :type node2: dict
742         :type interface1: str or int
743         :type interface2: str or int
744         :type n_tunnels: int
745         :type crypto_alg: CryptoAlg
746         :type crypto_key: str
747         :type integ_alg: str
748         :type integ_key: str
749         :type tunnel_ip1: str
750         :type tunnel_ip2: str
751         :type raddr_ip1: string
752         :type raddr_ip2: string
753         :type raddr_range: int
754         """
755         spd_id = 1
756         p_hi = 100
757         p_lo = 10
758         sa_id_1 = 10000
759         sa_id_2 = 20000
760         spi_1 = 30000
761         spi_2 = 40000
762         proto = 50
763
764         IPsecUtil.vpp_ipsec_add_spd(node1, spd_id)
765         IPsecUtil.vpp_ipsec_spd_add_if(node1, spd_id, interface1)
766         IPsecUtil.vpp_ipsec_policy_add(node1, spd_id, p_hi, PolicyAction.BYPASS,
767                                        inbound=False, proto=proto)
768         IPsecUtil.vpp_ipsec_policy_add(node1, spd_id, p_hi, PolicyAction.BYPASS,
769                                        inbound=True, proto=proto)
770
771         IPsecUtil.vpp_ipsec_add_spd(node2, spd_id)
772         IPsecUtil.vpp_ipsec_spd_add_if(node2, spd_id, interface2)
773         IPsecUtil.vpp_ipsec_policy_add(node2, spd_id, p_hi, PolicyAction.BYPASS,
774                                        inbound=False, proto=proto)
775         IPsecUtil.vpp_ipsec_policy_add(node2, spd_id, p_hi, PolicyAction.BYPASS,
776                                        inbound=True, proto=proto)
777
778         IPsecUtil.vpp_ipsec_add_sad_entries(node1, n_tunnels, sa_id_1, spi_1,
779                                             crypto_alg, crypto_key, integ_alg,
780                                             integ_key, tunnel_ip1, tunnel_ip2)
781
782         IPsecUtil.vpp_ipsec_spd_add_entries(node1, n_tunnels, spd_id, p_lo,
783                                             False, sa_id_1, raddr_ip2,
784                                             raddr_range)
785
786         IPsecUtil.vpp_ipsec_add_sad_entries(node2, n_tunnels, sa_id_1, spi_1,
787                                             crypto_alg, crypto_key, integ_alg,
788                                             integ_key, tunnel_ip1, tunnel_ip2)
789
790         IPsecUtil.vpp_ipsec_spd_add_entries(node2, n_tunnels, spd_id, p_lo,
791                                             True, sa_id_1, raddr_ip2,
792                                             raddr_range)
793
794         IPsecUtil.vpp_ipsec_add_sad_entries(node2, n_tunnels, sa_id_2, spi_2,
795                                             crypto_alg, crypto_key, integ_alg,
796                                             integ_key, tunnel_ip2, tunnel_ip1)
797
798         IPsecUtil.vpp_ipsec_spd_add_entries(node2, n_tunnels, spd_id, p_lo,
799                                             False, sa_id_2, raddr_ip1,
800                                             raddr_range)
801
802         IPsecUtil.vpp_ipsec_add_sad_entries(node1, n_tunnels, sa_id_2, spi_2,
803                                             crypto_alg, crypto_key, integ_alg,
804                                             integ_key, tunnel_ip2, tunnel_ip1)
805
806         IPsecUtil.vpp_ipsec_spd_add_entries(node1, n_tunnels, spd_id, p_lo,
807                                             True, sa_id_2, raddr_ip1,
808                                             raddr_range)
809
810     @staticmethod
811     def vpp_ipsec_show(node):
812         """Run "show ipsec" debug CLI command.
813
814         :param node: Node to run command on.
815         :type node: dict
816         """
817         VatExecutor().execute_script('ipsec/ipsec_show.vat', node,
818                                      json_out=False)