Skip to content

Commit d49010a

Browse files
kuba-mooPaolo Abeni
authored andcommitted
net: page_pool: expose page pool stats via netlink
Dump the stats into netlink. More clever approaches like dumping the stats per-CPU for each CPU individually to see where the packets get consumed can be implemented in the future. A trimmed example from a real (but recently booted system): $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \ --dump page-pool-stats-get [{'info': {'id': 19, 'ifindex': 2}, 'alloc-empty': 48, 'alloc-fast': 3024, 'alloc-refill': 0, 'alloc-slow': 48, 'alloc-slow-high-order': 0, 'alloc-waive': 0, 'recycle-cache-full': 0, 'recycle-cached': 0, 'recycle-released-refcnt': 0, 'recycle-ring': 0, 'recycle-ring-full': 0}, {'info': {'id': 18, 'ifindex': 2}, 'alloc-empty': 66, 'alloc-fast': 11811, 'alloc-refill': 35, 'alloc-slow': 66, 'alloc-slow-high-order': 0, 'alloc-waive': 0, 'recycle-cache-full': 1145, 'recycle-cached': 6541, 'recycle-released-refcnt': 0, 'recycle-ring': 1275, 'recycle-ring-full': 0}, {'info': {'id': 17, 'ifindex': 2}, 'alloc-empty': 73, 'alloc-fast': 62099, 'alloc-refill': 413, ... Acked-by: Jesper Dangaard Brouer <hawk@kernel.org> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 69cb495 commit d49010a

File tree

8 files changed

+250
-9
lines changed

8 files changed

+250
-9
lines changed

Documentation/netlink/specs/netdev.yaml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,59 @@ attribute-sets:
139139
"re-attached", they are just waiting to disappear.
140140
Attribute is absent if Page Pool has not been detached, and
141141
can still be used to allocate new memory.
142+
-
143+
name: page-pool-info
144+
subset-of: page-pool
145+
attributes:
146+
-
147+
name: id
148+
-
149+
name: ifindex
150+
-
151+
name: page-pool-stats
152+
doc: |
153+
Page pool statistics, see docs for struct page_pool_stats
154+
for information about individual statistics.
155+
attributes:
156+
-
157+
name: info
158+
doc: Page pool identifying information.
159+
type: nest
160+
nested-attributes: page-pool-info
161+
-
162+
name: alloc-fast
163+
type: uint
164+
value: 8 # reserve some attr ids in case we need more metadata later
165+
-
166+
name: alloc-slow
167+
type: uint
168+
-
169+
name: alloc-slow-high-order
170+
type: uint
171+
-
172+
name: alloc-empty
173+
type: uint
174+
-
175+
name: alloc-refill
176+
type: uint
177+
-
178+
name: alloc-waive
179+
type: uint
180+
-
181+
name: recycle-cached
182+
type: uint
183+
-
184+
name: recycle-cache-full
185+
type: uint
186+
-
187+
name: recycle-ring
188+
type: uint
189+
-
190+
name: recycle-ring-full
191+
type: uint
192+
-
193+
name: recycle-released-refcnt
194+
type: uint
142195

143196
operations:
144197
list:
@@ -212,6 +265,31 @@ operations:
212265
notify: page-pool-get
213266
mcgrp: page-pool
214267
config-cond: page-pool
268+
-
269+
name: page-pool-stats-get
270+
doc: Get page pool statistics.
271+
attribute-set: page-pool-stats
272+
do:
273+
request:
274+
attributes:
275+
- info
276+
reply: &pp-stats-reply
277+
attributes:
278+
- info
279+
- alloc-fast
280+
- alloc-slow
281+
- alloc-slow-high-order
282+
- alloc-empty
283+
- alloc-refill
284+
- alloc-waive
285+
- recycle-cached
286+
- recycle-cache-full
287+
- recycle-ring
288+
- recycle-ring-full
289+
- recycle-released-refcnt
290+
dump:
291+
reply: *pp-stats-reply
292+
config-cond: page-pool-stats
215293

216294
mcast-groups:
217295
list:

Documentation/networking/page_pool.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ Architecture overview
4141
| Fast cache | | ptr-ring cache |
4242
+-----------------+ +------------------+
4343
44+
Monitoring
45+
==========
46+
Information about page pools on the system can be accessed via the netdev
47+
genetlink family (see Documentation/netlink/specs/netdev.yaml).
48+
4449
API interface
4550
=============
4651
The number of pools created **must** match the number of hardware queues
@@ -107,8 +112,9 @@ page_pool_get_stats() and structures described below are available.
107112
It takes a pointer to a ``struct page_pool`` and a pointer to a struct
108113
page_pool_stats allocated by the caller.
109114

110-
The API will fill in the provided struct page_pool_stats with
111-
statistics about the page_pool.
115+
Older drivers expose page pool statistics via ethtool or debugfs.
116+
The same statistics are accessible via the netlink netdev family
117+
in a driver-independent fashion.
112118

113119
.. kernel-doc:: include/net/page_pool/types.h
114120
:identifiers: struct page_pool_recycle_stats

include/net/page_pool/helpers.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,12 @@
5555
#include <net/page_pool/types.h>
5656

5757
#ifdef CONFIG_PAGE_POOL_STATS
58+
/* Deprecated driver-facing API, use netlink instead */
5859
int page_pool_ethtool_stats_get_count(void);
5960
u8 *page_pool_ethtool_stats_get_strings(u8 *data);
6061
u64 *page_pool_ethtool_stats_get(u64 *data, void *stats);
6162

62-
/*
63-
* Drivers that wish to harvest page pool stats and report them to users
64-
* (perhaps via ethtool, debugfs, or another mechanism) can allocate a
65-
* struct page_pool_stats call page_pool_get_stats to get stats for the specified pool.
66-
*/
67-
bool page_pool_get_stats(struct page_pool *pool,
63+
bool page_pool_get_stats(const struct page_pool *pool,
6864
struct page_pool_stats *stats);
6965
#else
7066
static inline int page_pool_ethtool_stats_get_count(void)

include/uapi/linux/netdev.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ enum {
7676
NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
7777
};
7878

79+
enum {
80+
NETDEV_A_PAGE_POOL_STATS_INFO = 1,
81+
NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8,
82+
NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
83+
NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
84+
NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
85+
NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
86+
NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
87+
NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
88+
NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
89+
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
90+
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
91+
NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
92+
93+
__NETDEV_A_PAGE_POOL_STATS_MAX,
94+
NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1)
95+
};
96+
7997
enum {
8098
NETDEV_CMD_DEV_GET = 1,
8199
NETDEV_CMD_DEV_ADD_NTF,
@@ -85,6 +103,7 @@ enum {
85103
NETDEV_CMD_PAGE_POOL_ADD_NTF,
86104
NETDEV_CMD_PAGE_POOL_DEL_NTF,
87105
NETDEV_CMD_PAGE_POOL_CHANGE_NTF,
106+
NETDEV_CMD_PAGE_POOL_STATS_GET,
88107

89108
__NETDEV_CMD_MAX,
90109
NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)

net/core/netdev-genl-gen.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ static const struct netlink_range_validation netdev_a_page_pool_id_range = {
1616
.max = 4294967295ULL,
1717
};
1818

19+
static const struct netlink_range_validation netdev_a_page_pool_ifindex_range = {
20+
.min = 1ULL,
21+
.max = 2147483647ULL,
22+
};
23+
24+
/* Common nested types */
25+
const struct nla_policy netdev_page_pool_info_nl_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1] = {
26+
[NETDEV_A_PAGE_POOL_ID] = NLA_POLICY_FULL_RANGE(NLA_UINT, &netdev_a_page_pool_id_range),
27+
[NETDEV_A_PAGE_POOL_IFINDEX] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_page_pool_ifindex_range),
28+
};
29+
1930
/* NETDEV_CMD_DEV_GET - do */
2031
static const struct nla_policy netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1] = {
2132
[NETDEV_A_DEV_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1),
@@ -28,6 +39,13 @@ static const struct nla_policy netdev_page_pool_get_nl_policy[NETDEV_A_PAGE_POOL
2839
};
2940
#endif /* CONFIG_PAGE_POOL */
3041

42+
/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */
43+
#ifdef CONFIG_PAGE_POOL_STATS
44+
static const struct nla_policy netdev_page_pool_stats_get_nl_policy[NETDEV_A_PAGE_POOL_STATS_INFO + 1] = {
45+
[NETDEV_A_PAGE_POOL_STATS_INFO] = NLA_POLICY_NESTED(netdev_page_pool_info_nl_policy),
46+
};
47+
#endif /* CONFIG_PAGE_POOL_STATS */
48+
3149
/* Ops table for netdev */
3250
static const struct genl_split_ops netdev_nl_ops[] = {
3351
{
@@ -56,6 +74,20 @@ static const struct genl_split_ops netdev_nl_ops[] = {
5674
.flags = GENL_CMD_CAP_DUMP,
5775
},
5876
#endif /* CONFIG_PAGE_POOL */
77+
#ifdef CONFIG_PAGE_POOL_STATS
78+
{
79+
.cmd = NETDEV_CMD_PAGE_POOL_STATS_GET,
80+
.doit = netdev_nl_page_pool_stats_get_doit,
81+
.policy = netdev_page_pool_stats_get_nl_policy,
82+
.maxattr = NETDEV_A_PAGE_POOL_STATS_INFO,
83+
.flags = GENL_CMD_CAP_DO,
84+
},
85+
{
86+
.cmd = NETDEV_CMD_PAGE_POOL_STATS_GET,
87+
.dumpit = netdev_nl_page_pool_stats_get_dumpit,
88+
.flags = GENL_CMD_CAP_DUMP,
89+
},
90+
#endif /* CONFIG_PAGE_POOL_STATS */
5991
};
6092

6193
static const struct genl_multicast_group netdev_nl_mcgrps[] = {

net/core/netdev-genl-gen.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,18 @@
1111

1212
#include <uapi/linux/netdev.h>
1313

14+
/* Common nested types */
15+
extern const struct nla_policy netdev_page_pool_info_nl_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1];
16+
1417
int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info);
1518
int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
1619
int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info);
1720
int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb,
1821
struct netlink_callback *cb);
22+
int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb,
23+
struct genl_info *info);
24+
int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb,
25+
struct netlink_callback *cb);
1926

