-# Copyright (c) 2020 Cisco and/or its affiliates.
+# Copyright (c) 2021 Cisco and/or its affiliates.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
def get_integ_alg_key_len(integ_alg):
"""Return integrity algorithm key length.
+ None argument is accepted, returning zero.
+
:param integ_alg: Integrity algorithm.
- :type integ_alg: IntegAlg
+ :type integ_alg: Optional[IntegAlg]
:returns: Key length.
:rtype: int
"""
- return integ_alg.key_len
+ return 0 if integ_alg is None else integ_alg.key_len
@staticmethod
def get_integ_alg_scapy_name(integ_alg):
with PapiSocketExecutor(node) as papi_exec:
papi_exec.add(cmd, **args).get_reply(err_msg)
+ @staticmethod
+ def vpp_ipsec_crypto_sw_scheduler_set_worker(
+ node, worker_index, crypto_enable=False):
+ """Enable or disable crypto on specific vpp worker threads.
+
+ :param node: VPP node to enable or disable crypto for worker threads.
+ :param worker_index: VPP worker thread index.
+ :param crypto_enable: Disable or enable crypto work.
+ :type node: dict
+ :type worker_index: int
+ :type crypto_enable: bool
+ :raises RuntimeError: If failed to enable or disable crypto for worker
+ thread or if no API reply received.
+ """
+ cmd = u"crypto_sw_scheduler_set_worker"
+ err_msg = f"Failed to disable/enable crypto for worker thread " \
+ f"on host {node[u'host']}"
+ args = dict(
+ worker_index=worker_index,
+ crypto_enable=crypto_enable
+ )
+ with PapiSocketExecutor(node) as papi_exec:
+ papi_exec.add(cmd, **args).get_reply(err_msg)
+
@staticmethod
def vpp_ipsec_add_sad_entry(
node, sad_id, spi, crypto_alg, crypto_key, integ_alg=None,
:type spi: int
:type crypto_alg: CryptoAlg
:type crypto_key: str
- :type integ_alg: IntegAlg
+ :type integ_alg: Optional[IntegAlg]
:type integ_key: str
:type tunnel_src: str
:type tunnel_dst: str
src_addr = u""
dst_addr = u""
- cmd = u"ipsec_sad_entry_add_del"
+ cmd = u"ipsec_sad_entry_add_del_v2"
err_msg = f"Failed to add Security Association Database entry " \
f"on host {node[u'host']}"
sad_entry = dict(
flags=flags,
tunnel_src=str(src_addr),
tunnel_dst=str(dst_addr),
+ tunnel_flags=int(
+ TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
+ ),
+ dscp=int(IpDscp.IP_API_DSCP_CS0),
protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
udp_src_port=4500, # default value in api
udp_dst_port=4500 # default value in api
:type spi: int
:type crypto_alg: CryptoAlg
:type crypto_key: str
- :type integ_alg: IntegAlg
+ :type integ_alg: Optional[IntegAlg]
:type integ_key: str
:type tunnel_src: str
:type tunnel_dst: str
integ = f"integ-alg {integ_alg.alg_name} " \
f"integ-key {integ_key.hex()}" \
if integ_alg else u""
- tunnel = f"tunnel-src {src_addr + i * addr_incr} " \
- f"tunnel-dst {dst_addr + i * addr_incr}" \
+ tunnel = f"tunnel src {src_addr + i * addr_incr} " \
+ f"tunnel dst {dst_addr + i * addr_incr}" \
if tunnel_src and tunnel_dst else u""
conf = f"exec ipsec sa add {sad_id + i} esp spi {spi + i} "\
f"crypto-alg {crypto_alg.alg_name} " \
IPsecSadFlags.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
)
- cmd = u"ipsec_sad_entry_add_del"
+ cmd = u"ipsec_sad_entry_add_del_v2"
err_msg = f"Failed to add Security Association Database entry " \
f"on host {node[u'host']}"
flags=flags,
tunnel_src=str(src_addr),
tunnel_dst=str(dst_addr),
+ tunnel_flags=int(
+ TunnelEncpaDecapFlags.TUNNEL_API_ENCAP_DECAP_FLAG_NONE
+ ),
+ dscp=int(IpDscp.IP_API_DSCP_CS0),
protocol=int(IPsecProto.IPSEC_API_PROTO_ESP),
udp_src_port=4500, # default value in api
udp_dst_port=4500 # default value in api
raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
"""Create multiple IPsec tunnel interfaces on DUT1 node using VAT.
+ Generate random keys and return them (so DUT2 or TG can decrypt).
+
:param nodes: VPP nodes to create tunnel interfaces.
:param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
:type if2_key: str
:type n_tunnels: int
:type crypto_alg: CryptoAlg
- :type integ_alg: IntegAlg
+ :type integ_alg: Optional[IntegAlg]
:type raddr_ip2: IPv4Address or IPv6Address
:type addr_incr: int
:type spi_d: dict
:type existing_tunnels: int
+ :returns: Generated ckeys and ikeys.
+ :rtype: List[bytes], List[bytes]
"""
tmp_fn1 = u"/tmp/ipsec_create_tunnel_dut1.config"
if1_n = Topology.get_interface_name(nodes[u"DUT1"], if1_key)
ckeys.append(
gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
)
+ ikeys.append(
+ gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
+ )
if integ_alg:
- ikeys.append(
- gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
- )
integ = f"integ-alg {integ_alg.alg_name} " \
f"integ-key {ikeys[i].hex()} "
else:
ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
"""Create multiple IPsec tunnel interfaces on DUT2 node using VAT.
+ This method accesses keys generated by DUT1 method
+ and does not return anything.
+
:param nodes: VPP nodes to create tunnel interfaces.
:param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
:type if2_key: str
:type n_tunnels: int
:type crypto_alg: CryptoAlg
- :type ckeys: list
- :type integ_alg: IntegAlg
- :type ikeys: list
+ :type ckeys: Sequence[bytes]
+ :type integ_alg: Optional[IntegAlg]
+ :type ikeys: Sequence[bytes]
:type addr_incr: int
:type spi_d: dict
:type existing_tunnels: int
"""
with PapiSocketExecutor(nodes[u"DUT1"]) as papi_exec:
# Create loopback interface on DUT1, set it to up state
- cmd = u"create_loopback"
+ cmd = u"create_loopback_instance"
args = dict(
- mac_address=0
+ mac_address=0,
+ is_specified=False,
+ user_instance=0,
)
err_msg = f"Failed to create loopback interface " \
f"on host {nodes[u'DUT1'][u'host']}"
raddr_ip2, addr_incr, spi_d, existing_tunnels=0):
"""Create multiple IPsec tunnel interfaces on DUT1 node using PAPI.
+ Generate random keys and return them (so DUT2 or TG can decrypt).
+
:param nodes: VPP nodes to create tunnel interfaces.
:param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
:type if2_key: str
:type n_tunnels: int
:type crypto_alg: CryptoAlg
- :type integ_alg: IntegAlg
+ :type integ_alg: Optional[IntegAlg]
:type raddr_ip2: IPv4Address or IPv6Address
:type addr_incr: int
:type spi_d: dict
:type existing_tunnels: int
+ :returns: Generated ckeys and ikeys.
+ :rtype: List[bytes], List[bytes]
"""
if not existing_tunnels:
loop_sw_if_idx = IPsecUtil._ipsec_create_loopback_dut1_papi(
ckeys.append(
gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
)
- if integ_alg:
- ikeys.append(
- gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
- )
+ ikeys.append(
+ gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
+ )
# SAD entry for outband / tx path
args[u"entry"][u"sad_id"] = i
args[u"entry"][u"spi"] = spi_d[u"spi_1"] + i
ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels=0):
"""Create multiple IPsec tunnel interfaces on DUT2 node using PAPI.
+ This method accesses keys generated by DUT1 method
+ and does not return anything.
+
:param nodes: VPP nodes to create tunnel interfaces.
:param tun_ips: Dictionary with VPP node 1 ipsec tunnel interface
IPv4/IPv6 address (ip1) and VPP node 2 ipsec tunnel interface
:type if2_key: str
:type n_tunnels: int
:type crypto_alg: CryptoAlg
- :type ckeys: list
- :type integ_alg: IntegAlg
- :type ikeys: list
+ :type ckeys: Sequence[bytes]
+ :type integ_alg: Optional[IntegAlg]
+ :type ikeys: Sequence[bytes]
:type addr_incr: int
:type spi_d: dict
:type existing_tunnels: int
ckeys.append(
gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg))
)
- if integ_alg:
- ikeys.append(
- gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
- )
+ ikeys.append(
+ gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg))
+ )
# SAD entry for outband / tx path
args[u"entry"][u"sad_id"] = 100000 + i
args[u"entry"][u"spi"] = spi_d[u"spi_2"] + i
def vpp_ipsec_create_tunnel_interfaces(
nodes, tun_if1_ip_addr, tun_if2_ip_addr, if1_key, if2_key,
n_tunnels, crypto_alg, integ_alg, raddr_ip1, raddr_ip2, raddr_range,
- existing_tunnels=0):
+ existing_tunnels=0, return_keys=False):
"""Create multiple IPsec tunnel interfaces between two VPP nodes.
+ Some deployments (e.g. devicetest) need to know the generated keys.
+ But other deployments (e.g. scale perf test) would get spammed
+ if we returned keys every time.
+
:param nodes: VPP nodes to create tunnel interfaces.
:param tun_if1_ip_addr: VPP node 1 ipsec tunnel interface IPv4/IPv6
address.
and to 128 in case of IPv6.
:param existing_tunnels: Number of tunnel interfaces before creation.
Useful mainly for reconf tests. Default 0.
+ :param return_keys: Whether generated keys should be returned.
:type nodes: dict
:type tun_if1_ip_addr: str
:type tun_if2_ip_addr: str
:type if2_key: str
:type n_tunnels: int
:type crypto_alg: CryptoAlg
- :type integ_alg: IntegAlg
+ :type integ_alg: Optonal[IntegAlg]
:type raddr_ip1: string
:type raddr_ip2: string
:type raddr_range: int
:type existing_tunnels: int
+ :type return_keys: bool
+ :returns: Ckeys, ikeys, spi_1, spi_2.
+ :rtype: Optional[List[bytes], List[bytes], int, int]
"""
n_tunnels = int(n_tunnels)
existing_tunnels = int(existing_tunnels)
nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
)
- if u"DUT2" not in nodes.keys():
- return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
- IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
- nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
- integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
- )
+ if u"DUT2" in nodes.keys():
+ IPsecUtil._ipsec_create_tunnel_interfaces_dut2_vat(
+ nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
+ integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
+ existing_tunnels
+ )
else:
ckeys, ikeys = IPsecUtil._ipsec_create_tunnel_interfaces_dut1_papi(
nodes, tun_ips, if1_key, if2_key, n_tunnels, crypto_alg,
integ_alg, raddr_ip2, addr_incr, spi_d, existing_tunnels
)
- if u"DUT2" not in nodes.keys():
- return ckeys[0], ikeys[0], spi_d[u"spi_1"], spi_d[u"spi_2"]
- IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
- nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
- integ_alg, ikeys, raddr_ip1, addr_incr, spi_d, existing_tunnels
- )
+ if u"DUT2" in nodes.keys():
+ IPsecUtil._ipsec_create_tunnel_interfaces_dut2_papi(
+ nodes, tun_ips, if2_key, n_tunnels, crypto_alg, ckeys,
+ integ_alg, ikeys, raddr_ip1, addr_incr, spi_d,
+ existing_tunnels
+ )
- return None, None, None, None
+ if return_keys:
+ return ckeys, ikeys, spi_d[u"spi_1"], spi_d[u"spi_2"]
+ return None
@staticmethod
def _create_ipsec_script_files(dut, instances):
:type if2_ip_addr: str
:type n_tunnels: int
:type crypto_alg: CryptoAlg
- :type integ_alg: IntegAlg
+ :type integ_alg: Optional[IntegAlg]
:type raddr_ip1: string
:type raddr_ip2: string
:type raddr_range: int
gen_key(IPsecUtil.get_crypto_alg_key_len(crypto_alg)), u"hex"
)
integ = u""
+ ikey = getattr(
+ gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
+ )
if integ_alg:
- ikey = getattr(
- gen_key(IPsecUtil.get_integ_alg_key_len(integ_alg)), u"hex"
- )
integ = (
f"integ-alg {integ_alg.alg_name} "
f"local-integ-key {ikey} "
:type interface2: str or int
:type n_tunnels: int
:type crypto_alg: CryptoAlg
- :type integ_alg: IntegAlg
+ :type integ_alg: Optional[IntegAlg]
:type tunnel_ip1: str
:type tunnel_ip2: str
:type raddr_ip1: string