Skip to content

Commit d3256ef

Browse files
Paolo Abenidavem330
Paolo Abeni
authored andcommitted
veth: allow enabling NAPI even without XDP
Currently the veth device has the GRO feature bit set, even if no GRO aggregation is possible with the default configuration, as the veth device does not hook into the GRO engine. Flipping the GRO feature bit from user-space is a no-op, unless XDP is enabled. In such scenario GRO could actually take place, but TSO is forced to off on the peer device. This change allow user-space to really control the GRO feature, with no need for an XDP program. The GRO feature bit is now cleared by default - so that there are no user-visible behavior changes with the default configuration. When the GRO bit is set, the per-queue NAPI instances are initialized and registered. On xmit, when napi instances are available, we try to use them. Some additional checks are in place to ensure we initialize/delete NAPIs only when needed in case of overlapping XDP and GRO configuration changes. Signed-off-by: Paolo Abeni <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c75fb32 commit d3256ef

File tree

1 file changed

+116
-13
lines changed

1 file changed

+116
-13
lines changed

drivers/net/veth.c

+116-13
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct veth_rq_stats {
5757

5858
struct veth_rq {
5959
struct napi_struct xdp_napi;
60+
struct napi_struct __rcu *napi; /* points to xdp_napi when the latter is initialized */
6061
struct net_device *dev;
6162
struct bpf_prog __rcu *xdp_prog;
6263
struct xdp_mem_info xdp_mem;
@@ -299,7 +300,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
299300
struct veth_rq *rq = NULL;
300301
struct net_device *rcv;
301302
int length = skb->len;
302-
bool rcv_xdp = false;
303+
bool use_napi = false;
303304
int rxq;
304305

305306
rcu_read_lock();
@@ -313,20 +314,24 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
313314
rxq = skb_get_queue_mapping(skb);
314315
if (rxq < rcv->real_num_rx_queues) {
315316
rq = &rcv_priv->rq[rxq];
316-
rcv_xdp = rcu_access_pointer(rq->xdp_prog);
317+
318+
/* The napi pointer is available when an XDP program is
319+
* attached or when GRO is enabled
320+
*/
321+
use_napi = rcu_access_pointer(rq->napi);
317322
skb_record_rx_queue(skb, rxq);
318323
}
319324

320325
skb_tx_timestamp(skb);
321-
if (likely(veth_forward_skb(rcv, skb, rq, rcv_xdp) == NET_RX_SUCCESS)) {
322-
if (!rcv_xdp)
326+
if (likely(veth_forward_skb(rcv, skb, rq, use_napi) == NET_RX_SUCCESS)) {
327+
if (!use_napi)
323328
dev_lstats_add(dev, length);
324329
} else {
325330
drop:
326331
atomic64_inc(&priv->dropped);
327332
}
328333

329-
if (rcv_xdp)
334+
if (use_napi)
330335
__veth_xdp_flush(rq);
331336

332337
rcu_read_unlock();
@@ -903,7 +908,7 @@ static int veth_poll(struct napi_struct *napi, int budget)
903908
return done;
904909
}
905910

906-
static int veth_napi_add(struct net_device *dev)
911+
static int __veth_napi_enable(struct net_device *dev)
907912
{
908913
struct veth_priv *priv = netdev_priv(dev);
909914
int err, i;
@@ -920,6 +925,7 @@ static int veth_napi_add(struct net_device *dev)
920925
struct veth_rq *rq = &priv->rq[i];
921926

922927
napi_enable(&rq->xdp_napi);
928+
rcu_assign_pointer(priv->rq[i].napi, &priv->rq[i].xdp_napi);
923929
}
924930

925931
return 0;
@@ -938,6 +944,7 @@ static void veth_napi_del(struct net_device *dev)
938944
for (i = 0; i < dev->real_num_rx_queues; i++) {
939945
struct veth_rq *rq = &priv->rq[i];
940946

947+
rcu_assign_pointer(priv->rq[i].napi, NULL);
941948
napi_disable(&rq->xdp_napi);
942949
__netif_napi_del(&rq->xdp_napi);
943950
}
@@ -951,16 +958,23 @@ static void veth_napi_del(struct net_device *dev)
951958
}
952959
}
953960