2027
enum {
2128
NETDEV_NLGRP_MGMT,

net/core/page_pool.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static const char pp_stats[][ETH_GSTRING_LEN] = {
7171
* is passed to this API which is filled in. The caller can then report
7272
* those stats to the user (perhaps via ethtool, debugfs, etc.).
7373
*/
74-
bool page_pool_get_stats(struct page_pool *pool,
74+
bool page_pool_get_stats(const struct page_pool *pool,
7575
struct page_pool_stats *stats)
7676
{
7777
int cpu = 0;

net/core/page_pool_user.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/xarray.h>
66
#include <net/net_debug.h>
77
#include <net/page_pool/types.h>
8+
#include <net/page_pool/helpers.h>
89
#include <net/sock.h>
910

1011
#include "page_pool_priv.h"
@@ -106,6 +107,108 @@ netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb,
106107
return err;
107108
}
108109

110+
static int
111+
page_pool_nl_stats_fill(struct sk_buff *rsp, const struct page_pool *pool,
112+
const struct genl_info *info)
113+
{
114+
#ifdef CONFIG_PAGE_POOL_STATS
115+
struct page_pool_stats stats = {};
116+
struct nlattr *nest;
117+
void *hdr;
118+
119+
if (!page_pool_get_stats(pool, &stats))
120+
return 0;
121+
122+
hdr = genlmsg_iput(rsp, info);
123+
if (!hdr)
124+
return -EMSGSIZE;
125+
126+
nest = nla_nest_start(rsp, NETDEV_A_PAGE_POOL_STATS_INFO);
127+
128+
if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_ID, pool->user.id) ||
129+
(pool->slow.netdev->ifindex != LOOPBACK_IFINDEX &&
130+
nla_put_u32(rsp, NETDEV_A_PAGE_POOL_IFINDEX,
131+
pool->slow.netdev->ifindex)))
132+
goto err_cancel_nest;
133+
134+
nla_nest_end(rsp, nest);
135+
136+
if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST,
137+
stats.alloc_stats.fast) ||
138+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
139+
stats.alloc_stats.slow) ||
140+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
141+
stats.alloc_stats.slow_high_order) ||
142+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
143+
stats.alloc_stats.empty) ||
144+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
145+
stats.alloc_stats.refill) ||
146+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
147+
stats.alloc_stats.waive) ||
148+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
149+
stats.recycle_stats.cached) ||
150+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
151+
stats.recycle_stats.cache_full) ||
152+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
153+
stats.recycle_stats.ring) ||
154+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
155+
stats.recycle_stats.ring_full) ||
156+
nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
157+
stats.recycle_stats.released_refcnt))
158+
goto err_cancel_msg;
159+
160+
genlmsg_end(rsp, hdr);
161+
162+
return 0;
163+
err_cancel_nest:
164+
nla_nest_cancel(rsp, nest);
165+
err_cancel_msg:
166+
genlmsg_cancel(rsp, hdr);
167+
return -EMSGSIZE;
168+
#else
169+
GENL_SET_ERR_MSG(info, "kernel built without CONFIG_PAGE_POOL_STATS");
170+
return -EOPNOTSUPP;
171+
#endif
172+
}
173+
174+
int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb,
175+
struct genl_info *info)
176+
{
177+
struct nlattr *tb[ARRAY_SIZE(netdev_page_pool_info_nl_policy)];
178+
struct nlattr *nest;
179+
int err;
180+
u32 id;
181+
182+
if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_PAGE_POOL_STATS_INFO))
183+
return -EINVAL;
184+
185+
nest = info->attrs[NETDEV_A_PAGE_POOL_STATS_INFO];
186+
err = nla_parse_nested(tb, ARRAY_SIZE(tb) - 1, nest,
187+
netdev_page_pool_info_nl_policy,
188+
info->extack);
189+
if (err)
190+
return err;
191+
192+
if (NL_REQ_ATTR_CHECK(info->extack, nest, tb, NETDEV_A_PAGE_POOL_ID))
193+
return -EINVAL;
194+
if (tb[NETDEV_A_PAGE_POOL_IFINDEX]) {
195+
NL_SET_ERR_MSG_ATTR(info->extack,
196+
tb[NETDEV_A_PAGE_POOL_IFINDEX],
197+
"selecting by ifindex not supported");
198+
return -EINVAL;
199+
}
200+
201+
id = nla_get_uint(tb[NETDEV_A_PAGE_POOL_ID]);
202+
203+
return netdev_nl_page_pool_get_do(info, id, page_pool_nl_stats_fill);
204+
}
205+
206+
int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb,
207+
struct netlink_callback *cb)
208+
{
209+
return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_stats_fill);
210+
}
211+
109212
static int
110213
page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
111214
const struct genl_info *info)

0 commit comments

Comments
 (0)