1 # Copyright (c) 2021 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."""
18 from enum import Enum, IntEnum
20 from random import choice
21 from string import ascii_letters
23 from ipaddress import ip_network, ip_address
25 from resources.libraries.python.Constants import Constants
26 from resources.libraries.python.InterfaceUtil import InterfaceUtil, \
28 from resources.libraries.python.IPAddress import IPAddress
29 from resources.libraries.python.IPUtil import IPUtil, IpDscp, MPLS_LABEL_INVALID
30 from resources.libraries.python.PapiExecutor import PapiSocketExecutor
31 from resources.libraries.python.ssh import scp_node
32 from resources.libraries.python.topology import Topology
33 from resources.libraries.python.VatExecutor import VatExecutor
36 IPSEC_UDP_PORT_NONE = 0xffff
40 """Generate random string as a key.
42 :param length: Length of generated payload.
44 :returns: The generated payload.
48 choice(ascii_letters) for _ in range(length)
49 ).encode(encoding=u"utf-8")
52 class PolicyAction(Enum):
54 BYPASS = (u"bypass", 0)
55 DISCARD = (u"discard", 1)
56 PROTECT = (u"protect", 3)
58 def __init__(self, policy_name, policy_int_repr):
59 self.policy_name = policy_name
60 self.policy_int_repr = policy_int_repr
63 class CryptoAlg(Enum):
64 """Encryption algorithms."""
65 AES_CBC_128 = (u"aes-cbc-128", 1, u"AES-CBC", 16)
66 AES_CBC_256 = (u"aes-cbc-256", 3, u"AES-CBC", 32)
67 AES_GCM_128 = (u"aes-gcm-128", 7, u"AES-GCM", 16)
68 AES_GCM_256 = (u"aes-gcm-256", 9, u"AES-GCM", 32)
70 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
71 self.alg_name = alg_name
72 self.alg_int_repr = alg_int_repr
73 self.scapy_name = scapy_name
74 self.key_len = key_len
78 """Integrity algorithm."""
79 SHA_256_128 = (u"sha-256-128", 4, u"SHA2-256-128", 32)
80 SHA_512_256 = (u"sha-512-256", 6, u"SHA2-512-256", 64)
82 def __init__(self, alg_name, alg_int_repr, scapy_name, key_len):
83 self.alg_name = alg_name
84 self.alg_int_repr = alg_int_repr
85 self.scapy_name = scapy_name
86 self.key_len = key_len
89 class IPsecProto(IntEnum):
91 IPSEC_API_PROTO_ESP = 50
92 IPSEC_API_PROTO_AH = 51
95 class IPsecSadFlags(IntEnum):
96 """IPsec Security Association Database flags."""
97 IPSEC_API_SAD_FLAG_NONE = 0,
98 # Enable extended sequence numbers
99 IPSEC_API_SAD_FLAG_USE_ESN = 0x01,
100 # Enable Anti - replay
101 IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY = 0x02,
102 # IPsec tunnel mode if non-zero, else transport mode
103 IPSEC_API_SAD_FLAG_IS_TUNNEL = 0x04,
104 # IPsec tunnel mode is IPv6 if non-zero, else IPv4 tunnel
105 # only valid if is_tunnel is non-zero
106 IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 0x08,
107 # Enable UDP encapsulation for NAT traversal
108 IPSEC_API_SAD_FLAG_UDP_ENCAP = 0x10,
109 # IPsec SA is or inbound traffic
110 IPSEC_API_SAD_FLAG_IS_INBOUND = 0x40
113 class TunnelEncpaDecapFlags(IntEnum):
114 """Flags controlling tunnel behaviour."""
115 TUNNEL_API_ENCAP_DECAP_FLAG_NONE = 0
116 # at encap, copy the DF bit of the payload into the tunnel header
117 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF = 1
118 # at encap, set the DF bit in the tunnel header
119 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF = 2
120 # at encap, copy the DSCP bits of the payload into the tunnel header
121 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP = 4
122 # at encap, copy the ECN bit of the payload into the tunnel header
123 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN = 8
124 # at decap, copy the ECN bit of the tunnel header into the payload
125 TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_ECN = 16
128 class TunnelMode(IntEnum):
131 TUNNEL_API_MODE_P2P = 0
133 TUNNEL_API_MODE_MP = 1
137 """IPsec utilities."""
140 def policy_action_bypass():
141 """Return policy action bypass.
143 :returns: PolicyAction enum BYPASS object.
146 return PolicyAction.BYPASS
149 def policy_action_discard():
150 """Return policy action discard.
152 :returns: PolicyAction enum DISCARD object.
155 return PolicyAction.DISCARD
158 def policy_action_protect():
159 """Return policy action protect.
161 :returns: PolicyAction enum PROTECT object.
164 return PolicyAction.PROTECT
167 def crypto_alg_aes_cbc_128():
168 """Return encryption algorithm aes-cbc-128.
170 :returns: CryptoAlg enum AES_CBC_128 object.
173 return CryptoAlg.AES_CBC_128
176 def crypto_alg_aes_cbc_256():
177 """Return encryption algorithm aes-cbc-256.
179 :returns: CryptoAlg enum AES_CBC_256 object.
182 return CryptoAlg.AES_CBC_256
185 def crypto_alg_aes_gcm_128():
186 """Return encryption algorithm aes-gcm-128.
188 :returns: CryptoAlg enum AES_GCM_128 object.
191 return CryptoAlg.AES_GCM_128
194 def crypto_alg_aes_gcm_256():
195 """Return encryption algorithm aes-gcm-256.
197 :returns: CryptoAlg enum AES_GCM_128 object.
200 return CryptoAlg.AES_GCM_256
203 def get_crypto_alg_key_len(crypto_alg):
204 """Return encryption algorithm key length.
206 :param crypto_alg: Encryption algorithm.
207 :type crypto_alg: CryptoAlg
208 :returns: Key length.
211 return crypto_alg.key_len
214 def get_crypto_alg_scapy_name(crypto_alg):
215 """Return encryption algorithm scapy name.
217 :param crypto_alg: Encryption algorithm.
218 :type crypto_alg: CryptoAlg
219 :returns: Algorithm scapy name.
222 return crypto_alg.scapy_name
225 def integ_alg_sha_256_128():
226 """Return integrity algorithm SHA-256-128.
228 :returns: IntegAlg enum SHA_256_128 object.
231 return IntegAlg.SHA_256_128
234 def integ_alg_sha_512_256():
235 """Return integrity algorithm SHA-512-256.
237 :returns: IntegAlg enum SHA_512_256 object.
240 return IntegAlg.SHA_512_256
243 def get_integ_alg_key_len(integ_alg):
244 """Return integrity algorithm key length.
246 None argument is accepted, returning zero.
248 :param integ_alg: Integrity algorithm.
249 :type integ_alg: Optional[IntegAlg]
250 :returns: Key length.
253 return 0 if integ_alg is None else integ_alg.key_len
256 def get_integ_alg_scapy_name(integ_alg):
257 """Return integrity algorithm scapy name.
259 :param integ_alg: Integrity algorithm.
260 :type integ_alg: IntegAlg
261 :returns: Algorithm scapy name.
264 return integ_alg.scapy_name
267 def ipsec_proto_esp():
268 """Return IPSec protocol ESP.
270 :returns: IPsecProto enum ESP object.
273 return int(IPsecProto.IPSEC_API_PROTO_ESP)
276 def ipsec_proto_ah():
277 """Return IPSec protocol AH.
279 :returns: IPsecProto enum AH object.
282 return int(IPsecProto.IPSEC_API_PROTO_AH)
285 def vpp_ipsec_select_backend(node, protocol, index=1):
286 """Select IPsec backend.
288 :param node: VPP node to select IPsec backend on.
289 :param protocol: IPsec protocol.
290 :param index: Backend index.
292 :type protocol: IPsecProto
294 :raises RuntimeError: If failed to select IPsec backend or if no API
297 cmd = u"ipsec_select_backend"
298 err_msg = f"Failed to select IPsec backend on host {node[u'host']}"
303 with PapiSocketExecutor(node) as papi_exec:
304 papi_exec.add(cmd, **args).get_reply(err_msg)
307 def vpp_ipsec_set_async_mode(node, async_enable=1):
308 """Set IPsec async mode on|off.
310 :param node: VPP node to set IPsec async mode.
311 :param async_enable: Async mode on or off.
313 :type async_enable: int
314 :raises RuntimeError: If failed to set IPsec async mode or if no API
317 cmd = u"ipsec_set_async_mode"
318 err_msg = f"Failed to set IPsec async mode on host {node[u'host']}"
320 async_enable=async_enable
322 with PapiSocketExecutor(node) as papi_exec:
323 papi_exec.add(cmd, **args).get_reply(err_msg)
326 def vpp_ipsec_crypto_sw_scheduler_set_worker(
327 node, worker_index, crypto_enable=False):
328 """Enable or disable crypto on specific vpp worker threads.
330 :param node: VPP node to enable or disable crypto for worker threads.
331 :param worker_index: VPP worker thread index.
332 :param crypto_enable: Disable or enable crypto work.
334 :type worker_index: int
335 :type crypto_enable: bool
336 :raises RuntimeError: If failed to enable or disable crypto for worker
337 thread or if no API reply received.
339 cmd = u"crypto_sw_scheduler_set_worker"
340 err_msg = f"Failed to disable/enable crypto for worker thread " \
341 f"on host {node[u'host']}"
343 worker_index=worker_index,
344 crypto_enable=crypto_enable
346 with PapiSocketExecutor(node) as papi_exec:
347 papi_exec.add(cmd, **args).get_reply(err_msg)
350 def vpp_ipsec_add_sad_entry(
351 node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
352 integ_key=u"", tunnel_src=None, tunnel_dst=None):
353 """Create Security Association Database entry on the VPP node.
355 :param node: VPP node to add SAD entry on.
356 :param sad_id: SAD entry ID.
357 :param spi: Security Parameter Index of this SAD entry.
358 :param crypto_alg: The encryption algorithm name.
359 :param crypto_key: The encryption key string.
360 :param integ_alg: The integrity algorithm name.
361 :param integ_key: The integrity key string.
362 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
363 specified ESP transport mode is used.
364 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
365 not specified ESP transport mode is used.
369 :type crypto_alg: CryptoAlg
370 :type crypto_key: str
371 :type integ_alg: Optional[IntegAlg]
373 :type tunnel_src: str
374 :type tunnel_dst: str
376 if isinstance(crypto_key, str):
377 crypto_key = crypto_key.encode(encoding=u"utf-8")
378 if isinstance(integ_key, str):
379 integ_key = integ_key.encode(encoding=u"utf-8")
381 length=len(crypto_key),
385 length=len(integ_key),
386 data=integ_key if integ_key else 0
389 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
390 if tunnel_src and tunnel_dst:
391 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
392 src_addr = ip_address(tunnel_src)
393 dst_addr = ip_address(tunnel_dst)
394 if src_addr.version == 6:
396 flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6)
401 cmd = u"ipsec_sad_entry_add_del_v2"
402 err_msg = f"Failed to add Security Association Database entry " \
403 f"on host {node[u'host']}"
407 crypto_algorithm=crypto_alg.alg_int_repr,
409 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
412 tunnel_src=str(src_addr),
413 tunnel_dst=str(dst_addr),
415 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
417 dscp=int(IpDscp.IP_API_DSCP_CS0),
418 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
419 udp_src_port=4500, # default value in api
420 udp_dst_port=4500 # default value in api
426 with PapiSocketExecutor(node) as papi_exec:
427 papi_exec.add(cmd, **args).get_reply(err_msg)
430 def vpp_ipsec_add_sad_entries(
431 node, n_entries, sad_id, spi, crypto_alg, crypto_key,
432 integ_alg=None, integ_key=u"", tunnel_src=None, tunnel_dst=None):
433 """Create multiple Security Association Database entries on VPP node.
435 :param node: VPP node to add SAD entry on.
436 :param n_entries: Number of SAD entries to be created.
437 :param sad_id: First SAD entry ID. All subsequent SAD entries will have
439 :param spi: Security Parameter Index of first SAD entry. All subsequent
440 SAD entries will have spi incremented by 1.
441 :param crypto_alg: The encryption algorithm name.
442 :param crypto_key: The encryption key string.
443 :param integ_alg: The integrity algorithm name.
444 :param integ_key: The integrity key string.
445 :param tunnel_src: Tunnel header source IPv4 or IPv6 address. If not
446 specified ESP transport mode is used.
447 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address. If
448 not specified ESP transport mode is used.
453 :type crypto_alg: CryptoAlg
454 :type crypto_key: str
455 :type integ_alg: Optional[IntegAlg]
457 :type tunnel_src: str
458 :type tunnel_dst: str
460 if isinstance(crypto_key, str):
461 crypto_key = crypto_key.encode(encoding=u"utf-8")
462 if isinstance(integ_key, str):
463 integ_key = integ_key.encode(encoding=u"utf-8")
464 if tunnel_src and tunnel_dst:
465 src_addr = ip_address(tunnel_src)
466 dst_addr = ip_address(tunnel_dst)
471 addr_incr = 1 << (128 - 96) if src_addr.version == 6 \
474 if int(n_entries) > 10:
475 tmp_filename = f"/tmp/ipsec_sad_{sad_id}_add_del_entry.script"
477 with open(tmp_filename, 'w') as tmp_file:
478 for i in range(n_entries):
479 integ = f"integ-alg {integ_alg.alg_name} " \
480 f"integ-key {integ_key.hex()}" \
481 if integ_alg else u""
482 tunnel = f"tunnel src {src_addr + i * addr_incr} " \
483 f"tunnel dst {dst_addr + i * addr_incr}" \
484 if tunnel_src and tunnel_dst else u""
485 conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
486 f"crypto-alg {crypto_alg.alg_name} " \
487 f"crypto-key {crypto_key.hex()} " \
488 f"{integ} {tunnel}\n"
492 tmp_filename, node, timeout=300, json_out=False,
495 os.remove(tmp_filename)
499 length=len(crypto_key),
503 length=len(integ_key),
504 data=integ_key if integ_key else 0
507 flags = int(IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE)
508 if tunnel_src and tunnel_dst:
509 flags = flags | int(IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL)
510 if src_addr.version == 6:
512 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
515 cmd = u"ipsec_sad_entry_add_del_v2"
516 err_msg = f"Failed to add Security Association Database entry " \
517 f"on host {node[u'host']}"
522 crypto_algorithm=crypto_alg.alg_int_repr,
524 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
527 tunnel_src=str(src_addr),
528 tunnel_dst=str(dst_addr),
530 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
532 dscp=int(IpDscp.IP_API_DSCP_CS0),
533 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
534 udp_src_port=4500, # default value in api
535 udp_dst_port=4500 # default value in api
541 with PapiSocketExecutor(node) as papi_exec:
542 for i in range(n_entries):
543 args[u"entry"][u"sad_id"] = int(sad_id) + i
544 args[u"entry"][u"spi"] = int(spi) + i
545 args[u"entry"][u"tunnel_src"] = str(src_addr + i * addr_incr) \
546 if tunnel_src and tunnel_dst else src_addr
547 args[u"entry"][u"tunnel_dst"] = str(dst_addr + i * addr_incr) \
548 if tunnel_src and tunnel_dst else dst_addr
549 history = bool(not 1 < i < n_entries - 2)
550 papi_exec.add(cmd, history=history, **args)
551 papi_exec.get_replies(err_msg)
554 def vpp_ipsec_set_ip_route(
555 node, n_tunnels, tunnel_src, traffic_addr, tunnel_dst, interface,
556 raddr_range, dst_mac=None):
557 """Set IP address and route on interface.
559 :param node: VPP node to add config on.
560 :param n_tunnels: Number of tunnels to create.
561 :param tunnel_src: Tunnel header source IPv4 or IPv6 address.
562 :param traffic_addr: Traffic destination IP address to route.
563 :param tunnel_dst: Tunnel header destination IPv4 or IPv6 address.
564 :param interface: Interface key on node 1.
565 :param raddr_range: Mask specifying range of Policy selector Remote IP
566 addresses. Valid values are from 1 to 32 in case of IPv4 and to 128
568 :param dst_mac: The MAC address of destination tunnels.
571 :type tunnel_src: str
572 :type traffic_addr: str
573 :type tunnel_dst: str
575 :type raddr_range: int
578 tunnel_src = ip_address(tunnel_src)
579 tunnel_dst = ip_address(tunnel_dst)
580 traffic_addr = ip_address(traffic_addr)
581 addr_incr = 1 << (128 - raddr_range) if tunnel_src.version == 6 \
582 else 1 << (32 - raddr_range)
584 if int(n_tunnels) > 10:
585 tmp_filename = u"/tmp/ipsec_set_ip.script"
587 with open(tmp_filename, 'w') as tmp_file:
588 if_name = Topology.get_interface_name(node, interface)
589 for i in range(n_tunnels):
590 conf = f"exec set interface ip address {if_name} " \
591 f"{tunnel_src + i * addr_incr}/{raddr_range}\n" \
592 f"exec ip route add {traffic_addr + i}/" \
593 f"{128 if traffic_addr.version == 6 else 32} " \
594 f"via {tunnel_dst + i * addr_incr} {if_name}\n"
596 conf = f"{conf}exec set ip neighbor {if_name} " \
597 f"{tunnel_dst + i * addr_incr} {dst_mac}\n"
600 VatExecutor().execute_script(
601 tmp_filename, node, timeout=300, json_out=False,
604 os.remove(tmp_filename)
607 cmd1 = u"sw_interface_add_del_address"
609 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
614 cmd2 = u"ip_route_add_del"
620 cmd3 = u"ip_neighbor_add_del"
624 sw_if_index=Topology.get_interface_sw_index(node, interface),
626 mac_address=str(dst_mac),
630 err_msg = f"Failed to configure IP addresses, IP routes and " \
631 f"IP neighbor on interface {interface} on host {node[u'host']}" \
633 else f"Failed to configure IP addresses and IP routes " \
634 f"on interface {interface} on host {node[u'host']}"
636 with PapiSocketExecutor(node) as papi_exec:
637 for i in range(n_tunnels):
638 args1[u"prefix"] = IPUtil.create_prefix_object(
639 tunnel_src + i * addr_incr, raddr_range
641 args2[u"route"] = IPUtil.compose_vpp_route_structure(
642 node, traffic_addr + i,
643 prefix_len=128 if traffic_addr.version == 6 else 32,
644 interface=interface, gateway=tunnel_dst + i * addr_incr
646 history = bool(not 1 < i < n_tunnels - 2)
647 papi_exec.add(cmd1, history=history, **args1).\
648 add(cmd2, history=history, **args2)
650 args3[u"neighbor"][u"ip_address"] = ip_address(
651 tunnel_dst + i * addr_incr
653 papi_exec.add(cmd3, history=history, **args3)
654 papi_exec.get_replies(err_msg)
657 def vpp_ipsec_add_spd(node, spd_id):
658 """Create Security Policy Database on the VPP node.
660 :param node: VPP node to add SPD on.
661 :param spd_id: SPD ID.
665 cmd = u"ipsec_spd_add_del"
666 err_msg = f"Failed to add Security Policy Database " \
667 f"on host {node[u'host']}"
672 with PapiSocketExecutor(node) as papi_exec:
673 papi_exec.add(cmd, **args).get_reply(err_msg)
676 def vpp_ipsec_spd_add_if(node, spd_id, interface):
677 """Add interface to the Security Policy Database.
679 :param node: VPP node.
680 :param spd_id: SPD ID to add interface on.
681 :param interface: Interface name or sw_if_index.
684 :type interface: str or int
686 cmd = u"ipsec_interface_add_del_spd"
687 err_msg = f"Failed to add interface {interface} to Security Policy " \
688 f"Database {spd_id} on host {node[u'host']}"
691 sw_if_index=InterfaceUtil.get_interface_index(node, interface),
694 with PapiSocketExecutor(node) as papi_exec:
695 papi_exec.add(cmd, **args).get_reply(err_msg)
698 def vpp_ipsec_policy_add(
699 node, spd_id, priority, action, inbound=True, sa_id=None,
700 laddr_range=None, raddr_range=None, proto=None, lport_range=None,
701 rport_range=None, is_ipv6=False):
702 """Create Security Policy Database entry on the VPP node.
704 :param node: VPP node to add SPD entry on.
705 :param spd_id: SPD ID to add entry on.
706 :param priority: SPD entry priority, higher number = higher priority.
707 :param action: Policy action.
708 :param inbound: If True policy is for inbound traffic, otherwise
710 :param sa_id: SAD entry ID for protect action.
711 :param laddr_range: Policy selector local IPv4 or IPv6 address range in
712 format IP/prefix or IP/mask. If no mask is provided,
713 it's considered to be /32.
714 :param raddr_range: Policy selector remote IPv4 or IPv6 address range in
715 format IP/prefix or IP/mask. If no mask is provided,
716 it's considered to be /32.
717 :param proto: Policy selector next layer protocol number.
718 :param lport_range: Policy selector local TCP/UDP port range in format
719 <port_start>-<port_end>.
720 :param rport_range: Policy selector remote TCP/UDP port range in format
721 <port_start>-<port_end>.
722 :param is_ipv6: True in case of IPv6 policy when IPv6 address range is
723 not defined so it will default to address ::/0, otherwise False.
727 :type action: PolicyAction
730 :type laddr_range: string
731 :type raddr_range: string
733 :type lport_range: string
734 :type rport_range: string
737 if laddr_range is None:
738 laddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
740 if raddr_range is None:
741 raddr_range = u"::/0" if is_ipv6 else u"0.0.0.0/0"
743 cmd = u"ipsec_spd_entry_add_del"
744 err_msg = f"Failed to add entry to Security Policy Database {spd_id} " \
745 f"on host {node[u'host']}"
749 priority=int(priority),
750 is_outbound=not inbound,
751 sa_id=int(sa_id) if sa_id else 0,
752 policy=action.policy_int_repr,
753 protocol=int(proto) if proto else 0,
754 remote_address_start=IPAddress.create_ip_address_object(
755 ip_network(raddr_range, strict=False).network_address
757 remote_address_stop=IPAddress.create_ip_address_object(
758 ip_network(raddr_range, strict=False).broadcast_address
760 local_address_start=IPAddress.create_ip_address_object(
761 ip_network(laddr_range, strict=False).network_address
763 local_address_stop=IPAddress.create_ip_address_object(
764 ip_network(laddr_range, strict=False).broadcast_address
766 remote_port_start=int(rport_range.split(u"-")[0]) if rport_range
768 remote_port_stop=int(rport_range.split(u"-")[1]) if rport_range
770 local_port_start=int(lport_range.split(u"-")[0]) if lport_range
772 local_port_stop=int(lport_range.split(u"-")[1]) if rport_range
779 with PapiSocketExecutor(node) as papi_exec:
780 papi_exec.add(cmd, **args).get_reply(err_msg)
783 def vpp_ipsec_spd_add_entries(
784 node, n_entries, spd_id, priority, inbound, sa_id, raddr_ip,
786 """Create multiple Security Policy Database entries on the VPP node.
788 :param node: VPP node to add SPD entries on.
789 :param n_entries: Number of SPD entries to be added.
790 :param spd_id: SPD ID to add entries on.
791 :param priority: SPD entries priority, higher number = higher priority.
792 :param inbound: If True policy is for inbound traffic, otherwise
794 :param sa_id: SAD entry ID for first entry. Each subsequent entry will
795 SAD entry ID incremented by 1.
796 :param raddr_ip: Policy selector remote IPv4 start address for the first
797 entry. Remote IPv4 end address will be calculated depending on
798 raddr_range parameter. Each subsequent entry will have start address
799 next after IPv4 end address of previous entry.
800 :param raddr_range: Required IP addres range.
808 :type raddr_range: int
810 raddr_ip = ip_address(raddr_ip)
811 if int(n_entries) > 10:
812 tmp_filename = f"/tmp/ipsec_spd_{sa_id}_add_del_entry.script"
814 with open(tmp_filename, 'w') as tmp_file:
815 for i in range(n_entries):
816 direction = u'inbound' if inbound else u'outbound'
817 tunnel = f"exec ipsec policy add spd {spd_id} " \
818 f"priority {priority} {direction} " \
819 f"action protect sa {sa_id+i} " \
820 f"remote-ip-range {raddr_ip + i * (raddr_range + 1)} " \
821 f"- {raddr_ip + (i + 1) * raddr_range + i} " \
822 f"local-ip-range 0.0.0.0 - 255.255.255.255\n"
823 tmp_file.write(tunnel)
824 VatExecutor().execute_script(
825 tmp_filename, node, timeout=300, json_out=False,
828 os.remove(tmp_filename)
831 laddr_range = u"::/0" if raddr_ip.version == 6 else u"0.0.0.0/0"
833 cmd = u"ipsec_spd_entry_add_del"
834 err_msg = f"ailed to add entry to Security Policy Database '{spd_id} " \
835 f"on host {node[u'host']}"
839 priority=int(priority),
840 is_outbound=not inbound,
841 sa_id=int(sa_id) if sa_id else 0,
842 policy=getattr(PolicyAction.PROTECT, u"policy_int_repr"),
844 remote_address_start=IPAddress.create_ip_address_object(raddr_ip),
845 remote_address_stop=IPAddress.create_ip_address_object(raddr_ip),
846 local_address_start=IPAddress.create_ip_address_object(
847 ip_network(laddr_range, strict=False).network_address
849 local_address_stop=IPAddress.create_ip_address_object(
850 ip_network(laddr_range, strict=False).broadcast_address
853 remote_port_stop=65535,
855 local_port_stop=65535
862 with PapiSocketExecutor(node) as papi_exec:
863 for i in range(n_entries):
864 args[u"entry"][u"remote_address_start"][u"un"] = \
865 IPAddress.union_addr(raddr_ip + i)
866 args[u"entry"][u"remote_address_stop"][u"un"] = \
867 IPAddress.union_addr(raddr_ip + i)
868 history = bool(not 1 < i < n_entries - 2)
869 papi_exec.add(cmd, history=history, **args)
870 papi_exec.get_replies(err_msg)
873 def _ipsec_create_tunnel_interfaces_dut1_vat(
874 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
875 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
876 """Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
878 Generate random keys and return them (so DUT2 or TG can decrypt).
880 :param nodes: VPP nodes to create tunnel interfaces.
881 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
882 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
883 IPv4/IPv6 address (ip2).
884 :param if1_key: VPP node 1 interface key from topology file.
885 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
886 interface key from topology file.
887 :param n_tunnels: Number of tunnel interfaces to be there at the end.
888 :param crypto_alg: The encryption algorithm name.
889 :param integ_alg: The integrity algorithm name.
890 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
891 first tunnel in direction node2->node1.
892 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
893 :param addr_incr: IP / IPv6 address incremental step.
894 :param existing_tunnels: Number of tunnel interfaces before creation.
895 Useful mainly for reconf tests. Default 0.
901 :type crypto_alg: CryptoAlg
902 :type integ_alg: Optional[IntegAlg]
903 :type raddr_ip2: IPv4Address or IPv6Address
906 :type existing_tunnels: int
907 :returns: Generated ckeys and ikeys.
908 :rtype: List[bytes], List[bytes]
910 tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
911 if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
913 ckeys = [bytes()] * existing_tunnels
914 ikeys = [bytes()] * existing_tunnels
917 with open(tmp_fn1, u"w") as tmp_f1:
918 rmac = Topology.get_interface_mac(nodes[u"DUT2"], if2_key) \
919 if u"DUT2" in nodes.keys() \
920 else Topology.get_interface_mac(nodes[u"TG"], if2_key)
921 if not existing_tunnels:
923 f"exec create loopback interface\n"
924 f"exec set interface state loop0 up\n"
925 f"exec set interface ip address {if1_n} "
926 f"{tun_ips[u'ip2'] - 1}/"
927 f"{len(tun_ips[u'ip2'].packed)*8*3//4}\n"
928 f"exec set ip neighbor {if1_n} {tun_ips[u'ip2']} {rmac} "
931 for i in range(existing_tunnels, n_tunnels):
933 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
936 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
939 integ = f"integ-alg {integ_alg.alg_name} " \
940 f"integ-key {ikeys[i].hex()} "
944 f"exec set interface ip address loop0 "
945 f"{tun_ips[u'ip1'] + i * addr_incr}/32\n"
946 f"exec create ipip tunnel "
947 f"src {tun_ips[u'ip1'] + i * addr_incr} "
948 f"dst {tun_ips[u'ip2']} "
950 f"exec ipsec sa add {i} "
951 f"spi {spi_d[u'spi_1'] + i} "
952 f"crypto-alg {crypto_alg.alg_name} "
953 f"crypto-key {ckeys[i].hex()} "
956 f"exec ipsec sa add {100000 + i} "
957 f"spi {spi_d[u'spi_2'] + i} "
958 f"crypto-alg {crypto_alg.alg_name} "
959 f"crypto-key {ckeys[i].hex()} "
962 f"exec ipsec tunnel protect ipip{i} "
964 f"sa-in {100000 + i} "
968 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
969 copy_on_execute=True,
970 history=bool(n_tunnels < 100)
974 with open(tmp_fn1, 'w') as tmp_f1:
975 for i in range(existing_tunnels, n_tunnels):
977 f"exec set interface unnumbered ipip{i} use {if1_n}\n"
978 f"exec set interface state ipip{i} up\n"
979 f"exec ip route add "
980 f"{raddr_ip2 + i}/{len(raddr_ip2.packed)*8} "
984 tmp_fn1, nodes[u"DUT1"], timeout=1800, json_out=False,
985 copy_on_execute=True,
986 history=bool(n_tunnels < 100)
993 def _ipsec_create_tunnel_interfaces_dut2_vat(
994 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
995 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
996 """Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
998 This method accesses keys generated by DUT1 method
999 and does not return anything.
1001 :param nodes: VPP nodes to create tunnel interfaces.
1002 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1003 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1004 IPv4/IPv6 address (ip2).
1005 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1006 interface key from topology file.
1007 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1008 :param crypto_alg: The encryption algorithm name.
1009 :param ckeys: List of encryption keys.
1010 :param integ_alg: The integrity algorithm name.
1011 :param ikeys: List of integrity keys.
1012 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1013 :param addr_incr: IP / IPv6 address incremental step.
1014 :param existing_tunnels: Number of tunnel interfaces before creation.
1015 Useful mainly for reconf tests. Default 0.
1019 :type n_tunnels: int
1020 :type crypto_alg: CryptoAlg
1021 :type ckeys: Sequence[bytes]
1022 :type integ_alg: Optional[IntegAlg]
1023 :type ikeys: Sequence[bytes]
1024 :type addr_incr: int
1026 :type existing_tunnels: int
1028 tmp_fn2 = u"/tmp/ipsec_create_tunnel_dut2.config"
1029 if2_n = Topology.get_interface_name(nodes[u"DUT2"], if2_key)
1032 with open(tmp_fn2, 'w') as tmp_f2:
1033 if not existing_tunnels:
1035 f"exec set interface ip address {if2_n}"
1036 f" {tun_ips[u'ip2']}/{len(tun_ips[u'ip2'].packed)*8*3/4}\n"
1038 for i in range(existing_tunnels, n_tunnels):
1040 integ = f"integ-alg {integ_alg.alg_name} " \
1041 f"integ-key {ikeys[i].hex()} "
1045 f"exec create ipip tunnel "
1046 f"src {tun_ips[u'ip2']} "
1047 f"dst {tun_ips[u'ip1'] + i * addr_incr} "
1049 f"exec ipsec sa add {100000 + i} "
1050 f"spi {spi_d[u'spi_2'] + i} "
1051 f"crypto-alg {crypto_alg.alg_name} "
1052 f"crypto-key {ckeys[i].hex()} "
1055 f"exec ipsec sa add {i} "
1056 f"spi {spi_d[u'spi_1'] + i} "
1057 f"crypto-alg {crypto_alg.alg_name} "
1058 f"crypto-key {ckeys[i].hex()} "
1061 f"exec ipsec tunnel protect ipip{i} "
1062 f"sa-out {100000 + i} "
1067 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1068 copy_on_execute=True,
1069 history=bool(n_tunnels < 100)
1073 with open(tmp_fn2, 'w') as tmp_f2:
1074 if not existing_tunnels:
1076 f"exec ip route add {tun_ips[u'ip1']}/8 "
1077 f"via {tun_ips[u'ip2'] - 1} {if2_n}\n"
1079 for i in range(existing_tunnels, n_tunnels):
1081 f"exec set interface unnumbered ipip{i} use {if2_n}\n"
1082 f"exec set interface state ipip{i} up\n"
1083 f"exec ip route add "
1084 f"{raddr_ip1 + i}/{len(raddr_ip1.packed)*8} "
1088 tmp_fn2, nodes[u"DUT2"], timeout=1800, json_out=False,
1089 copy_on_execute=True,
1090 history=bool(n_tunnels < 100)
1095 def _ipsec_create_loopback_dut1_papi(nodes, tun_ips, if1_key, if2_key):
1096 """Create loopback interface and set IP address on VPP node 1 interface
1099 :param nodes: VPP nodes to create tunnel interfaces.
1100 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1101 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1102 IPv4/IPv6 address (ip2).
1103 :param if1_key: VPP node 1 interface key from topology file.
1104 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1105 interface key from topology file.
1111 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1112 # Create loopback interface on DUT1, set it to up state
1113 cmd = u"create_loopback_instance"
1119 err_msg = f"Failed to create loopback interface " \
1120 f"on host {nodes[u'DUT1'][u'host']}"
1121 loop_sw_if_idx = papi_exec.add(cmd, **args). \
1122 get_sw_if_index(err_msg)
1123 cmd = u"sw_interface_set_flags"
1125 sw_if_index=loop_sw_if_idx,
1126 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1128 err_msg = f"Failed to set loopback interface state up " \
1129 f"on host {nodes[u'DUT1'][u'host']}"
1130 papi_exec.add(cmd, **args).get_reply(err_msg)
1131 # Set IP address on VPP node 1 interface
1132 cmd = u"sw_interface_add_del_address"
1134 sw_if_index=InterfaceUtil.get_interface_index(
1135 nodes[u"DUT1"], if1_key
1139 prefix=IPUtil.create_prefix_object(
1140 tun_ips[u"ip2"] - 1, 96 if tun_ips[u"ip2"].version == 6
1144 err_msg = f"Failed to set IP address on interface {if1_key} " \
1145 f"on host {nodes[u'DUT1'][u'host']}"
1146 papi_exec.add(cmd, **args).get_reply(err_msg)
1147 cmd2 = u"ip_neighbor_add_del"
1151 sw_if_index=Topology.get_interface_sw_index(
1152 nodes[u"DUT1"], if1_key
1156 Topology.get_interface_mac(nodes[u"DUT2"], if2_key)
1157 if u"DUT2" in nodes.keys()
1158 else Topology.get_interface_mac(
1159 nodes[u"TG"], if2_key
1162 ip_address=tun_ips[u"ip2"].compressed
1165 err_msg = f"Failed to add IP neighbor on interface {if1_key}"
1166 papi_exec.add(cmd2, **args2).get_reply(err_msg)
1168 return loop_sw_if_idx
1171 def _ipsec_create_tunnel_interfaces_dut1_papi(
1172 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg, integ_alg,
1173 raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
1174 """Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
1176 Generate random keys and return them (so DUT2 or TG can decrypt).
1178 :param nodes: VPP nodes to create tunnel interfaces.
1179 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1180 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1181 IPv4/IPv6 address (ip2).
1182 :param if1_key: VPP node 1 interface key from topology file.
1183 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1184 interface key from topology file.
1185 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1186 :param crypto_alg: The encryption algorithm name.
1187 :param integ_alg: The integrity algorithm name.
1188 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1189 first tunnel in direction node2->node1.
1190 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1191 :param addr_incr: IP / IPv6 address incremental step.
1192 :param existing_tunnels: Number of tunnel interfaces before creation.
1193 Useful mainly for reconf tests. Default 0.
1198 :type n_tunnels: int
1199 :type crypto_alg: CryptoAlg
1200 :type integ_alg: Optional[IntegAlg]
1201 :type raddr_ip2: IPv4Address or IPv6Address
1202 :type addr_incr: int
1204 :type existing_tunnels: int
1205 :returns: Generated ckeys and ikeys.
1206 :rtype: List[bytes], List[bytes]
1208 if not existing_tunnels:
1209 loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
1210 nodes, tun_ips, if1_key, if2_key
1213 loop_sw_if_idx = InterfaceUtil.vpp_get_interface_sw_index(
1214 nodes[u"DUT1"], u"loop0"
1216 with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
1217 # Configure IP addresses on loop0 interface
1218 cmd = u"sw_interface_add_del_address"
1220 sw_if_index=loop_sw_if_idx,
1225 for i in range(existing_tunnels, n_tunnels):
1226 args[u"prefix"] = IPUtil.create_prefix_object(
1227 tun_ips[u"ip1"] + i * addr_incr,
1228 128 if tun_ips[u"ip1"].version == 6 else 32
1231 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1233 # Configure IPIP tunnel interfaces
1234 cmd = u"ipip_add_tunnel"
1236 instance=Constants.BITWISE_NON_ZERO,
1241 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1243 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1244 dscp=int(IpDscp.IP_API_DSCP_CS0)
1249 ipip_tunnels = [None] * existing_tunnels
1250 for i in range(existing_tunnels, n_tunnels):
1251 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1252 tun_ips[u"ip1"] + i * addr_incr
1254 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1258 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1260 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1261 f" {nodes[u'DUT1'][u'host']}"
1262 ipip_tunnels.extend(
1264 reply[u"sw_if_index"]
1265 for reply in papi_exec.get_replies(err_msg)
1266 if u"sw_if_index" in reply
1269 # Configure IPSec SAD entries
1270 ckeys = [bytes()] * existing_tunnels
1271 ikeys = [bytes()] * existing_tunnels
1272 cmd = u"ipsec_sad_entry_add_del_v2"
1284 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1285 crypto_algorithm=crypto_alg.alg_int_repr,
1287 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1288 integrity_key=i_key,
1293 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1295 dscp=int(IpDscp.IP_API_DSCP_CS0),
1298 udp_src_port=IPSEC_UDP_PORT_NONE,
1299 udp_dst_port=IPSEC_UDP_PORT_NONE
1305 for i in range(existing_tunnels, n_tunnels):
1307 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1310 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1312 # SAD entry for outband / tx path
1313 args[u"entry"][u"sad_id"] = i
1314 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1316 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1317 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1319 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1320 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1321 args[u"entry"][u"flags"] = int(
1322 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1325 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1327 # SAD entry for inband / rx path
1328 args[u"entry"][u"sad_id"] = 100000 + i
1329 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1331 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1332 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1334 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1335 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1336 args[u"entry"][u"flags"] = int(
1337 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1338 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1341 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1343 err_msg = f"Failed to add IPsec SAD entries on host" \
1344 f" {nodes[u'DUT1'][u'host']}"
1345 papi_exec.get_replies(err_msg)
1346 # Add protection for tunnels with IPSEC
1347 cmd = u"ipsec_tunnel_protect_update"
1350 via_label=MPLS_LABEL_INVALID,
1351 obj_id=Constants.BITWISE_NON_ZERO
1353 ipsec_tunnel_protect = dict(
1361 tunnel=ipsec_tunnel_protect
1363 for i in range(existing_tunnels, n_tunnels):
1364 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1365 args[u"tunnel"][u"sa_out"] = i
1366 args[u"tunnel"][u"sa_in"] = [100000 + i]
1368 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1370 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1371 f"on host {nodes[u'DUT1'][u'host']}"
1372 papi_exec.get_replies(err_msg)
1374 # Configure unnumbered interfaces
1375 cmd = u"sw_interface_set_unnumbered"
1378 sw_if_index=InterfaceUtil.get_interface_index(
1379 nodes[u"DUT1"], if1_key
1381 unnumbered_sw_if_index=0
1383 for i in range(existing_tunnels, n_tunnels):
1384 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1386 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1389 cmd = u"sw_interface_set_flags"
1392 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1394 for i in range(existing_tunnels, n_tunnels):
1395 args[u"sw_if_index"] = ipip_tunnels[i]
1397 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1399 # Configure IP routes
1400 cmd = u"ip_route_add_del"
1406 for i in range(existing_tunnels, n_tunnels):
1407 args[u"route"] = IPUtil.compose_vpp_route_structure(
1408 nodes[u"DUT1"], (raddr_ip2 + i).compressed,
1409 prefix_len=128 if raddr_ip2.version == 6 else 32,
1410 interface=ipip_tunnels[i]
1413 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1415 err_msg = f"Failed to add IP routes on host " \
1416 f"{nodes[u'DUT1'][u'host']}"
1417 papi_exec.get_replies(err_msg)
1422 def _ipsec_create_tunnel_interfaces_dut2_papi(
1423 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys, integ_alg,
1424 ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
1425 """Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
1427 This method accesses keys generated by DUT1 method
1428 and does not return anything.
1430 :param nodes: VPP nodes to create tunnel interfaces.
1431 :param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
1432 IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
1433 IPv4/IPv6 address (ip2).
1434 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1435 interface key from topology file.
1436 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1437 :param crypto_alg: The encryption algorithm name.
1438 :param ckeys: List of encryption keys.
1439 :param integ_alg: The integrity algorithm name.
1440 :param ikeys: List of integrity keys.
1441 :param spi_d: Dictionary with SPIs for VPP node 1 and VPP node 2.
1442 :param addr_incr: IP / IPv6 address incremental step.
1443 :param existing_tunnels: Number of tunnel interfaces before creation.
1444 Useful mainly for reconf tests. Default 0.
1448 :type n_tunnels: int
1449 :type crypto_alg: CryptoAlg
1450 :type ckeys: Sequence[bytes]
1451 :type integ_alg: Optional[IntegAlg]
1452 :type ikeys: Sequence[bytes]
1453 :type addr_incr: int
1455 :type existing_tunnels: int
1457 with PapiSocketExecutor(nodes[u"DUT2"]) as papi_exec:
1458 if not existing_tunnels:
1459 # Set IP address on VPP node 2 interface
1460 cmd = u"sw_interface_add_del_address"
1462 sw_if_index=InterfaceUtil.get_interface_index(
1463 nodes[u"DUT2"], if2_key
1467 prefix=IPUtil.create_prefix_object(
1468 tun_ips[u"ip2"], 96 if tun_ips[u"ip2"].version == 6
1472 err_msg = f"Failed to set IP address on interface {if2_key} " \
1473 f"on host {nodes[u'DUT2'][u'host']}"
1474 papi_exec.add(cmd, **args).get_reply(err_msg)
1475 # Configure IPIP tunnel interfaces
1476 cmd = u"ipip_add_tunnel"
1478 instance=Constants.BITWISE_NON_ZERO,
1483 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1485 mode=int(TunnelMode.TUNNEL_API_MODE_P2P),
1486 dscp=int(IpDscp.IP_API_DSCP_CS0)
1491 ipip_tunnels = [None] * existing_tunnels
1492 for i in range(existing_tunnels, n_tunnels):
1493 args[u"tunnel"][u"src"] = IPAddress.create_ip_address_object(
1496 args[u"tunnel"][u"dst"] = IPAddress.create_ip_address_object(
1497 tun_ips[u"ip1"] + i * addr_incr
1500 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1502 err_msg = f"Failed to add IPIP tunnel interfaces on host" \
1503 f" {nodes[u'DUT2'][u'host']}"
1504 ipip_tunnels.extend(
1506 reply[u"sw_if_index"]
1507 for reply in papi_exec.get_replies(err_msg)
1508 if u"sw_if_index" in reply
1511 # Configure IPSec SAD entries
1512 cmd = u"ipsec_sad_entry_add_del_v2"
1524 protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
1526 crypto_algorithm=crypto_alg.alg_int_repr,
1528 integrity_algorithm=integ_alg.alg_int_repr if integ_alg else 0,
1529 integrity_key=i_key,
1535 TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
1537 dscp=int(IpDscp.IP_API_DSCP_CS0),
1540 udp_src_port=IPSEC_UDP_PORT_NONE,
1541 udp_dst_port=IPSEC_UDP_PORT_NONE
1547 for i in range(existing_tunnels, n_tunnels):
1549 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
1552 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
1554 # SAD entry for outband / tx path
1555 args[u"entry"][u"sad_id"] = 100000 + i
1556 args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
1558 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1559 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1561 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1562 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1563 args[u"entry"][u"flags"] = int(
1564 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE
1567 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1569 # SAD entry for inband / rx path
1570 args[u"entry"][u"sad_id"] = i
1571 args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
1573 args[u"entry"][u"crypto_key"][u"length"] = len(ckeys[i])
1574 args[u"entry"][u"crypto_key"][u"data"] = ckeys[i]
1576 args[u"entry"][u"integrity_key"][u"length"] = len(ikeys[i])
1577 args[u"entry"][u"integrity_key"][u"data"] = ikeys[i]
1578 args[u"entry"][u"flags"] = int(
1579 IPsecSadFlags.IPSEC_API_SAD_FLAG_NONE |
1580 IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_INBOUND
1583 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1585 err_msg = f"Failed to add IPsec SAD entries on host" \
1586 f" {nodes[u'DUT2'][u'host']}"
1587 papi_exec.get_replies(err_msg)
1588 # Add protection for tunnels with IPSEC
1589 cmd = u"ipsec_tunnel_protect_update"
1592 via_label=MPLS_LABEL_INVALID,
1593 obj_id=Constants.BITWISE_NON_ZERO
1595 ipsec_tunnel_protect = dict(
1603 tunnel=ipsec_tunnel_protect
1605 for i in range(existing_tunnels, n_tunnels):
1606 args[u"tunnel"][u"sw_if_index"] = ipip_tunnels[i]
1607 args[u"tunnel"][u"sa_out"] = 100000 + i
1608 args[u"tunnel"][u"sa_in"] = [i]
1610 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1612 err_msg = f"Failed to add protection for tunnels with IPSEC " \
1613 f"on host {nodes[u'DUT2'][u'host']}"
1614 papi_exec.get_replies(err_msg)
1616 if not existing_tunnels:
1617 # Configure IP route
1618 cmd = u"ip_route_add_del"
1619 route = IPUtil.compose_vpp_route_structure(
1620 nodes[u"DUT2"], tun_ips[u"ip1"].compressed,
1621 prefix_len=32 if tun_ips[u"ip1"].version == 6 else 8,
1623 gateway=(tun_ips[u"ip2"] - 1).compressed
1630 papi_exec.add(cmd, **args)
1631 # Configure unnumbered interfaces
1632 cmd = u"sw_interface_set_unnumbered"
1635 sw_if_index=InterfaceUtil.get_interface_index(
1636 nodes[u"DUT2"], if2_key
1638 unnumbered_sw_if_index=0
1640 for i in range(existing_tunnels, n_tunnels):
1641 args[u"unnumbered_sw_if_index"] = ipip_tunnels[i]
1643 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1646 cmd = u"sw_interface_set_flags"
1649 flags=InterfaceStatusFlags.IF_STATUS_API_FLAG_ADMIN_UP.value
1651 for i in range(existing_tunnels, n_tunnels):
1652 args[u"sw_if_index"] = ipip_tunnels[i]
1654 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1656 # Configure IP routes
1657 cmd = u"ip_route_add_del"
1663 for i in range(existing_tunnels, n_tunnels):
1664 args[u"route"] = IPUtil.compose_vpp_route_structure(
1665 nodes[u"DUT1"], (raddr_ip1 + i).compressed,
1666 prefix_len=128 if raddr_ip1.version == 6 else 32,
1667 interface=ipip_tunnels[i]
1670 cmd, history=bool(not 1 < i < n_tunnels - 2), **args
1672 err_msg = f"Failed to add IP routes " \
1673 f"on host {nodes[u'DUT2'][u'host']}"
1674 papi_exec.get_replies(err_msg)
1677 def vpp_ipsec_create_tunnel_interfaces(
1678 nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
1679 n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
1680 existing_tunnels=0, return_keys=False):
1681 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1683 Some deployments (e.g. devicetest) need to know the generated keys.
1684 But other deployments (e.g. scale perf test) would get spammed
1685 if we returned keys every time.
1687 :param nodes: VPP nodes to create tunnel interfaces.
1688 :param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
1690 :param tun_if2_ip_addr: VPP node 2 ipsec tunnel interface IPv4/IPv6
1692 :param if1_key: VPP node 1 interface key from topology file.
1693 :param if2_key: VPP node 2 / TG node (in case of 2-node topology)
1694 interface key from topology file.
1695 :param n_tunnels: Number of tunnel interfaces to be there at the end.
1696 :param crypto_alg: The encryption algorithm name.
1697 :param integ_alg: The integrity algorithm name.
1698 :param raddr_ip1: Policy selector remote IPv4/IPv6 start address for the
1699 first tunnel in direction node1->node2.
1700 :param raddr_ip2: Policy selector remote IPv4/IPv6 start address for the
1701 first tunnel in direction node2->node1.
1702 :param raddr_range: Mask specifying range of Policy selector Remote
1703 IPv4/IPv6 addresses. Valid values are from 1 to 32 in case of IPv4
1704 and to 128 in case of IPv6.
1705 :param existing_tunnels: Number of tunnel interfaces before creation.
1706 Useful mainly for reconf tests. Default 0.
1707 :param return_keys: Whether generated keys should be returned.
1709 :type tun_if1_ip_addr: str
1710 :type tun_if2_ip_addr: str
1713 :type n_tunnels: int
1714 :type crypto_alg: CryptoAlg
1715 :type integ_alg: Optonal[IntegAlg]
1716 :type raddr_ip1: string
1717 :type raddr_ip2: string
1718 :type raddr_range: int
1719 :type existing_tunnels: int
1720 :type return_keys: bool
1721 :returns: Ckeys, ikeys, spi_1, spi_2.
1722 :rtype: Optional[List[bytes], List[bytes], int, int]
1724 n_tunnels = int(n_tunnels)
1725 existing_tunnels = int(existing_tunnels)
1731 ip1=ip_address(tun_if1_ip_addr),
1732 ip2=ip_address(tun_if2_ip_addr)
1734 raddr_ip1 = ip_address(raddr_ip1)
1735 raddr_ip2 = ip_address(raddr_ip2)
1736 addr_incr = 1 << (128 - raddr_range) if tun_ips[u"ip1"].version == 6 \
1737 else 1 << (32 - raddr_range)
1739 if n_tunnels - existing_tunnels > 10:
1740 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_vat(
1741 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1742 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1744 if u"DUT2" in nodes.keys():
1745 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
1746 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1747 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1751 ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
1752 nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
1753 integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
1755 if u"DUT2" in nodes.keys():
1756 IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
1757 nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
1758 integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
1763 return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
1767 def _create_ipsec_script_files(dut, instances):
1768 """Create script files for configuring IPsec in containers
1770 :param dut: DUT node on which to create the script files
1771 :param instances: number of containers on DUT node
1773 :type instances: int
1776 for cnf in range(0, instances):
1778 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1780 scripts.append(open(script_filename, 'w'))
1784 def _close_and_copy_ipsec_script_files(
1785 dut, nodes, instances, scripts):
1786 """Close created scripts and copy them to containers
1788 :param dut: DUT node on which to create the script files
1789 :param nodes: VPP nodes
1790 :param instances: number of containers on DUT node
1791 :param scripts: dictionary holding the script files
1794 :type instances: int
1797 for cnf in range(0, instances):
1798 scripts[cnf].close()
1800 f"/tmp/ipsec_create_tunnel_cnf_{dut}_{cnf + 1}.config"
1802 scp_node(nodes[dut], script_filename, script_filename)
1806 def vpp_ipsec_create_tunnel_interfaces_in_containers(
1807 nodes, if1_ip_addr, if2_ip_addr, n_tunnels, crypto_alg, integ_alg,
1808 raddr_ip1, raddr_ip2, raddr_range, n_instances):
1809 """Create multiple IPsec tunnel interfaces between two VPP nodes.
1811 :param nodes: VPP nodes to create tunnel interfaces.
1812 :param if1_ip_addr: VPP node 1 interface IP4 address.
1813 :param if2_ip_addr: VPP node 2 interface IP4 address.
1814 :param n_tunnels: Number of tunnell interfaces to create.
1815 :param crypto_alg: The encryption algorithm name.
1816 :param integ_alg: The integrity algorithm name.
1817 :param raddr_ip1: Policy selector remote IPv4 start address for the
1818 first tunnel in direction node1->node2.
1819 :param raddr_ip2: Policy selector remote IPv4 start address for the
1820 first tunnel in direction node2->node1.
1821 :param raddr_range: Mask specifying range of Policy selector Remote
1822 IPv4 addresses. Valid values are from 1 to 32.
1823 :param n_instances: Number of containers.
1825 :type if1_ip_addr: str
1826 :type if2_ip_addr: str
1827 :type n_tunnels: int
1828 :type crypto_alg: CryptoAlg
1829 :type integ_alg: Optional[IntegAlg]
1830 :type raddr_ip1: string
1831 :type raddr_ip2: string
1832 :type raddr_range: int
1833 :type n_instances: int
1837 addr_incr = 1 << (32 - raddr_range)
1839 dut1_scripts = IPsecUtil._create_ipsec_script_files(
1840 u"DUT1", n_instances
1842 dut2_scripts = IPsecUtil._create_ipsec_script_files(
1843 u"DUT2", n_instances
1846 for cnf in range(0, n_instances):
1847 dut1_scripts[cnf].write(
1848 u"create loopback interface\n"
1849 u"set interface state loop0 up\n\n"
1851 dut2_scripts[cnf].write(
1852 f"ip route add {if1_ip_addr}/8 via "
1853 f"{ip_address(if2_ip_addr) + cnf + 100} memif1/{cnf + 1}\n\n"
1856 for tnl in range(0, n_tunnels):
1857 cnf = tnl % n_instances
1859 gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
1863 gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
1867 f"integ-alg {integ_alg.alg_name} "
1868 f"local-integ-key {ikey} "
1869 f"remote-integ-key {ikey} "
1871 # Configure tunnel end point(s) on left side
1872 dut1_scripts[cnf].write(
1873 u"set interface ip address loop0 "
1874 f"{ip_address(if1_ip_addr) + tnl * addr_incr}/32\n"
1875 f"create ipsec tunnel "
1876 f"local-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1877 f"local-spi {spi_1 + tnl} "
1878 f"remote-ip {ip_address(if2_ip_addr) + cnf} "
1879 f"remote-spi {spi_2 + tnl} "
1880 f"crypto-alg {crypto_alg.alg_name} "
1881 f"local-crypto-key {ckey} "
1882 f"remote-crypto-key {ckey} "
1883 f"instance {tnl // n_instances} "
1886 f"set interface unnumbered ipip{tnl // n_instances} use loop0\n"
1887 f"set interface state ipip{tnl // n_instances} up\n"
1888 f"ip route add {ip_address(raddr_ip2)+tnl}/32 "
1889 f"via ipip{tnl // n_instances}\n\n"
1891 # Configure tunnel end point(s) on right side
1892 dut2_scripts[cnf].write(
1893 f"set ip neighbor memif1/{cnf + 1} "
1894 f"{ip_address(if1_ip_addr) + tnl * addr_incr} "
1895 f"02:02:00:00:{17:02X}:{cnf:02X} static\n"
1896 f"create ipsec tunnel local-ip {ip_address(if2_ip_addr) + cnf} "
1897 f"local-spi {spi_2 + tnl} "
1898 f"remote-ip {ip_address(if1_ip_addr) + tnl * addr_incr} "
1899 f"remote-spi {spi_1 + tnl} "
1900 f"crypto-alg {crypto_alg.alg_name} "
1901 f"local-crypto-key {ckey} "
1902 f"remote-crypto-key {ckey} "
1903 f"instance {tnl // n_instances} "
1906 f"set interface unnumbered ipip{tnl // n_instances} "
1907 f"use memif1/{cnf + 1}\n"
1908 f"set interface state ipip{tnl // n_instances} up\n"
1909 f"ip route add {ip_address(raddr_ip1) + tnl}/32 "
1910 f"via ipip{tnl // n_instances}\n\n"
1913 IPsecUtil._close_and_copy_ipsec_script_files(
1914 u"DUT1", nodes, n_instances, dut1_scripts)
1915 IPsecUtil._close_and_copy_ipsec_script_files(
1916 u"DUT2", nodes, n_instances, dut2_scripts)
1919 def vpp_ipsec_add_multiple_tunnels(
1920 nodes, interface1, interface2, n_tunnels, crypto_alg, integ_alg,
1921 tunnel_ip1, tunnel_ip2, raddr_ip1, raddr_ip2, raddr_range):
1922 """Create multiple IPsec tunnels between two VPP nodes.
1924 :param nodes: VPP nodes to create tunnels.
1925 :param interface1: Interface name or sw_if_index on node 1.
1926 :param interface2: Interface name or sw_if_index on node 2.
1927 :param n_tunnels: Number of tunnels to create.
1928 :param crypto_alg: The encryption algorithm name.
1929 :param integ_alg: The integrity algorithm name.
1930 :param tunnel_ip1: Tunnel node1 IPv4 address.
1931 :param tunnel_ip2: Tunnel node2 IPv4 address.
1932 :param raddr_ip1: Policy selector remote IPv4 start address for the
1933 first tunnel in direction node1->node2.
1934 :param raddr_ip2: Policy selector remote IPv4 start address for the
1935 first tunnel in direction node2->node1.
1936 :param raddr_range: Mask specifying range of Policy selector Remote
1937 IPv4 addresses. Valid values are from 1 to 32.
1939 :type interface1: str or int
1940 :type interface2: str or int
1941 :type n_tunnels: int
1942 :type crypto_alg: CryptoAlg
1943 :type integ_alg: Optional[IntegAlg]
1944 :type tunnel_ip1: str
1945 :type tunnel_ip2: str
1946 :type raddr_ip1: string
1947 :type raddr_ip2: string
1948 :type raddr_range: int
1958 crypto_key = gen_key(
1959 IPsecUtil.get_crypto_alg_key_len(crypto_alg)
1961 integ_key = gen_key(
1962 IPsecUtil.get_integ_alg_key_len(integ_alg)
1963 ).decode() if integ_alg else u""
1965 rmac = Topology.get_interface_mac(nodes[u"DUT2"], interface2) \
1966 if u"DUT2" in nodes.keys() \
1967 else Topology.get_interface_mac(nodes[u"TG"], interface2)
1968 IPsecUtil.vpp_ipsec_set_ip_route(
1969 nodes[u"DUT1"], n_tunnels, tunnel_ip1, raddr_ip2, tunnel_ip2,
1970 interface1, raddr_range, rmac)
1972 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT1"], spd_id)
1973 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT1"], spd_id, interface1)
1974 IPsecUtil.vpp_ipsec_policy_add(
1975 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=False,
1976 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1978 IPsecUtil.vpp_ipsec_policy_add(
1979 nodes[u"DUT1"], spd_id, p_hi, PolicyAction.BYPASS, inbound=True,
1980 proto=50, laddr_range=u"100.0.0.0/8", raddr_range=u"100.0.0.0/8"
1983 IPsecUtil.vpp_ipsec_add_sad_entries(
1984 nodes[u"DUT1"], n_tunnels, sa_id_1, spi_1, crypto_alg, crypto_key,
1985 integ_alg, integ_key, tunnel_ip1, tunnel_ip2
1987 IPsecUtil.vpp_ipsec_spd_add_entries(
1988 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, False, sa_id_1, raddr_ip2
1991 IPsecUtil.vpp_ipsec_add_sad_entries(
1992 nodes[u"DUT1"], n_tunnels, sa_id_2, spi_2, crypto_alg, crypto_key,
1993 integ_alg, integ_key, tunnel_ip2, tunnel_ip1
1995 IPsecUtil.vpp_ipsec_spd_add_entries(
1996 nodes[u"DUT1"], n_tunnels, spd_id, p_lo, True, sa_id_2, raddr_ip1
1999 if u"DUT2" in nodes.keys():
2000 IPsecUtil.vpp_ipsec_set_ip_route(
2001 nodes[u"DUT2"], n_tunnels, tunnel_ip2, raddr_ip1, tunnel_ip1,
2002 interface2, raddr_range)
2004 IPsecUtil.vpp_ipsec_add_spd(nodes[u"DUT2"], spd_id)
2005 IPsecUtil.vpp_ipsec_spd_add_if(nodes[u"DUT2"], spd_id, interface2)
2006 IPsecUtil.vpp_ipsec_policy_add(
2007 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2008 inbound=False, proto=50, laddr_range=u"100.0.0.0/8",
2009 raddr_range=u"100.0.0.0/8"
2011 IPsecUtil.vpp_ipsec_policy_add(
2012 nodes[u"DUT2"], spd_id, p_hi, PolicyAction.BYPASS,
2013 inbound=True, proto=50, laddr_range=u"100.0.0.0/8",
2014 raddr_range=u"100.0.0.0/8"
2017 IPsecUtil.vpp_ipsec_add_sad_entries(
2018 nodes[u"DUT2"], n_tunnels, sa_id_1, spi_1, crypto_alg,
2019 crypto_key, integ_alg, integ_key, tunnel_ip1, tunnel_ip2
2021 IPsecUtil.vpp_ipsec_spd_add_entries(
2022 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, True, sa_id_1,
2026 IPsecUtil.vpp_ipsec_add_sad_entries(
2027 nodes[u"DUT2"], n_tunnels, sa_id_2, spi_2, crypto_alg,
2028 crypto_key, integ_alg, integ_key, tunnel_ip2, tunnel_ip1
2030 IPsecUtil.vpp_ipsec_spd_add_entries(
2031 nodes[u"DUT2"], n_tunnels, spd_id, p_lo, False, sa_id_2,
2037 def vpp_ipsec_show(node):
2038 """Run "show ipsec" debug CLI command.
2040 :param node: Node to run command on.
2043 PapiSocketExecutor.run_cli_cmd(node, u"show ipsec")
2046 def show_ipsec_security_association(node):
2047 """Show IPSec security association.
2049 :param node: DUT node.
2055 PapiSocketExecutor.dump_and_log(node, cmds)