961+
static bool veth_gro_requested(const struct net_device *dev)
962+
{
963+
return !!(dev->wanted_features & NETIF_F_GRO);
964+
}
965+
954966
static int veth_enable_xdp(struct net_device *dev)
955967
{
968+
bool napi_already_on = veth_gro_requested(dev) && (dev->flags & IFF_UP);
956969
struct veth_priv *priv = netdev_priv(dev);
957970
int err, i;
958971

959972
if (!xdp_rxq_info_is_reg(&priv->rq[0].xdp_rxq)) {
960973
for (i = 0; i < dev->real_num_rx_queues; i++) {
961974
struct veth_rq *rq = &priv->rq[i];
962975

963-
netif_napi_add(dev, &rq->xdp_napi, veth_poll, NAPI_POLL_WEIGHT);
976+
if (!napi_already_on)
977+
netif_napi_add(dev, &rq->xdp_napi, veth_poll, NAPI_POLL_WEIGHT);
964978
err = xdp_rxq_info_reg(&rq->xdp_rxq, dev, i, rq->xdp_napi.napi_id);
965979
if (err < 0)
966980
goto err_rxq_reg;
@@ -975,13 +989,25 @@ static int veth_enable_xdp(struct net_device *dev)
975989
rq->xdp_mem = rq->xdp_rxq.mem;
976990
}
977991

978-
err = veth_napi_add(dev);
979-
if (err)
980-
goto err_rxq_reg;
992+
if (!napi_already_on) {
993+
err = __veth_napi_enable(dev);
994+
if (err)
995+
goto err_rxq_reg;
996+
997+
if (!veth_gro_requested(dev)) {
998+
/* user-space did not require GRO, but adding XDP
999+
* is supposed to get GRO working
1000+
*/
1001+
dev->features |= NETIF_F_GRO;
1002+
netdev_features_change(dev);
1003+
}
1004+
}
9811005
}
9821006

983-
for (i = 0; i < dev->real_num_rx_queues; i++)
1007+
for (i = 0; i < dev->real_num_rx_queues; i++) {
9841008
rcu_assign_pointer(priv->rq[i].xdp_prog, priv->_xdp_prog);
1009+
rcu_assign_pointer(priv->rq[i].napi, &priv->rq[i].xdp_napi);
1010+
}
9851011

9861012
return 0;
9871013
err_reg_mem:
@@ -991,7 +1017,8 @@ static int veth_enable_xdp(struct net_device *dev)
9911017
struct veth_rq *rq = &priv->rq[i];
9921018

9931019
xdp_rxq_info_unreg(&rq->xdp_rxq);
994-
netif_napi_del(&rq->xdp_napi);
1020+
if (!napi_already_on)
1021+
netif_napi_del(&rq->xdp_napi);
9951022
}
9961023

9971024
return err;
@@ -1004,7 +1031,19 @@ static void veth_disable_xdp(struct net_device *dev)
10041031

10051032
for (i = 0; i < dev->real_num_rx_queues; i++)
10061033
rcu_assign_pointer(priv->rq[i].xdp_prog, NULL);
1007-
veth_napi_del(dev);
1034+
1035+
if (!netif_running(dev) || !veth_gro_requested(dev)) {
1036+
veth_napi_del(dev);
1037+
1038+
/* if user-space did not require GRO, since adding XDP
1039+
* enabled it, clear it now
1040+
*/
1041+
if (!veth_gro_requested(dev) && netif_running(dev)) {
1042+
dev->features &= ~NETIF_F_GRO;
1043+
netdev_features_change(dev);
1044+
}
1045+
}
1046+
10081047
for (i = 0; i < dev->real_num_rx_queues; i++) {
10091048
struct veth_rq *rq = &priv->rq[i];
10101049

@@ -1013,6 +1052,29 @@ static void veth_disable_xdp(struct net_device *dev)
10131052
}
10141053
}
10151054

