Message ID | 1600257625-2353-1-git-send-email-magnus.karlsson@gmail.com |
---|---|
State | Superseded |
Headers | show |
Series | [bpf,v5] xsk: do not discard packet when NETDEV_TX_BUSY | expand |
On 9/16/20 2:00 PM, Magnus Karlsson wrote: > From: Magnus Karlsson <magnus.karlsson@intel.com> > > In the skb Tx path, transmission of a packet is performed with > dev_direct_xmit(). When NETDEV_TX_BUSY is set in the drivers, it > signifies that it was not possible to send the packet right now, > please try later. Unfortunately, the xsk transmit code discarded the > packet and returned EBUSY to the application. Fix this unnecessary > packet loss, by not discarding the packet in the Tx ring and return > EAGAIN. As EAGAIN is returned to the application, it can then retry > the send operation later and the packet will then likely be sent as > the driver will then likely have space/resources to send the packet. > > In summary, EAGAIN tells the application that the packet was not > discarded from the Tx ring and that it needs to call send() > again. EBUSY, on the other hand, signifies that the packet was not > sent and discarded from the Tx ring. The application needs to put the > packet on the Tx ring again if it wants it to be sent. > > Fixes: 35fcde7f8deb ("xsk: support for Tx") > Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com> > Reported-by: Arkadiusz Zema <A.Zema@falconvsystems.com> > Suggested-by: Arkadiusz Zema <A.Zema@falconvsystems.com> > Suggested-by: Daniel Borkmann <daniel@iogearbox.net> Hopefully patchwork/vger recovers soon, but looks good & I've applied this one in meantime (also kept Jesse's prior Reviewed-by given there were no fundamental changes). Thanks!
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index c323162..6c5e09e 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -377,15 +377,30 @@ static int xsk_generic_xmit(struct sock *sk) skb_shinfo(skb)->destructor_arg = (void *)(long)desc.addr; skb->destructor = xsk_destruct_skb; + /* Hinder dev_direct_xmit from freeing the packet and + * therefore completing it in the destructor + */ + refcount_inc(&skb->users); err = dev_direct_xmit(skb, xs->queue_id); + if (err == NETDEV_TX_BUSY) { + /* Tell user-space to retry the send */ + skb->destructor = sock_wfree; + /* Free skb without triggering the perf drop trace */ + consume_skb(skb); + err = -EAGAIN; + goto out; + } + xskq_cons_release(xs->tx); /* Ignore NET_XMIT_CN as packet might have been sent */ - if (err == NET_XMIT_DROP || err == NETDEV_TX_BUSY) { + if (err == NET_XMIT_DROP) { /* SKB completed but not sent */ + kfree_skb(skb); err = -EBUSY; goto out; } + consume_skb(skb); sent_frame = true; }