Commit a5a91f54 authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'support-udp-encapsulation-in-packet-offload-mode'

Leon Romanovsky says:

====================
Support UDP encapsulation in packet offload mode

As was raised by Ilia in this thread [1], the ESP over UDP feature is
supported in packet offload mode. So comes this series, which adds
relevant bits to the mlx5 driver and opens XFRM core code to accept
such configuration.

NAT-T is part of IKEv2 and strongswan uses it automatically [2].

[1] https://lore.kernel.org/all/20230718092405.4124345-1-quic_ilial@quicinc.com
[2] https://wiki.strongswan.org/projects/1/wiki/NatTraversal
====================

Link: https://lore.kernel.org/r/cover.1689757619.git.leon@kernel.orgSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 9e10fb4c 89edf402
...@@ -354,6 +354,12 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry, ...@@ -354,6 +354,12 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
mlx5e_ipsec_init_limits(sa_entry, attrs); mlx5e_ipsec_init_limits(sa_entry, attrs);
mlx5e_ipsec_init_macs(sa_entry, attrs); mlx5e_ipsec_init_macs(sa_entry, attrs);
if (x->encap) {
attrs->encap = true;
attrs->sport = x->encap->encap_sport;
attrs->dport = x->encap->encap_dport;
}
} }
static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev, static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
...@@ -387,9 +393,26 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev, ...@@ -387,9 +393,26 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
return -EINVAL; return -EINVAL;
} }
if (x->encap) { if (x->encap) {
NL_SET_ERR_MSG_MOD(extack, "Encapsulated xfrm state may not be offloaded"); if (!(mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ESPINUDP)) {
NL_SET_ERR_MSG_MOD(extack, "Encapsulation is not supported");
return -EINVAL; return -EINVAL;
} }
if (x->encap->encap_type != UDP_ENCAP_ESPINUDP) {
NL_SET_ERR_MSG_MOD(extack, "Encapsulation other than UDP is not supported");
return -EINVAL;
}
if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) {
NL_SET_ERR_MSG_MOD(extack, "Encapsulation is supported in packet offload mode only");
return -EINVAL;
}
if (x->props.mode != XFRM_MODE_TRANSPORT) {
NL_SET_ERR_MSG_MOD(extack, "Encapsulation is supported in transport mode only");
return -EINVAL;
}
}
if (!x->aead) { if (!x->aead) {
NL_SET_ERR_MSG_MOD(extack, "Cannot offload xfrm states without aead"); NL_SET_ERR_MSG_MOD(extack, "Cannot offload xfrm states without aead");
return -EINVAL; return -EINVAL;
......
...@@ -94,13 +94,20 @@ struct mlx5_accel_esp_xfrm_attrs { ...@@ -94,13 +94,20 @@ struct mlx5_accel_esp_xfrm_attrs {
u8 dir : 2; u8 dir : 2;
u8 type : 2; u8 type : 2;
u8 drop : 1; u8 drop : 1;
u8 encap : 1;
u8 family; u8 family;
struct mlx5_replay_esn replay_esn; struct mlx5_replay_esn replay_esn;
u32 authsize; u32 authsize;
u32 reqid; u32 reqid;
struct mlx5_ipsec_lft lft; struct mlx5_ipsec_lft lft;
union {
u8 smac[ETH_ALEN]; u8 smac[ETH_ALEN];
__be16 sport;
};
union {
u8 dmac[ETH_ALEN]; u8 dmac[ETH_ALEN];
__be16 dport;
};
}; };
enum mlx5_ipsec_cap { enum mlx5_ipsec_cap {
...@@ -110,6 +117,7 @@ enum mlx5_ipsec_cap { ...@@ -110,6 +117,7 @@ enum mlx5_ipsec_cap {
MLX5_IPSEC_CAP_ROCE = 1 << 3, MLX5_IPSEC_CAP_ROCE = 1 << 3,
MLX5_IPSEC_CAP_PRIO = 1 << 4, MLX5_IPSEC_CAP_PRIO = 1 << 4,
MLX5_IPSEC_CAP_TUNNEL = 1 << 5, MLX5_IPSEC_CAP_TUNNEL = 1 << 5,
MLX5_IPSEC_CAP_ESPINUDP = 1 << 6,
}; };
struct mlx5e_priv; struct mlx5e_priv;
......
...@@ -951,37 +951,70 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev, ...@@ -951,37 +951,70 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
return -EINVAL; return -EINVAL;
} }
static int get_reformat_type(struct mlx5_accel_esp_xfrm_attrs *attrs)
{
switch (attrs->dir) {
case XFRM_DEV_OFFLOAD_IN:
if (attrs->encap)
return MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT_OVER_UDP;
return MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT;
case XFRM_DEV_OFFLOAD_OUT:
if (attrs->family == AF_INET) {
if (attrs->encap)
return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV4;
return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4;
}
if (attrs->encap)
return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV6;
return MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6;
default:
WARN_ON(true);
}
return -EINVAL;
}
static int static int
setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs, setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs,
struct mlx5_pkt_reformat_params *reformat_params) struct mlx5_pkt_reformat_params *reformat_params)
{ {
u8 *reformatbf; struct udphdr *udphdr;
char *reformatbf;
size_t bfflen;
__be32 spi; __be32 spi;
void *hdr;
reformat_params->type = get_reformat_type(attrs);
if (reformat_params->type < 0)
return reformat_params->type;
switch (attrs->dir) { switch (attrs->dir) {
case XFRM_DEV_OFFLOAD_IN: case XFRM_DEV_OFFLOAD_IN:
reformat_params->type = MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT;
break; break;
case XFRM_DEV_OFFLOAD_OUT: case XFRM_DEV_OFFLOAD_OUT:
if (attrs->family == AF_INET) bfflen = MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE;
reformat_params->type = if (attrs->encap)
MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4; bfflen += sizeof(*udphdr);
else
reformat_params->type =
MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6;
reformatbf = kzalloc(MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE, reformatbf = kzalloc(bfflen, GFP_KERNEL);
GFP_KERNEL);
if (!reformatbf) if (!reformatbf)
return -ENOMEM; return -ENOMEM;
hdr = reformatbf;
if (attrs->encap) {
udphdr = (struct udphdr *)reformatbf;
udphdr->source = attrs->sport;
udphdr->dest = attrs->dport;
hdr += sizeof(*udphdr);
}
/* convert to network format */ /* convert to network format */
spi = htonl(attrs->spi); spi = htonl(attrs->spi);
memcpy(reformatbf, &spi, sizeof(spi)); memcpy(hdr, &spi, sizeof(spi));
reformat_params->param_0 = attrs->authsize; reformat_params->param_0 = attrs->authsize;
reformat_params->size = reformat_params->size = bfflen;
MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE;
reformat_params->data = reformatbf; reformat_params->data = reformatbf;
break; break;
default: default:
......
...@@ -54,6 +54,12 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev) ...@@ -54,6 +54,12 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev)
MLX5_CAP_FLOWTABLE_NIC_RX(mdev, MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
reformat_l3_esp_tunnel_to_l2)) reformat_l3_esp_tunnel_to_l2))
caps |= MLX5_IPSEC_CAP_TUNNEL; caps |= MLX5_IPSEC_CAP_TUNNEL;
if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev,
reformat_add_esp_transport_over_udp) &&
MLX5_CAP_FLOWTABLE_NIC_RX(mdev,
reformat_del_esp_transport_over_udp))
caps |= MLX5_IPSEC_CAP_ESPINUDP;
} }
if (mlx5_get_roce_state(mdev) && if (mlx5_get_roce_state(mdev) &&
......
...@@ -464,10 +464,10 @@ struct mlx5_ifc_flow_table_prop_layout_bits { ...@@ -464,10 +464,10 @@ struct mlx5_ifc_flow_table_prop_layout_bits {
u8 reformat_add_esp_trasport[0x1]; u8 reformat_add_esp_trasport[0x1];
u8 reformat_l2_to_l3_esp_tunnel[0x1]; u8 reformat_l2_to_l3_esp_tunnel[0x1];
u8 reserved_at_42[0x1]; u8 reformat_add_esp_transport_over_udp[0x1];
u8 reformat_del_esp_trasport[0x1]; u8 reformat_del_esp_trasport[0x1];
u8 reformat_l3_esp_tunnel_to_l2[0x1]; u8 reformat_l3_esp_tunnel_to_l2[0x1];
u8 reserved_at_45[0x1]; u8 reformat_del_esp_transport_over_udp[0x1];
u8 execute_aso[0x1]; u8 execute_aso[0x1];
u8 reserved_at_47[0x19]; u8 reserved_at_47[0x19];
...@@ -6665,9 +6665,12 @@ enum mlx5_reformat_ctx_type { ...@@ -6665,9 +6665,12 @@ enum mlx5_reformat_ctx_type {
MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL = 0x4, MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL = 0x4,
MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4 = 0x5, MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4 = 0x5,
MLX5_REFORMAT_TYPE_L2_TO_L3_ESP_TUNNEL = 0x6, MLX5_REFORMAT_TYPE_L2_TO_L3_ESP_TUNNEL = 0x6,
MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV4 = 0x7,
MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT = 0x8, MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT = 0x8,
MLX5_REFORMAT_TYPE_L3_ESP_TUNNEL_TO_L2 = 0x9, MLX5_REFORMAT_TYPE_L3_ESP_TUNNEL_TO_L2 = 0x9,
MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT_OVER_UDP = 0xa,
MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6 = 0xb, MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6 = 0xb,
MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_UDPV6 = 0xc,
MLX5_REFORMAT_TYPE_INSERT_HDR = 0xf, MLX5_REFORMAT_TYPE_INSERT_HDR = 0xf,
MLX5_REFORMAT_TYPE_REMOVE_HDR = 0x10, MLX5_REFORMAT_TYPE_REMOVE_HDR = 0x10,
MLX5_REFORMAT_TYPE_ADD_MACSEC = 0x11, MLX5_REFORMAT_TYPE_ADD_MACSEC = 0x11,
......
...@@ -247,12 +247,6 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, ...@@ -247,12 +247,6 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
return -EINVAL; return -EINVAL;
} }
/* We don't yet support UDP encapsulation and TFC padding. */
if (x->encap || x->tfcpad) {
NL_SET_ERR_MSG(extack, "Encapsulation and TFC padding can't be offloaded");
return -EINVAL;
}
if (xuo->flags & if (xuo->flags &
~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND | XFRM_OFFLOAD_PACKET)) { ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND | XFRM_OFFLOAD_PACKET)) {
NL_SET_ERR_MSG(extack, "Unrecognized flags in offload request"); NL_SET_ERR_MSG(extack, "Unrecognized flags in offload request");
...@@ -260,6 +254,13 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, ...@@ -260,6 +254,13 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
} }
is_packet_offload = xuo->flags & XFRM_OFFLOAD_PACKET; is_packet_offload = xuo->flags & XFRM_OFFLOAD_PACKET;
/* We don't yet support UDP encapsulation and TFC padding. */
if ((!is_packet_offload && x->encap) || x->tfcpad) {
NL_SET_ERR_MSG(extack, "Encapsulation and TFC padding can't be offloaded");
return -EINVAL;
}
dev = dev_get_by_index(net, xuo->ifindex); dev = dev_get_by_index(net, xuo->ifindex);
if (!dev) { if (!dev) {
if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) { if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment