diff mbox series

[net-next,6/6] sfc: generate encap headers for TC offload

Message ID 672e66e6a4cf0f54917eddbca7c27a6f0d2823bf.1685992503.git.ecree.xilinx@gmail.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series sfc: TC encap actions offload | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/cc_maintainers success CCed 8 of 8 maintainers
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch warning WARNING: line length of 100 exceeds 80 columns WARNING: line length of 101 exceeds 80 columns WARNING: line length of 102 exceeds 80 columns WARNING: line length of 103 exceeds 80 columns WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

edward.cree@amd.com June 5, 2023, 7:17 p.m. UTC
From: Edward Cree <ecree.xilinx@gmail.com>

Support constructing VxLAN and GENEVE headers, on either IPv4 or IPv6,
 using the neighbouring information obtained in encap->neigh to
 populate the Ethernet header.
Note that the ef100 hardware does not insert UDP checksums when
 performing encap, so for IPv6 the remote endpoint will need to be
 configured with udp6zerocsumrx or equivalent.

Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
---
 drivers/net/ethernet/sfc/tc_encap_actions.c | 194 +++++++++++++++++++-
 1 file changed, 185 insertions(+), 9 deletions(-)

Comments

Hao Lan June 6, 2023, 3:52 a.m. UTC | #1
On 2023/6/6 3:17, edward.cree@amd.com wrote:
> From: Edward Cree <ecree.xilinx@gmail.com>
> 
> Support constructing VxLAN and GENEVE headers, on either IPv4 or IPv6,
>  using the neighbouring information obtained in encap->neigh to
>  populate the Ethernet header.
> Note that the ef100 hardware does not insert UDP checksums when
>  performing encap, so for IPv6 the remote endpoint will need to be
>  configured with udp6zerocsumrx or equivalent.
> 
> Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>
> ---
>  drivers/net/ethernet/sfc/tc_encap_actions.c | 194 +++++++++++++++++++-
>  1 file changed, 185 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c
> index 601141190f42..9a51d91d16bd 100644
> --- a/drivers/net/ethernet/sfc/tc_encap_actions.c
> +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c
> @@ -239,12 +239,183 @@ static void efx_release_neigh(struct efx_nic *efx,
>  	efx_free_neigh(neigh);
>  }
>  
> -static void efx_gen_encap_header(struct efx_tc_encap_action *encap)
> +static void efx_gen_tun_header_eth(struct efx_tc_encap_action *encap, u16 proto)
>  {
> -	/* stub for now */
> -	encap->n_valid = false;
> -	memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr));
> -	encap->encap_hdr_len = ETH_HLEN;
> +	struct efx_neigh_binder *neigh = encap->neigh;
> +	struct ethhdr *eth;
> +
> +	encap->encap_hdr_len = sizeof(*eth);
> +	eth = (struct ethhdr *)encap->encap_hdr;
> +
> +	if (encap->neigh->n_valid)
> +		ether_addr_copy(eth->h_dest, neigh->ha);
> +	else
> +		eth_zero_addr(eth->h_dest);
> +	ether_addr_copy(eth->h_source, neigh->egdev->dev_addr);
> +	eth->h_proto = htons(proto);
> +}
> +
> +static void efx_gen_tun_header_ipv4(struct efx_tc_encap_action *encap, u8 ipproto, u8 len)
> +{
> +	struct efx_neigh_binder *neigh = encap->neigh;
> +	struct ip_tunnel_key *key = &encap->key;
> +	struct iphdr *ip;
> +
> +	ip = (struct iphdr *)(encap->encap_hdr + encap->encap_hdr_len);
> +	encap->encap_hdr_len += sizeof(*ip);
> +
> +	ip->daddr = key->u.ipv4.dst;
> +	ip->saddr = key->u.ipv4.src;
> +	ip->ttl = neigh->ttl;
> +	ip->protocol = ipproto;
> +	ip->version = 0x4;
> +	ip->ihl = 0x5;
> +	ip->tot_len = cpu_to_be16(ip->ihl * 4 + len);
> +	ip_send_check(ip);
> +}
> +
> +#ifdef CONFIG_IPV6
> +static void efx_gen_tun_header_ipv6(struct efx_tc_encap_action *encap, u8 ipproto, u8 len)
> +{
> +	struct efx_neigh_binder *neigh = encap->neigh;
> +	struct ip_tunnel_key *key = &encap->key;
> +	struct ipv6hdr *ip;
> +
> +	ip = (struct ipv6hdr *)(encap->encap_hdr + encap->encap_hdr_len);
> +	encap->encap_hdr_len += sizeof(*ip);
> +
> +	ip6_flow_hdr(ip, key->tos, key->label);
> +	ip->daddr = key->u.ipv6.dst;
> +	ip->saddr = key->u.ipv6.src;
> +	ip->hop_limit = neigh->ttl;
> +	ip->nexthdr = ipproto;
> +	ip->version = 0x6;
> +	ip->payload_len = cpu_to_be16(len);
> +}
> +#endif
> +
> +static void efx_gen_tun_header_udp(struct efx_tc_encap_action *encap, u8 len)
> +{
> +	struct ip_tunnel_key *key = &encap->key;
> +	struct udphdr *udp;
> +
> +	udp = (struct udphdr *)(encap->encap_hdr + encap->encap_hdr_len);
> +	encap->encap_hdr_len += sizeof(*udp);
> +
> +	udp->dest = key->tp_dst;
> +	udp->len = cpu_to_be16(sizeof(*udp) + len);
> +}
> +
> +static void efx_gen_tun_header_vxlan(struct efx_tc_encap_action *encap)
> +{
> +	struct ip_tunnel_key *key = &encap->key;
> +	struct vxlanhdr *vxlan;
> +
> +	vxlan = (struct vxlanhdr *)(encap->encap_hdr + encap->encap_hdr_len);
> +	encap->encap_hdr_len += sizeof(*vxlan);
> +
> +	vxlan->vx_flags = VXLAN_HF_VNI;
> +	vxlan->vx_vni = vxlan_vni_field(tunnel_id_to_key32(key->tun_id));
> +}
> +
> +static void efx_gen_tun_header_geneve(struct efx_tc_encap_action *encap)
> +{
> +	struct ip_tunnel_key *key = &encap->key;
> +	struct genevehdr *geneve;
> +	u32 vni;
> +
> +	geneve = (struct genevehdr *)(encap->encap_hdr + encap->encap_hdr_len);
> +	encap->encap_hdr_len += sizeof(*geneve);
> +
> +	geneve->proto_type = htons(ETH_P_TEB);
> +	/* convert tun_id to host-endian so we can use host arithmetic to
> +	 * extract individual bytes.
> +	 */
> +	vni = ntohl(tunnel_id_to_key32(key->tun_id));
> +	geneve->vni[0] = vni >> 16;
> +	geneve->vni[1] = vni >> 8;
> +	geneve->vni[2] = vni;
> +}
> +
> +#define vxlan_header_l4_len	(sizeof(struct udphdr) + sizeof(struct vxlanhdr))
> +#define vxlan4_header_len	(sizeof(struct ethhdr) + sizeof(struct iphdr) + vxlan_header_l4_len)
> +static void efx_gen_vxlan_header_ipv4(struct efx_tc_encap_action *encap)
> +{
> +	BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan4_header_len);
> +	efx_gen_tun_header_eth(encap, ETH_P_IP);
> +	efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, vxlan_header_l4_len);
> +	efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr));
> +	efx_gen_tun_header_vxlan(encap);
> +}
> +
> +#define geneve_header_l4_len	(sizeof(struct udphdr) + sizeof(struct genevehdr))
> +#define geneve4_header_len	(sizeof(struct ethhdr) + sizeof(struct iphdr) + geneve_header_l4_len)
> +static void efx_gen_geneve_header_ipv4(struct efx_tc_encap_action *encap)
> +{
> +	BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve4_header_len);
> +	efx_gen_tun_header_eth(encap, ETH_P_IP);
> +	efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, geneve_header_l4_len);
> +	efx_gen_tun_header_udp(encap, sizeof(struct genevehdr));
> +	efx_gen_tun_header_geneve(encap);
> +}
> +
> +#ifdef CONFIG_IPV6
> +#define vxlan6_header_len	(sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + vxlan_header_l4_len)
> +static void efx_gen_vxlan_header_ipv6(struct efx_tc_encap_action *encap)
> +{
> +	BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan6_header_len);
> +	efx_gen_tun_header_eth(encap, ETH_P_IPV6);
> +	efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, vxlan_header_l4_len);
> +	efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr));
> +	efx_gen_tun_header_vxlan(encap);
> +}
> +
> +#define geneve6_header_len	(sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + geneve_header_l4_len)
> +static void efx_gen_geneve_header_ipv6(struct efx_tc_encap_action *encap)
> +{
> +	BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve6_header_len);
> +	efx_gen_tun_header_eth(encap, ETH_P_IPV6);
> +	efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, geneve_header_l4_len);
> +	efx_gen_tun_header_udp(encap, sizeof(struct genevehdr));
> +	efx_gen_tun_header_geneve(encap);
> +}
> +#endif
> +
> +static void efx_gen_encap_header(struct efx_nic *efx,
> +				 struct efx_tc_encap_action *encap)
> +{
> +	encap->n_valid = encap->neigh->n_valid;
> +
> +	/* GCC stupidly thinks that only values explicitly listed in the enum
> +	 * definition can _possibly_ be sensible case values, so without this
> +	 * cast it complains about the IPv6 versions.
> +	 */
> +	switch ((int)encap->type) {
> +	case EFX_ENCAP_TYPE_VXLAN:
> +		efx_gen_vxlan_header_ipv4(encap);
> +		break;
> +	case EFX_ENCAP_TYPE_GENEVE:
> +		efx_gen_geneve_header_ipv4(encap);
> +		break;
> +#ifdef CONFIG_IPV6
> +	case EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6:
> +		efx_gen_vxlan_header_ipv6(encap);
> +		break;
> +	case EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6:
> +		efx_gen_geneve_header_ipv6(encap);
> +		break;
> +#endif
> +	default:
> +		/* unhandled encap type, can't happen */
> +		if (net_ratelimit())
> +			netif_err(efx, drv, efx->net_dev,
> +				  "Bogus encap type %d, can't generate\n",
> +				  encap->type);
> +
> +		/* Use fallback action. */
> +		encap->n_valid = false;
> +		break;
> +	}
>  }
>  
Hello Edward Cree,

