net/mlx5e: Support IPsec TX packet offload in tunnel mode
authorLeon Romanovsky <leonro@nvidia.com>
Thu, 13 Apr 2023 12:29:24 +0000 (15:29 +0300)
committerJakub Kicinski <kuba@kernel.org>
Tue, 18 Apr 2023 01:55:25 +0000 (18:55 -0700)
Extend mlx5 driver with logic to support IPsec TX packet offload
in tunnel mode.

Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.c

index 7c55b37..36f3ffd 100644 (file)
@@ -271,6 +271,18 @@ static void mlx5e_ipsec_init_macs(struct mlx5e_ipsec_sa_entry *sa_entry,
                neigh_ha_snapshot(addr, n, netdev);
                ether_addr_copy(attrs->smac, addr);
                break;
+       case XFRM_DEV_OFFLOAD_OUT:
+               ether_addr_copy(attrs->smac, addr);
+               n = neigh_lookup(&arp_tbl, &attrs->daddr.a4, netdev);
+               if (!n) {
+                       n = neigh_create(&arp_tbl, &attrs->daddr.a4, netdev);
+                       if (IS_ERR(n))
+                               return;
+                       neigh_event_send(n, NULL);
+               }
+               neigh_ha_snapshot(addr, n, netdev);
+               ether_addr_copy(attrs->dmac, addr);
+               break;
        default:
                return;
        }
index 001d7c3..4c800b5 100644 (file)
@@ -11,6 +11,7 @@
 
 #define NUM_IPSEC_FTE BIT(15)
 #define MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE 16
+#define IPSEC_TUNNEL_DEFAULT_TTL 0x40
 
 struct mlx5e_ipsec_fc {
        struct mlx5_fc *cnt;
@@ -842,12 +843,31 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
                          struct mlx5_accel_esp_xfrm_attrs *attrs,
                          struct mlx5_pkt_reformat_params *reformat_params)
 {
+       struct ip_esp_hdr *esp_hdr;
+       struct ipv6hdr *ipv6hdr;
        struct ethhdr *eth_hdr;
+       struct iphdr *iphdr;
        char *reformatbf;
        size_t bfflen;
+       void *hdr;
 
        bfflen = sizeof(*eth_hdr);
 
+       if (attrs->dir == XFRM_DEV_OFFLOAD_OUT) {
+               bfflen += sizeof(*esp_hdr) + 8;
+
+               switch (attrs->family) {
+               case AF_INET:
+                       bfflen += sizeof(*iphdr);
+                       break;
+               case AF_INET6:
+                       bfflen += sizeof(*ipv6hdr);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
        reformatbf = kzalloc(bfflen, GFP_KERNEL);
        if (!reformatbf)
                return -ENOMEM;
@@ -871,6 +891,38 @@ setup_pkt_tunnel_reformat(struct mlx5_core_dev *mdev,
        case XFRM_DEV_OFFLOAD_IN:
                reformat_params->type = MLX5_REFORMAT_TYPE_L3_ESP_TUNNEL_TO_L2;
                break;
+       case XFRM_DEV_OFFLOAD_OUT:
+               reformat_params->type = MLX5_REFORMAT_TYPE_L2_TO_L3_ESP_TUNNEL;
+               reformat_params->param_0 = attrs->authsize;
+
+               hdr = reformatbf + sizeof(*eth_hdr);
+               switch (attrs->family) {
+               case AF_INET:
+                       iphdr = (struct iphdr *)hdr;
+                       memcpy(&iphdr->saddr, &attrs->saddr.a4, 4);
+                       memcpy(&iphdr->daddr, &attrs->daddr.a4, 4);
+                       iphdr->version = 4;
+                       iphdr->ihl = 5;
+                       iphdr->ttl = IPSEC_TUNNEL_DEFAULT_TTL;
+                       iphdr->protocol = IPPROTO_ESP;
+                       hdr += sizeof(*iphdr);
+                       break;
+               case AF_INET6:
+                       ipv6hdr = (struct ipv6hdr *)hdr;
+                       memcpy(&ipv6hdr->saddr, &attrs->saddr.a6, 16);
+                       memcpy(&ipv6hdr->daddr, &attrs->daddr.a6, 16);
+                       ipv6hdr->nexthdr = IPPROTO_ESP;
+                       ipv6hdr->version = 6;
+                       ipv6hdr->hop_limit = IPSEC_TUNNEL_DEFAULT_TTL;
+                       hdr += sizeof(*ipv6hdr);
+                       break;
+               default:
+                       goto free_reformatbf;
+               }
+
+               esp_hdr = (struct ip_esp_hdr *)hdr;
+               esp_hdr->spi = htonl(attrs->spi);
+               break;
        default:
                goto free_reformatbf;
        }