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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """IPsec utilities library."""
17 from ipaddress import ip_network, ip_address
19 from enum import Enum, IntEnum
20 from robot.api import logger
22 from resources.libraries.python.PapiExecutor import PapiExecutor
23 from resources.libraries.python.PapiErrors import PapiError, PapiCommandError
24 from resources.libraries.python.topology import Topology
25 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
26 from resources.libraries.python.VatJsonUtil import VatJsonUtil
29 class PolicyAction(Enum):
35 def __init__(self, string):
39 class CryptoAlg(Enum):
40 """Encryption algorithms."""
41 AES_CBC_128 = ('aes-cbc-128', 'AES-CBC', 16)
42 AES_CBC_192 = ('aes-cbc-192', 'AES-CBC', 24)
43 AES_CBC_256 = ('aes-cbc-256', 'AES-CBC', 32)
44 AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
46 def __init__(self, alg_name, scapy_name, key_len):
47 self.alg_name = alg_name
48 self.scapy_name = scapy_name
49 self.key_len = key_len
53 """Integrity algorithm."""
54 SHA1_96 = ('sha1-96', 'HMAC-SHA1-96', 20)
55 SHA_256_128 = ('sha-256-128', 'SHA2-256-128', 32)
56 SHA_384_192 = ('sha-384-192', 'SHA2-384-192', 48)
57 SHA_512_256 = ('sha-512-256', 'SHA2-512-256', 64)
58 AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
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
66 class IPsecProto(IntEnum):
72 class IPsecUtil(object):
73 """IPsec utilities."""
76 def policy_action_bypass():
77 """Return policy action bypass.
79 :returns: PolicyAction enum BYPASS object.
82 return PolicyAction.BYPASS
85 def policy_action_discard():
86 """Return policy action discard.
88 :returns: PolicyAction enum DISCARD object.
91 return PolicyAction.DISCARD
94 def policy_action_protect():
95 """Return policy action protect.
97 :returns: PolicyAction enum PROTECT object.
100 return PolicyAction.PROTECT
103 def crypto_alg_aes_cbc_128():
104 """Return encryption algorithm aes-cbc-128.
106 :returns: CryptoAlg enum AES_CBC_128 object.
109 return CryptoAlg.AES_CBC_128
112 def crypto_alg_aes_cbc_192():
113 """Return encryption algorithm aes-cbc-192.
115 :returns: CryptoAlg enum AES_CBC_192 objec.
118 return CryptoAlg.AES_CBC_192
121 def crypto_alg_aes_cbc_256():
122 """Return encryption algorithm aes-cbc-256.
124 :returns: CryptoAlg enum AES_CBC_256 object.
127 return CryptoAlg.AES_CBC_256
130 def crypto_alg_aes_gcm_128():
131 """Return encryption algorithm aes-gcm-128.
133 :returns: CryptoAlg enum AES_GCM_128 object.
136 return CryptoAlg.AES_GCM_128
139 def get_crypto_alg_key_len(crypto_alg):
140 """Return encryption algorithm key length.
142 :param crypto_alg: Encryption algorithm.
143 :type crypto_alg: CryptoAlg
144 :returns: Key length.
147 return crypto_alg.key_len
150 def get_crypto_alg_scapy_name(crypto_alg):
151 """Return encryption algorithm scapy name.
153 :param crypto_alg: Encryption algorithm.
154 :type crypto_alg: CryptoAlg
155 :returns: Algorithm scapy name.
158 return crypto_alg.scapy_name
161 def integ_alg_sha1_96():
162 """Return integrity algorithm SHA1-96.
164 :returns: IntegAlg enum SHA1_96 object.
167 return IntegAlg.SHA1_96
170 def integ_alg_sha_256_128():
171 """Return integrity algorithm SHA-256-128.
173 :returns: IntegAlg enum SHA_256_128 object.
176 return IntegAlg.SHA_256_128
179 def integ_alg_sha_384_192():
180 """Return integrity algorithm SHA-384-192.
182 :returns: IntegAlg enum SHA_384_192 object.
185 return IntegAlg.SHA_384_192
188 def integ_alg_sha_512_256():
189 """Return integrity algorithm SHA-512-256.
191 :returns: IntegAlg enum SHA_512_256 object.
194 return IntegAlg.SHA_512_256
197 def integ_alg_aes_gcm_128():
198 """Return integrity algorithm AES-GCM-128.
200 :returns: IntegAlg enum AES_GCM_128 object.
203 return IntegAlg.AES_GCM_128
206 def get_integ_alg_key_len(integ_alg):
207 """Return integrity algorithm key length.
209 :param integ_alg: Integrity algorithm.
210 :type integ_alg: IntegAlg
211 :returns: Key length.
214 return integ_alg.key_len
217 def get_integ_alg_scapy_name(integ_alg):
218 """Return integrity algorithm scapy name.
220 :param integ_alg: Integrity algorithm.
221 :type integ_alg: IntegAlg
222 :returns: Algorithm scapy name.
225 return integ_alg.scapy_name
228 def ipsec_proto_esp():
229 """Return IPSec protocol ESP.
231 :returns: IPsecProto enum ESP object.
234 return int(IPsecProto.ESP)
237 def ipsec_proto_ah():
238 """Return IPSec protocol AH.
240 :returns: IPsecProto enum AH object.
243 return int(IPsecProto.AH)
246 def vpp_ipsec_select_backend(node, protocol, index=1):
247 """Select IPsec backend.
249 :param node: VPP node to select IPsec backend on.
250 :param protocol: IPsec protocol.
251 :param index: Backend index.
253 :type protocol: IPsecProto
256 # TODO: move composition of api data to separate method
258 api = dict(api_name='ipsec_select_backend')
259 api_args = dict(protocol=protocol)
260 api_args['index'] = index
261 api['api_args'] = api_args
265 with PapiExecutor(node) as papi_executor:
266 papi_executor.execute_papi(api_data)
268 papi_executor.papi_should_have_passed()
269 except AssertionError:
270 raise PapiError('Failed to select IPsec backend on host {host}'.
271 format(host=node['host']))
272 api_reply = papi_executor.get_papi_reply()
274 if api_reply is not None:
275 api_r = api_reply[0]['api_reply']['ipsec_select_backend_reply']
276 if api_r['retval'] == 0:
277 logger.trace('IPsec backend successfully selected on host '
278 '{host}'.format(host=node['host']))
280 raise PapiError('Failed to select IPsec backend on host {host}'.
281 format(host=node['host']))
283 raise PapiError('No reply received for ipsec_select_backend API '
284 'command on host {host}'.format(host=node['host']))
287 def vpp_ipsec_backend_dump(node):
288 """Dump IPsec backends.
290 :param node: VPP node to dump IPsec backend on.
293 # TODO: move composition of api data to separate method
295 api = dict(api_name='ipsec_backend_dump')
297 api['api_args'] = api_args
301 with PapiExecutor(node) as papi_executor:
302 papi_executor.execute_papi(api_data)
304 papi_executor.papi_should_have_passed()
305 except AssertionError:
306 raise PapiError('Failed to dump IPsec backends on host {host}'.
307 format(host=node['host']))
308 api_reply = papi_executor.get_papi_reply()
310 if api_reply is not None:
311 # api_r = api_reply[0]['api_reply']['ipsec_select_backend_reply']
312 # if api_r['retval'] == 0:
313 # logger.trace('IPsec backend successfully selected on host '
314 # '{host}'.format(host=node['host']))
316 # raise PapiError('Failed to select IPsec backend on host {host}'.
317 # format(host=node['host']))
318 logger.trace('IPsec backend dump\n{dump}'.format(dump=api_reply))
320 raise PapiError('No reply received for ipsec_select_backend API '
321 'command on host {host}'.format(host=node['host']))
324 def vpp_ipsec_add_sad_entry(node, sad_id, spi, crypto_alg, crypto_key,
325 integ_alg, integ_key, tunnel_src=None,
327 """Create Security Association Database entry on the VPP node.
329 :param node: VPP node to add SAD entry on.
330 :param sad_id: SAD entry ID.
331 :param spi: Security Parameter Index of this SAD entry.
332 :param crypto_alg: The encryption algorithm name.
333 :param crypto_key: The encryption key string.
334 :param integ_alg: The integrity algorithm name.
335 :param integ_key: The integrity key string.
336 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
337 specified ESP transport mode is used.
338 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
339 not specified ESP transport mode is used.
343 :type crypto_alg: CryptoAlg
344 :type crypto_key: str
345 :type integ_alg: IntegAlg
347 :type tunnel_src: str
348 :type tunnel_dst: str
350 ckey = crypto_key.encode('hex')
351 ikey = integ_key.encode('hex')
352 tunnel = 'tunnel_src {0} tunnel_dst {1}'.format(tunnel_src, tunnel_dst)\
353 if tunnel_src is not None and tunnel_dst is not None else ''
355 out = VatExecutor.cmd_from_template(node,
356 'ipsec/ipsec_sad_add_entry.vat',
357 sad_id=sad_id, spi=spi,
358 calg=crypto_alg.alg_name, ckey=ckey,
359 ialg=integ_alg.alg_name, ikey=ikey,
361 VatJsonUtil.verify_vat_retval(
363 err_msg='Add SAD entry failed on {0}'.format(node['host']))
366 def vpp_ipsec_add_sad_entries(node, n_entries, sad_id, spi, crypto_alg,
367 crypto_key, integ_alg, integ_key,
368 tunnel_src=None, tunnel_dst=None):
369 """Create multiple Security Association Database entries on VPP node.
371 :param node: VPP node to add SAD entry on.
372 :param n_entries: Number of SAD entries to be created.
373 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
375 :param spi: Security Parameter Index of first SAD entry. All subsequent
376 SAD entries will have spi incremented by 1.
377 :param crypto_alg: The encryption algorithm name.
378 :param crypto_key: The encryption key string.
379 :param integ_alg: The integrity algorithm name.
380 :param integ_key: The integrity key string.
381 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
382 specified ESP transport mode is used.
383 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
384 not specified ESP transport mode is used.
389 :type crypto_alg: CryptoAlg
390 :type crypto_key: str
391 :type integ_alg: IntegAlg
393 :type tunnel_src: str
394 :type tunnel_dst: str
396 tmp_filename = '/tmp/ipsec_sad_{0}_add_del_entry.script'.format(sad_id)
397 ckey = crypto_key.encode('hex')
398 ikey = integ_key.encode('hex')
399 tunnel = 'tunnel_src {0} tunnel_dst {1}'.format(tunnel_src, tunnel_dst)\
400 if tunnel_src is not None and tunnel_dst is not None else ''
402 integ = 'integ_alg {0} integ_key {1}'.format(integ_alg.alg_name, ikey)\
403 if crypto_alg.alg_name != 'aes-gcm-128' else ''
405 with open(tmp_filename, 'w') as tmp_file:
406 for i in range(0, n_entries):
407 buf_str = 'ipsec_sad_add_del_entry esp sad_id {0} spi {1} ' \
408 'crypto_alg {2} crypto_key {3} {4} {5}\n'.format(
409 sad_id+i, spi+i, crypto_alg.alg_name, ckey, integ,
411 tmp_file.write(buf_str)
413 vat.execute_script(tmp_filename, node, timeout=300, json_out=False,
414 copy_on_execute=True)
415 os.remove(tmp_filename)
418 def vpp_ipsec_sa_set_key(node, sa_id, crypto_key, integ_key):
419 """Update Security Association (SA) keys.
421 :param node: VPP node to update SA keys.
422 :param sa_id: SAD entry ID.
423 :param crypto_key: The encryption key string.
424 :param integ_key: The integrity key string.
427 :type crypto_key: str
430 ckey = crypto_key.encode('hex')
431 ikey = integ_key.encode('hex')
433 out = VatExecutor.cmd_from_template(node,
434 'ipsec/ipsec_sa_set_key.vat',
436 ckey=ckey, ikey=ikey)
437 VatJsonUtil.verify_vat_retval(
439 err_msg='Update SA key failed on {0}'.format(node['host']))
442 def vpp_ipsec_add_spd(node, spd_id):
443 """Create Security Policy Database on the VPP node.
445 :param node: VPP node to add SPD on.
446 :param spd_id: SPD ID.
450 out = VatExecutor.cmd_from_template(node, 'ipsec/ipsec_spd_add.vat',
452 VatJsonUtil.verify_vat_retval(
454 err_msg='Add SPD {0} failed on {1}'.format(spd_id, node['host']))
457 def vpp_ipsec_spd_add_if(node, spd_id, interface):
458 """Add interface to the Security Policy Database.
460 :param node: VPP node.
461 :param spd_id: SPD ID to add interface on.
462 :param interface: Interface name or sw_if_index.
465 :type interface: str or int
467 sw_if_index = Topology.get_interface_sw_index(node, interface)\
468 if isinstance(interface, basestring) else interface
470 out = VatExecutor.cmd_from_template(node,
471 'ipsec/ipsec_interface_add_spd.vat',
472 spd_id=spd_id, sw_if_id=sw_if_index)
473 VatJsonUtil.verify_vat_retval(
475 err_msg='Add interface {0} to SPD {1} failed on {2}'.format(
476 interface, spd_id, node['host']))
479 def vpp_ipsec_spd_add_entry(node, spd_id, priority, action, inbound=True,
480 sa_id=None, laddr_range=None, raddr_range=None,
481 proto=None, lport_range=None, rport_range=None):
482 """Create Security Policy Database entry on the VPP node.
484 :param node: VPP node to add SPD entry on.
485 :param spd_id: SPD ID to add entry on.
486 :param priority: SPD entry priority, higher number = higher priority.
487 :param action: Policy action.
488 :param inbound: If True policy is for inbound traffic, otherwise
490 :param sa_id: SAD entry ID for protect action.
491 :param laddr_range: Policy selector local IPv4 or IPv6 address range in
492 format IP/prefix or IP/mask. If no mask is provided,
493 it's considered to be /32.
494 :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
495 format IP/prefix or IP/mask. If no mask is provided,
496 it's considered to be /32.
497 :param proto: Policy selector next layer protocol number.
498 :param lport_range: Policy selector local TCP/UDP port range in format
499 <port_start>-<port_end>.
500 :param rport_range: Policy selector remote TCP/UDP port range in format
501 <port_start>-<port_end>.
505 :type action: PolicyAction
508 :type laddr_range: string
509 :type raddr_range: string
511 :type lport_range: string
512 :type rport_range: string
514 direction = 'inbound' if inbound else 'outbound'
516 act_str = action.value
517 if PolicyAction.PROTECT == action and sa_id is not None:
518 act_str += 'sa_id {0}'.format(sa_id)
521 if laddr_range is not None:
522 net = ip_network(unicode(laddr_range), strict=False)
523 selector += 'laddr_start {0} laddr_stop {1} '.format(
524 net.network_address, net.broadcast_address)
525 if raddr_range is not None:
526 net = ip_network(unicode(raddr_range), strict=False)
527 selector += 'raddr_start {0} raddr_stop {1} '.format(
528 net.network_address, net.broadcast_address)
529 if proto is not None:
530 selector += 'protocol {0} '.format(proto)
531 if lport_range is not None:
532 selector += 'lport_start {p[0]} lport_stop {p[1]} '.format(
533 p=lport_range.split('-'))
534 if rport_range is not None:
535 selector += 'rport_start {p[0]} rport_stop {p[1]} '.format(
536 p=rport_range.split('-'))
538 out = VatExecutor.cmd_from_template(node,
539 'ipsec/ipsec_spd_add_entry.vat',
540 spd_id=spd_id, priority=priority,
541 action=act_str, direction=direction,
543 VatJsonUtil.verify_vat_retval(
545 err_msg='Add entry to SPD {0} failed on {1}'.format(spd_id,
549 def vpp_ipsec_spd_add_entries(node, n_entries, spd_id, priority, inbound,
550 sa_id, raddr_ip, raddr_range):
551 """Create multiple Security Policy Database entries on the VPP node.
553 :param node: VPP node to add SPD entries on.
554 :param n_entries: Number of SPD entries to be added.
555 :param spd_id: SPD ID to add entries on.
556 :param priority: SPD entries priority, higher number = higher priority.
557 :param inbound: If True policy is for inbound traffic, otherwise
559 :param sa_id: SAD entry ID for first entry. Each subsequent entry will
560 SAD entry ID incremented by 1.
561 :param raddr_ip: Policy selector remote IPv4 start address for the first
562 entry. Remote IPv4 end address will be calculated depending on
563 raddr_range parameter. Each subsequent entry will have start address
564 next after IPv4 end address of previous entry.
565 :param raddr_range: Mask specifying range of Policy selector Remote IPv4
566 addresses. Valid values are from 1 to 32.
573 :type raddr_ip: string
574 :type raddr_range: int
576 tmp_filename = '/tmp/ipsec_spd_{0}_add_del_entry.script'.format(sa_id)
578 direction = 'inbound' if inbound else 'outbound'
579 addr_incr = 1 << (32 - raddr_range)
580 addr_ip = int(ip_address(unicode(raddr_ip)))
581 start_str = 'ipsec_spd_add_del_entry spd_id {0} priority {1} {2} ' \
582 'action protect sa_id'.format(spd_id, priority, direction)
583 with open(tmp_filename, 'w') as tmp_file:
584 for i in range(0, n_entries):
585 r_ip_s = ip_address(addr_ip + addr_incr * i)
586 r_ip_e = ip_address(addr_ip + addr_incr * (i+1) - 1)
587 buf_str = '{0} {1} raddr_start {2} raddr_stop {3}\n'.format(
588 start_str, sa_id+i, r_ip_s, r_ip_e)
589 tmp_file.write(buf_str)
591 vat.execute_script(tmp_filename, node, timeout=300, json_out=False,
592 copy_on_execute=True)
593 os.remove(tmp_filename)
596 def vpp_ipsec_create_tunnel_interfaces(node1, node2, if1_ip_addr,
597 if2_ip_addr, if1_key, if2_key,
598 n_tunnels, crypto_alg, crypto_key,
599 integ_alg, integ_key, raddr_ip1,
600 raddr_ip2, raddr_range):
601 """Create multiple IPsec tunnel interfaces between two VPP nodes.
603 :param node1: VPP node 1 to create tunnel interfaces.
604 :param node2: VPP node 2 to create tunnel interfaces.
605 :param if1_ip_addr: VPP node 1 interface IP4 address.
606 :param if2_ip_addr: VPP node 2 interface IP4 address.
607 :param if1_key: VPP node 1 interface key from topology file.
608 :param if2_key: VPP node 2 interface key from topology file.
609 :param n_tunnels: Number of tunnell interfaces to create.
610 :param crypto_alg: The encryption algorithm name.
611 :param crypto_key: The encryption key string.
612 :param integ_alg: The integrity algorithm name.
613 :param integ_key: The integrity key string.
614 :param raddr_ip1: Policy selector remote IPv4 start address for the
615 first tunnel in direction node1->node2.
616 :param raddr_ip2: Policy selector remote IPv4 start address for the
617 first tunnel in direction node2->node1.
618 :param raddr_range: Mask specifying range of Policy selector Remote IPv4
619 addresses. Valid values are from 1 to 32.
622 :type if1_ip_addr: str
623 :type if2_ip_addr: str
627 :type crypto_alg: CryptoAlg
628 :type crypto_key: str
629 :type integ_alg: IntegAlg
631 :type raddr_ip1: string
632 :type raddr_ip2: string
633 :type raddr_range: int
638 raddr_ip1_i = int(ip_address(unicode(raddr_ip1)))
639 raddr_ip2_i = int(ip_address(unicode(raddr_ip2)))
640 addr_incr = 1 << (32 - raddr_range)
642 tmp_fn1 = '/tmp/ipsec_create_tunnel_dut1.config'
643 tmp_fn2 = '/tmp/ipsec_create_tunnel_dut2.config'
645 ckey = crypto_key.encode('hex')
646 ikey = integ_key.encode('hex')
649 with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
650 for i in range(0, n_tunnels):
652 # if crypto_alg.alg_name != 'aes-gcm-128':
653 if not crypto_alg.alg_name.startswith('aes-gcm-'):
654 integ = 'integ_alg {integ_alg} '\
655 'local_integ_key {local_integ_key} '\
656 'remote_integ_key {remote_integ_key} '\
657 .format(integ_alg=integ_alg.alg_name,
658 local_integ_key=ikey,
659 remote_integ_key=ikey)
660 dut1_tunnel = 'ipsec_tunnel_if_add_del '\
661 'local_spi {local_spi} '\
662 'remote_spi {remote_spi} '\
663 'crypto_alg {crypto_alg} '\
664 'local_crypto_key {local_crypto_key} '\
665 'remote_crypto_key {remote_crypto_key} '\
667 'local_ip {local_ip} '\
668 'remote_ip {remote_ip}\n'\
669 .format(local_spi=spi_1+i,
671 crypto_alg=crypto_alg.alg_name,
672 local_crypto_key=ckey,
673 remote_crypto_key=ckey,
675 local_ip=if1_ip_addr,
676 remote_ip=if2_ip_addr)
677 dut2_tunnel = 'ipsec_tunnel_if_add_del '\
678 'local_spi {local_spi} '\
679 'remote_spi {remote_spi} '\
680 'crypto_alg {crypto_alg} '\
681 'local_crypto_key {local_crypto_key} '\
682 'remote_crypto_key {remote_crypto_key} '\
684 'local_ip {local_ip} '\
685 'remote_ip {remote_ip}\n'\
686 .format(local_spi=spi_2+i,
688 crypto_alg=crypto_alg.alg_name,
689 local_crypto_key=ckey,
690 remote_crypto_key=ckey,
692 local_ip=if2_ip_addr,
693 remote_ip=if1_ip_addr)
694 tmp_f1.write(dut1_tunnel)
695 tmp_f2.write(dut2_tunnel)
696 vat.execute_script(tmp_fn1, node1, timeout=300, json_out=False,
697 copy_on_execute=True)
698 vat.execute_script(tmp_fn2, node2, timeout=300, json_out=False,
699 copy_on_execute=True)
703 with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
704 for i in range(0, n_tunnels):
705 raddr_ip1 = ip_address(raddr_ip1_i + addr_incr*i)
706 raddr_ip2 = ip_address(raddr_ip2_i + addr_incr*i)
707 dut1_if = Topology.get_interface_name(node1, if1_key)
708 dut1 = 'exec ip route add {raddr}/{mask} via {addr} ipsec{i}\n'\
709 'exec set interface unnumbered ipsec{i} use {uifc}\n'\
710 'exec set interface state ipsec{i} up\n'\
711 .format(raddr=raddr_ip2, mask=raddr_range,
712 addr=if2_ip_addr, i=i, uifc=dut1_if)
713 dut2_if = Topology.get_interface_name(node2, if2_key)
714 dut2 = 'exec ip route add {raddr}/{mask} via {addr} ipsec{i}\n'\
715 'exec set interface unnumbered ipsec{i} use {uifc}\n'\
716 'exec set interface state ipsec{i} up\n'\
717 .format(raddr=raddr_ip1, mask=raddr_range,
718 addr=if1_ip_addr, i=i, uifc=dut2_if)
722 vat.execute_script(tmp_fn1, node1, timeout=300, json_out=False,
723 copy_on_execute=True)
724 vat.execute_script(tmp_fn2, node2, timeout=300, json_out=False,
725 copy_on_execute=True)
730 def vpp_ipsec_add_multiple_tunnels(node1, node2, interface1, interface2,
731 n_tunnels, crypto_alg, crypto_key,
732 integ_alg, integ_key, tunnel_ip1,
733 tunnel_ip2, raddr_ip1, raddr_ip2,
735 """Create multiple IPsec tunnels between two VPP nodes.
737 :param node1: VPP node 1 to create tunnels.
738 :param node2: VPP node 2 to create tunnels.
739 :param interface1: Interface name or sw_if_index on node 1.
740 :param interface2: Interface name or sw_if_index on node 2.
741 :param n_tunnels: Number of tunnels to create.
742 :param crypto_alg: The encryption algorithm name.
743 :param crypto_key: The encryption key string.
744 :param integ_alg: The integrity algorithm name.
745 :param integ_key: The integrity key string.
746 :param tunnel_ip1: Tunnel node1 IPv4 address.
747 :param tunnel_ip2: Tunnel node2 IPv4 address.
748 :param raddr_ip1: Policy selector remote IPv4 start address for the
749 first tunnel in direction node1->node2.
750 :param raddr_ip2: Policy selector remote IPv4 start address for the
751 first tunnel in direction node2->node1.
752 :param raddr_range: Mask specifying range of Policy selector Remote IPv4
753 addresses. Valid values are from 1 to 32.
756 :type interface1: str or int
757 :type interface2: str or int
759 :type crypto_alg: CryptoAlg
760 :type crypto_key: str
763 :type tunnel_ip1: str
764 :type tunnel_ip2: str
765 :type raddr_ip1: string
766 :type raddr_ip2: string
767 :type raddr_range: int
778 IPsecUtil.vpp_ipsec_add_spd(node1, spd_id)
779 IPsecUtil.vpp_ipsec_spd_add_if(node1, spd_id, interface1)
780 IPsecUtil.vpp_ipsec_spd_add_entry(node1, spd_id, p_hi,
781 PolicyAction.BYPASS, inbound=False,
783 IPsecUtil.vpp_ipsec_spd_add_entry(node1, spd_id, p_hi,
784 PolicyAction.BYPASS, inbound=True,
787 IPsecUtil.vpp_ipsec_add_spd(node2, spd_id)
788 IPsecUtil.vpp_ipsec_spd_add_if(node2, spd_id, interface2)
789 IPsecUtil.vpp_ipsec_spd_add_entry(node2, spd_id, p_hi,
790 PolicyAction.BYPASS, inbound=False,
792 IPsecUtil.vpp_ipsec_spd_add_entry(node2, spd_id, p_hi,
793 PolicyAction.BYPASS, inbound=True,
796 IPsecUtil.vpp_ipsec_add_sad_entries(node1, n_tunnels, sa_id_1, spi_1,
797 crypto_alg, crypto_key, integ_alg,
798 integ_key, tunnel_ip1, tunnel_ip2)
800 IPsecUtil.vpp_ipsec_spd_add_entries(node1, n_tunnels, spd_id, p_lo,
801 False, sa_id_1, raddr_ip2,
804 IPsecUtil.vpp_ipsec_add_sad_entries(node2, n_tunnels, sa_id_1, spi_1,
805 crypto_alg, crypto_key, integ_alg,
806 integ_key, tunnel_ip1, tunnel_ip2)
808 IPsecUtil.vpp_ipsec_spd_add_entries(node2, n_tunnels, spd_id, p_lo,
809 True, sa_id_1, raddr_ip2,
812 IPsecUtil.vpp_ipsec_add_sad_entries(node2, n_tunnels, sa_id_2, spi_2,
813 crypto_alg, crypto_key, integ_alg,
814 integ_key, tunnel_ip2, tunnel_ip1)
816 IPsecUtil.vpp_ipsec_spd_add_entries(node2, n_tunnels, spd_id, p_lo,
817 False, sa_id_2, raddr_ip1,
820 IPsecUtil.vpp_ipsec_add_sad_entries(node1, n_tunnels, sa_id_2, spi_2,
821 crypto_alg, crypto_key, integ_alg,
822 integ_key, tunnel_ip2, tunnel_ip1)
824 IPsecUtil.vpp_ipsec_spd_add_entries(node1, n_tunnels, spd_id, p_lo,
825 True, sa_id_2, raddr_ip1,
829 def vpp_ipsec_show(node):
830 """Run "show ipsec" debug CLI command.
832 :param node: Node to run command on.
835 VatExecutor().execute_script('ipsec/ipsec_show.vat', node,