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
24 from resources.libraries.python.topology import Topology
25 from resources.libraries.python.VatExecutor import VatExecutor
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.SEC_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 # After API change there is returned VPP internal enum object
309 # representing VPP IPSEC protocol instead of integer representation
310 # so JSON fails to decode it - we need to check if it is Python API
311 # bug or we need to adapt vpp_papi_provider to correctly encode
312 # such object into JSON
313 # api_reply = papi_executor.get_papi_reply()
314 api_reply = papi_executor.get_papi_stdout()
316 if api_reply is not None:
317 logger.trace('IPsec backend dump\n{dump}'.format(dump=api_reply))
319 raise PapiError('No reply received for ipsec_select_backend API '
320 'command on host {host}'.format(host=node['host']))
323 def vpp_ipsec_add_sad_entry(node, sad_id, spi, crypto_alg, crypto_key,
324 integ_alg, integ_key, tunnel_src=None,
326 """Create Security Association Database entry on the VPP node.
328 :param node: VPP node to add SAD entry on.
329 :param sad_id: SAD entry ID.
330 :param spi: Security Parameter Index of this SAD entry.
331 :param crypto_alg: The encryption algorithm name.
332 :param crypto_key: The encryption key string.
333 :param integ_alg: The integrity algorithm name.
334 :param integ_key: The integrity key string.
335 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
336 specified ESP transport mode is used.
337 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
338 not specified ESP transport mode is used.
342 :type crypto_alg: CryptoAlg
343 :type crypto_key: str
344 :type integ_alg: IntegAlg
346 :type tunnel_src: str
347 :type tunnel_dst: str
349 ckey = crypto_key.encode('hex')
350 ikey = integ_key.encode('hex')
351 tunnel = 'tunnel-src {0} tunnel-dst {1}'.format(tunnel_src, tunnel_dst)\
352 if tunnel_src is not None and tunnel_dst is not None else ''
354 out = VatExecutor.cmd_from_template(node,
355 'ipsec/ipsec_sad_add_entry.vat',
356 sad_id=sad_id, spi=spi,
357 calg=crypto_alg.alg_name, ckey=ckey,
358 ialg=integ_alg.alg_name, ikey=ikey,
360 VatJsonUtil.verify_vat_retval(
362 err_msg='Add SAD entry failed on {0}'.format(node['host']))
365 def vpp_ipsec_add_sad_entries(node, n_entries, sad_id, spi, crypto_alg,
366 crypto_key, integ_alg, integ_key,
367 tunnel_src=None, tunnel_dst=None):
368 """Create multiple Security Association Database entries on VPP node.
370 :param node: VPP node to add SAD entry on.
371 :param n_entries: Number of SAD entries to be created.
372 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
374 :param spi: Security Parameter Index of first SAD entry. All subsequent
375 SAD entries will have spi incremented by 1.
376 :param crypto_alg: The encryption algorithm name.
377 :param crypto_key: The encryption key string.
378 :param integ_alg: The integrity algorithm name.
379 :param integ_key: The integrity key string.
380 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
381 specified ESP transport mode is used.
382 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
383 not specified ESP transport mode is used.
388 :type crypto_alg: CryptoAlg
389 :type crypto_key: str
390 :type integ_alg: IntegAlg
392 :type tunnel_src: str
393 :type tunnel_dst: str
395 tmp_filename = '/tmp/ipsec_sad_{0}_add_del_entry.script'.format(sad_id)
396 ckey = crypto_key.encode('hex')
397 ikey = integ_key.encode('hex')
398 tunnel = 'tunnel-src {0} tunnel-dst {1}'.format(tunnel_src, tunnel_dst)\
399 if tunnel_src is not None and tunnel_dst is not None else ''
401 integ = 'integ-alg {0} integ-key {1}'.format(integ_alg.alg_name, ikey)\
402 if crypto_alg.alg_name != 'aes-gcm-128' else ''
404 with open(tmp_filename, 'w') as tmp_file:
405 for i in range(0, n_entries):
406 buf_str = 'exec ipsec sa add {0} esp spi {1} ' \
407 'crypto-alg {2} crypto-key {3} {4} {5}\n'.format(
408 sad_id+i, spi+i, crypto_alg.alg_name, ckey, integ,
410 tmp_file.write(buf_str)
412 vat.execute_script(tmp_filename, node, timeout=300, json_out=False,
413 copy_on_execute=True)
414 os.remove(tmp_filename)
417 def vpp_ipsec_sa_set_key(node, sa_id, crypto_key, integ_key):
418 """Update Security Association (SA) keys.
420 :param node: VPP node to update SA keys.
421 :param sa_id: SAD entry ID.
422 :param crypto_key: The encryption key string.
423 :param integ_key: The integrity key string.
426 :type crypto_key: str
429 ckey = crypto_key.encode('hex')
430 ikey = integ_key.encode('hex')
432 out = VatExecutor.cmd_from_template(
433 node, 'ipsec/ipsec_sa_set_key.vat', json_param=False, sa_id=sa_id,
434 ckey=ckey, ikey=ikey)
435 VatJsonUtil.verify_vat_retval(
437 err_msg='Update SA key failed on {0}'.format(node['host']))
440 def vpp_ipsec_add_spd(node, spd_id):
441 """Create Security Policy Database on the VPP node.
443 :param node: VPP node to add SPD on.
444 :param spd_id: SPD ID.
448 out = VatExecutor.cmd_from_template(node, 'ipsec/ipsec_spd_add.vat',
450 VatJsonUtil.verify_vat_retval(
452 err_msg='Add SPD {0} failed on {1}'.format(spd_id, node['host']))
455 def vpp_ipsec_spd_add_if(node, spd_id, interface):
456 """Add interface to the Security Policy Database.
458 :param node: VPP node.
459 :param spd_id: SPD ID to add interface on.
460 :param interface: Interface name or sw_if_index.
463 :type interface: str or int
465 sw_if_index = Topology.get_interface_sw_index(node, interface)\
466 if isinstance(interface, basestring) else interface
468 out = VatExecutor.cmd_from_template(node,
469 'ipsec/ipsec_interface_add_spd.vat',
470 spd_id=spd_id, sw_if_id=sw_if_index)
471 VatJsonUtil.verify_vat_retval(
473 err_msg='Add interface {0} to SPD {1} failed on {2}'.format(
474 interface, spd_id, node['host']))
477 def vpp_ipsec_policy_add(node, spd_id, priority, action, inbound=True,
478 sa_id=None, laddr_range=None, raddr_range=None,
479 proto=None, lport_range=None, rport_range=None,
481 """Create Security Policy Database entry on the VPP node.
483 :param node: VPP node to add SPD entry on.
484 :param spd_id: SPD ID to add entry on.
485 :param priority: SPD entry priority, higher number = higher priority.
486 :param action: Policy action.
487 :param inbound: If True policy is for inbound traffic, otherwise
489 :param sa_id: SAD entry ID for protect action.
490 :param laddr_range: Policy selector local IPv4 or IPv6 address range in
491 format IP/prefix or IP/mask. If no mask is provided,
492 it's considered to be /32.
493 :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
494 format IP/prefix or IP/mask. If no mask is provided,
495 it's considered to be /32.
496 :param proto: Policy selector next layer protocol number.
497 :param lport_range: Policy selector local TCP/UDP port range in format
498 <port_start>-<port_end>.
499 :param rport_range: Policy selector remote TCP/UDP port range in format
500 <port_start>-<port_end>.
501 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
502 not defined so it will default to address ::/0, otherwise False.
506 :type action: PolicyAction
509 :type laddr_range: string
510 :type raddr_range: string
512 :type lport_range: string
513 :type rport_range: string
516 direction = 'inbound' if inbound else 'outbound'
518 if laddr_range is None and is_ipv6:
521 if raddr_range is None and is_ipv6:
524 act_str = action.value
525 if PolicyAction.PROTECT == action and sa_id is not None:
526 act_str += ' sa {0}'.format(sa_id)
529 if laddr_range is not None:
530 net = ip_network(unicode(laddr_range), strict=False)
531 selector += 'local-ip-range {0} - {1} '.format(
532 net.network_address, net.broadcast_address)
533 if raddr_range is not None:
534 net = ip_network(unicode(raddr_range), strict=False)
535 selector += 'remote-ip-range {0} - {1} '.format(
536 net.network_address, net.broadcast_address)
537 if proto is not None:
538 selector += 'protocol {0} '.format(proto)
539 if lport_range is not None:
540 selector += 'local-port-range {0} '.format(lport_range)
541 if rport_range is not None:
542 selector += 'remote-port-range {0} '.format(rport_range)
544 out = VatExecutor.cmd_from_template(
545 node, 'ipsec/ipsec_policy_add.vat', json_param=False, spd_id=spd_id,
546 priority=priority, action=act_str, direction=direction,
548 VatJsonUtil.verify_vat_retval(
550 err_msg='Add IPsec policy ID {0} failed on {1}'.format(
551 spd_id, node['host']))
554 def vpp_ipsec_spd_add_entries(node, n_entries, spd_id, priority, inbound,
555 sa_id, raddr_ip, raddr_range):
556 """Create multiple Security Policy Database entries on the VPP node.
558 :param node: VPP node to add SPD entries on.
559 :param n_entries: Number of SPD entries to be added.
560 :param spd_id: SPD ID to add entries on.
561 :param priority: SPD entries priority, higher number = higher priority.
562 :param inbound: If True policy is for inbound traffic, otherwise
564 :param sa_id: SAD entry ID for first entry. Each subsequent entry will
565 SAD entry ID incremented by 1.
566 :param raddr_ip: Policy selector remote IPv4 start address for the first
567 entry. Remote IPv4 end address will be calculated depending on
568 raddr_range parameter. Each subsequent entry will have start address
569 next after IPv4 end address of previous entry.
570 :param raddr_range: Mask specifying range of Policy selector Remote IPv4
571 addresses. Valid values are from 1 to 32.
578 :type raddr_ip: string
579 :type raddr_range: int
581 tmp_filename = '/tmp/ipsec_spd_{0}_add_del_entry.script'.format(sa_id)
583 direction = 'inbound' if inbound else 'outbound'
584 addr_incr = 1 << (32 - raddr_range)
585 addr_ip = int(ip_address(unicode(raddr_ip)))
586 start_str = 'exec ipsec policy add spd {0} priority {1} {2} ' \
587 'action protect sa'.format(spd_id, priority, direction)
588 with open(tmp_filename, 'w') as tmp_file:
589 for i in range(0, n_entries):
590 r_ip_s = ip_address(addr_ip + addr_incr * i)
591 r_ip_e = ip_address(addr_ip + addr_incr * (i+1) - 1)
592 buf_str = '{0} {1} remote-ip-range {2} - {3}\n'.format(
593 start_str, sa_id+i, r_ip_s, r_ip_e)
594 tmp_file.write(buf_str)
596 vat.execute_script(tmp_filename, node, timeout=300, json_out=False,
597 copy_on_execute=True)
598 os.remove(tmp_filename)
601 def vpp_ipsec_create_tunnel_interfaces(node1, node2, if1_ip_addr,
602 if2_ip_addr, if1_key, if2_key,
603 n_tunnels, crypto_alg, crypto_key,
604 integ_alg, integ_key, raddr_ip1,
605 raddr_ip2, raddr_range):
606 """Create multiple IPsec tunnel interfaces between two VPP nodes.
608 :param node1: VPP node 1 to create tunnel interfaces.
609 :param node2: VPP node 2 to create tunnel interfaces.
610 :param if1_ip_addr: VPP node 1 interface IP4 address.
611 :param if2_ip_addr: VPP node 2 interface IP4 address.
612 :param if1_key: VPP node 1 interface key from topology file.
613 :param if2_key: VPP node 2 interface key from topology file.
614 :param n_tunnels: Number of tunnell interfaces to create.
615 :param crypto_alg: The encryption algorithm name.
616 :param crypto_key: The encryption key string.
617 :param integ_alg: The integrity algorithm name.
618 :param integ_key: The integrity key string.
619 :param raddr_ip1: Policy selector remote IPv4 start address for the
620 first tunnel in direction node1->node2.
621 :param raddr_ip2: Policy selector remote IPv4 start address for the
622 first tunnel in direction node2->node1.
623 :param raddr_range: Mask specifying range of Policy selector Remote IPv4
624 addresses. Valid values are from 1 to 32.
627 :type if1_ip_addr: str
628 :type if2_ip_addr: str
632 :type crypto_alg: CryptoAlg
633 :type crypto_key: str
634 :type integ_alg: IntegAlg
636 :type raddr_ip1: string
637 :type raddr_ip2: string
638 :type raddr_range: int
643 raddr_ip1_i = int(ip_address(unicode(raddr_ip1)))
644 raddr_ip2_i = int(ip_address(unicode(raddr_ip2)))
645 addr_incr = 1 << (32 - raddr_range)
647 tmp_fn1 = '/tmp/ipsec_create_tunnel_dut1.config'
648 tmp_fn2 = '/tmp/ipsec_create_tunnel_dut2.config'
650 ckey = crypto_key.encode('hex')
651 ikey = integ_key.encode('hex')
654 with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
655 for i in range(0, n_tunnels):
657 if not crypto_alg.alg_name.startswith('aes-gcm-'):
658 integ = 'integ_alg {integ_alg} '\
659 'local_integ_key {local_integ_key} '\
660 'remote_integ_key {remote_integ_key} '\
661 .format(integ_alg=integ_alg.alg_name,
662 local_integ_key=ikey,
663 remote_integ_key=ikey)
664 dut1_tunnel = 'ipsec_tunnel_if_add_del '\
665 'local_spi {local_spi} '\
666 'remote_spi {remote_spi} '\
667 'crypto_alg {crypto_alg} '\
668 'local_crypto_key {local_crypto_key} '\
669 'remote_crypto_key {remote_crypto_key} '\
671 'local_ip {local_ip} '\
672 'remote_ip {remote_ip}\n'\
673 .format(local_spi=spi_1+i,
675 crypto_alg=crypto_alg.alg_name,
676 local_crypto_key=ckey,
677 remote_crypto_key=ckey,
679 local_ip=if1_ip_addr,
680 remote_ip=if2_ip_addr)
681 dut2_tunnel = 'ipsec_tunnel_if_add_del '\
682 'local_spi {local_spi} '\
683 'remote_spi {remote_spi} '\
684 'crypto_alg {crypto_alg} '\
685 'local_crypto_key {local_crypto_key} '\
686 'remote_crypto_key {remote_crypto_key} '\
688 'local_ip {local_ip} '\
689 'remote_ip {remote_ip}\n'\
690 .format(local_spi=spi_2+i,
692 crypto_alg=crypto_alg.alg_name,
693 local_crypto_key=ckey,
694 remote_crypto_key=ckey,
696 local_ip=if2_ip_addr,
697 remote_ip=if1_ip_addr)
698 tmp_f1.write(dut1_tunnel)
699 tmp_f2.write(dut2_tunnel)
700 vat.execute_script(tmp_fn1, node1, timeout=300, json_out=False,
701 copy_on_execute=True)
702 vat.execute_script(tmp_fn2, node2, timeout=300, json_out=False,
703 copy_on_execute=True)
707 with open(tmp_fn1, 'w') as tmp_f1, open(tmp_fn2, 'w') as tmp_f2:
708 for i in range(0, n_tunnels):
709 raddr_ip1 = ip_address(raddr_ip1_i + addr_incr*i)
710 raddr_ip2 = ip_address(raddr_ip2_i + addr_incr*i)
711 dut1_if = Topology.get_interface_name(node1, if1_key)
712 dut1 = 'exec ip route add {raddr}/{mask} via {addr} ipsec{i}\n'\
713 'exec set interface unnumbered ipsec{i} use {uifc}\n'\
714 'exec set interface state ipsec{i} up\n'\
715 .format(raddr=raddr_ip2, mask=raddr_range,
716 addr=if2_ip_addr, i=i, uifc=dut1_if)
717 dut2_if = Topology.get_interface_name(node2, if2_key)
718 dut2 = 'exec ip route add {raddr}/{mask} via {addr} ipsec{i}\n'\
719 'exec set interface unnumbered ipsec{i} use {uifc}\n'\
720 'exec set interface state ipsec{i} up\n'\
721 .format(raddr=raddr_ip1, mask=raddr_range,
722 addr=if1_ip_addr, i=i, uifc=dut2_if)
726 vat.execute_script(tmp_fn1, node1, timeout=300, json_out=False,
727 copy_on_execute=True)
728 vat.execute_script(tmp_fn2, node2, timeout=300, json_out=False,
729 copy_on_execute=True)
734 def vpp_ipsec_add_multiple_tunnels(node1, node2, interface1, interface2,
735 n_tunnels, crypto_alg, crypto_key,
736 integ_alg, integ_key, tunnel_ip1,
737 tunnel_ip2, raddr_ip1, raddr_ip2,
739 """Create multiple IPsec tunnels between two VPP nodes.
741 :param node1: VPP node 1 to create tunnels.
742 :param node2: VPP node 2 to create tunnels.
743 :param interface1: Interface name or sw_if_index on node 1.
744 :param interface2: Interface name or sw_if_index on node 2.
745 :param n_tunnels: Number of tunnels to create.
746 :param crypto_alg: The encryption algorithm name.
747 :param crypto_key: The encryption key string.
748 :param integ_alg: The integrity algorithm name.
749 :param integ_key: The integrity key string.
750 :param tunnel_ip1: Tunnel node1 IPv4 address.
751 :param tunnel_ip2: Tunnel node2 IPv4 address.
752 :param raddr_ip1: Policy selector remote IPv4 start address for the
753 first tunnel in direction node1->node2.
754 :param raddr_ip2: Policy selector remote IPv4 start address for the
755 first tunnel in direction node2->node1.
756 :param raddr_range: Mask specifying range of Policy selector Remote IPv4
757 addresses. Valid values are from 1 to 32.
760 :type interface1: str or int
761 :type interface2: str or int
763 :type crypto_alg: CryptoAlg
764 :type crypto_key: str
767 :type tunnel_ip1: str
768 :type tunnel_ip2: str
769 :type raddr_ip1: string
770 :type raddr_ip2: string
771 :type raddr_range: int
782 IPsecUtil.vpp_ipsec_add_spd(node1, spd_id)
783 IPsecUtil.vpp_ipsec_spd_add_if(node1, spd_id, interface1)
784 IPsecUtil.vpp_ipsec_policy_add(node1, spd_id, p_hi, PolicyAction.BYPASS,
785 inbound=False, proto=proto)
786 IPsecUtil.vpp_ipsec_policy_add(node1, spd_id, p_hi, PolicyAction.BYPASS,
787 inbound=True, proto=proto)
789 IPsecUtil.vpp_ipsec_add_spd(node2, spd_id)
790 IPsecUtil.vpp_ipsec_spd_add_if(node2, spd_id, interface2)
791 IPsecUtil.vpp_ipsec_policy_add(node2, spd_id, p_hi, PolicyAction.BYPASS,
792 inbound=False, proto=proto)
793 IPsecUtil.vpp_ipsec_policy_add(node2, spd_id, p_hi, PolicyAction.BYPASS,
794 inbound=True, proto=proto)
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,