On Wed, 2021-06-23 at 11:45 +0800, Jason Wang wrote: > As replied in previous version, it would be better if we can unify > similar logic in tun_get_user(). Ah sorry, I missed that the first time. Yes, that was my initial inclination too. But in the tun_get_user() case we already *have* "pi", having read it separately into a local variable; it never made it to the skb. So the cases are subtly different enough that abstracting it out didn't seem to make sense. If I try harder to unify it, I suppose it looks something like this and *might* just make the cut for "simple enough to be backported to stable kernels in a bug fix". I'll add the PI mode to my test cases and try it (as well as *actually* unifying the offending code, of course). --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2332,10 +2332,12 @@ static int tun_xdp_one(struct tun_struct *tun, unsigned int datasize = xdp->data_end - xdp->data; struct tun_xdp_hdr *hdr = xdp->data_hard_start; struct virtio_net_hdr *gso = NULL; + struct tun_pi *pi = NULL; struct bpf_prog *xdp_prog; struct sk_buff *skb = NULL; u32 rxhash = 0, act; int buflen = hdr->buflen; + int reservelen = xdp->data - xdp->data_hard_start; int err = 0; bool skb_xdp = false; struct page *page; @@ -2343,6 +2345,11 @@ static int tun_xdp_one(struct tun_struct *tun, if (tun->flags & IFF_VNET_HDR) gso = &hdr->gso; + if (!(tun->flags & IFF_NO_PI)) { + pi = xdp->data; + reservelen += sizeof(*pi); + } + xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog) { if (gso && gso->gso_type) { @@ -2388,7 +2395,7 @@ static int tun_xdp_one(struct tun_struct *tun, goto out; } - skb_reserve(skb, xdp->data - xdp->data_hard_start); + skb_reserve(skb, reservelen); skb_put(skb, xdp->data_end - xdp->data); if (gso && virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) {