All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] veth: Avoid drop packets when xdp_redirect performs
@ 2022-10-31  6:19 Heng Qi
  2022-11-02 12:10 ` patchwork-bot+netdevbpf
  0 siblings, 1 reply; 2+ messages in thread
From: Heng Qi @ 2022-10-31  6:19 UTC (permalink / raw)
  To: linux-kernel, netdev, bpf
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
	John Fastabend, Toke Høiland-Jørgensen, Xuan Zhuo,
	Heng Qi

From: Heng Qi <henqqi@linux.alibaba.com>

In the current processing logic, when xdp_redirect occurs, it transmits
the xdp frame based on napi.

If napi of the peer veth is not ready, the veth will drop the packets.
This doesn't meet our expectations.

In this context, we enable napi of the peer veth automatically when the
veth loads the xdp. Then if the veth unloads the xdp, we need to
correctly judge whether to disable napi of the peer veth, because the peer
veth may have loaded xdp, or even the user has enabled GRO.

Signed-off-by: Heng Qi <henqqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
---
Previous discussion on this issue is here
https://lore.kernel.org/all/87r0yxgxba.fsf@toke.dk/ .

 drivers/net/veth.c | 88 +++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 76 insertions(+), 12 deletions(-)

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 466da01ba2e3..105682237a9d 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1119,10 +1119,14 @@ static void veth_disable_xdp_range(struct net_device *dev, int start, int end,
 
 static int veth_enable_xdp(struct net_device *dev)
 {
-	bool napi_already_on = veth_gro_requested(dev) && (dev->flags & IFF_UP);
 	struct veth_priv *priv = netdev_priv(dev);
+	bool napi_already_on;
+	struct veth_rq *rq;
 	int err, i;
 
+	rq = &priv->rq[0];
+	napi_already_on = (dev->flags & IFF_UP) && rcu_access_pointer(rq->napi);
+
 	if (!xdp_rxq_info_is_reg(&priv->rq[0].xdp_rxq)) {
 		err = veth_enable_xdp_range(dev, 0, dev->real_num_rx_queues, napi_already_on);
 		if (err)
@@ -1323,18 +1327,28 @@ static int veth_set_channels(struct net_device *dev,
 
 static int veth_open(struct net_device *dev)
 {
-	struct veth_priv *priv = netdev_priv(dev);
+	struct veth_priv *peer_priv, *priv = netdev_priv(dev);
 	struct net_device *peer = rtnl_dereference(priv->peer);
+	struct veth_rq *peer_rq;
 	int err;
 
 	if (!peer)
 		return -ENOTCONN;
 
+	peer_priv = netdev_priv(peer);
+	peer_rq = &peer_priv->rq[0];
+
 	if (priv->_xdp_prog) {
 		err = veth_enable_xdp(dev);
 		if (err)
 			return err;
-	} else if (veth_gro_requested(dev)) {
+		/* refer to the logic in veth_xdp_set() */
+		if (!rtnl_dereference(peer_rq->napi)) {
+			err = veth_napi_enable(peer);
+			if (err)
+				return err;
+		}
+	} else if (veth_gro_requested(dev) || peer_priv->_xdp_prog) {
 		err = veth_napi_enable(dev);
 		if (err)
 			return err;
@@ -1350,17 +1364,29 @@ static int veth_open(struct net_device *dev)
 
 static int veth_close(struct net_device *dev)
 {
-	struct veth_priv *priv = netdev_priv(dev);
+	struct veth_priv *peer_priv, *priv = netdev_priv(dev);
 	struct net_device *peer = rtnl_dereference(priv->peer);
+	struct veth_rq *peer_rq;
 
 	netif_carrier_off(dev);
-	if (peer)
-		netif_carrier_off(peer);
+	if (peer) {
+		peer_priv = netdev_priv(peer);
+		peer_rq = &peer_priv->rq[0];
+	}
 
-	if (priv->_xdp_prog)
+	if (priv->_xdp_prog) {
 		veth_disable_xdp(dev);
-	else if (veth_gro_requested(dev))
+		/* refer to the logic in veth_xdp_set */
+		if (peer && rtnl_dereference(peer_rq->napi)) {
+			if (!veth_gro_requested(peer) && !peer_priv->_xdp_prog)
+				veth_napi_del(peer);
+		}
+	} else if (veth_gro_requested(dev) || (peer && peer_priv->_xdp_prog)) {
 		veth_napi_del(dev);
+	}
+
+	if (peer)
+		netif_carrier_off(peer);
 
 	return 0;
 }
@@ -1470,17 +1496,21 @@ static int veth_set_features(struct net_device *dev,
 {
 	netdev_features_t changed = features ^ dev->features;
 	struct veth_priv *priv = netdev_priv(dev);
+	struct veth_rq *rq = &priv->rq[0];
 	int err;
 
 	if (!(changed & NETIF_F_GRO) || !(dev->flags & IFF_UP) || priv->_xdp_prog)
 		return 0;
 
 	if (features & NETIF_F_GRO) {
-		err = veth_napi_enable(dev);
-		if (err)
-			return err;
+		if (!rtnl_dereference(rq->napi)) {
+			err = veth_napi_enable(dev);
+			if (err)
+				return err;
+		}
 	} else {
-		veth_napi_del(dev);
+		if (rtnl_dereference(rq->napi))
+			veth_napi_del(dev);
 	}
 	return 0;
 }
@@ -1512,14 +1542,19 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
 			struct netlink_ext_ack *extack)
 {
 	struct veth_priv *priv = netdev_priv(dev);
+	struct veth_priv *peer_priv;
 	struct bpf_prog *old_prog;
+	struct veth_rq *peer_rq;
 	struct net_device *peer;
+	bool napi_already_off;
 	unsigned int max_mtu;
+	bool noreq_napi;
 	int err;
 
 	old_prog = priv->_xdp_prog;
 	priv->_xdp_prog = prog;
 	peer = rtnl_dereference(priv->peer);
+	peer_priv = netdev_priv(peer);
 
 	if (prog) {
 		if (!peer) {
@@ -1556,6 +1591,24 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
 			}
 		}
 
+		if (peer && (peer->flags & IFF_UP)) {
+			peer_rq = &peer_priv->rq[0];
+
+			/* If the peer hasn't enabled GRO and loaded xdp,
+			 * then we enable napi automatically if its napi
+			 * is not ready.
+			 */
+			napi_already_off = !rtnl_dereference(peer_rq->napi);
+			if (napi_already_off) {
+				err = veth_napi_enable(peer);
+				if (err) {
+					NL_SET_ERR_MSG_MOD(extack,
+							   "Failed to automatically enable napi of peer");
+					goto err;
+				}
+			}
+		}
+
 		if (!old_prog) {
 			peer->hw_features &= ~NETIF_F_GSO_SOFTWARE;
 			peer->max_mtu = max_mtu;
@@ -1570,6 +1623,17 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
 			if (peer) {
 				peer->hw_features |= NETIF_F_GSO_SOFTWARE;
 				peer->max_mtu = ETH_MAX_MTU;
+				peer_rq = &peer_priv->rq[0];
+
+				/* If the peer doesn't has its xdp and enabled
+				 * GRO, then we disable napi if its napi is ready;
+				 */
+				if (rtnl_dereference(peer_rq->napi)) {
+					noreq_napi = !veth_gro_requested(peer) &&
+						     !peer_priv->_xdp_prog;
+					if (noreq_napi && (peer->flags & IFF_UP))
+						veth_napi_del(peer);
+				}
 			}
 		}
 		bpf_prog_put(old_prog);
-- 
2.19.1.6.gb485710b


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] veth: Avoid drop packets when xdp_redirect performs
  2022-10-31  6:19 [PATCH] veth: Avoid drop packets when xdp_redirect performs Heng Qi
@ 2022-11-02 12:10 ` patchwork-bot+netdevbpf
  0 siblings, 0 replies; 2+ messages in thread
From: patchwork-bot+netdevbpf @ 2022-11-02 12:10 UTC (permalink / raw)
  To: Heng Qi
  Cc: linux-kernel, netdev, bpf, davem, edumazet, kuba, pabeni, ast,
	daniel, hawk, john.fastabend, toke, xuanzhuo, henqqi

Hello:

This patch was applied to netdev/net-next.git (master)
by David S. Miller <davem@davemloft.net>:

On Mon, 31 Oct 2022 14:19:22 +0800 you wrote:
> From: Heng Qi <henqqi@linux.alibaba.com>
> 
> In the current processing logic, when xdp_redirect occurs, it transmits
> the xdp frame based on napi.
> 
> If napi of the peer veth is not ready, the veth will drop the packets.
> This doesn't meet our expectations.
> 
> [...]

Here is the summary with links:
  - veth: Avoid drop packets when xdp_redirect performs
    https://git.kernel.org/netdev/net-next/c/2e0de6366ac1

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-11-02 12:10 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-31  6:19 [PATCH] veth: Avoid drop packets when xdp_redirect performs Heng Qi
2022-11-02 12:10 ` patchwork-bot+netdevbpf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.