Commit d6595493 authored by Leon Romanovsky's avatar Leon Romanovsky Committed by Paolo Abeni
Browse files

net/mlx5e: Support IPsec NAT-T functionality



Extend mlx5 IPsec packet offload to support UDP encapsulation
of IPsec ESP packets.

Signed-off-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 4acea83a
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -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_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,
@@ -387,9 +393,26 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
		return -EINVAL;
	}
	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;
		}

		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) {
		NL_SET_ERR_MSG_MOD(extack, "Cannot offload xfrm states without aead");
		return -EINVAL;
+9 −2
Original line number Diff line number Diff line
@@ -94,13 +94,20 @@ struct mlx5_accel_esp_xfrm_attrs {
	u8 dir : 2;
	u8 type : 2;
	u8 drop : 1;
	u8 encap : 1;
	u8 family;
	struct mlx5_replay_esn replay_esn;
	u32 authsize;
	u32 reqid;
	struct mlx5_ipsec_lft lft;
	union {
		u8 smac[ETH_ALEN];
		__be16 sport;
	};
	union {
		u8 dmac[ETH_ALEN];
		__be16 dport;
	};
};

enum mlx5_ipsec_cap {
+47 −14
Original line number Diff line number Diff line
@@ -951,37 +951,70 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
	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
setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs,
			     struct mlx5_pkt_reformat_params *reformat_params)
{
	u8 *reformatbf;
	struct udphdr *udphdr;
	char *reformatbf;
	size_t bfflen;
	__be32 spi;
	void *hdr;

	reformat_params->type = get_reformat_type(attrs);
	if (reformat_params->type < 0)
		return reformat_params->type;

	switch (attrs->dir) {
	case XFRM_DEV_OFFLOAD_IN:
		reformat_params->type = MLX5_REFORMAT_TYPE_DEL_ESP_TRANSPORT;
		break;
	case XFRM_DEV_OFFLOAD_OUT:
		if (attrs->family == AF_INET)
			reformat_params->type =
				MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV4;
		else
			reformat_params->type =
				MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_OVER_IPV6;
		bfflen = MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE;
		if (attrs->encap)
			bfflen += sizeof(*udphdr);

		reformatbf = kzalloc(MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE,
				     GFP_KERNEL);
		reformatbf = kzalloc(bfflen, GFP_KERNEL);
		if (!reformatbf)
			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 */
		spi = htonl(attrs->spi);
		memcpy(reformatbf, &spi, sizeof(spi));
		memcpy(hdr, &spi, sizeof(spi));

		reformat_params->param_0 = attrs->authsize;
		reformat_params->size =
			MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE;
		reformat_params->size = bfflen;
		reformat_params->data = reformatbf;
		break;
	default: