Skip to content

Commit 1d97708

Browse files
committed
Merge branch 'net-ethtool-add-dedicated-grxrings-driver-callbacks'
Breno Leitao says: ==================== net: ethtool: add dedicated GRXRINGS driver callbacks This patchset introduces a new dedicated ethtool_ops callback, .get_rx_ring_count, which enables drivers to provide the number of RX rings directly, improving efficiency and clarity in RX ring queries and RSS configuration. Number of drivers implements .get_rxnfc callback just to report the ring count, so, having a proper callback makes sense and simplify .get_rxnfc (in some cases remove it completely). This has been suggested by Jakub, and follow the same idea as RXFH driver callbacks [1]. This also port virtio_net to this new callback. Once there is consensus on this approach, I can start moving the drivers to this new callback. Link: https://lore.kernel.org/all/20250611145949.2674086-1-kuba@kernel.org/ [1] v3: https://lore.kernel.org/20250915-gxrings-v3-0-bfd717dbcaad@debian.org v2: https://lore.kernel.org/20250912-gxrings-v2-0-3c7a60bbeebf@debian.org v1: https://lore.kernel.org/20250909-gxrings-v1-0-634282f06a54@debian.org RFC: https://lore.kernel.org/20250905-gxrings-v1-0-984fc471f28f@debian.org ==================== Link: https://patch.msgid.link/20250917-gxrings-v4-0-dae520e2e1cb@debian.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 672beab + 4834466 commit 1d97708

6 files changed

Lines changed: 82 additions & 41 deletions

File tree

drivers/net/virtio_net.c

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5609,20 +5609,11 @@ static int virtnet_set_rxfh(struct net_device *dev,
56095609
return 0;
56105610
}
56115611

5612-
static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
5612+
static u32 virtnet_get_rx_ring_count(struct net_device *dev)
56135613
{
56145614
struct virtnet_info *vi = netdev_priv(dev);
5615-
int rc = 0;
56165615

5617-
switch (info->cmd) {
5618-
case ETHTOOL_GRXRINGS:
5619-
info->data = vi->curr_queue_pairs;
5620-
break;
5621-
default:
5622-
rc = -EOPNOTSUPP;
5623-
}
5624-
5625-
return rc;
5616+
return vi->curr_queue_pairs;
56265617
}
56275618

56285619
static const struct ethtool_ops virtnet_ethtool_ops = {
@@ -5650,7 +5641,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
56505641
.set_rxfh = virtnet_set_rxfh,
56515642
.get_rxfh_fields = virtnet_get_hashflow,
56525643
.set_rxfh_fields = virtnet_set_hashflow,
5653-
.get_rxnfc = virtnet_get_rxnfc,
5644+
.get_rx_ring_count = virtnet_get_rx_ring_count,
56545645
};
56555646

56565647
static void virtnet_get_queue_stats_rx(struct net_device *dev, int i,

include/linux/ethtool.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,7 @@ struct kernel_ethtool_ts_info {
968968
* @reset: Reset (part of) the device, as specified by a bitmask of
969969
* flags from &enum ethtool_reset_flags. Returns a negative
970970
* error code or zero.
971+
* @get_rx_ring_count: Return the number of RX rings
971972
* @get_rxfh_key_size: Get the size of the RX flow hash key.
972973
* Returns zero if not supported for this specific device.
973974
* @get_rxfh_indir_size: Get the size of the RX flow hash indirection table.
@@ -1162,6 +1163,7 @@ struct ethtool_ops {
11621163
int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
11631164
int (*flash_device)(struct net_device *, struct ethtool_flash *);
11641165
int (*reset)(struct net_device *, u32 *);
1166+
u32 (*get_rx_ring_count)(struct net_device *dev);
11651167
u32 (*get_rxfh_key_size)(struct net_device *);
11661168
u32 (*get_rxfh_indir_size)(struct net_device *);
11671169
int (*get_rxfh)(struct net_device *, struct ethtool_rxfh_param *);

net/ethtool/common.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,26 @@ int __ethtool_get_link(struct net_device *dev)
577577
return netif_running(dev) && dev->ethtool_ops->get_link(dev);
578578
}
579579

580+
int ethtool_get_rx_ring_count(struct net_device *dev)
581+
{
582+
const struct ethtool_ops *ops = dev->ethtool_ops;
583+
struct ethtool_rxnfc rx_rings = {};
584+
int ret;
585+
586+
if (ops->get_rx_ring_count)
587+
return ops->get_rx_ring_count(dev);
588+
589+
if (!ops->get_rxnfc)
590+
return -EOPNOTSUPP;
591+
592+
rx_rings.cmd = ETHTOOL_GRXRINGS;
593+
ret = ops->get_rxnfc(dev, &rx_rings, NULL);
594+
if (ret < 0)
595+
return ret;
596+
597+
return rx_rings.data;
598+
}
599+
580600
static int ethtool_get_rxnfc_rule_count(struct net_device *dev)
581601
{
582602
const struct ethtool_ops *ops = dev->ethtool_ops;

net/ethtool/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,
5454
struct kernel_ethtool_ringparam *kparam,
5555
struct netlink_ext_ack *extack);
5656

57+
int ethtool_get_rx_ring_count(struct net_device *dev);
58+
5759
int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info);
5860
int ethtool_get_ts_info_by_phc(struct net_device *dev,
5961
struct kernel_ethtool_ts_info *info,

net/ethtool/ioctl.c

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,18 +1208,41 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
12081208
return 0;
12091209
}
12101210

1211+
static noinline_for_stack int ethtool_get_rxrings(struct net_device *dev,
1212+
u32 cmd,
1213+
void __user *useraddr)
1214+
{
1215+
struct ethtool_rxnfc info;
1216+
size_t info_size;
1217+
int ret;
1218+
1219+
info_size = sizeof(info);
1220+
ret = ethtool_rxnfc_copy_struct(cmd, &info, &info_size, useraddr);
1221+
if (ret)
1222+
return ret;
1223+
1224+
ret = ethtool_get_rx_ring_count(dev);
1225+
if (ret < 0)
1226+
return ret;
1227+
1228+
info.data = ret;
1229+
1230+
return ethtool_rxnfc_copy_to_user(useraddr, &info, info_size, NULL);
1231+
}
1232+
12111233
static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
12121234
u32 cmd, void __user *useraddr)
12131235
{
1214-
struct ethtool_rxnfc info;
1215-
size_t info_size = sizeof(info);
12161236
const struct ethtool_ops *ops = dev->ethtool_ops;
1217-
int ret;
1237+
struct ethtool_rxnfc info;
12181238
void *rule_buf = NULL;
1239+
size_t info_size;
1240+
int ret;
12191241

12201242
if (!ops->get_rxnfc)
12211243
return -EOPNOTSUPP;
12221244

1245+
info_size = sizeof(info);
12231246
ret = ethtool_rxnfc_copy_struct(cmd, &info, &info_size, useraddr);
12241247
if (ret)
12251248
return ret;
@@ -1246,8 +1269,8 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
12461269
}
12471270

12481271
static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
1249-
struct ethtool_rxnfc *rx_rings,
1250-
u32 size)
1272+
int num_rx_rings,
1273+
u32 size)
12511274
{
12521275
int i;
12531276

@@ -1256,7 +1279,7 @@ static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr,
12561279

12571280
/* Validate ring indices */
12581281
for (i = 0; i < size; i++)
1259-
if (indir[i] >= rx_rings->data)
1282+
if (indir[i] >= num_rx_rings)
12601283
return -EINVAL;
12611284

12621285
return 0;
@@ -1327,13 +1350,12 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
13271350
const struct ethtool_ops *ops = dev->ethtool_ops;
13281351
struct ethtool_rxfh_param rxfh_dev = {};
13291352
struct netlink_ext_ack *extack = NULL;
1330-
struct ethtool_rxnfc rx_rings;
1353+
int num_rx_rings;
13311354
u32 user_size, i;
13321355
int ret;
13331356
u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]);
13341357

1335-
if (!ops->get_rxfh_indir_size || !ops->set_rxfh ||
1336-
!ops->get_rxnfc)
1358+
if (!ops->get_rxfh_indir_size || !ops->set_rxfh)
13371359
return -EOPNOTSUPP;
13381360

13391361
rxfh_dev.indir_size = ops->get_rxfh_indir_size(dev);
@@ -1353,20 +1375,21 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
13531375
if (!rxfh_dev.indir)
13541376
return -ENOMEM;
13551377

1356-
rx_rings.cmd = ETHTOOL_GRXRINGS;
1357-
ret = ops->get_rxnfc(dev, &rx_rings, NULL);
1358-
if (ret)
1378+
num_rx_rings = ethtool_get_rx_ring_count(dev);
1379+
if (num_rx_rings < 0) {
1380+
ret = num_rx_rings;
13591381
goto out;
1382+
}
13601383

