Skip to content

Commit b0b672c

Browse files
Jiri Bencdavem330
authored andcommitted
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. Fixes: e1e5314 ("vxlan: implement GPE") Reported-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Jiri Benc <jbenc@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 17a0a64 commit b0b672c

File tree

1 file changed

+69
-15
lines changed

1 file changed

+69
-15
lines changed

drivers/net/vxlan/vxlan_core.c

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -675,39 +675,37 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
675675
return vh;
676676
}
677677

678-
static struct sk_buff *vxlan_gro_receive(struct sock *sk,
679-
struct list_head *head,
680-
struct sk_buff *skb)
678+
static struct vxlanhdr *vxlan_gro_prepare_receive(struct sock *sk,
679+
struct list_head *head,
680+
struct sk_buff *skb,
681+
struct gro_remcsum *grc)
681682
{
682-
struct sk_buff *pp = NULL;
683683
struct sk_buff *p;
684684
struct vxlanhdr *vh, *vh2;
685685
unsigned int hlen, off_vx;
686-
int flush = 1;
687686
struct vxlan_sock *vs = rcu_dereference_sk_user_data(sk);
688687
__be32 flags;
689-
struct gro_remcsum grc;
690688

691-
skb_gro_remcsum_init(&grc);
689+
skb_gro_remcsum_init(grc);
692690

693691
off_vx = skb_gro_offset(skb);
694692
hlen = off_vx + sizeof(*vh);
695693
vh = skb_gro_header(skb, hlen, off_vx);
696694
if (unlikely(!vh))
697-
goto out;
695+
return NULL;
698696

699697
skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
700698

701699
flags = vh->vx_flags;
702700

703701
if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
704702
vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr),
705-
vh->vx_vni, &grc,
703+
vh->vx_vni, grc,
706704
!!(vs->flags &
707705
VXLAN_F_REMCSUM_NOPARTIAL));
708706

709707
if (!vh)
710-
goto out;
708+
return NULL;
711709
}
712710

713711
skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
@@ -724,12 +722,48 @@ static struct sk_buff *vxlan_gro_receive(struct sock *sk,
724722
}
725723
}
726724

727-
pp = call_gro_receive(eth_gro_receive, head, skb);
728-
flush = 0;
725+
return vh;
726+
}
727+
728+
static struct sk_buff *vxlan_gro_receive(struct sock *sk,
729+
struct list_head *head,
730+
struct sk_buff *skb)
731+
{
732+
struct sk_buff *pp = NULL;
733+
struct gro_remcsum grc;
734+
int flush = 1;
729735

730-
out:
736+
if (vxlan_gro_prepare_receive(sk, head, skb, &grc)) {
737+
pp = call_gro_receive(eth_gro_receive, head, skb);
738+
flush = 0;
739+
}
731740
skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
741+
return pp;
742+
}
732743

744+
static struct sk_buff *vxlan_gpe_gro_receive(struct sock *sk,
745+
struct list_head *head,
746+
struct sk_buff *skb)
747+
{
748+
const struct packet_offload *ptype;
749+
struct sk_buff *pp = NULL;
750+
struct gro_remcsum grc;
751+
struct vxlanhdr *vh;
752+
__be16 protocol;
753+
int flush = 1;
754+
755+
vh = vxlan_gro_prepare_receive(sk, head, skb, &grc);
756+
if (vh) {
757+
if (!vxlan_parse_gpe_proto(vh, &protocol))
758+
goto out;
759+
ptype = gro_find_receive_by_type(protocol);
760+
if (!ptype)
761+
goto out;
762+
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
763+
flush = 0;
764+
}
765+
out:
766+
skb_gro_flush_final_remcsum(skb, pp, flush, &grc);
733767
return pp;
734768
}
735769

@@ -741,6 +775,21 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
741775
return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
742776
}
743777

778+
static int vxlan_gpe_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
779+
{
780+
struct vxlanhdr *vh = (struct vxlanhdr *)(skb->data + nhoff);
781+
const struct packet_offload *ptype;
782+
int err = -ENOSYS;
783+
__be16 protocol;
784+
785+
if (!vxlan_parse_gpe_proto(vh, &protocol))
786+
return err;
787+
ptype = gro_find_complete_by_type(protocol);
788+
if (ptype)
789+
err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
790+
return err;
791+
}
792+
744793
static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, const u8 *mac,
745794
__u16 state, __be32 src_vni,
746795
__u16 ndm_flags)
@@ -3376,8 +3425,13 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6,
33763425
tunnel_cfg.encap_rcv = vxlan_rcv;
33773426
tunnel_cfg.encap_err_lookup = vxlan_err_lookup;
33783427
tunnel_cfg.encap_destroy = NULL;
3379-
tunnel_cfg.gro_receive = vxlan_gro_receive;
3380-
tunnel_cfg.gro_complete = vxlan_gro_complete;
3428+
if (vs->flags & VXLAN_F_GPE) {
3429+
tunnel_cfg.gro_receive = vxlan_gpe_gro_receive;
3430+
tunnel_cfg.gro_complete = vxlan_gpe_gro_complete;
3431+
} else {
3432+
tunnel_cfg.gro_receive = vxlan_gro_receive;
3433+
tunnel_cfg.gro_complete = vxlan_gro_complete;
3434+
}
33813435

33823436
setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
33833437

0 commit comments

Comments
 (0)