In order to support XDP_TX from offloaded XDP program, we need a way to inject Tx path packet into Rx path. Let's modify the Rx path function tun_xdp_one() for this purpose. This patch adds a parameter to pass information whether packet has virtio_net header. When header isn't present, it is considered as XDP_TX'ed packet from offloaded program. Signed-off-by: Prashant Bhole <prashantbhole.linux@xxxxxxxxx> --- drivers/net/tun.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 466ea69f00ee..8d6cdd3e5139 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2221,6 +2221,13 @@ static u32 tun_do_xdp_offload_generic(struct tun_struct *tun, return act; } +static int tun_xdp_one(struct tun_struct *tun, + struct tun_file *tfile, + struct xdp_buff *xdp, int *flush, + struct tun_page *tpage, int has_hdr); + +static void tun_put_page(struct tun_page *tpage); + static u32 tun_do_xdp_offload(struct tun_struct *tun, struct tun_file *tfile, struct xdp_frame *frame) { @@ -2527,23 +2534,36 @@ static void tun_put_page(struct tun_page *tpage) static int tun_xdp_one(struct tun_struct *tun, struct tun_file *tfile, struct xdp_buff *xdp, int *flush, - struct tun_page *tpage) + struct tun_page *tpage, int has_hdr) { unsigned int datasize = xdp->data_end - xdp->data; - struct tun_xdp_hdr *hdr = xdp->data_hard_start; - struct virtio_net_hdr *gso = &hdr->gso; + struct tun_xdp_hdr *hdr; + struct virtio_net_hdr *gso; struct tun_pcpu_stats *stats; struct bpf_prog *xdp_prog; struct sk_buff *skb = NULL; + unsigned int headroom; u32 rxhash = 0, act; - int buflen = hdr->buflen; + int buflen; int err = 0; bool skb_xdp = false; struct page *page; + if (has_hdr) { + hdr = xdp->data_hard_start; + gso = &hdr->gso; + buflen = hdr->buflen; + } else { + /* came here from tun tx path */ + xdp->data_hard_start -= sizeof(struct xdp_frame); + headroom = xdp->data - xdp->data_hard_start; + buflen = datasize + headroom + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + } + xdp_prog = rcu_dereference(tun->xdp_prog); if (xdp_prog) { - if (gso->gso_type) { + if (has_hdr && gso->gso_type) { skb_xdp = true; goto build; } @@ -2588,7 +2608,8 @@ static int tun_xdp_one(struct tun_struct *tun, skb_reserve(skb, xdp->data - xdp->data_hard_start); skb_put(skb, xdp->data_end - xdp->data); - if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) { + if (has_hdr && + virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) { this_cpu_inc(tun->pcpu_stats->rx_frame_errors); kfree_skb(skb); err = -EINVAL; @@ -2652,7 +2673,7 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) for (i = 0; i < n; i++) { xdp = &((struct xdp_buff *)ctl->ptr)[i]; - tun_xdp_one(tun, tfile, xdp, &flush, &tpage); + tun_xdp_one(tun, tfile, xdp, &flush, &tpage, true); } if (flush) -- 2.20.1