On Tue, 25 Sep 2018 22:36:39 -0700 Song Liu <liu.song....@gmail.com> wrote:
> On Tue, Sep 25, 2018 at 7:26 AM Jesper Dangaard Brouer > <bro...@redhat.com> wrote: > > > > XDP can modify (and resize) the Ethernet header in the packet. > > > > There is a bug in generic-XDP, because skb->protocol and skb->pkt_type > > are setup before reaching (netif_receive_)generic_xdp. > > > > This bug was hit when XDP were popping VLAN headers (changing > > eth->h_proto), as skb->protocol still contains VLAN-indication > > (ETH_P_8021Q) causing invocation of skb_vlan_untag(skb), which corrupt > > the packet (basically popping the VLAN again). > > > > This patch catch if XDP changed eth header in such a way, that SKB > > fields needs to be updated. > > > > Fixes: d445516966dc ("net: xdp: support xdp generic on virtual devices") > > Signed-off-by: Jesper Dangaard Brouer <bro...@redhat.com> > > --- > > net/core/dev.c | 14 ++++++++++++++ > > 1 file changed, 14 insertions(+) > > > > diff --git a/net/core/dev.c b/net/core/dev.c > > index ca78dc5a79a3..db6d89f536cb 100644 > > --- a/net/core/dev.c > > +++ b/net/core/dev.c > > @@ -4258,6 +4258,9 @@ static u32 netif_receive_generic_xdp(struct sk_buff > > *skb, > > struct netdev_rx_queue *rxqueue; > > void *orig_data, *orig_data_end; > > u32 metalen, act = XDP_DROP; > > + __be16 orig_eth_type; > > + struct ethhdr *eth; > > + bool orig_bcast; > > int hlen, off; > > u32 mac_len; > > > > @@ -4298,6 +4301,9 @@ static u32 netif_receive_generic_xdp(struct sk_buff > > *skb, > > xdp->data_hard_start = skb->data - skb_headroom(skb); > > orig_data_end = xdp->data_end; > > orig_data = xdp->data; > > + eth = (struct ethhdr *)xdp->data; > > + orig_bcast = is_multicast_ether_addr_64bits(eth->h_dest); > > + orig_eth_type = eth->h_proto; > > > > rxqueue = netif_get_rxqueue(skb); > > xdp->rxq = &rxqueue->xdp_rxq; > > @@ -4321,6 +4327,14 @@ static u32 netif_receive_generic_xdp(struct sk_buff > > *skb, > > > > } > > > > + /* check if XDP changed eth hdr such SKB needs update */ > > + eth = (struct ethhdr *)xdp->data; > > + if ((orig_eth_type != eth->h_proto) || > > + (orig_bcast != is_multicast_ether_addr_64bits(eth->h_dest))) { > > Is the actions below always correct for the condition above? Do we need > to confirm the SKB is updated properly? I cannot find the issue that you are hinting to? If the BPF prog used bpf_xdp_adjust_head(), which the included selftest program does, then skb->data have been appropriately adjusted just above (with __skb_pull(skb, off) or __skb_push(skb, -off)), which makes the call to skb_reset_mac_header(skb) inside eth_type_trans() correct. I've double checked the code, and I cannot find anything wrong... please let me know if I missed something!? > > + __skb_push(skb, mac_len); > > + skb->protocol = eth_type_trans(skb, skb->dev); We could change mac_len to be ETH_HLEN, because inside eth_type_trans() the constant ETH_HLEN is used, that way we are 100% sure the skb_push/skb_pull are "paired". Will that be better for you? > > + } > > + > > switch (act) { > > case XDP_REDIRECT: > > case XDP_TX: > > -- Best regards, Jesper Dangaard Brouer MSc.CS, Principal Kernel Engineer at Red Hat LinkedIn: http://www.linkedin.com/in/brouer