Skip to content

Commit 2e0de63

Browse files
Heng Qidavem330
authored andcommitted
veth: Avoid drop packets when xdp_redirect performs
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 <[email protected]> Reviewed-by: Xuan Zhuo <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7e8cdc9 commit 2e0de63

File tree

1 file changed

+76
-12
lines changed

1 file changed

+76
-12
lines changed

drivers/net/veth.c

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,10 +1119,14 @@ static void veth_disable_xdp_range(struct net_device *dev, int start, int end,
11191119

11201120
static int veth_enable_xdp(struct net_device *dev)
11211121
{
1122-
bool napi_already_on = veth_gro_requested(dev) && (dev->flags & IFF_UP);
11231122
struct veth_priv *priv = netdev_priv(dev);
1123+
bool napi_already_on;
1124+
struct veth_rq *rq;
11241125
int err, i;
11251126

1127+
rq = &priv->rq[0];
1128+
napi_already_on = (dev->flags & IFF_UP) && rcu_access_pointer(rq->napi);
1129+
11261130
if (!xdp_rxq_info_is_reg(&priv->rq[0].xdp_rxq)) {
11271131
err = veth_enable_xdp_range(dev, 0, dev->real_num_rx_queues, napi_already_on);
11281132
if (err)
@@ -1323,18 +1327,28 @@ static int veth_set_channels(struct net_device *dev,
13231327

13241328
static int veth_open(struct net_device *dev)
13251329
{
1326-
struct veth_priv *priv = netdev_priv(dev);
1330+
struct veth_priv *peer_priv, *priv = netdev_priv(dev);
13271331
struct net_device *peer = rtnl_dereference(priv->peer);
1332+
struct veth_rq *peer_rq;
13281333
int err;
13291334

13301335
if (!peer)
13311336
return -ENOTCONN;
13321337

1338+
peer_priv = netdev_priv(peer);
1339+
peer_rq = &peer_priv->rq[0];
1340+
13331341
if (priv->_xdp_prog) {
13341342
err = veth_enable_xdp(dev);
13351343
if (err)
13361344
return err;
1337-
} else if (veth_gro_requested(dev)) {
1345+
/* refer to the logic in veth_xdp_set() */
1346+
if (!rtnl_dereference(peer_rq->napi)) {
1347+
err = veth_napi_enable(peer);
1348+
if (err)
1349+
return err;
1350+
}
1351+
} else if (veth_gro_requested(dev) || peer_priv->_xdp_prog) {
13381352
err = veth_napi_enable(dev);
13391353
if (err)
13401354
return err;
@@ -1350,17 +1364,29 @@ static int veth_open(struct net_device *dev)
13501364

13511365
static int veth_close(struct net_device *dev)
13521366
{
1353-
struct veth_priv *priv = netdev_priv(dev);
1367+
struct veth_priv *peer_priv, *priv = netdev_priv(dev);
13541368
struct net_device *peer = rtnl_dereference(priv->peer);
1369+
struct veth_rq *peer_rq;
13551370

13561371
netif_carrier_off(dev);
1357-
if (peer)
1358-
netif_carrier_off(peer);
1372+
if (peer) {
1373+
peer_priv = netdev_priv(peer);
1374+
peer_rq = &peer_priv->rq[0];
1375+
}
13591376

1360-
if (priv->_xdp_prog)
1377+
if (priv->_xdp_prog) {
13611378
veth_disable_xdp(dev);
1362-
else if (veth_gro_requested(dev))
1379+
/* refer to the logic in veth_xdp_set */
1380+
if (peer && rtnl_dereference(peer_rq->napi)) {
1381+
if (!veth_gro_requested(peer) && !peer_priv->_xdp_prog)
1382+
veth_napi_del(peer);
1383+
}
1384+
} else if (veth_gro_requested(dev) || (peer && peer_priv->_xdp_prog)) {
13631385
veth_napi_del(dev);
1386+
}
1387+
1388+
if (peer)
1389+
netif_carrier_off(peer);
13641390

13651391
return 0;
13661392
}
@@ -1470,17 +1496,21 @@ static int veth_set_features(struct net_device *dev,
14701496
{
14711497
netdev_features_t changed = features ^ dev->features;
14721498
struct veth_priv *priv = netdev_priv(dev);
1499+
struct veth_rq *rq = &priv->rq[0];
14731500
int err;
14741501

14751502
if (!(changed & NETIF_F_GRO) || !(dev->flags & IFF_UP) || priv->_xdp_prog)
14761503
return 0;
14771504

14781505
if (features & NETIF_F_GRO) {
1479-
err = veth_napi_enable(dev);
1480-
if (err)
1481-
return err;
1506+
if (!rtnl_dereference(rq->napi)) {
1507+
err = veth_napi_enable(dev);
1508+
if (err)
1509+
return err;
1510+
}
14821511
} else {
1483-
veth_napi_del(dev);
1512+
if (rtnl_dereference(rq->napi))
1513+
veth_napi_del(dev);
14841514
}
14851515
return 0;
14861516
}
@@ -1512,14 +1542,19 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
15121542
struct netlink_ext_ack *extack)
15131543
{
15141544
struct veth_priv *priv = netdev_priv(dev);
1545+
struct veth_priv *peer_priv;
15151546
struct bpf_prog *old_prog;
1547+
struct veth_rq *peer_rq;
15161548
struct net_device *peer;
1549+
bool napi_already_off;
15171550
unsigned int max_mtu;
1551+
bool noreq_napi;
15181552
int err;
15191553

15201554
old_prog = priv->_xdp_prog;
15211555
priv->_xdp_prog = prog;
15221556
peer = rtnl_dereference(priv->peer);
1557+
peer_priv = netdev_priv(peer);
15231558

15241559
if (prog) {
15251560
if (!peer) {
@@ -1556,6 +1591,24 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
15561591
}
15571592
}
15581593

1594+
if (peer && (peer->flags & IFF_UP)) {
1595+
peer_rq = &peer_priv->rq[0];
1596+
1597+
/* If the peer hasn't enabled GRO and loaded xdp,
1598+
* then we enable napi automatically if its napi
1599+
* is not ready.
1600+
*/
1601+
napi_already_off = !rtnl_dereference(peer_rq->napi);
1602+
if (napi_already_off) {
1603+
err = veth_napi_enable(peer);
1604+
if (err) {
1605+
NL_SET_ERR_MSG_MOD(extack,
1606+
"Failed to automatically enable napi of peer");
1607+
goto err;
1608+
}
1609+
}
1610+
}
1611+
15591612
if (!old_prog) {
15601613
peer->hw_features &= ~NETIF_F_GSO_SOFTWARE;
15611614
peer->max_mtu = max_mtu;
@@ -1570,6 +1623,17 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
15701623
if (peer) {
15711624
peer->hw_features |= NETIF_F_GSO_SOFTWARE;
15721625
peer->max_mtu = ETH_MAX_MTU;
1626+
peer_rq = &peer_priv->rq[0];
1627+
1628+
/* If the peer doesn't has its xdp and enabled
1629+
* GRO, then we disable napi if its napi is ready;
1630+
*/
1631+
if (rtnl_dereference(peer_rq->napi)) {
1632+
noreq_napi = !veth_gro_requested(peer) &&
1633+
!peer_priv->_xdp_prog;
1634+
if (noreq_napi && (peer->flags & IFF_UP))
1635+
veth_napi_del(peer);
1636+
}
15731637
}
15741638
}
15751639
bpf_prog_put(old_prog);

0 commit comments

Comments
 (0)