diff options
author | Jakub Kicinski <kuba@kernel.org> | 2024-04-23 10:09:52 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2024-04-23 10:09:52 -0700 |
commit | b2c8599f6443cac67dd10cec25e361c449bab1ef (patch) | |
tree | 29534a354ee4ae330feb4b9f2823252accf19945 /net/core/netdev-genl.c | |
parent | 1af2dface5d286dd1f2f3405a0d6fa9f2c8fb998 (diff) | |
parent | 23710925928310ec481fc0909a4d44ef89f4241a (diff) |
Merge branch 'netdev-support-dumping-a-single-netdev-in-qstats'
Jakub Kicinski says:
====================
netdev: support dumping a single netdev in qstats
I was writing a test for page pool which depended on qstats,
and got tired of having to filter dumps in user space.
Add support for dumping stats for a single netdev.
To get there we first need to add full support for extack
in dumps (and fix a dump error handling bug in YNL, sent
separately to the net tree).
====================
Link: https://lore.kernel.org/r/20240420023543.3300306-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/core/netdev-genl.c')
-rw-r--r-- | net/core/netdev-genl.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c index 7004b3399c2b..dd6510f2c652 100644 --- a/net/core/netdev-genl.c +++ b/net/core/netdev-genl.c @@ -639,6 +639,24 @@ nla_put_failure: return -EMSGSIZE; } +static int +netdev_nl_qstats_get_dump_one(struct net_device *netdev, unsigned int scope, + struct sk_buff *skb, const struct genl_info *info, + struct netdev_nl_dump_ctx *ctx) +{ + if (!netdev->stat_ops) + return 0; + + switch (scope) { + case 0: + return netdev_nl_stats_by_netdev(netdev, skb, info); + case NETDEV_QSTATS_SCOPE_QUEUE: + return netdev_nl_stats_by_queue(netdev, skb, info, ctx); + } + + return -EINVAL; /* Should not happen, per netlink policy */ +} + int netdev_nl_qstats_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { @@ -646,6 +664,7 @@ int netdev_nl_qstats_get_dumpit(struct sk_buff *skb, const struct genl_info *info = genl_info_dump(cb); struct net *net = sock_net(skb->sk); struct net_device *netdev; + unsigned int ifindex; unsigned int scope; int err = 0; @@ -653,21 +672,28 @@ int netdev_nl_qstats_get_dumpit(struct sk_buff *skb, if (info->attrs[NETDEV_A_QSTATS_SCOPE]) scope = nla_get_uint(info->attrs[NETDEV_A_QSTATS_SCOPE]); - rtnl_lock(); - for_each_netdev_dump(net, netdev, ctx->ifindex) { - if (!netdev->stat_ops) - continue; + ifindex = 0; + if (info->attrs[NETDEV_A_QSTATS_IFINDEX]) + ifindex = nla_get_u32(info->attrs[NETDEV_A_QSTATS_IFINDEX]); - switch (scope) { - case 0: - err = netdev_nl_stats_by_netdev(netdev, skb, info); - break; - case NETDEV_QSTATS_SCOPE_QUEUE: - err = netdev_nl_stats_by_queue(netdev, skb, info, ctx); - break; + rtnl_lock(); + if (ifindex) { + netdev = __dev_get_by_index(net, ifindex); + if (netdev && netdev->stat_ops) { + err = netdev_nl_qstats_get_dump_one(netdev, scope, skb, + info, ctx); + } else { + NL_SET_BAD_ATTR(info->extack, + info->attrs[NETDEV_A_QSTATS_IFINDEX]); + err = netdev ? -EOPNOTSUPP : -ENODEV; + } + } else { + for_each_netdev_dump(net, netdev, ctx->ifindex) { + err = netdev_nl_qstats_get_dump_one(netdev, scope, skb, + info, ctx); + if (err < 0) + break; } - if (err < 0) - break; } rtnl_unlock(); |