vxlan: fix GRO with VXLAN-GPE
Subsystems (2)
PATCH 1/2 vxlan: generalize vxlan_parse_gpe_hdr and remove unused args
In reply to Jiri BencThe vxlan_parse_gpe_hdr function extracts the next protocol value from the GPE header and marks GPE bits as parsed.
In order to be used in the next patch, split the function into protocol extraction and bit marking. The bit marking is meaningful only in vxlan_rcv; move it directly there.
Rename the function to vxlan_parse_gpe_proto to reflect what it now does. Remove unused arguments skb and vxflags. Move the function earlier in the file to allow it to be called from more places in the next patch.
--- drivers/net/vxlan/vxlan_core.c | 58 ++++++++++++++++------------------ 1 file changed, 28 insertions(+), 30 deletions(-)
drivers/net/vxlan/vxlan_core.c +28 -30
@@ -623,6 +623,32 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,return 1 ; } +static bool vxlan_parse_gpe_proto (struct vxlanhdr *hdr,__be16 *protocol) +{ +struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)hdr; + +/* Need to have Next Protocol set for interfaces in GPE mode. */ +if (!gpe->np_applied) +return false; +/* "The initial version is 0. If a receiver does not support the +* version indicated it MUST drop the packet. +*/ +if (gpe->version !=0 ) +return false; +/* "When the O bit is set to 1, the packet is an OAM packet and OAM +* processing MUST occur." However, we don't implement OAM +* processing, thus drop the packet. +*/ +if (gpe->oam_flag) +return false; + + *protocol =tun_p_to_eth_p (gpe->next_protocol); +if (!*protocol) +return false; + +return true; +} + static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, unsigned int off, struct vxlanhdr *vh, size_t hdrlen,
@@ -1525,35 +1551,6 @@ static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed, unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS ; } -static bool vxlan_parse_gpe_hdr (struct vxlanhdr *unparsed, -__be16 *protocol, -struct sk_buff *skb,u32 vxflags) -{ -struct vxlanhdr_gpe *gpe = (struct vxlanhdr_gpe *)unparsed; - -/* Need to have Next Protocol set for interfaces in GPE mode. */ -if (!gpe->np_applied) -return false; -/* "The initial version is 0. If a receiver does not support the -* version indicated it MUST drop the packet. -*/ -if (gpe->version !=0 ) -return false; -/* "When the O bit is set to 1, the packet is an OAM packet and OAM -* processing MUST occur." However, we don't implement OAM -* processing, thus drop the packet. -*/ -if (gpe->oam_flag) -return false; - - *protocol =tun_p_to_eth_p (gpe->next_protocol); -if (!*protocol) -return false; - - unparsed->vx_flags &= ~VXLAN_GPE_USED_BITS ; -return true; -} -static bool vxlan_set_mac (struct vxlan_dev *vxlan,struct vxlan_sock *vs,struct sk_buff *skb,__be32 vni)
@@ -1655,8 +1652,9 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)* used by VXLAN extensions if explicitly requested. */ if (vs->flags &VXLAN_F_GPE ) { -if (!vxlan_parse_gpe_hdr (&unparsed, &protocol, skb, vs->flags)) +if (!vxlan_parse_gpe_proto (&unparsed, &protocol)) goto drop; + unparsed.vx_flags &= ~VXLAN_GPE_USED_BITS ; raw_proto = true; }
Signature · 1 line
2.39.2
cover vxlan: fix GRO with VXLAN-GPE
The first patch generalizes code for the second patch, which is a fix for broken VXLAN-GPE GRO. Thanks to Paolo for noticing the bug.
Jiri Benc (2):
vxlan: generalize vxlan_parse_gpe_hdr and remove unused args
vxlan: fix GRO with VXLAN-GPE
drivers/net/vxlan/vxlan_core.c | 142 ++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 45 deletions(-)
Signature · 1 line
2.39.2
PATCH 2/2 vxlan: fix GRO with VXLAN-GPE
In VXLAN-GPE, there may not be an Ethernet header following the VXLAN header. But in GRO, the vxlan driver calls eth_gro_receive unconditionally, which means the following header is incorrectly parsed as Ethernet.
Introduce GPE specific GRO handling.
For better performance, do not check for GPE during GRO but rather install a different set of functions at setup time.
--- drivers/net/vxlan/vxlan_core.c | 84 ++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 15 deletions(-)
drivers/net/vxlan/vxlan_core.c +69 -15
@@ -675,26 +675,24 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,return vh; } -static struct sk_buff *vxlan_gro_receive (struct sock *sk, -struct list_head *head, -struct sk_buff *skb) +static struct vxlanhdr *vxlan_gro_prepare_receive (struct sock *sk, +struct list_head *head, +struct sk_buff *skb, +struct gro_remcsum *grc) { -struct sk_buff *pp =NULL ;struct sk_buff *p;struct vxlanhdr *vh, *vh2;unsigned int hlen, off_vx; -int flush =1 ;struct vxlan_sock *vs =rcu_dereference_sk_user_data (sk);__be32 flags; -struct gro_remcsum grc; -skb_gro_remcsum_init (&grc); +skb_gro_remcsum_init (grc); off_vx =skb_gro_offset (skb); hlen = off_vx +sizeof (*vh); vh =skb_gro_header (skb, hlen, off_vx);if (unlikely (!vh)) - goto out; +return NULL ;skb_gro_postpull_rcsum (skb, vh,sizeof (struct vxlanhdr ));
@@ -702,12 +700,12 @@ static struct sk_buff *vxlan_gro_receive(struct sock *sk,if ((flags &VXLAN_HF_RCO ) && (vs->flags &VXLAN_F_REMCSUM_RX )) { vh =vxlan_gro_remcsum (skb, off_vx, vh,sizeof (struct vxlanhdr ), - vh->vx_vni, &grc, + vh->vx_vni, grc, !!(vs->flags &VXLAN_F_REMCSUM_NOPARTIAL ));if (!vh) - goto out; +return NULL ; }skb_gro_pull (skb,sizeof (struct vxlanhdr ));/* pull vxlan header */
@@ -724,12 +722,48 @@ static struct sk_buff *vxlan_gro_receive(struct sock *sk, } } - pp =call_gro_receive (eth_gro_receive, head, skb); - flush =0 ; +return vh; +} + +static struct sk_buff *vxlan_gro_receive (struct sock *sk, +struct list_head *head, +struct sk_buff *skb) +{ +struct sk_buff *pp =NULL ; +struct gro_remcsum grc; +int flush =1 ; -out: +if (vxlan_gro_prepare_receive (sk, head, skb, &grc)) { + pp =call_gro_receive (eth_gro_receive, head, skb); + flush =0 ; + }skb_gro_flush_final_remcsum (skb, pp, flush, &grc); +return pp; +} +static struct sk_buff *vxlan_gpe_gro_receive (struct sock *sk, +struct list_head *head, +struct sk_buff *skb) +{ +const struct packet_offload *ptype; +struct sk_buff *pp =NULL ; +struct gro_remcsum grc; +struct vxlanhdr *vh; +__be16 protocol; +int flush =1 ; + + vh =vxlan_gro_prepare_receive (sk, head, skb, &grc); +if (vh) { +if (!vxlan_parse_gpe_proto (vh, &protocol)) + goto out; + ptype =gro_find_receive_by_type (protocol); +if (!ptype) + goto out; + pp =call_gro_receive (ptype->callbacks.gro_receive, head, skb); + flush =0 ; + } +out: +skb_gro_flush_final_remcsum (skb, pp, flush, &grc);return pp; }
@@ -741,6 +775,21 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)return eth_gro_complete (skb, nhoff +sizeof (struct vxlanhdr )); } +static int vxlan_gpe_gro_complete (struct sock *sk,struct sk_buff *skb,int nhoff) +{ +struct vxlanhdr *vh = (struct vxlanhdr *)(skb->data + nhoff); +const struct packet_offload *ptype; +int err = -ENOSYS ; +__be16 protocol; + +if (!vxlan_parse_gpe_proto (vh, &protocol)) +return err; + ptype =gro_find_complete_by_type (protocol); +if (ptype) + err = ptype->callbacks.gro_complete (skb, nhoff +sizeof (struct vxlanhdr )); +return err; +} +static struct vxlan_fdb *vxlan_fdb_alloc (struct vxlan_dev *vxlan,const u8 *mac,__u16 state,__be32 src_vni,__u16 ndm_flags)
@@ -3376,8 +3425,13 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6, tunnel_cfg.encap_rcv = vxlan_rcv; tunnel_cfg.encap_err_lookup = vxlan_err_lookup; tunnel_cfg.encap_destroy =NULL ; - tunnel_cfg.gro_receive = vxlan_gro_receive; - tunnel_cfg.gro_complete = vxlan_gro_complete; +if (vs->flags &VXLAN_F_GPE ) { + tunnel_cfg.gro_receive = vxlan_gpe_gro_receive; + tunnel_cfg.gro_complete = vxlan_gpe_gro_complete; + }else { + tunnel_cfg.gro_receive = vxlan_gro_receive; + tunnel_cfg.gro_complete = vxlan_gro_complete; + }setup_udp_tunnel_sock (net, sock, &tunnel_cfg);
Signature · 1 line
2.39.2
This series was applied to netdev/net.git (main) by David S. Miller <[email protected]>:
Hello:
This series was applied to netdev/net.git (main)
by David S. Miller <[email protected]>:
Quoted 8 lines · On Fri, 21 Jul 2023 16:30:45 +0200 you wrote:
The first patch generalizes code for the second patch, which is a fix for broken VXLAN-GPE GRO. Thanks to Paolo for noticing the bug.
Jiri Benc (2):
vxlan: generalizevxlan_parse_gpe_hdrand remove unused args
vxlan: fix GRO with VXLAN-GPE[...]
Here is the summary with links:
- [net,1/2] vxlan: generalize vxlan_parse_gpe_hdr and remove unused args
https://git.kernel.org/netdev/net/c/17a0a64448b5 - [net,2/2] vxlan: fix GRO with VXLAN-GPE https://git.kernel.org/netdev/net/c/b0b672c4d095
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html