Why do you need to refactor the efx_gen_encap_header function in the same series?
I saw that patch 5 defined this function, and patch 6 refactored it,
instead of writing it all at once?

Regards,
Hao Lan

>  static void efx_tc_update_encap(struct efx_nic *efx,
> @@ -278,14 +449,19 @@ static void efx_tc_update_encap(struct efx_nic *efx,
>  		}
>  	}
>  
> +	/* Make sure we don't leak arbitrary bytes on the wire;
> +	 * set an all-0s ethernet header.  A successful call to
> +	 * efx_gen_encap_header() will overwrite this.
> +	 */
> +	memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr));
> +	encap->encap_hdr_len = ETH_HLEN;
> +
>  	if (encap->neigh) {
>  		read_lock_bh(&encap->neigh->lock);
> -		efx_gen_encap_header(encap);
> +		efx_gen_encap_header(efx, encap);
>  		read_unlock_bh(&encap->neigh->lock);
>  	} else {
>  		encap->n_valid = false;
> -		memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr));
> -		encap->encap_hdr_len = ETH_HLEN;
>  	}
>  
>  	rc = efx_mae_update_encap_md(efx, encap);
> @@ -482,7 +658,7 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md(
>  	}
>  	encap->dest_mport = rc;
>  	read_lock_bh(&encap->neigh->lock);
> -	efx_gen_encap_header(encap);
> +	efx_gen_encap_header(efx, encap);
>  	read_unlock_bh(&encap->neigh->lock);
>  
>  	rc = efx_mae_allocate_encap_md(efx, encap);
> 
> .
>
Pieter Jansen van Vuuren June 6, 2023, 11:02 a.m. UTC | #2
On 05/06/2023 20:17, edward.cree@amd.com wrote:
> From: Edward Cree <ecree.xilinx@gmail.com>
> 
> Support constructing VxLAN and GENEVE headers, on either IPv4 or IPv6,
>  using the neighbouring information obtained in encap->neigh to
>  populate the Ethernet header.
> Note that the ef100 hardware does not insert UDP checksums when
>  performing encap, so for IPv6 the remote endpoint will need to be
>  configured with udp6zerocsumrx or equivalent.
> 
> Signed-off-by: Edward Cree <ecree.xilinx@gmail.com>