13611384
if (user_size == 0) {
13621385
u32 *indir = rxfh_dev.indir;
13631386

13641387
for (i = 0; i < rxfh_dev.indir_size; i++)
1365-
indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1388+
indir[i] = ethtool_rxfh_indir_default(i, num_rx_rings);
13661389
} else {
13671390
ret = ethtool_copy_validate_indir(rxfh_dev.indir,
13681391
useraddr + ringidx_offset,
1369-
&rx_rings,
1392+
num_rx_rings,
13701393
rxfh_dev.indir_size);
13711394
if (ret)
13721395
goto out;
@@ -1508,14 +1531,14 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
15081531
struct ethtool_rxfh_param rxfh_dev = {};
15091532
struct ethtool_rxfh_context *ctx = NULL;
15101533
struct netlink_ext_ack *extack = NULL;
1511-
struct ethtool_rxnfc rx_rings;
15121534
struct ethtool_rxfh rxfh;
15131535
bool create = false;
1536+
int num_rx_rings;
15141537
u8 *rss_config;
15151538
int ntf = 0;
15161539
int ret;
15171540

1518-
if (!ops->get_rxnfc || !ops->set_rxfh)
1541+
if (!ops->set_rxfh)
15191542
return -EOPNOTSUPP;
15201543

15211544
if (ops->get_rxfh_indir_size)
@@ -1571,10 +1594,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
15711594
if (!rss_config)
15721595
return -ENOMEM;
15731596

1574-
rx_rings.cmd = ETHTOOL_GRXRINGS;
1575-
ret = ops->get_rxnfc(dev, &rx_rings, NULL);
1576-
if (ret)
1597+
num_rx_rings = ethtool_get_rx_ring_count(dev);
1598+
if (num_rx_rings < 0) {
1599+
ret = num_rx_rings;
15771600
goto out_free;
1601+
}
15781602

15791603
/* rxfh.indir_size == 0 means reset the indir table to default (master
15801604
* context) or delete the context (other RSS contexts).
@@ -1587,7 +1611,7 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
15871611
rxfh_dev.indir_size = dev_indir_size;
15881612
ret = ethtool_copy_validate_indir(rxfh_dev.indir,
15891613
useraddr + rss_cfg_offset,
1590-
&rx_rings,
1614+
num_rx_rings,
15911615
rxfh.indir_size);
15921616
if (ret)
15931617
goto out_free;
@@ -1599,7 +1623,8 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
15991623
rxfh_dev.indir_size = dev_indir_size;
16001624
indir = rxfh_dev.indir;
16011625
for (i = 0; i < dev_indir_size; i++)
1602-
indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
1626+
indir[i] =
1627+
ethtool_rxfh_indir_default(i, num_rx_rings);
16031628
} else {
16041629
rxfh_dev.rss_delete = true;
16051630
}
@@ -3377,6 +3402,8 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
33773402
rc = ethtool_set_rxfh_fields(dev, ethcmd, useraddr);
33783403
break;
33793404
case ETHTOOL_GRXRINGS:
3405+
rc = ethtool_get_rxrings(dev, ethcmd, useraddr);
3406+
break;
33803407
case ETHTOOL_GRXCLSRLCNT:
33813408
case ETHTOOL_GRXCLSRULE:
33823409
case ETHTOOL_GRXCLSRLALL:

net/ethtool/rss.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -620,23 +620,22 @@ rss_set_prep_indir(struct net_device *dev, struct genl_info *info,
620620
struct rss_reply_data *data, struct ethtool_rxfh_param *rxfh,
621621
bool *reset, bool *mod)
622622
{
623-
const struct ethtool_ops *ops = dev->ethtool_ops;
624623
struct netlink_ext_ack *extack = info->extack;
625624
struct nlattr **tb = info->attrs;
626-
struct ethtool_rxnfc rx_rings;
627625
size_t alloc_size;
626+
int num_rx_rings;
628627
u32 user_size;
629628
int i, err;
630629

631630
if (!tb[ETHTOOL_A_RSS_INDIR])
632631
return 0;
633-
if (!data->indir_size || !ops->get_rxnfc)
632+
if (!data->indir_size)
634633
return -EOPNOTSUPP;
635634

636-
rx_rings.cmd = ETHTOOL_GRXRINGS;
637-
err = ops->get_rxnfc(dev, &rx_rings, NULL);
638-
if (err)
635+
err = ethtool_get_rx_ring_count(dev);
636+
if (err < 0)
639637
return err;
638+
num_rx_rings = err;
640639

641640
if (nla_len(tb[ETHTOOL_A_RSS_INDIR]) % 4) {
642641
NL_SET_BAD_ATTR(info->extack, tb[ETHTOOL_A_RSS_INDIR]);
@@ -665,7 +664,7 @@ rss_set_prep_indir(struct net_device *dev, struct genl_info *info,
665664

666665
nla_memcpy(rxfh->indir, tb[ETHTOOL_A_RSS_INDIR], alloc_size);
667666
for (i = 0; i < user_size; i++) {
668-
if (rxfh->indir[i] < rx_rings.data)
667+
if (rxfh->indir[i] < num_rx_rings)
669668
continue;
670669

671670
NL_SET_ERR_MSG_ATTR_FMT(extack, tb[ETHTOOL_A_RSS_INDIR],
@@ -682,7 +681,7 @@ rss_set_prep_indir(struct net_device *dev, struct genl_info *info,
682681
} else {
683682
for (i = 0; i < data->indir_size; i++)
684683
rxfh->indir[i] =
685-
ethtool_rxfh_indir_default(i, rx_rings.data);
684+
ethtool_rxfh_indir_default(i, num_rx_rings);
686685
}
687686

688687
*mod |= memcmp(rxfh->indir, data->indir_table, data->indir_size);

0 commit comments

Comments
 (0)