Hi Jesper, On Wed, Oct 3, 2018 at 7:04 AM Jesper Dangaard Brouer <bro...@redhat.com> wrote: > > 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?
Thanks for the explanation. Now I understand it better. I think using ETH_HLEN is better. Both napi_frags_finish() and __dev_forward_skb() use similar pattern. Song