Reviewed-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com>
Edward Cree June 6, 2023, 3:03 p.m. UTC | #3
On 06/06/2023 04:52, Hao Lan wrote:
> Why do you need to refactor the efx_gen_encap_header function in the same series?
> I saw that patch 5 defined this function, and patch 6 refactored it,
> instead of writing it all at once?

Patch 5 introduces it only as a stub, because the calling code needs
 it to exist.  Patch 6 then provides the implementation; this is not
 a refactoring.
They're in separate patches to split things up logically for review
 and to assist future bisection.  Patch 5 is already big and complex
 without this part.

(Also, please trim your quotes when replying to patches: you only
 need to quote the part you're commenting on.)

-ed
Hao Lan June 6, 2023, 3:23 p.m. UTC | #4
On 2023/6/6 23:03, Edward Cree wrote:
> On 06/06/2023 04:52, Hao Lan wrote:
>> Why do you need to refactor the efx_gen_encap_header function in the same series?
>> I saw that patch 5 defined this function, and patch 6 refactored it,
>> instead of writing it all at once?
> Patch 5 introduces it only as a stub, because the calling code needs
>  it to exist.  Patch 6 then provides the implementation; this is not
>  a refactoring.
> They're in separate patches to split things up logically for review
>  and to assist future bisection.  Patch 5 is already big and complex
>  without this part.
> 
> (Also, please trim your quotes when replying to patches: you only
>  need to quote the part you're commenting on.)
> 
> -ed
> .
> 

This is a great idea for committing complex code,
thank you.

Reviewed-by: Hao Lan <lanhao@huawei.com>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c
index 601141190f42..9a51d91d16bd 100644
--- a/drivers/net/ethernet/sfc/tc_encap_actions.c
+++ b/drivers/net/ethernet/sfc/tc_encap_actions.c
@@ -239,12 +239,183 @@  static void efx_release_neigh(struct efx_nic *efx,
 	efx_free_neigh(neigh);
 }
 
-static void efx_gen_encap_header(struct efx_tc_encap_action *encap)
+static void efx_gen_tun_header_eth(struct efx_tc_encap_action *encap, u16 proto)
 {
-	/* stub for now */
-	encap->n_valid = false;
-	memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr));
-	encap->encap_hdr_len = ETH_HLEN;
+	struct efx_neigh_binder *neigh = encap->neigh;
+	struct ethhdr *eth;
+
+	encap->encap_hdr_len = sizeof(*eth);
+	eth = (struct ethhdr *)encap->encap_hdr;
+
+	if (encap->neigh->n_valid)
+		ether_addr_copy(eth->h_dest, neigh->ha);
+	else
+		eth_zero_addr(eth->h_dest);
+	ether_addr_copy(eth->h_source, neigh->egdev->dev_addr);
+	eth->h_proto = htons(proto);
+}
+
+static void efx_gen_tun_header_ipv4(struct efx_tc_encap_action *encap, u8 ipproto, u8 len)
+{
+	struct efx_neigh_binder *neigh = encap->neigh;
+	struct ip_tunnel_key *key = &encap->key;
+	struct iphdr *ip;
+
+	ip = (struct iphdr *)(encap->encap_hdr + encap->encap_hdr_len);
+	encap->encap_hdr_len += sizeof(*ip);
+
+	ip->daddr = key->u.ipv4.dst;
+	ip->saddr = key->u.ipv4.src;
+	ip->ttl = neigh->ttl;
+	ip->protocol = ipproto;
+	ip->version = 0x4;
+	ip->ihl = 0x5;
+	ip->tot_len = cpu_to_be16(ip->ihl * 4 + len);
+	ip_send_check(ip);
+}
+
+#ifdef CONFIG_IPV6
+static void efx_gen_tun_header_ipv6(struct efx_tc_encap_action *encap, u8 ipproto, u8 len)
+{
+	struct efx_neigh_binder *neigh = encap->neigh;
+	struct ip_tunnel_key *key = &encap->key;
+	struct ipv6hdr *ip;
+
+	ip = (struct ipv6hdr *)(encap->encap_hdr + encap->encap_hdr_len);
+	encap->encap_hdr_len += sizeof(*ip);
+
+	ip6_flow_hdr(ip, key->tos, key->label);
+	ip->daddr = key->u.ipv6.dst;
+	ip->saddr = key->u.ipv6.src;
+	ip->hop_limit = neigh->ttl;
+	ip->nexthdr = ipproto;
+	ip->version = 0x6;
+	ip->payload_len = cpu_to_be16(len);
+}
+#endif
+
+static void efx_gen_tun_header_udp(struct efx_tc_encap_action *encap, u8 len)
+{
+	struct ip_tunnel_key *key = &encap->key;
+	struct udphdr *udp;
+
+	udp = (struct udphdr *)(encap->encap_hdr + encap->encap_hdr_len);
+	encap->encap_hdr_len += sizeof(*udp);
+
+	udp->dest = key->tp_dst;
+	udp->len = cpu_to_be16(sizeof(*udp) + len);
+}
+
+static void efx_gen_tun_header_vxlan(struct efx_tc_encap_action *encap)
+{
+	struct ip_tunnel_key *key = &encap->key;
+	struct vxlanhdr *vxlan;
+
+	vxlan = (struct vxlanhdr *)(encap->encap_hdr + encap->encap_hdr_len);
+	encap->encap_hdr_len += sizeof(*vxlan);
+
+	vxlan->vx_flags = VXLAN_HF_VNI;
+	vxlan->vx_vni = vxlan_vni_field(tunnel_id_to_key32(key->tun_id));
+}
+
+static void efx_gen_tun_header_geneve(struct efx_tc_encap_action *encap)
+{
+	struct ip_tunnel_key *key = &encap->key;
+	struct genevehdr *geneve;
+	u32 vni;
+
+	geneve = (struct genevehdr *)(encap->encap_hdr + encap->encap_hdr_len);
+	encap->encap_hdr_len += sizeof(*geneve);
+
+	geneve->proto_type = htons(ETH_P_TEB);
+	/* convert tun_id to host-endian so we can use host arithmetic to
+	 * extract individual bytes.
+	 */
+	vni = ntohl(tunnel_id_to_key32(key->tun_id));
+	geneve->vni[0] = vni >> 16;
+	geneve->vni[1] = vni >> 8;
+	geneve->vni[2] = vni;
+}
+
+#define vxlan_header_l4_len	(sizeof(struct udphdr) + sizeof(struct vxlanhdr))
+#define vxlan4_header_len	(sizeof(struct ethhdr) + sizeof(struct iphdr) + vxlan_header_l4_len)
+static void efx_gen_vxlan_header_ipv4(struct efx_tc_encap_action *encap)
+{
+	BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan4_header_len);
+	efx_gen_tun_header_eth(encap, ETH_P_IP);
+	efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, vxlan_header_l4_len);
+	efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr));
+	efx_gen_tun_header_vxlan(encap);
+}
+
+#define geneve_header_l4_len	(sizeof(struct udphdr) + sizeof(struct genevehdr))
+#define geneve4_header_len	(sizeof(struct ethhdr) + sizeof(struct iphdr) + geneve_header_l4_len)
+static void efx_gen_geneve_header_ipv4(struct efx_tc_encap_action *encap)
+{
+	BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve4_header_len);
+	efx_gen_tun_header_eth(encap, ETH_P_IP);
+	efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, geneve_header_l4_len);
+	efx_gen_tun_header_udp(encap, sizeof(struct genevehdr));
+	efx_gen_tun_header_geneve(encap);
+}
+
+#ifdef CONFIG_IPV6
+#define vxlan6_header_len	(sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + vxlan_header_l4_len)
+static void efx_gen_vxlan_header_ipv6(struct efx_tc_encap_action *encap)
+{
+	BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan6_header_len);
+	efx_gen_tun_header_eth(encap, ETH_P_IPV6);
+	efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, vxlan_header_l4_len);
+	efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr));
+	efx_gen_tun_header_vxlan(encap);
+}
+
+#define geneve6_header_len	(sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + geneve_header_l4_len)
+static void efx_gen_geneve_header_ipv6(struct efx_tc_encap_action *encap)
+{
+	BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve6_header_len);
+	efx_gen_tun_header_eth(encap, ETH_P_IPV6);
+	efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, geneve_header_l4_len);
+	efx_gen_tun_header_udp(encap, sizeof(struct genevehdr));
+	efx_gen_tun_header_geneve(encap);
+}
+#endif
+
+static void efx_gen_encap_header(struct efx_nic *efx,
+				 struct efx_tc_encap_action *encap)
+{
+	encap->n_valid = encap->neigh->n_valid;
+
+	/* GCC stupidly thinks that only values explicitly listed in the enum
+	 * definition can _possibly_ be sensible case values, so without this
+	 * cast it complains about the IPv6 versions.
+	 */
+	switch ((int)encap->type) {
+	case EFX_ENCAP_TYPE_VXLAN:
+		efx_gen_vxlan_header_ipv4(encap);
+		break;
+	case EFX_ENCAP_TYPE_GENEVE:
+		efx_gen_geneve_header_ipv4(encap);
+		break;
+#ifdef CONFIG_IPV6
+	case EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6:
+		efx_gen_vxlan_header_ipv6(encap);
+		break;
+	case EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6:
+		efx_gen_geneve_header_ipv6(encap);
+		break;
+#endif
+	default:
+		/* unhandled encap type, can't happen */
+		if (net_ratelimit())
+			netif_err(efx, drv, efx->net_dev,
+				  "Bogus encap type %d, can't generate\n",
+				  encap->type);
+
+		/* Use fallback action. */
+		encap->n_valid = false;
+		break;
+	}
 }
 
 static void efx_tc_update_encap(struct efx_nic *efx,
@@ -278,14 +449,19 @@  static void efx_tc_update_encap(struct efx_nic *efx,
 		}
 	}
 
+	/* Make sure we don't leak arbitrary bytes on the wire;
+	 * set an all-0s ethernet header.  A successful call to
+	 * efx_gen_encap_header() will overwrite this.
+	 */
+	memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr));
+	encap->encap_hdr_len = ETH_HLEN;
+
 	if (encap->neigh) {
 		read_lock_bh(&encap->neigh->lock);
-		efx_gen_encap_header(encap);
+		efx_gen_encap_header(efx, encap);
 		read_unlock_bh(&encap->neigh->lock);
 	} else {
 		encap->n_valid = false;
-		memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr));
-		encap->encap_hdr_len = ETH_HLEN;
 	}
 
 	rc = efx_mae_update_encap_md(efx, encap);
@@ -482,7 +658,7 @@  struct efx_tc_encap_action *efx_tc_flower_create_encap_md(
 	}
 	encap->dest_mport = rc;
 	read_lock_bh(&encap->neigh->lock);
-	efx_gen_encap_header(encap);
+	efx_gen_encap_header(efx, encap);
 	read_unlock_bh(&encap->neigh->lock);
 
 	rc = efx_mae_allocate_encap_md(efx, encap);