1055+
static int veth_napi_enable(struct net_device *dev)
1056+
{
1057+
struct veth_priv *priv = netdev_priv(dev);
1058+
int err, i;
1059+
1060+
for (i = 0; i < dev->real_num_rx_queues; i++) {
1061+
struct veth_rq *rq = &priv->rq[i];
1062+
1063+
netif_napi_add(dev, &rq->xdp_napi, veth_poll, NAPI_POLL_WEIGHT);
1064+
}
1065+
1066+
err = __veth_napi_enable(dev);
1067+
if (err) {
1068+
for (i = 0; i < dev->real_num_rx_queues; i++) {
1069+
struct veth_rq *rq = &priv->rq[i];
1070+
1071+
netif_napi_del(&rq->xdp_napi);
1072+
}
1073+
return err;
1074+
}
1075+
return err;
1076+
}
1077+
10161078
static int veth_open(struct net_device *dev)
10171079
{
10181080
struct veth_priv *priv = netdev_priv(dev);
@@ -1026,6 +1088,10 @@ static int veth_open(struct net_device *dev)
10261088
err = veth_enable_xdp(dev);
10271089
if (err)
10281090
return err;
1091+
} else if (veth_gro_requested(dev)) {
1092+
err = veth_napi_enable(dev);
1093+
if (err)
1094+
return err;
10291095
}
10301096

10311097
if (peer->flags & IFF_UP) {
@@ -1047,6 +1113,8 @@ static int veth_close(struct net_device *dev)
10471113

10481114
if (priv->_xdp_prog)
10491115
veth_disable_xdp(dev);
1116+
else if (veth_gro_requested(dev))
1117+
veth_napi_del(dev);
10501118

10511119
return 0;
10521120
}
@@ -1145,10 +1213,32 @@ static netdev_features_t veth_fix_features(struct net_device *dev,
11451213
if (peer_priv->_xdp_prog)
11461214
features &= ~NETIF_F_GSO_SOFTWARE;
11471215
}
1216+
if (priv->_xdp_prog)
1217+
features |= NETIF_F_GRO;
11481218

11491219
return features;
11501220
}
11511221

1222+
static int veth_set_features(struct net_device *dev,
1223+
netdev_features_t features)
1224+
{
1225+
netdev_features_t changed = features ^ dev->features;
1226+
struct veth_priv *priv = netdev_priv(dev);
1227+
int err;
1228+
1229+
if (!(changed & NETIF_F_GRO) || !(dev->flags & IFF_UP) || priv->_xdp_prog)
1230+
return 0;
1231+
1232+
if (features & NETIF_F_GRO) {
1233+
err = veth_napi_enable(dev);
1234+
if (err)
1235+
return err;
1236+
} else {
1237+
veth_napi_del(dev);
1238+
}
1239+
return 0;
1240+
}
1241+
11521242
static void veth_set_rx_headroom(struct net_device *dev, int new_hr)
11531243
{
11541244
struct veth_priv *peer_priv, *priv = netdev_priv(dev);
@@ -1267,6 +1357,7 @@ static const struct net_device_ops veth_netdev_ops = {
12671357
#endif
12681358
.ndo_get_iflink = veth_get_iflink,
12691359
.ndo_fix_features = veth_fix_features,
1360+
.ndo_set_features = veth_set_features,
12701361
.ndo_features_check = passthru_features_check,
12711362
.ndo_set_rx_headroom = veth_set_rx_headroom,
12721363
.ndo_bpf = veth_xdp,
@@ -1329,6 +1420,13 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[],
13291420

13301421
static struct rtnl_link_ops veth_link_ops;
13311422

1423+
static void veth_disable_gro(struct net_device *dev)
1424+
{
1425+
dev->features &= ~NETIF_F_GRO;
1426+
dev->wanted_features &= ~NETIF_F_GRO;
1427+
netdev_update_features(dev);
1428+
}
1429+
13321430
static int veth_newlink(struct net *src_net, struct net_device *dev,
13331431
struct nlattr *tb[], struct nlattr *data[],
13341432
struct netlink_ext_ack *extack)
@@ -1401,6 +1499,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
14011499
if (err < 0)
14021500
goto err_register_peer;
14031501

1502+
/* keep GRO disabled by default to be consistent with the established
1503+
* veth behavior
1504+
*/
1505+
veth_disable_gro(peer);
14041506
netif_carrier_off(peer);
14051507

14061508
err = rtnl_configure_link(peer, ifmp);
@@ -1438,6 +1540,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
14381540
priv = netdev_priv(peer);
14391541
rcu_assign_pointer(priv->peer, dev);
14401542

1543+
veth_disable_gro(dev);
14411544
return 0;
14421545

14431546
err_register_dev:

0 commit comments

Comments
 (0)