Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <henqqi@linux.alibaba.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Heng Qi and committed by
David S. Miller
2e0de636 7e8cdc97

+77 -13
+77 -13
drivers/net/veth.c
··· 1119 1119 1120 1120 static int veth_enable_xdp(struct net_device *dev) 1121 1121 { 1122 - bool napi_already_on = veth_gro_requested(dev) && (dev->flags & IFF_UP); 1123 1122 struct veth_priv *priv = netdev_priv(dev); 1123 + bool napi_already_on; 1124 + struct veth_rq *rq; 1124 1125 int err, i; 1126 + 1127 + rq = &priv->rq[0]; 1128 + napi_already_on = (dev->flags & IFF_UP) && rcu_access_pointer(rq->napi); 1125 1129 1126 1130 if (!xdp_rxq_info_is_reg(&priv->rq[0].xdp_rxq)) { 1127 1131 err = veth_enable_xdp_range(dev, 0, dev->real_num_rx_queues, napi_already_on); ··· 1327 1323 1328 1324 static int veth_open(struct net_device *dev) 1329 1325 { 1330 - struct veth_priv *priv = netdev_priv(dev); 1326 + struct veth_priv *peer_priv, *priv = netdev_priv(dev); 1331 1327 struct net_device *peer = rtnl_dereference(priv->peer); 1328 + struct veth_rq *peer_rq; 1332 1329 int err; 1333 1330 1334 1331 if (!peer) 1335 1332 return -ENOTCONN; 1336 1333 1334 + peer_priv = netdev_priv(peer); 1335 + peer_rq = &peer_priv->rq[0]; 1336 + 1337 1337 if (priv->_xdp_prog) { 1338 1338 err = veth_enable_xdp(dev); 1339 1339 if (err) 1340 1340 return err; 1341 - } else if (veth_gro_requested(dev)) { 1341 + /* refer to the logic in veth_xdp_set() */ 1342 + if (!rtnl_dereference(peer_rq->napi)) { 1343 + err = veth_napi_enable(peer); 1344 + if (err) 1345 + return err; 1346 + } 1347 + } else if (veth_gro_requested(dev) || peer_priv->_xdp_prog) { 1342 1348 err = veth_napi_enable(dev); 1343 1349 if (err) 1344 1350 return err; ··· 1364 1350 1365 1351 static int veth_close(struct net_device *dev) 1366 1352 { 1367 - struct veth_priv *priv = netdev_priv(dev); 1353 + struct veth_priv *peer_priv, *priv = netdev_priv(dev); 1368 1354 struct net_device *peer = rtnl_dereference(priv->peer); 1355 + struct veth_rq *peer_rq; 1369 1356 1370 1357 netif_carrier_off(dev); 1358 + if (peer) { 1359 + peer_priv = netdev_priv(peer); 1360 + peer_rq = &peer_priv->rq[0]; 1361 + } 1362 + 1363 + if (priv->_xdp_prog) { 1364 + veth_disable_xdp(dev); 1365 + /* refer to the logic in veth_xdp_set */ 1366 + if (peer && rtnl_dereference(peer_rq->napi)) { 1367 + if (!veth_gro_requested(peer) && !peer_priv->_xdp_prog) 1368 + veth_napi_del(peer); 1369 + } 1370 + } else if (veth_gro_requested(dev) || (peer && peer_priv->_xdp_prog)) { 1371 + veth_napi_del(dev); 1372 + } 1373 + 1371 1374 if (peer) 1372 1375 netif_carrier_off(peer); 1373 - 1374 - if (priv->_xdp_prog) 1375 - veth_disable_xdp(dev); 1376 - else if (veth_gro_requested(dev)) 1377 - veth_napi_del(dev); 1378 1376 1379 1377 return 0; 1380 1378 } ··· 1496 1470 { 1497 1471 netdev_features_t changed = features ^ dev->features; 1498 1472 struct veth_priv *priv = netdev_priv(dev); 1473 + struct veth_rq *rq = &priv->rq[0]; 1499 1474 int err; 1500 1475 1501 1476 if (!(changed & NETIF_F_GRO) || !(dev->flags & IFF_UP) || priv->_xdp_prog) 1502 1477 return 0; 1503 1478 1504 1479 if (features & NETIF_F_GRO) { 1505 - err = veth_napi_enable(dev); 1506 - if (err) 1507 - return err; 1480 + if (!rtnl_dereference(rq->napi)) { 1481 + err = veth_napi_enable(dev); 1482 + if (err) 1483 + return err; 1484 + } 1508 1485 } else { 1509 - veth_napi_del(dev); 1486 + if (rtnl_dereference(rq->napi)) 1487 + veth_napi_del(dev); 1510 1488 } 1511 1489 return 0; 1512 1490 } ··· 1542 1512 struct netlink_ext_ack *extack) 1543 1513 { 1544 1514 struct veth_priv *priv = netdev_priv(dev); 1515 + struct veth_priv *peer_priv; 1545 1516 struct bpf_prog *old_prog; 1517 + struct veth_rq *peer_rq; 1546 1518 struct net_device *peer; 1519 + bool napi_already_off; 1547 1520 unsigned int max_mtu; 1521 + bool noreq_napi; 1548 1522 int err; 1549 1523 1550 1524 old_prog = priv->_xdp_prog; 1551 1525 priv->_xdp_prog = prog; 1552 1526 peer = rtnl_dereference(priv->peer); 1527 + peer_priv = netdev_priv(peer); 1553 1528 1554 1529 if (prog) { 1555 1530 if (!peer) { ··· 1591 1556 } 1592 1557 } 1593 1558 1559 + if (peer && (peer->flags & IFF_UP)) { 1560 + peer_rq = &peer_priv->rq[0]; 1561 + 1562 + /* If the peer hasn't enabled GRO and loaded xdp, 1563 + * then we enable napi automatically if its napi 1564 + * is not ready. 1565 + */ 1566 + napi_already_off = !rtnl_dereference(peer_rq->napi); 1567 + if (napi_already_off) { 1568 + err = veth_napi_enable(peer); 1569 + if (err) { 1570 + NL_SET_ERR_MSG_MOD(extack, 1571 + "Failed to automatically enable napi of peer"); 1572 + goto err; 1573 + } 1574 + } 1575 + } 1576 + 1594 1577 if (!old_prog) { 1595 1578 peer->hw_features &= ~NETIF_F_GSO_SOFTWARE; 1596 1579 peer->max_mtu = max_mtu; ··· 1623 1570 if (peer) { 1624 1571 peer->hw_features |= NETIF_F_GSO_SOFTWARE; 1625 1572 peer->max_mtu = ETH_MAX_MTU; 1573 + peer_rq = &peer_priv->rq[0]; 1574 + 1575 + /* If the peer doesn't has its xdp and enabled 1576 + * GRO, then we disable napi if its napi is ready; 1577 + */ 1578 + if (rtnl_dereference(peer_rq->napi)) { 1579 + noreq_napi = !veth_gro_requested(peer) && 1580 + !peer_priv->_xdp_prog; 1581 + if (noreq_napi && (peer->flags & IFF_UP)) 1582 + veth_napi_del(peer); 1583 + } 1626 1584 } 1627 1585 } 1628 1586 bpf_prog_put(old_prog);