netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection
@ 2023-11-22  3:44 Jakub Kicinski
  2023-11-22  3:44 ` [PATCH net-next v3 01/13] net: page_pool: factor out uninit Jakub Kicinski
                   ` (13 more replies)
  0 siblings, 14 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

We recently started to deploy newer kernels / drivers at Meta,
making significant use of page pools for the first time.
We immediately run into page pool leaks both real and false positive
warnings. As Eric pointed out/predicted there's no guarantee that
applications will read / close their sockets so a page pool page
may be stuck in a socket (but not leaked) forever. This happens
a lot in our fleet. Most of these are obviously due to application
bugs but we should not be printing kernel warnings due to minor
application resource leaks.

Conversely the page pool memory may get leaked at runtime, and
we have no way to detect / track that, unless someone reconfigures
the NIC and destroys the page pools which leaked the pages.

The solution presented here is to expose the memory use of page
pools via netlink. This allows for continuous monitoring of memory
used by page pools, regardless if they were destroyed or not.
Sample in patch 15 can print the memory use and recycling
efficiency:

$ ./page-pool
    eth0[2]	page pools: 10 (zombies: 0)
		refs: 41984 bytes: 171966464 (refs: 0 bytes: 0)
		recycling: 90.3% (alloc: 656:397681 recycle: 89652:270201)

v3:
 - ID is still here, can't decide if it matters
 - rename destroyed -> detach-time, good enough?
 - fix build for netsec
v2: https://lore.kernel.org/r/20231121000048.789613-1-kuba@kernel.org
 - hopefully fix build with PAGE_POOL=n
v1: https://lore.kernel.org/all/20231024160220.3973311-1-kuba@kernel.org/
 - The main change compared to the RFC is that the API now exposes
   outstanding references and byte counts even for "live" page pools.
   The warning is no longer printed if page pool is accessible via netlink.
RFC: https://lore.kernel.org/all/20230816234303.3786178-1-kuba@kernel.org/

Jakub Kicinski (13):
  net: page_pool: factor out uninit
  net: page_pool: id the page pools
  net: page_pool: record pools per netdev
  net: page_pool: stash the NAPI ID for easier access
  eth: link netdev to page_pools in drivers
  net: page_pool: add nlspec for basic access to page pools
  net: page_pool: implement GET in the netlink API
  net: page_pool: add netlink notifications for state changes
  net: page_pool: report amount of memory held by page pools
  net: page_pool: report when page pool was destroyed
  net: page_pool: expose page pool stats via netlink
  net: page_pool: mute the periodic warning for visible page pools
  tools: ynl: add sample for getting page-pool information

 Documentation/netlink/specs/netdev.yaml       | 170 +++++++
 Documentation/networking/page_pool.rst        |  10 +-
 drivers/net/ethernet/broadcom/bnxt/bnxt.c     |   1 +
 .../net/ethernet/mellanox/mlx5/core/en_main.c |   1 +
 drivers/net/ethernet/microsoft/mana/mana_en.c |   1 +
 drivers/net/ethernet/socionext/netsec.c       |   2 +
 include/linux/list.h                          |  20 +
 include/linux/netdevice.h                     |   4 +
 include/linux/poison.h                        |   2 +
 include/net/page_pool/helpers.h               |   8 +-
 include/net/page_pool/types.h                 |  10 +
 include/uapi/linux/netdev.h                   |  36 ++
 net/core/Makefile                             |   2 +-
 net/core/netdev-genl-gen.c                    |  60 +++
 net/core/netdev-genl-gen.h                    |  11 +
 net/core/page_pool.c                          |  69 ++-
 net/core/page_pool_priv.h                     |  12 +
 net/core/page_pool_user.c                     | 414 +++++++++++++++++
 tools/include/uapi/linux/netdev.h             |  36 ++
 tools/net/ynl/generated/netdev-user.c         | 419 ++++++++++++++++++
 tools/net/ynl/generated/netdev-user.h         | 171 +++++++
 tools/net/ynl/lib/ynl.h                       |   2 +-
 tools/net/ynl/samples/.gitignore              |   1 +
 tools/net/ynl/samples/Makefile                |   2 +-
 tools/net/ynl/samples/page-pool.c             | 147 ++++++
 25 files changed, 1578 insertions(+), 33 deletions(-)
 create mode 100644 net/core/page_pool_priv.h
 create mode 100644 net/core/page_pool_user.c
 create mode 100644 tools/net/ynl/samples/page-pool.c

-- 
2.42.0


^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 01/13] net: page_pool: factor out uninit
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  8:38   ` Eric Dumazet
  2023-11-22 14:15   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 02/13] net: page_pool: id the page pools Jakub Kicinski
                   ` (12 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

We'll soon (next change in the series) need a fuller unwind path
in page_pool_create() so create the inverse of page_pool_init().

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/core/page_pool.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index df2a06d7da52..2e4575477e71 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -238,6 +238,18 @@ static int page_pool_init(struct page_pool *pool,
 	return 0;
 }
 
+static void page_pool_uninit(struct page_pool *pool)
+{
+	ptr_ring_cleanup(&pool->ring, NULL);
+
+	if (pool->p.flags & PP_FLAG_DMA_MAP)
+		put_device(pool->p.dev);
+
+#ifdef CONFIG_PAGE_POOL_STATS
+	free_percpu(pool->recycle_stats);
+#endif
+}
+
 /**
  * page_pool_create() - create a page pool.
  * @params: parameters, see struct page_pool_params
@@ -821,14 +833,7 @@ static void __page_pool_destroy(struct page_pool *pool)
 	if (pool->disconnect)
 		pool->disconnect(pool);
 
-	ptr_ring_cleanup(&pool->ring, NULL);
-
-	if (pool->p.flags & PP_FLAG_DMA_MAP)
-		put_device(pool->p.dev);
-
-#ifdef CONFIG_PAGE_POOL_STATS
-	free_percpu(pool->recycle_stats);
-#endif
+	page_pool_uninit(pool);
 	kfree(pool);
 }
 
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 02/13] net: page_pool: id the page pools
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
  2023-11-22  3:44 ` [PATCH net-next v3 01/13] net: page_pool: factor out uninit Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  8:40   ` Eric Dumazet
  2023-11-22 14:16   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 03/13] net: page_pool: record pools per netdev Jakub Kicinski
                   ` (11 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

To give ourselves the flexibility of creating netlink commands
and ability to refer to page pool instances in uAPIs create
IDs for page pools.

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/net/page_pool/types.h |  4 ++++
 net/core/Makefile             |  2 +-
 net/core/page_pool.c          | 21 +++++++++++++++-----
 net/core/page_pool_priv.h     |  9 +++++++++
 net/core/page_pool_user.c     | 36 +++++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+), 6 deletions(-)
 create mode 100644 net/core/page_pool_priv.h
 create mode 100644 net/core/page_pool_user.c

diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index e1bb92c192de..c19f0df3bf0b 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -187,6 +187,10 @@ struct page_pool {
 
 	/* Slow/Control-path information follows */
 	struct page_pool_params_slow slow;
+	/* User-facing fields, protected by page_pools_lock */
+	struct {
+		u32 id;
+	} user;
 };
 
 struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp);
diff --git a/net/core/Makefile b/net/core/Makefile
index 0cb734cbc24b..821aec06abf1 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -18,7 +18,7 @@ obj-y		     += dev.o dev_addr_lists.o dst.o netevent.o \
 obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
 
 obj-y += net-sysfs.o
-obj-$(CONFIG_PAGE_POOL) += page_pool.o
+obj-$(CONFIG_PAGE_POOL) += page_pool.o page_pool_user.o
 obj-$(CONFIG_PROC_FS) += net-procfs.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_NETPOLL) += netpoll.o
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index 2e4575477e71..a8d96ea38d18 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -23,6 +23,8 @@
 
 #include <trace/events/page_pool.h>
 
+#include "page_pool_priv.h"
+
 #define DEFER_TIME (msecs_to_jiffies(1000))
 #define DEFER_WARN_INTERVAL (60 * HZ)
 
@@ -264,13 +266,21 @@ struct page_pool *page_pool_create(const struct page_pool_params *params)
 		return ERR_PTR(-ENOMEM);
 
 	err = page_pool_init(pool, params);
-	if (err < 0) {
-		pr_warn("%s() gave up with errno %d\n", __func__, err);
-		kfree(pool);
-		return ERR_PTR(err);
-	}
+	if (err < 0)
+		goto err_free;
+
+	err = page_pool_list(pool);
+	if (err)
+		goto err_uninit;
 
 	return pool;
+
+err_uninit:
+	page_pool_uninit(pool);
+err_free:
+	pr_warn("%s() gave up with errno %d\n", __func__, err);
+	kfree(pool);
+	return ERR_PTR(err);
 }
 EXPORT_SYMBOL(page_pool_create);
 
@@ -833,6 +843,7 @@ static void __page_pool_destroy(struct page_pool *pool)
 	if (pool->disconnect)
 		pool->disconnect(pool);
 
+	page_pool_unlist(pool);
 	page_pool_uninit(pool);
 	kfree(pool);
 }
diff --git a/net/core/page_pool_priv.h b/net/core/page_pool_priv.h
new file mode 100644
index 000000000000..c17ea092b4ab
--- /dev/null
+++ b/net/core/page_pool_priv.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __PAGE_POOL_PRIV_H
+#define __PAGE_POOL_PRIV_H
+
+int page_pool_list(struct page_pool *pool);
+void page_pool_unlist(struct page_pool *pool);
+
+#endif
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
new file mode 100644
index 000000000000..630d1eeecf2a
--- /dev/null
+++ b/net/core/page_pool_user.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/mutex.h>
+#include <linux/xarray.h>
+#include <net/page_pool/types.h>
+
+#include "page_pool_priv.h"
+
+static DEFINE_XARRAY_FLAGS(page_pools, XA_FLAGS_ALLOC1);
+static DEFINE_MUTEX(page_pools_lock);
+
+int page_pool_list(struct page_pool *pool)
+{
+	static u32 id_alloc_next;
+	int err;
+
+	mutex_lock(&page_pools_lock);
+	err = xa_alloc_cyclic(&page_pools, &pool->user.id, pool, xa_limit_32b,
+			      &id_alloc_next, GFP_KERNEL);
+	if (err < 0)
+		goto err_unlock;
+
+	mutex_unlock(&page_pools_lock);
+	return 0;
+
+err_unlock:
+	mutex_unlock(&page_pools_lock);
+	return err;
+}
+
+void page_pool_unlist(struct page_pool *pool)
+{
+	mutex_lock(&page_pools_lock);
+	xa_erase(&page_pools, pool->user.id);
+	mutex_unlock(&page_pools_lock);
+}
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 03/13] net: page_pool: record pools per netdev
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
  2023-11-22  3:44 ` [PATCH net-next v3 01/13] net: page_pool: factor out uninit Jakub Kicinski
  2023-11-22  3:44 ` [PATCH net-next v3 02/13] net: page_pool: id the page pools Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  8:55   ` Eric Dumazet
  2023-11-22 14:20   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access Jakub Kicinski
                   ` (10 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Link the page pools with netdevs. This needs to be netns compatible
so we have two options. Either we record the pools per netns and
have to worry about moving them as the netdev gets moved.
Or we record them directly on the netdev so they move with the netdev
without any extra work.

Implement the latter option. Since pools may outlast netdev we need
a place to store orphans. In time honored tradition use loopback
for this purpose.

Reviewed-by: Mina Almasry <almasrymina@google.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
v1: fix race between page pool and netdev disappearing (Simon)
---
 include/linux/list.h          | 20 ++++++++
 include/linux/netdevice.h     |  4 ++
 include/linux/poison.h        |  2 +
 include/net/page_pool/types.h |  4 ++
 net/core/page_pool_user.c     | 90 +++++++++++++++++++++++++++++++++++
 5 files changed, 120 insertions(+)

diff --git a/include/linux/list.h b/include/linux/list.h
index 1837caedf723..059aa1fff41e 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -1119,6 +1119,26 @@ static inline void hlist_move_list(struct hlist_head *old,
 	old->first = NULL;
 }
 
+/**
+ * hlist_splice_init() - move all entries from one list to another
+ * @from: hlist_head from which entries will be moved
+ * @last: last entry on the @from list
+ * @to:   hlist_head to which entries will be moved
+ *
+ * @to can be empty, @from must contain at least @last.
+ */
+static inline void hlist_splice_init(struct hlist_head *from,
+				     struct hlist_node *last,
+				     struct hlist_head *to)
+{
+	if (to->first)
+		to->first->pprev = &last->next;
+	last->next = to->first;
+	to->first = from->first;
+	from->first->pprev = &to->first;
+	from->first = NULL;
+}
+
 #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
 
 #define hlist_for_each(pos, head) \
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2d840d7056f2..d6554f308ff1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2435,6 +2435,10 @@ struct net_device {
 #if IS_ENABLED(CONFIG_DPLL)
 	struct dpll_pin		*dpll_pin;
 #endif
+#if IS_ENABLED(CONFIG_PAGE_POOL)
+	/** @page_pools: page pools created for this netdevice */
+	struct hlist_head	page_pools;
+#endif
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 851a855d3868..27a7dad17eef 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -83,6 +83,8 @@
 
 /********** net/core/skbuff.c **********/
 #define SKB_LIST_POISON_NEXT	((void *)(0x800 + POISON_POINTER_DELTA))
+/********** net/ **********/
+#define NET_PTR_POISON		((void *)(0x801 + POISON_POINTER_DELTA))
 
 /********** kernel/bpf/ **********/
 #define BPF_PTR_POISON ((void *)(0xeB9FUL + POISON_POINTER_DELTA))
diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index c19f0df3bf0b..b258a571201e 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -5,6 +5,7 @@
 
 #include <linux/dma-direction.h>
 #include <linux/ptr_ring.h>
+#include <linux/types.h>
 
 #define PP_FLAG_DMA_MAP		BIT(0) /* Should page_pool do the DMA
 					* map/unmap
@@ -48,6 +49,7 @@ struct pp_alloc_cache {
  * @pool_size:	size of the ptr_ring
  * @nid:	NUMA node id to allocate from pages from
  * @dev:	device, for DMA pre-mapping purposes
+ * @netdev:	netdev this pool will serve (leave as NULL if none or multiple)
  * @napi:	NAPI which is the sole consumer of pages, otherwise NULL
  * @dma_dir:	DMA mapping direction
  * @max_len:	max DMA sync memory size for PP_FLAG_DMA_SYNC_DEV
@@ -66,6 +68,7 @@ struct page_pool_params {
 		unsigned int	offset;
 	);
 	struct_group_tagged(page_pool_params_slow, slow,
+		struct net_device *netdev;
 /* private: used by test code only */
 		void (*init_callback)(struct page *page, void *arg);
 		void *init_arg;
@@ -189,6 +192,7 @@ struct page_pool {
 	struct page_pool_params_slow slow;
 	/* User-facing fields, protected by page_pools_lock */
 	struct {
+		struct hlist_node list;
 		u32 id;
 	} user;
 };
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index 630d1eeecf2a..1591dbd66d51 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -1,14 +1,31 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include <linux/mutex.h>
+#include <linux/netdevice.h>
 #include <linux/xarray.h>
+#include <net/net_debug.h>
 #include <net/page_pool/types.h>
 
 #include "page_pool_priv.h"
 
 static DEFINE_XARRAY_FLAGS(page_pools, XA_FLAGS_ALLOC1);
+/* Protects: page_pools, netdevice->page_pools, pool->slow.netdev, pool->user.
+ * Ordering: inside rtnl_lock
+ */
 static DEFINE_MUTEX(page_pools_lock);
 
+/* Page pools are only reachable from user space (via netlink) if they are
+ * linked to a netdev at creation time. Following page pool "visibility"
+ * states are possible:
+ *  - normal
+ *    - user.list: linked to real netdev, netdev: real netdev
+ *  - orphaned - real netdev has disappeared
+ *    - user.list: linked to lo, netdev: lo
+ *  - invisible - either (a) created without netdev linking, (b) unlisted due
+ *      to error, or (c) the entire namespace which owned this pool disappeared
+ *    - user.list: unhashed, netdev: unknown
+ */
+
 int page_pool_list(struct page_pool *pool)
 {
 	static u32 id_alloc_next;
@@ -20,6 +37,10 @@ int page_pool_list(struct page_pool *pool)
 	if (err < 0)
 		goto err_unlock;
 
+	if (pool->slow.netdev)
+		hlist_add_head(&pool->user.list,
+			       &pool->slow.netdev->page_pools);
+
 	mutex_unlock(&page_pools_lock);
 	return 0;
 
@@ -32,5 +53,74 @@ void page_pool_unlist(struct page_pool *pool)
 {
 	mutex_lock(&page_pools_lock);
 	xa_erase(&page_pools, pool->user.id);
+	hlist_del(&pool->user.list);
 	mutex_unlock(&page_pools_lock);
 }
+
+static void page_pool_unreg_netdev_wipe(struct net_device *netdev)
+{
+	struct page_pool *pool;
+	struct hlist_node *n;
+
+	mutex_lock(&page_pools_lock);
+	hlist_for_each_entry_safe(pool, n, &netdev->page_pools, user.list) {
+		hlist_del_init(&pool->user.list);
+		pool->slow.netdev = NET_PTR_POISON;
+	}
+	mutex_unlock(&page_pools_lock);
+}
+
+static void page_pool_unreg_netdev(struct net_device *netdev)
+{
+	struct page_pool *pool, *last;
+	struct net_device *lo;
+
+	lo = __dev_get_by_index(dev_net(netdev), 1);
+	if (!lo) {
+		netdev_err_once(netdev,
+				"can't get lo to store orphan page pools\n");
+		page_pool_unreg_netdev_wipe(netdev);
+		return;
+	}
+
+	mutex_lock(&page_pools_lock);
+	last = NULL;
+	hlist_for_each_entry(pool, &netdev->page_pools, user.list) {
+		pool->slow.netdev = lo;
+		last = pool;
+	}
+	if (last)
+		hlist_splice_init(&netdev->page_pools, &last->user.list,
+				  &lo->page_pools);
+	mutex_unlock(&page_pools_lock);
+}
+
+static int
+page_pool_netdevice_event(struct notifier_block *nb,
+			  unsigned long event, void *ptr)
+{
+	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+
+	if (event != NETDEV_UNREGISTER)
+		return NOTIFY_DONE;
+
+	if (hlist_empty(&netdev->page_pools))
+		return NOTIFY_OK;
+
+	if (netdev->ifindex != LOOPBACK_IFINDEX)
+		page_pool_unreg_netdev(netdev);
+	else
+		page_pool_unreg_netdev_wipe(netdev);
+	return NOTIFY_OK;
+}
+
+static struct notifier_block page_pool_netdevice_nb = {
+	.notifier_call = page_pool_netdevice_event,
+};
+
+static int __init page_pool_user_init(void)
+{
+	return register_netdevice_notifier(&page_pool_netdevice_nb);
+}
+
+subsys_initcall(page_pool_user_init);
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (2 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 03/13] net: page_pool: record pools per netdev Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  8:57   ` Eric Dumazet
  2023-11-22 14:21   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers Jakub Kicinski
                   ` (9 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

To avoid any issues with race conditions on accessing napi
and having to think about the lifetime of NAPI objects
in netlink GET - stash the napi_id to which page pool
was linked at creation time.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/net/page_pool/types.h | 1 +
 net/core/page_pool_user.c     | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index b258a571201e..7e47d7bb2c1e 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -193,6 +193,7 @@ struct page_pool {
 	/* User-facing fields, protected by page_pools_lock */
 	struct {
 		struct hlist_node list;
+		u32 napi_id;
 		u32 id;
 	} user;
 };
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index 1591dbd66d51..23074d4c75fc 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -37,9 +37,11 @@ int page_pool_list(struct page_pool *pool)
 	if (err < 0)
 		goto err_unlock;
 
-	if (pool->slow.netdev)
+	if (pool->slow.netdev) {
 		hlist_add_head(&pool->user.list,
 			       &pool->slow.netdev->page_pools);
+		pool->user.napi_id = pool->p.napi ? pool->p.napi->napi_id : 0;
+	}
 
 	mutex_unlock(&page_pools_lock);
 	return 0;
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (3 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  8:59   ` Eric Dumazet
  2023-11-22 14:22   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools Jakub Kicinski
                   ` (8 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Link page pool instances to netdev for the drivers which
already link to NAPI. Unless the driver is doing something
very weird per-NAPI should imply per-netdev.

Add netsec as well, Ilias indicates that it fits the mold.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
v3: fix netsec build
v2: add netsec
---
 drivers/net/ethernet/broadcom/bnxt/bnxt.c         | 1 +
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 +
 drivers/net/ethernet/microsoft/mana/mana_en.c     | 1 +
 drivers/net/ethernet/socionext/netsec.c           | 2 ++
 4 files changed, 5 insertions(+)

diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index d8cf7b30bd03..e35e7e02538c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -3331,6 +3331,7 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
 		pp.pool_size += bp->rx_ring_size;
 	pp.nid = dev_to_node(&bp->pdev->dev);
 	pp.napi = &rxr->bnapi->napi;
+	pp.netdev = bp->dev;
 	pp.dev = &bp->pdev->dev;
 	pp.dma_dir = bp->rx_dir;
 	pp.max_len = PAGE_SIZE;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 3aecdf099a2f..af5e0d3c8ee1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -902,6 +902,7 @@ static int mlx5e_alloc_rq(struct mlx5e_params *params,
 		pp_params.nid       = node;
 		pp_params.dev       = rq->pdev;
 		pp_params.napi      = rq->cq.napi;
+		pp_params.netdev    = rq->netdev;
 		pp_params.dma_dir   = rq->buff.map_dir;
 		pp_params.max_len   = PAGE_SIZE;
 
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index fc3d2903a80f..d1adec01299c 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2137,6 +2137,7 @@ static int mana_create_page_pool(struct mana_rxq *rxq, struct gdma_context *gc)
 	pprm.pool_size = RX_BUFFERS_PER_QUEUE;
 	pprm.nid = gc->numa_node;
 	pprm.napi = &rxq->rx_cq.napi;
+	pprm.netdev = rxq->ndev;
 
 	rxq->page_pool = page_pool_create(&pprm);
 
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index 0891e9e49ecb..5ab8b81b84e6 100644
--- a/drivers/net/ethernet/socionext/netsec.c
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -1302,6 +1302,8 @@ static int netsec_setup_rx_dring(struct netsec_priv *priv)
 		.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE,
 		.offset = NETSEC_RXBUF_HEADROOM,
 		.max_len = NETSEC_RX_BUF_SIZE,
+		.napi = &priv->napi,
+		.netdev = priv->ndev,
 	};
 	int i, err;
 
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (4 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  9:00   ` Eric Dumazet
  2023-11-22 14:24   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API Jakub Kicinski
                   ` (7 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Add a Netlink spec in YAML for getting very basic information
about page pools.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Documentation/netlink/specs/netdev.yaml | 46 +++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index 14511b13f305..84ca3c2ab872 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -86,6 +86,34 @@ name: netdev
              See Documentation/networking/xdp-rx-metadata.rst for more details.
         type: u64
         enum: xdp-rx-metadata
+  -
+    name: page-pool
+    attributes:
+      -
+        name: id
+        doc: Unique ID of a Page Pool instance.
+        type: uint
+        checks:
+          min: 1
+          max: u32-max
+      -
+        name: ifindex
+        doc: |
+          ifindex of the netdev to which the pool belongs.
+          May be reported as 0 if the page pool was allocated for a netdev
+          which got destroyed already (page pools may outlast their netdevs
+          because they wait for all memory to be returned).
+        type: u32
+        checks:
+          min: 1
+          max: s32-max
+      -
+        name: napi-id
+        doc: Id of NAPI using this Page Pool instance.
+        type: uint
+        checks:
+          min: 1
+          max: u32-max
 
 operations:
   list:
@@ -120,6 +148,24 @@ name: netdev
       doc: Notification about device configuration being changed.
       notify: dev-get
       mcgrp: mgmt
+    -
+      name: page-pool-get
+      doc: |
+        Get / dump information about Page Pools.
+        (Only Page Pools associated with a net_device can be listed.)
+      attribute-set: page-pool
+      do:
+        request:
+          attributes:
+            - id
+        reply: &pp-reply
+          attributes:
+            - id
+            - ifindex
+            - napi-id
+      dump:
+        reply: *pp-reply
+      config-cond: page-pool
 
 mcast-groups:
   list:
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (5 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  9:35   ` Eric Dumazet
  2023-11-22 14:39   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes Jakub Kicinski
                   ` (6 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Expose the very basic page pool information via netlink.

Example using ynl-py for a system with 9 queues:

$ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \
           --dump page-pool-get
[{'id': 19, 'ifindex': 2, 'napi-id': 147},
 {'id': 18, 'ifindex': 2, 'napi-id': 146},
 {'id': 17, 'ifindex': 2, 'napi-id': 145},
 {'id': 16, 'ifindex': 2, 'napi-id': 144},
 {'id': 15, 'ifindex': 2, 'napi-id': 143},
 {'id': 14, 'ifindex': 2, 'napi-id': 142},
 {'id': 13, 'ifindex': 2, 'napi-id': 141},
 {'id': 12, 'ifindex': 2, 'napi-id': 140},
 {'id': 11, 'ifindex': 2, 'napi-id': 139},
 {'id': 10, 'ifindex': 2, 'napi-id': 138}]

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/uapi/linux/netdev.h |  10 +++
 net/core/netdev-genl-gen.c  |  27 ++++++++
 net/core/netdev-genl-gen.h  |   3 +
 net/core/page_pool_user.c   | 127 ++++++++++++++++++++++++++++++++++++
 4 files changed, 167 insertions(+)

diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index 2943a151d4f1..176665bcf0da 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -64,11 +64,21 @@ enum {
 	NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1)
 };
 
+enum {
+	NETDEV_A_PAGE_POOL_ID = 1,
+	NETDEV_A_PAGE_POOL_IFINDEX,
+	NETDEV_A_PAGE_POOL_NAPI_ID,
+
+	__NETDEV_A_PAGE_POOL_MAX,
+	NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
+};
+
 enum {
 	NETDEV_CMD_DEV_GET = 1,
 	NETDEV_CMD_DEV_ADD_NTF,
 	NETDEV_CMD_DEV_DEL_NTF,
 	NETDEV_CMD_DEV_CHANGE_NTF,
+	NETDEV_CMD_PAGE_POOL_GET,
 
 	__NETDEV_CMD_MAX,
 	NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c
index ea9231378aa6..9d34b451cfa7 100644
--- a/net/core/netdev-genl-gen.c
+++ b/net/core/netdev-genl-gen.c
@@ -10,11 +10,24 @@
 
 #include <uapi/linux/netdev.h>
 
+/* Integer value ranges */
+static const struct netlink_range_validation netdev_a_page_pool_id_range = {
+	.min	= 1,
+	.max	= 4294967295,
+};
+
 /* NETDEV_CMD_DEV_GET - do */
 static const struct nla_policy netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1] = {
 	[NETDEV_A_DEV_IFINDEX] = NLA_POLICY_MIN(NLA_U32, 1),
 };
 
+/* NETDEV_CMD_PAGE_POOL_GET - do */
+#ifdef CONFIG_PAGE_POOL
+static const struct nla_policy netdev_page_pool_get_nl_policy[NETDEV_A_PAGE_POOL_ID + 1] = {
+	[NETDEV_A_PAGE_POOL_ID] = NLA_POLICY_FULL_RANGE(NLA_UINT, &netdev_a_page_pool_id_range),
+};
+#endif /* CONFIG_PAGE_POOL */
+
 /* Ops table for netdev */
 static const struct genl_split_ops netdev_nl_ops[] = {
 	{
@@ -29,6 +42,20 @@ static const struct genl_split_ops netdev_nl_ops[] = {
 		.dumpit	= netdev_nl_dev_get_dumpit,
 		.flags	= GENL_CMD_CAP_DUMP,
 	},
+#ifdef CONFIG_PAGE_POOL
+	{
+		.cmd		= NETDEV_CMD_PAGE_POOL_GET,
+		.doit		= netdev_nl_page_pool_get_doit,
+		.policy		= netdev_page_pool_get_nl_policy,
+		.maxattr	= NETDEV_A_PAGE_POOL_ID,
+		.flags		= GENL_CMD_CAP_DO,
+	},
+	{
+		.cmd	= NETDEV_CMD_PAGE_POOL_GET,
+		.dumpit	= netdev_nl_page_pool_get_dumpit,
+		.flags	= GENL_CMD_CAP_DUMP,
+	},
+#endif /* CONFIG_PAGE_POOL */
 };
 
 static const struct genl_multicast_group netdev_nl_mcgrps[] = {
diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h
index 7b370c073e7d..a011d12abff4 100644
--- a/net/core/netdev-genl-gen.h
+++ b/net/core/netdev-genl-gen.h
@@ -13,6 +13,9 @@
 
 int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info);
 int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
+int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info);
+int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb,
+				   struct netlink_callback *cb);
 
 enum {
 	NETDEV_NLGRP_MGMT,
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index 23074d4c75fc..24f4e54f6266 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -5,8 +5,10 @@
 #include <linux/xarray.h>
 #include <net/net_debug.h>
 #include <net/page_pool/types.h>
+#include <net/sock.h>
 
 #include "page_pool_priv.h"
+#include "netdev-genl-gen.h"
 
 static DEFINE_XARRAY_FLAGS(page_pools, XA_FLAGS_ALLOC1);
 /* Protects: page_pools, netdevice->page_pools, pool->slow.netdev, pool->user.
@@ -26,6 +28,131 @@ static DEFINE_MUTEX(page_pools_lock);
  *    - user.list: unhashed, netdev: unknown
  */
 
+typedef int (*pp_nl_fill_cb)(struct sk_buff *rsp, const struct page_pool *pool,
+			     const struct genl_info *info);
+
+static int
+netdev_nl_page_pool_get_do(struct genl_info *info, u32 id, pp_nl_fill_cb fill)
+{
+	struct page_pool *pool;
+	struct sk_buff *rsp;
+	int err;
+
+	mutex_lock(&page_pools_lock);
+	pool = xa_load(&page_pools, id);
+	if (!pool || hlist_unhashed(&pool->user.list) ||
+	    !net_eq(dev_net(pool->slow.netdev), genl_info_net(info))) {
+		err = -ENOENT;
+		goto err_unlock;
+	}
+
+	rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!rsp) {
+		err = -ENOMEM;
+		goto err_unlock;
+	}
+
+	err = fill(rsp, pool, info);
+	if (err)
+		goto err_free_msg;
+
+	mutex_unlock(&page_pools_lock);
+
+	return genlmsg_reply(rsp, info);
+
+err_free_msg:
+	nlmsg_free(rsp);
+err_unlock:
+	mutex_unlock(&page_pools_lock);
+	return err;
+}
+
+struct page_pool_dump_cb {
+	unsigned long ifindex;
+	u32 pp_id;
+};
+
+static int
+netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb,
+			     pp_nl_fill_cb fill)
+{
+	struct page_pool_dump_cb *state = (void *)cb->ctx;
+	const struct genl_info *info = genl_info_dump(cb);
+	struct net *net = sock_net(skb->sk);
+	struct net_device *netdev;
+	struct page_pool *pool;
+	int err = 0;
+
+	rtnl_lock();
+	mutex_lock(&page_pools_lock);
+	for_each_netdev_dump(net, netdev, state->ifindex) {
+		hlist_for_each_entry(pool, &netdev->page_pools, user.list) {
+			if (state->pp_id && state->pp_id < pool->user.id)
+				continue;
+
+			state->pp_id = pool->user.id;
+			err = fill(skb, pool, info);
+			if (err)
+				break;
+		}
+
+		state->pp_id = 0;
+	}
+	mutex_unlock(&page_pools_lock);
+	rtnl_unlock();
+
+	if (skb->len && err == -EMSGSIZE)
+		return skb->len;
+	return err;
+}
+
+static int
+page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
+		  const struct genl_info *info)
+{
+	void *hdr;
+
+	hdr = genlmsg_iput(rsp, info);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_ID, pool->user.id))
+		goto err_cancel;
+
+	if (pool->slow.netdev->ifindex != LOOPBACK_IFINDEX &&
+	    nla_put_u32(rsp, NETDEV_A_PAGE_POOL_IFINDEX,
+			pool->slow.netdev->ifindex))
+		goto err_cancel;
+	if (pool->user.napi_id &&
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_NAPI_ID, pool->user.napi_id))
+		goto err_cancel;
+
+	genlmsg_end(rsp, hdr);
+
+	return 0;
+err_cancel:
+	genlmsg_cancel(rsp, hdr);
+	return -EMSGSIZE;
+}
+
+int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info)
+{
+	u32 id;
+
+	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_PAGE_POOL_ID))
+		return -EINVAL;
+
+	id = nla_get_uint(info->attrs[NETDEV_A_PAGE_POOL_ID]);
+
+	return netdev_nl_page_pool_get_do(info, id, page_pool_nl_fill);
+}
+
+int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb,
+				   struct netlink_callback *cb)
+{
+	return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_fill);
+}
+
 int page_pool_list(struct page_pool *pool)
 {
 	static u32 id_alloc_next;
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (6 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  9:44   ` Eric Dumazet
  2023-11-22 14:41   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools Jakub Kicinski
                   ` (5 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Generate netlink notifications about page pool state changes.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Documentation/netlink/specs/netdev.yaml | 20 ++++++++++++++
 include/uapi/linux/netdev.h             |  4 +++
 net/core/netdev-genl-gen.c              |  1 +
 net/core/netdev-genl-gen.h              |  1 +
 net/core/page_pool_user.c               | 36 +++++++++++++++++++++++++
 5 files changed, 62 insertions(+)

diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index 84ca3c2ab872..82fbe81f7a49 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -166,8 +166,28 @@ name: netdev
       dump:
         reply: *pp-reply
       config-cond: page-pool
+    -
+      name: page-pool-add-ntf
+      doc: Notification about page pool appearing.
+      notify: page-pool-get
+      mcgrp: page-pool
+      config-cond: page-pool
+    -
+      name: page-pool-del-ntf
+      doc: Notification about page pool disappearing.
+      notify: page-pool-get
+      mcgrp: page-pool
+      config-cond: page-pool
+    -
+      name: page-pool-change-ntf
+      doc: Notification about page pool configuration being changed.
+      notify: page-pool-get
+      mcgrp: page-pool
+      config-cond: page-pool
 
 mcast-groups:
   list:
     -
       name: mgmt
+    -
+      name: page-pool
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index 176665bcf0da..beb158872226 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -79,11 +79,15 @@ enum {
 	NETDEV_CMD_DEV_DEL_NTF,
 	NETDEV_CMD_DEV_CHANGE_NTF,
 	NETDEV_CMD_PAGE_POOL_GET,
+	NETDEV_CMD_PAGE_POOL_ADD_NTF,
+	NETDEV_CMD_PAGE_POOL_DEL_NTF,
+	NETDEV_CMD_PAGE_POOL_CHANGE_NTF,
 
 	__NETDEV_CMD_MAX,
 	NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
 };
 
 #define NETDEV_MCGRP_MGMT	"mgmt"
+#define NETDEV_MCGRP_PAGE_POOL	"page-pool"
 
 #endif /* _UAPI_LINUX_NETDEV_H */
diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c
index 9d34b451cfa7..278b43f5ed50 100644
--- a/net/core/netdev-genl-gen.c
+++ b/net/core/netdev-genl-gen.c
@@ -60,6 +60,7 @@ static const struct genl_split_ops netdev_nl_ops[] = {
 
 static const struct genl_multicast_group netdev_nl_mcgrps[] = {
 	[NETDEV_NLGRP_MGMT] = { "mgmt", },
+	[NETDEV_NLGRP_PAGE_POOL] = { "page-pool", },
 };
 
 struct genl_family netdev_nl_family __ro_after_init = {
diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h
index a011d12abff4..738097847100 100644
--- a/net/core/netdev-genl-gen.h
+++ b/net/core/netdev-genl-gen.h
@@ -19,6 +19,7 @@ int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb,
 
 enum {
 	NETDEV_NLGRP_MGMT,
+	NETDEV_NLGRP_PAGE_POOL,
 };
 
 extern struct genl_family netdev_nl_family;
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index 24f4e54f6266..35c56fb41c46 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -135,6 +135,37 @@ page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
 	return -EMSGSIZE;
 }
 
+static void netdev_nl_page_pool_event(const struct page_pool *pool, u32 cmd)
+{
+	struct genl_info info;
+	struct sk_buff *ntf;
+	struct net *net;
+
+	lockdep_assert_held(&page_pools_lock);
+
+	/* 'invisible' page pools don't matter */
+	if (hlist_unhashed(&pool->user.list))
+		return;
+	net = dev_net(pool->slow.netdev);
+
+	if (!genl_has_listeners(&netdev_nl_family, net, NETDEV_NLGRP_PAGE_POOL))
+		return;
+
+	genl_info_init_ntf(&info, &netdev_nl_family, cmd);
+
+	ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!ntf)
+		return;
+
+	if (page_pool_nl_fill(ntf, pool, &info)) {
+		nlmsg_free(ntf);
+		return;
+	}
+
+	genlmsg_multicast_netns(&netdev_nl_family, net, ntf,
+				0, NETDEV_NLGRP_PAGE_POOL, GFP_KERNEL);
+}
+
 int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info)
 {
 	u32 id;
@@ -168,6 +199,8 @@ int page_pool_list(struct page_pool *pool)
 		hlist_add_head(&pool->user.list,
 			       &pool->slow.netdev->page_pools);
 		pool->user.napi_id = pool->p.napi ? pool->p.napi->napi_id : 0;
+
+		netdev_nl_page_pool_event(pool, NETDEV_CMD_PAGE_POOL_ADD_NTF);
 	}
 
 	mutex_unlock(&page_pools_lock);
@@ -181,6 +214,7 @@ int page_pool_list(struct page_pool *pool)
 void page_pool_unlist(struct page_pool *pool)
 {
 	mutex_lock(&page_pools_lock);
+	netdev_nl_page_pool_event(pool, NETDEV_CMD_PAGE_POOL_DEL_NTF);
 	xa_erase(&page_pools, pool->user.id);
 	hlist_del(&pool->user.list);
 	mutex_unlock(&page_pools_lock);
@@ -216,6 +250,8 @@ static void page_pool_unreg_netdev(struct net_device *netdev)
 	last = NULL;
 	hlist_for_each_entry(pool, &netdev->page_pools, user.list) {
 		pool->slow.netdev = lo;
+		netdev_nl_page_pool_event(pool,
+					  NETDEV_CMD_PAGE_POOL_CHANGE_NTF);
 		last = pool;
 	}
 	if (last)
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (7 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22 10:16   ` Eric Dumazet
  2023-11-22 15:24   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed Jakub Kicinski
                   ` (4 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Advanced deployments need the ability to check memory use
of various system components. It makes it possible to make informed
decisions about memory allocation and to find regressions and leaks.

Report memory use of page pools. Report both number of references
and bytes held.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Documentation/netlink/specs/netdev.yaml | 13 +++++++++++++
 include/uapi/linux/netdev.h             |  2 ++
 net/core/page_pool.c                    | 13 +++++++++----
 net/core/page_pool_priv.h               |  2 ++
 net/core/page_pool_user.c               |  8 ++++++++
 5 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index 82fbe81f7a49..85209e19dca9 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -114,6 +114,17 @@ name: netdev
         checks:
           min: 1
           max: u32-max
+      -
+        name: inflight
+        type: uint
+        doc: |
+          Number of outstanding references to this page pool (allocated
+          but yet to be freed pages).
+      -
+        name: inflight-mem
+        type: uint
+        doc: |
+          Amount of memory held by inflight pages.
 
 operations:
   list:
@@ -163,6 +174,8 @@ name: netdev
             - id
             - ifindex
             - napi-id
+            - inflight
+            - inflight-mem
       dump:
         reply: *pp-reply
       config-cond: page-pool
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index beb158872226..26ae5bdd3187 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -68,6 +68,8 @@ enum {
 	NETDEV_A_PAGE_POOL_ID = 1,
 	NETDEV_A_PAGE_POOL_IFINDEX,
 	NETDEV_A_PAGE_POOL_NAPI_ID,
+	NETDEV_A_PAGE_POOL_INFLIGHT,
+	NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
 
 	__NETDEV_A_PAGE_POOL_MAX,
 	NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index a8d96ea38d18..566390759294 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -529,7 +529,7 @@ EXPORT_SYMBOL(page_pool_alloc_pages);
  */
 #define _distance(a, b)	(s32)((a) - (b))
 
-static s32 page_pool_inflight(struct page_pool *pool)
+s32 page_pool_inflight(const struct page_pool *pool, bool strict)
 {
 	u32 release_cnt = atomic_read(&pool->pages_state_release_cnt);
 	u32 hold_cnt = READ_ONCE(pool->pages_state_hold_cnt);
@@ -537,8 +537,13 @@ static s32 page_pool_inflight(struct page_pool *pool)
 
 	inflight = _distance(hold_cnt, release_cnt);
 
-	trace_page_pool_release(pool, inflight, hold_cnt, release_cnt);
-	WARN(inflight < 0, "Negative(%d) inflight packet-pages", inflight);
+	if (strict) {
+		trace_page_pool_release(pool, inflight, hold_cnt, release_cnt);
+		WARN(inflight < 0, "Negative(%d) inflight packet-pages",
+		     inflight);
+	} else {
+		inflight = max(0, inflight);
+	}
 
 	return inflight;
 }
@@ -881,7 +886,7 @@ static int page_pool_release(struct page_pool *pool)
 	int inflight;
 
 	page_pool_scrub(pool);
-	inflight = page_pool_inflight(pool);
+	inflight = page_pool_inflight(pool, true);
 	if (!inflight)
 		__page_pool_destroy(pool);
 
diff --git a/net/core/page_pool_priv.h b/net/core/page_pool_priv.h
index c17ea092b4ab..72fb21ea1ddc 100644
--- a/net/core/page_pool_priv.h
+++ b/net/core/page_pool_priv.h
@@ -3,6 +3,8 @@
 #ifndef __PAGE_POOL_PRIV_H
 #define __PAGE_POOL_PRIV_H
 
+s32 page_pool_inflight(const struct page_pool *pool, bool strict);
+
 int page_pool_list(struct page_pool *pool);
 void page_pool_unlist(struct page_pool *pool);
 
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index 35c56fb41c46..d889b347f8f4 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -110,6 +110,7 @@ static int
 page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
 		  const struct genl_info *info)
 {
+	size_t inflight, refsz;
 	void *hdr;
 
 	hdr = genlmsg_iput(rsp, info);
@@ -127,6 +128,13 @@ page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
 	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_NAPI_ID, pool->user.napi_id))
 		goto err_cancel;
 
+	inflight = page_pool_inflight(pool, false);
+	refsz =	PAGE_SIZE << pool->p.order;
+	if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_INFLIGHT, inflight) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
+			 inflight * refsz))
+		goto err_cancel;
+
 	genlmsg_end(rsp, hdr);
 
 	return 0;
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (8 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22  9:02   ` Jesper Dangaard Brouer
  2023-11-22 10:21   ` Eric Dumazet
  2023-11-22  3:44 ` [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink Jakub Kicinski
                   ` (3 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Report when page pool was destroyed. Together with the inflight
/ memory use reporting this can serve as a replacement for the
warning about leaked page pools we currently print to dmesg.

Example output for a fake leaked page pool using some hacks
in netdevsim (one "live" pool, and one "leaked" on the same dev):

$ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \
           --dump page-pool-get
[{'id': 2, 'ifindex': 3},
 {'id': 1, 'ifindex': 3, 'destroyed': 133, 'inflight': 1}]

Tested-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Documentation/netlink/specs/netdev.yaml | 13 +++++++++++++
 include/net/page_pool/types.h           |  1 +
 include/uapi/linux/netdev.h             |  1 +
 net/core/page_pool.c                    |  1 +
 net/core/page_pool_priv.h               |  1 +
 net/core/page_pool_user.c               | 12 ++++++++++++
 6 files changed, 29 insertions(+)

diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index 85209e19dca9..695e0e4e0d8b 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -125,6 +125,18 @@ name: netdev
         type: uint
         doc: |
           Amount of memory held by inflight pages.
+      -
+        name: detach-time
+        type: uint
+        doc: |
+          Seconds in CLOCK_BOOTTIME of when Page Pool was detached by
+          the driver. Once detached Page Pool can no longer be used to
+          allocate memory.
+          Page Pools wait for all the memory allocated from them to be freed
+          before truly disappearing. "Detached" Page Pools cannot be
+          "re-attached", they are just waiting to disappear.
+          Attribute is absent if Page Pool has not been detached, and
+          can still be used to allocate new memory.
 
 operations:
   list:
@@ -176,6 +188,7 @@ name: netdev
             - napi-id
             - inflight
             - inflight-mem
+            - detach-time
       dump:
         reply: *pp-reply
       config-cond: page-pool
diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
index 7e47d7bb2c1e..ac286ea8ce2d 100644
--- a/include/net/page_pool/types.h
+++ b/include/net/page_pool/types.h
@@ -193,6 +193,7 @@ struct page_pool {
 	/* User-facing fields, protected by page_pools_lock */
 	struct {
 		struct hlist_node list;
+		u64 detach_time;
 		u32 napi_id;
 		u32 id;
 	} user;
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index 26ae5bdd3187..756410274120 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -70,6 +70,7 @@ enum {
 	NETDEV_A_PAGE_POOL_NAPI_ID,
 	NETDEV_A_PAGE_POOL_INFLIGHT,
 	NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
+	NETDEV_A_PAGE_POOL_DETACH_TIME,
 
 	__NETDEV_A_PAGE_POOL_MAX,
 	NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index 566390759294..a821fb5fe054 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -953,6 +953,7 @@ void page_pool_destroy(struct page_pool *pool)
 	if (!page_pool_release(pool))
 		return;
 
+	page_pool_detached(pool);
 	pool->defer_start = jiffies;
 	pool->defer_warn  = jiffies + DEFER_WARN_INTERVAL;
 
diff --git a/net/core/page_pool_priv.h b/net/core/page_pool_priv.h
index 72fb21ea1ddc..90665d40f1eb 100644
--- a/net/core/page_pool_priv.h
+++ b/net/core/page_pool_priv.h
@@ -6,6 +6,7 @@
 s32 page_pool_inflight(const struct page_pool *pool, bool strict);
 
 int page_pool_list(struct page_pool *pool);
+void page_pool_detached(struct page_pool *pool);
 void page_pool_unlist(struct page_pool *pool);
 
 #endif
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index d889b347f8f4..f28ad2179f53 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -134,6 +134,10 @@ page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
 	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
 			 inflight * refsz))
 		goto err_cancel;
+	if (pool->user.detach_time &&
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_DETACH_TIME,
+			 pool->user.detach_time))
+		goto err_cancel;
 
 	genlmsg_end(rsp, hdr);
 
@@ -219,6 +223,14 @@ int page_pool_list(struct page_pool *pool)
 	return err;
 }
 
+void page_pool_detached(struct page_pool *pool)
+{
+	mutex_lock(&page_pools_lock);
+	pool->user.detach_time = ktime_get_boottime_seconds();
+	netdev_nl_page_pool_event(pool, NETDEV_CMD_PAGE_POOL_CHANGE_NTF);
+	mutex_unlock(&page_pools_lock);
+}
+
 void page_pool_unlist(struct page_pool *pool)
 {
 	mutex_lock(&page_pools_lock);
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (9 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22 10:27   ` Eric Dumazet
  2023-11-22 15:51   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools Jakub Kicinski
                   ` (2 subsequent siblings)
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

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,
...

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 Documentation/netlink/specs/netdev.yaml |  78 ++++++++++++++++++
 Documentation/networking/page_pool.rst  |  10 ++-
 include/net/page_pool/helpers.h         |   8 +-
 include/uapi/linux/netdev.h             |  19 +++++
 net/core/netdev-genl-gen.c              |  32 ++++++++
 net/core/netdev-genl-gen.h              |   7 ++
 net/core/page_pool.c                    |   2 +-
 net/core/page_pool_user.c               | 103 ++++++++++++++++++++++++
 8 files changed, 250 insertions(+), 9 deletions(-)

diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index 695e0e4e0d8b..77d991738a17 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -137,6 +137,59 @@ name: netdev
           "re-attached", they are just waiting to disappear.
           Attribute is absent if Page Pool has not been detached, and
           can still be used to allocate new memory.
+  -
+    name: page-pool-info
+    subset-of: page-pool
+    attributes:
+      -
+        name: id
+      -
+        name: ifindex
+  -
+    name: page-pool-stats
+    doc: |
+      Page pool statistics, see docs for struct page_pool_stats
+      for information about individual statistics.
+    attributes:
+      -
+        name: info
+        doc: Page pool identifying information.
+        type: nest
+        nested-attributes: page-pool-info
+      -
+        name: alloc-fast
+        type: uint
+        value: 8 # reserve some attr ids in case we need more metadata later
+      -
+        name: alloc-slow
+        type: uint
+      -
+        name: alloc-slow-high-order
+        type: uint
+      -
+        name: alloc-empty
+        type: uint
+      -
+        name: alloc-refill
+        type: uint
+      -
+        name: alloc-waive
+        type: uint
+      -
+        name: recycle-cached
+        type: uint
+      -
+        name: recycle-cache-full
+        type: uint
+      -
+        name: recycle-ring
+        type: uint
+      -
+        name: recycle-ring-full
+        type: uint
+      -
+        name: recycle-released-refcnt
+        type: uint
 
 operations:
   list:
@@ -210,6 +263,31 @@ name: netdev
       notify: page-pool-get
       mcgrp: page-pool
       config-cond: page-pool
+    -
+      name: page-pool-stats-get
+      doc: Get page pool statistics.
+      attribute-set: page-pool-stats
+      do:
+        request:
+          attributes:
+            - info
+        reply: &pp-stats-reply
+          attributes:
+            - info
+            - alloc-fast
+            - alloc-slow
+            - alloc-slow-high-order
+            - alloc-empty
+            - alloc-refill
+            - alloc-waive
+            - recycle-cached
+            - recycle-cache-full
+            - recycle-ring
+            - recycle-ring-full
+            - recycle-released-refcnt
+      dump:
+        reply: *pp-stats-reply
+      config-cond: page-pool-stats
 
 mcast-groups:
   list:
diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst
index 60993cb56b32..9d958128a57c 100644
--- a/Documentation/networking/page_pool.rst
+++ b/Documentation/networking/page_pool.rst
@@ -41,6 +41,11 @@ Architecture overview
                           |   Fast cache    |     |  ptr-ring cache  |
                           +-----------------+     +------------------+
 
+Monitoring
+==========
+Information about page pools on the system can be accessed via the netdev
+genetlink family (see Documentation/netlink/specs/netdev.yaml).
+
 API interface
 =============
 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.
 It takes a  pointer to a ``struct page_pool`` and a pointer to a struct
 page_pool_stats allocated by the caller.
 
-The API will fill in the provided struct page_pool_stats with
-statistics about the page_pool.
+Older drivers expose page pool statistics via ethtool or debugfs.
+The same statistics are accessible via the netlink netdev family
+in a driver-independent fashion.
 
 .. kernel-doc:: include/net/page_pool/types.h
    :identifiers: struct page_pool_recycle_stats
diff --git a/include/net/page_pool/helpers.h b/include/net/page_pool/helpers.h
index 4ebd544ae977..7dc65774cde5 100644
--- a/include/net/page_pool/helpers.h
+++ b/include/net/page_pool/helpers.h
@@ -55,16 +55,12 @@
 #include <net/page_pool/types.h>
 
 #ifdef CONFIG_PAGE_POOL_STATS
+/* Deprecated driver-facing API, use netlink instead */
 int page_pool_ethtool_stats_get_count(void);
 u8 *page_pool_ethtool_stats_get_strings(u8 *data);
 u64 *page_pool_ethtool_stats_get(u64 *data, void *stats);
 
-/*
- * Drivers that wish to harvest page pool stats and report them to users
- * (perhaps via ethtool, debugfs, or another mechanism) can allocate a
- * struct page_pool_stats call page_pool_get_stats to get stats for the specified pool.
- */
-bool page_pool_get_stats(struct page_pool *pool,
+bool page_pool_get_stats(const struct page_pool *pool,
 			 struct page_pool_stats *stats);
 #else
 static inline int page_pool_ethtool_stats_get_count(void)
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index 756410274120..2b37233e00c0 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -76,6 +76,24 @@ enum {
 	NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
 };
 
+enum {
+	NETDEV_A_PAGE_POOL_STATS_INFO = 1,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
+
+	__NETDEV_A_PAGE_POOL_STATS_MAX,
+	NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1)
+};
+
 enum {
 	NETDEV_CMD_DEV_GET = 1,
 	NETDEV_CMD_DEV_ADD_NTF,
@@ -85,6 +103,7 @@ enum {
 	NETDEV_CMD_PAGE_POOL_ADD_NTF,
 	NETDEV_CMD_PAGE_POOL_DEL_NTF,
 	NETDEV_CMD_PAGE_POOL_CHANGE_NTF,
+	NETDEV_CMD_PAGE_POOL_STATS_GET,
 
 	__NETDEV_CMD_MAX,
 	NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c
index 278b43f5ed50..b8af054b9fe5 100644
--- a/net/core/netdev-genl-gen.c
+++ b/net/core/netdev-genl-gen.c
@@ -16,6 +16,17 @@ static const struct netlink_range_validation netdev_a_page_pool_id_range = {
 	.max	= 4294967295,
 };
 
+static const struct netlink_range_validation netdev_a_page_pool_ifindex_range = {
+	.min	= 1,
+	.max	= 2147483647,
+};
+
+/* Common nested types */
+const struct nla_policy netdev_page_pool_info_nl_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1] = {
+	[NETDEV_A_PAGE_POOL_ID] = NLA_POLICY_FULL_RANGE(NLA_UINT, &netdev_a_page_pool_id_range),
+	[NETDEV_A_PAGE_POOL_IFINDEX] = NLA_POLICY_FULL_RANGE(NLA_U32, &netdev_a_page_pool_ifindex_range),
+};
+
 /* NETDEV_CMD_DEV_GET - do */
 static const struct nla_policy netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1] = {
 	[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
 };
 #endif /* CONFIG_PAGE_POOL */
 
+/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */
+#ifdef CONFIG_PAGE_POOL_STATS
+static const struct nla_policy netdev_page_pool_stats_get_nl_policy[NETDEV_A_PAGE_POOL_STATS_INFO + 1] = {
+	[NETDEV_A_PAGE_POOL_STATS_INFO] = NLA_POLICY_NESTED(netdev_page_pool_info_nl_policy),
+};
+#endif /* CONFIG_PAGE_POOL_STATS */
+
 /* Ops table for netdev */
 static const struct genl_split_ops netdev_nl_ops[] = {
 	{
@@ -56,6 +74,20 @@ static const struct genl_split_ops netdev_nl_ops[] = {
 		.flags	= GENL_CMD_CAP_DUMP,
 	},
 #endif /* CONFIG_PAGE_POOL */
+#ifdef CONFIG_PAGE_POOL_STATS
+	{
+		.cmd		= NETDEV_CMD_PAGE_POOL_STATS_GET,
+		.doit		= netdev_nl_page_pool_stats_get_doit,
+		.policy		= netdev_page_pool_stats_get_nl_policy,
+		.maxattr	= NETDEV_A_PAGE_POOL_STATS_INFO,
+		.flags		= GENL_CMD_CAP_DO,
+	},
+	{
+		.cmd	= NETDEV_CMD_PAGE_POOL_STATS_GET,
+		.dumpit	= netdev_nl_page_pool_stats_get_dumpit,
+		.flags	= GENL_CMD_CAP_DUMP,
+	},
+#endif /* CONFIG_PAGE_POOL_STATS */
 };
 
 static const struct genl_multicast_group netdev_nl_mcgrps[] = {
diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h
index 738097847100..649e4b46eccf 100644
--- a/net/core/netdev-genl-gen.h
+++ b/net/core/netdev-genl-gen.h
@@ -11,11 +11,18 @@
 
 #include <uapi/linux/netdev.h>
 
+/* Common nested types */
+extern const struct nla_policy netdev_page_pool_info_nl_policy[NETDEV_A_PAGE_POOL_IFINDEX + 1];
+
 int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info);
 int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
 int netdev_nl_page_pool_get_doit(struct sk_buff *skb, struct genl_info *info);
 int netdev_nl_page_pool_get_dumpit(struct sk_buff *skb,
 				   struct netlink_callback *cb);
+int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb,
+				       struct genl_info *info);
+int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb,
+					 struct netlink_callback *cb);
 
 enum {
 	NETDEV_NLGRP_MGMT,
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index a821fb5fe054..3d0938a60646 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -71,7 +71,7 @@ static const char pp_stats[][ETH_GSTRING_LEN] = {
  * is passed to this API which is filled in. The caller can then report
  * those stats to the user (perhaps via ethtool, debugfs, etc.).
  */
-bool page_pool_get_stats(struct page_pool *pool,
+bool page_pool_get_stats(const struct page_pool *pool,
 			 struct page_pool_stats *stats)
 {
 	int cpu = 0;
diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
index f28ad2179f53..ce56bd3aae2c 100644
--- a/net/core/page_pool_user.c
+++ b/net/core/page_pool_user.c
@@ -5,6 +5,7 @@
 #include <linux/xarray.h>
 #include <net/net_debug.h>
 #include <net/page_pool/types.h>
+#include <net/page_pool/helpers.h>
 #include <net/sock.h>
 
 #include "page_pool_priv.h"
@@ -106,6 +107,108 @@ netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb,
 	return err;
 }
 
+static int
+page_pool_nl_stats_fill(struct sk_buff *rsp, const struct page_pool *pool,
+			const struct genl_info *info)
+{
+#ifdef CONFIG_PAGE_POOL_STATS
+	struct page_pool_stats stats = {};
+	struct nlattr *nest;
+	void *hdr;
+
+	if (!page_pool_get_stats(pool, &stats))
+		return 0;
+
+	hdr = genlmsg_iput(rsp, info);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	nest = nla_nest_start(rsp, NETDEV_A_PAGE_POOL_STATS_INFO);
+
+	if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_ID, pool->user.id) ||
+	    (pool->slow.netdev->ifindex != LOOPBACK_IFINDEX &&
+	     nla_put_u32(rsp, NETDEV_A_PAGE_POOL_IFINDEX,
+			 pool->slow.netdev->ifindex)))
+		goto err_cancel_nest;
+
+	nla_nest_end(rsp, nest);
+
+	if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST,
+			 stats.alloc_stats.fast) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
+			 stats.alloc_stats.slow) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
+			 stats.alloc_stats.slow_high_order) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
+			 stats.alloc_stats.empty) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
+			 stats.alloc_stats.refill) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
+			 stats.alloc_stats.waive) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
+			 stats.recycle_stats.cached) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
+			 stats.recycle_stats.cache_full) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
+			 stats.recycle_stats.ring) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
+			 stats.recycle_stats.ring_full) ||
+	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
+			 stats.recycle_stats.released_refcnt))
+		goto err_cancel_msg;
+
+	genlmsg_end(rsp, hdr);
+
+	return 0;
+err_cancel_nest:
+	nla_nest_cancel(rsp, nest);
+err_cancel_msg:
+	genlmsg_cancel(rsp, hdr);
+	return -EMSGSIZE;
+#else
+	GENL_SET_ERR_MSG(info, "kernel built without CONFIG_PAGE_POOL_STATS");
+	return -EOPNOTSUPP;
+#endif
+}
+
+int netdev_nl_page_pool_stats_get_doit(struct sk_buff *skb,
+				       struct genl_info *info)
+{
+	struct nlattr *tb[ARRAY_SIZE(netdev_page_pool_info_nl_policy)];
+	struct nlattr *nest;
+	int err;
+	u32 id;
+
+	if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_PAGE_POOL_STATS_INFO))
+		return -EINVAL;
+
+	nest = info->attrs[NETDEV_A_PAGE_POOL_STATS_INFO];
+	err = nla_parse_nested(tb, ARRAY_SIZE(tb) - 1, nest,
+			       netdev_page_pool_info_nl_policy,
+			       info->extack);
+	if (err)
+		return err;
+
+	if (NL_REQ_ATTR_CHECK(info->extack, nest, tb, NETDEV_A_PAGE_POOL_ID))
+		return -EINVAL;
+	if (tb[NETDEV_A_PAGE_POOL_IFINDEX]) {
+		NL_SET_ERR_MSG_ATTR(info->extack,
+				    tb[NETDEV_A_PAGE_POOL_IFINDEX],
+				    "selecting by ifindex not supported");
+		return -EINVAL;
+	}
+
+	id = nla_get_uint(tb[NETDEV_A_PAGE_POOL_ID]);
+
+	return netdev_nl_page_pool_get_do(info, id, page_pool_nl_stats_fill);
+}
+
+int netdev_nl_page_pool_stats_get_dumpit(struct sk_buff *skb,
+					 struct netlink_callback *cb)
+{
+	return netdev_nl_page_pool_get_dump(skb, cb, page_pool_nl_stats_fill);
+}
+
 static int
 page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
 		  const struct genl_info *info)
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (10 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22 13:53   ` Eric Dumazet
  2023-11-22 16:06   ` Jesper Dangaard Brouer
  2023-11-22  3:44 ` [PATCH net-next v3 13/13] tools: ynl: add sample for getting page-pool information Jakub Kicinski
  2023-11-25 20:57 ` [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Shakeel Butt
  13 siblings, 2 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Mute the periodic "stalled pool shutdown" warning if the page pool
is visible to user space. Rolling out a driver using page pools
to just a few hundred hosts at Meta surfaces applications which
fail to reap their broken sockets. Obviously it's best if the
applications are fixed, but we don't generally print warnings
for application resource leaks. Admins can now depend on the
netlink interface for getting page pool info to detect buggy
apps.

While at it throw in the ID of the pool into the message,
in rare cases (pools from destroyed netns) this will make
finding the pool with a debugger easier.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/core/page_pool.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index 3d0938a60646..c2e7c9a6efbe 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -897,18 +897,21 @@ static void page_pool_release_retry(struct work_struct *wq)
 {
 	struct delayed_work *dwq = to_delayed_work(wq);
 	struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw);
+	void *netdev;
 	int inflight;
 
 	inflight = page_pool_release(pool);
 	if (!inflight)
 		return;
 
-	/* Periodic warning */
-	if (time_after_eq(jiffies, pool->defer_warn)) {
+	/* Periodic warning for page pools the user can't see */
+	netdev = READ_ONCE(pool->slow.netdev);
+	if (time_after_eq(jiffies, pool->defer_warn) &&
+	    (!netdev || netdev == NET_PTR_POISON)) {
 		int sec = (s32)((u32)jiffies - (u32)pool->defer_start) / HZ;
 
-		pr_warn("%s() stalled pool shutdown %d inflight %d sec\n",
-			__func__, inflight, sec);
+		pr_warn("%s() stalled pool shutdown: id %u, %d inflight %d sec\n",
+			__func__, pool->user.id, inflight, sec);
 		pool->defer_warn = jiffies + DEFER_WARN_INTERVAL;
 	}
 
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH net-next v3 13/13] tools: ynl: add sample for getting page-pool information
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (11 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools Jakub Kicinski
@ 2023-11-22  3:44 ` Jakub Kicinski
  2023-11-22 16:17   ` Jesper Dangaard Brouer
  2023-11-25 20:57 ` [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Shakeel Butt
  13 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22  3:44 UTC (permalink / raw)
  To: davem
  Cc: netdev, edumazet, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb, Jakub Kicinski

Regenerate the tools/ code after netdev spec changes.

Add sample to query page-pool info in a concise fashion:

$ ./page-pool
    eth0[2]	page pools: 10 (zombies: 0)
		refs: 41984 bytes: 171966464 (refs: 0 bytes: 0)
		recycling: 90.3% (alloc: 656:397681 recycle: 89652:270201)

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/include/uapi/linux/netdev.h     |  36 +++
 tools/net/ynl/generated/netdev-user.c | 419 ++++++++++++++++++++++++++
 tools/net/ynl/generated/netdev-user.h | 171 +++++++++++
 tools/net/ynl/lib/ynl.h               |   2 +-
 tools/net/ynl/samples/.gitignore      |   1 +
 tools/net/ynl/samples/Makefile        |   2 +-
 tools/net/ynl/samples/page-pool.c     | 147 +++++++++
 7 files changed, 776 insertions(+), 2 deletions(-)
 create mode 100644 tools/net/ynl/samples/page-pool.c

diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h
index 2943a151d4f1..9d0a48717d1f 100644
--- a/tools/include/uapi/linux/netdev.h
+++ b/tools/include/uapi/linux/netdev.h
@@ -64,16 +64,52 @@ enum {
 	NETDEV_A_DEV_MAX = (__NETDEV_A_DEV_MAX - 1)
 };
 
+enum {
+	NETDEV_A_PAGE_POOL_ID = 1,
+	NETDEV_A_PAGE_POOL_IFINDEX,
+	NETDEV_A_PAGE_POOL_NAPI_ID,
+	NETDEV_A_PAGE_POOL_INFLIGHT,
+	NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
+	NETDEV_A_PAGE_POOL_DESTROYED,
+
+	__NETDEV_A_PAGE_POOL_MAX,
+	NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
+};
+
+enum {
+	NETDEV_A_PAGE_POOL_STATS_INFO = 1,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST = 8,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
+	NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
+	NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
+
+	__NETDEV_A_PAGE_POOL_STATS_MAX,
+	NETDEV_A_PAGE_POOL_STATS_MAX = (__NETDEV_A_PAGE_POOL_STATS_MAX - 1)
+};
+
 enum {
 	NETDEV_CMD_DEV_GET = 1,
 	NETDEV_CMD_DEV_ADD_NTF,
 	NETDEV_CMD_DEV_DEL_NTF,
 	NETDEV_CMD_DEV_CHANGE_NTF,
+	NETDEV_CMD_PAGE_POOL_GET,
+	NETDEV_CMD_PAGE_POOL_ADD_NTF,
+	NETDEV_CMD_PAGE_POOL_DEL_NTF,
+	NETDEV_CMD_PAGE_POOL_CHANGE_NTF,
+	NETDEV_CMD_PAGE_POOL_STATS_GET,
 
 	__NETDEV_CMD_MAX,
 	NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1)
 };
 
 #define NETDEV_MCGRP_MGMT	"mgmt"
+#define NETDEV_MCGRP_PAGE_POOL	"page-pool"
 
 #endif /* _UAPI_LINUX_NETDEV_H */
diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c
index b5ffe8cd1144..f9a000584493 100644
--- a/tools/net/ynl/generated/netdev-user.c
+++ b/tools/net/ynl/generated/netdev-user.c
@@ -18,6 +18,11 @@ static const char * const netdev_op_strmap[] = {
 	[NETDEV_CMD_DEV_ADD_NTF] = "dev-add-ntf",
 	[NETDEV_CMD_DEV_DEL_NTF] = "dev-del-ntf",
 	[NETDEV_CMD_DEV_CHANGE_NTF] = "dev-change-ntf",
+	[NETDEV_CMD_PAGE_POOL_GET] = "page-pool-get",
+	[NETDEV_CMD_PAGE_POOL_ADD_NTF] = "page-pool-add-ntf",
+	[NETDEV_CMD_PAGE_POOL_DEL_NTF] = "page-pool-del-ntf",
+	[NETDEV_CMD_PAGE_POOL_CHANGE_NTF] = "page-pool-change-ntf",
+	[NETDEV_CMD_PAGE_POOL_STATS_GET] = "page-pool-stats-get",
 };
 
 const char *netdev_op_str(int op)
@@ -59,6 +64,16 @@ const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value)
 }
 
 /* Policies */
+struct ynl_policy_attr netdev_page_pool_info_policy[NETDEV_A_PAGE_POOL_MAX + 1] = {
+	[NETDEV_A_PAGE_POOL_ID] = { .name = "id", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, },
+};
+
+struct ynl_policy_nest netdev_page_pool_info_nest = {
+	.max_attr = NETDEV_A_PAGE_POOL_MAX,
+	.table = netdev_page_pool_info_policy,
+};
+
 struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = {
 	[NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, },
 	[NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, },
@@ -72,7 +87,85 @@ struct ynl_policy_nest netdev_dev_nest = {
 	.table = netdev_dev_policy,
 };
 
+struct ynl_policy_attr netdev_page_pool_policy[NETDEV_A_PAGE_POOL_MAX + 1] = {
+	[NETDEV_A_PAGE_POOL_ID] = { .name = "id", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, },
+	[NETDEV_A_PAGE_POOL_NAPI_ID] = { .name = "napi-id", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_INFLIGHT] = { .name = "inflight", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_INFLIGHT_MEM] = { .name = "inflight-mem", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_DESTROYED] = { .name = "destroyed", .type = YNL_PT_UINT, },
+};
+
+struct ynl_policy_nest netdev_page_pool_nest = {
+	.max_attr = NETDEV_A_PAGE_POOL_MAX,
+	.table = netdev_page_pool_policy,
+};
+
+struct ynl_policy_attr netdev_page_pool_stats_policy[NETDEV_A_PAGE_POOL_STATS_MAX + 1] = {
+	[NETDEV_A_PAGE_POOL_STATS_INFO] = { .name = "info", .type = YNL_PT_NEST, .nest = &netdev_page_pool_info_nest, },
+	[NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST] = { .name = "alloc-fast", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW] = { .name = "alloc-slow", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER] = { .name = "alloc-slow-high-order", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY] = { .name = "alloc-empty", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL] = { .name = "alloc-refill", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE] = { .name = "alloc-waive", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED] = { .name = "recycle-cached", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL] = { .name = "recycle-cache-full", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING] = { .name = "recycle-ring", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL] = { .name = "recycle-ring-full", .type = YNL_PT_UINT, },
+	[NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT] = { .name = "recycle-released-refcnt", .type = YNL_PT_UINT, },
+};
+
+struct ynl_policy_nest netdev_page_pool_stats_nest = {
+	.max_attr = NETDEV_A_PAGE_POOL_STATS_MAX,
+	.table = netdev_page_pool_stats_policy,
+};
+
 /* Common nested types */
+void netdev_page_pool_info_free(struct netdev_page_pool_info *obj)
+{
+}
+
+int netdev_page_pool_info_put(struct nlmsghdr *nlh, unsigned int attr_type,
+			      struct netdev_page_pool_info *obj)
+{
+	struct nlattr *nest;
+
+	nest = mnl_attr_nest_start(nlh, attr_type);
+	if (obj->_present.id)
+		mnl_attr_put_uint(nlh, NETDEV_A_PAGE_POOL_ID, obj->id);
+	if (obj->_present.ifindex)
+		mnl_attr_put_u32(nlh, NETDEV_A_PAGE_POOL_IFINDEX, obj->ifindex);
+	mnl_attr_nest_end(nlh, nest);
+
+	return 0;
+}
+
+int netdev_page_pool_info_parse(struct ynl_parse_arg *yarg,
+				const struct nlattr *nested)
+{
+	struct netdev_page_pool_info *dst = yarg->data;
+	const struct nlattr *attr;
+
+	mnl_attr_for_each_nested(attr, nested) {
+		unsigned int type = mnl_attr_get_type(attr);
+
+		if (type == NETDEV_A_PAGE_POOL_ID) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.id = 1;
+			dst->id = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_IFINDEX) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.ifindex = 1;
+			dst->ifindex = mnl_attr_get_u32(attr);
+		}
+	}
+
+	return 0;
+}
+
 /* ============== NETDEV_CMD_DEV_GET ============== */
 /* NETDEV_CMD_DEV_GET - do */
 void netdev_dev_get_req_free(struct netdev_dev_get_req *req)
@@ -197,6 +290,314 @@ void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp)
 	free(rsp);
 }
 
+/* ============== NETDEV_CMD_PAGE_POOL_GET ============== */
+/* NETDEV_CMD_PAGE_POOL_GET - do */
+void netdev_page_pool_get_req_free(struct netdev_page_pool_get_req *req)
+{
+	free(req);
+}
+
+void netdev_page_pool_get_rsp_free(struct netdev_page_pool_get_rsp *rsp)
+{
+	free(rsp);
+}
+
+int netdev_page_pool_get_rsp_parse(const struct nlmsghdr *nlh, void *data)
+{
+	struct netdev_page_pool_get_rsp *dst;
+	struct ynl_parse_arg *yarg = data;
+	const struct nlattr *attr;
+
+	dst = yarg->data;
+
+	mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
+		unsigned int type = mnl_attr_get_type(attr);
+
+		if (type == NETDEV_A_PAGE_POOL_ID) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.id = 1;
+			dst->id = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_IFINDEX) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.ifindex = 1;
+			dst->ifindex = mnl_attr_get_u32(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_NAPI_ID) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.napi_id = 1;
+			dst->napi_id = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_INFLIGHT) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.inflight = 1;
+			dst->inflight = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_INFLIGHT_MEM) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.inflight_mem = 1;
+			dst->inflight_mem = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_DESTROYED) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.destroyed = 1;
+			dst->destroyed = mnl_attr_get_uint(attr);
+		}
+	}
+
+	return MNL_CB_OK;
+}
+
+struct netdev_page_pool_get_rsp *
+netdev_page_pool_get(struct ynl_sock *ys, struct netdev_page_pool_get_req *req)
+{
+	struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };
+	struct netdev_page_pool_get_rsp *rsp;
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_GET, 1);
+	ys->req_policy = &netdev_page_pool_nest;
+	yrs.yarg.rsp_policy = &netdev_page_pool_nest;
+
+	if (req->_present.id)
+		mnl_attr_put_uint(nlh, NETDEV_A_PAGE_POOL_ID, req->id);
+
+	rsp = calloc(1, sizeof(*rsp));
+	yrs.yarg.data = rsp;
+	yrs.cb = netdev_page_pool_get_rsp_parse;
+	yrs.rsp_cmd = NETDEV_CMD_PAGE_POOL_GET;
+
+	err = ynl_exec(ys, nlh, &yrs);
+	if (err < 0)
+		goto err_free;
+
+	return rsp;
+
+err_free:
+	netdev_page_pool_get_rsp_free(rsp);
+	return NULL;
+}
+
+/* NETDEV_CMD_PAGE_POOL_GET - dump */
+void netdev_page_pool_get_list_free(struct netdev_page_pool_get_list *rsp)
+{
+	struct netdev_page_pool_get_list *next = rsp;
+
+	while ((void *)next != YNL_LIST_END) {
+		rsp = next;
+		next = rsp->next;
+
+		free(rsp);
+	}
+}
+
+struct netdev_page_pool_get_list *
+netdev_page_pool_get_dump(struct ynl_sock *ys)
+{
+	struct ynl_dump_state yds = {};
+	struct nlmsghdr *nlh;
+	int err;
+
+	yds.ys = ys;
+	yds.alloc_sz = sizeof(struct netdev_page_pool_get_list);
+	yds.cb = netdev_page_pool_get_rsp_parse;
+	yds.rsp_cmd = NETDEV_CMD_PAGE_POOL_GET;
+	yds.rsp_policy = &netdev_page_pool_nest;
+
+	nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_GET, 1);
+
+	err = ynl_exec_dump(ys, nlh, &yds);
+	if (err < 0)
+		goto free_list;
+
+	return yds.first;
+
+free_list:
+	netdev_page_pool_get_list_free(yds.first);
+	return NULL;
+}
+
+/* NETDEV_CMD_PAGE_POOL_GET - notify */
+void netdev_page_pool_get_ntf_free(struct netdev_page_pool_get_ntf *rsp)
+{
+	free(rsp);
+}
+
+/* ============== NETDEV_CMD_PAGE_POOL_STATS_GET ============== */
+/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */
+void
+netdev_page_pool_stats_get_req_free(struct netdev_page_pool_stats_get_req *req)
+{
+	netdev_page_pool_info_free(&req->info);
+	free(req);
+}
+
+void
+netdev_page_pool_stats_get_rsp_free(struct netdev_page_pool_stats_get_rsp *rsp)
+{
+	netdev_page_pool_info_free(&rsp->info);
+	free(rsp);
+}
+
+int netdev_page_pool_stats_get_rsp_parse(const struct nlmsghdr *nlh,
+					 void *data)
+{
+	struct netdev_page_pool_stats_get_rsp *dst;
+	struct ynl_parse_arg *yarg = data;
+	const struct nlattr *attr;
+	struct ynl_parse_arg parg;
+
+	dst = yarg->data;
+	parg.ys = yarg->ys;
+
+	mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) {
+		unsigned int type = mnl_attr_get_type(attr);
+
+		if (type == NETDEV_A_PAGE_POOL_STATS_INFO) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.info = 1;
+
+			parg.rsp_policy = &netdev_page_pool_info_nest;
+			parg.data = &dst->info;
+			if (netdev_page_pool_info_parse(&parg, attr))
+				return MNL_CB_ERROR;
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.alloc_fast = 1;
+			dst->alloc_fast = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.alloc_slow = 1;
+			dst->alloc_slow = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.alloc_slow_high_order = 1;
+			dst->alloc_slow_high_order = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.alloc_empty = 1;
+			dst->alloc_empty = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.alloc_refill = 1;
+			dst->alloc_refill = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.alloc_waive = 1;
+			dst->alloc_waive = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.recycle_cached = 1;
+			dst->recycle_cached = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.recycle_cache_full = 1;
+			dst->recycle_cache_full = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.recycle_ring = 1;
+			dst->recycle_ring = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.recycle_ring_full = 1;
+			dst->recycle_ring_full = mnl_attr_get_uint(attr);
+		} else if (type == NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT) {
+			if (ynl_attr_validate(yarg, attr))
+				return MNL_CB_ERROR;
+			dst->_present.recycle_released_refcnt = 1;
+			dst->recycle_released_refcnt = mnl_attr_get_uint(attr);
+		}
+	}
+
+	return MNL_CB_OK;
+}
+
+struct netdev_page_pool_stats_get_rsp *
+netdev_page_pool_stats_get(struct ynl_sock *ys,
+			   struct netdev_page_pool_stats_get_req *req)
+{
+	struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };
+	struct netdev_page_pool_stats_get_rsp *rsp;
+	struct nlmsghdr *nlh;
+	int err;
+
+	nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_STATS_GET, 1);
+	ys->req_policy = &netdev_page_pool_stats_nest;
+	yrs.yarg.rsp_policy = &netdev_page_pool_stats_nest;
+
+	if (req->_present.info)
+		netdev_page_pool_info_put(nlh, NETDEV_A_PAGE_POOL_STATS_INFO, &req->info);
+
+	rsp = calloc(1, sizeof(*rsp));
+	yrs.yarg.data = rsp;
+	yrs.cb = netdev_page_pool_stats_get_rsp_parse;
+	yrs.rsp_cmd = NETDEV_CMD_PAGE_POOL_STATS_GET;
+
+	err = ynl_exec(ys, nlh, &yrs);
+	if (err < 0)
+		goto err_free;
+
+	return rsp;
+
+err_free:
+	netdev_page_pool_stats_get_rsp_free(rsp);
+	return NULL;
+}
+
+/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */
+void
+netdev_page_pool_stats_get_list_free(struct netdev_page_pool_stats_get_list *rsp)
+{
+	struct netdev_page_pool_stats_get_list *next = rsp;
+
+	while ((void *)next != YNL_LIST_END) {
+		rsp = next;
+		next = rsp->next;
+
+		netdev_page_pool_info_free(&rsp->obj.info);
+		free(rsp);
+	}
+}
+
+struct netdev_page_pool_stats_get_list *
+netdev_page_pool_stats_get_dump(struct ynl_sock *ys)
+{
+	struct ynl_dump_state yds = {};
+	struct nlmsghdr *nlh;
+	int err;
+
+	yds.ys = ys;
+	yds.alloc_sz = sizeof(struct netdev_page_pool_stats_get_list);
+	yds.cb = netdev_page_pool_stats_get_rsp_parse;
+	yds.rsp_cmd = NETDEV_CMD_PAGE_POOL_STATS_GET;
+	yds.rsp_policy = &netdev_page_pool_stats_nest;
+
+	nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_PAGE_POOL_STATS_GET, 1);
+
+	err = ynl_exec_dump(ys, nlh, &yds);
+	if (err < 0)
+		goto free_list;
+
+	return yds.first;
+
+free_list:
+	netdev_page_pool_stats_get_list_free(yds.first);
+	return NULL;
+}
+
 static const struct ynl_ntf_info netdev_ntf_info[] =  {
 	[NETDEV_CMD_DEV_ADD_NTF] =  {
 		.alloc_sz	= sizeof(struct netdev_dev_get_ntf),
@@ -216,6 +617,24 @@ static const struct ynl_ntf_info netdev_ntf_info[] =  {
 		.policy		= &netdev_dev_nest,
 		.free		= (void *)netdev_dev_get_ntf_free,
 	},
+	[NETDEV_CMD_PAGE_POOL_ADD_NTF] =  {
+		.alloc_sz	= sizeof(struct netdev_page_pool_get_ntf),
+		.cb		= netdev_page_pool_get_rsp_parse,
+		.policy		= &netdev_page_pool_nest,
+		.free		= (void *)netdev_page_pool_get_ntf_free,
+	},
+	[NETDEV_CMD_PAGE_POOL_DEL_NTF] =  {
+		.alloc_sz	= sizeof(struct netdev_page_pool_get_ntf),
+		.cb		= netdev_page_pool_get_rsp_parse,
+		.policy		= &netdev_page_pool_nest,
+		.free		= (void *)netdev_page_pool_get_ntf_free,
+	},
+	[NETDEV_CMD_PAGE_POOL_CHANGE_NTF] =  {
+		.alloc_sz	= sizeof(struct netdev_page_pool_get_ntf),
+		.cb		= netdev_page_pool_get_rsp_parse,
+		.policy		= &netdev_page_pool_nest,
+		.free		= (void *)netdev_page_pool_get_ntf_free,
+	},
 };
 
 const struct ynl_family ynl_netdev_family =  {
diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h
index 4fafac879df3..f27ad84fe020 100644
--- a/tools/net/ynl/generated/netdev-user.h
+++ b/tools/net/ynl/generated/netdev-user.h
@@ -21,6 +21,16 @@ const char *netdev_xdp_act_str(enum netdev_xdp_act value);
 const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value);
 
 /* Common nested types */
+struct netdev_page_pool_info {
+	struct {
+		__u32 id:1;
+		__u32 ifindex:1;
+	} _present;
+
+	__u64 id;
+	__u32 ifindex;
+};
+
 /* ============== NETDEV_CMD_DEV_GET ============== */
 /* NETDEV_CMD_DEV_GET - do */
 struct netdev_dev_get_req {
@@ -87,4 +97,165 @@ struct netdev_dev_get_ntf {
 
 void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp);
 
+/* ============== NETDEV_CMD_PAGE_POOL_GET ============== */
+/* NETDEV_CMD_PAGE_POOL_GET - do */
+struct netdev_page_pool_get_req {
+	struct {
+		__u32 id:1;
+	} _present;
+
+	__u64 id;
+};
+
+static inline struct netdev_page_pool_get_req *
+netdev_page_pool_get_req_alloc(void)
+{
+	return calloc(1, sizeof(struct netdev_page_pool_get_req));
+}
+void netdev_page_pool_get_req_free(struct netdev_page_pool_get_req *req);
+
+static inline void
+netdev_page_pool_get_req_set_id(struct netdev_page_pool_get_req *req, __u64 id)
+{
+	req->_present.id = 1;
+	req->id = id;
+}
+
+struct netdev_page_pool_get_rsp {
+	struct {
+		__u32 id:1;
+		__u32 ifindex:1;
+		__u32 napi_id:1;
+		__u32 inflight:1;
+		__u32 inflight_mem:1;
+		__u32 destroyed:1;
+	} _present;
+
+	__u64 id;
+	__u32 ifindex;
+	__u64 napi_id;
+	__u64 inflight;
+	__u64 inflight_mem;
+	__u64 destroyed;
+};
+
+void netdev_page_pool_get_rsp_free(struct netdev_page_pool_get_rsp *rsp);
+
+/*
+ * Get / dump information about Page Pools.
+(Only Page Pools associated with a net_device can be listed.)
+
+ */
+struct netdev_page_pool_get_rsp *
+netdev_page_pool_get(struct ynl_sock *ys, struct netdev_page_pool_get_req *req);
+
+/* NETDEV_CMD_PAGE_POOL_GET - dump */
+struct netdev_page_pool_get_list {
+	struct netdev_page_pool_get_list *next;
+	struct netdev_page_pool_get_rsp obj __attribute__((aligned(8)));
+};
+
+void netdev_page_pool_get_list_free(struct netdev_page_pool_get_list *rsp);
+
+struct netdev_page_pool_get_list *
+netdev_page_pool_get_dump(struct ynl_sock *ys);
+
+/* NETDEV_CMD_PAGE_POOL_GET - notify */
+struct netdev_page_pool_get_ntf {
+	__u16 family;
+	__u8 cmd;
+	struct ynl_ntf_base_type *next;
+	void (*free)(struct netdev_page_pool_get_ntf *ntf);
+	struct netdev_page_pool_get_rsp obj __attribute__((aligned(8)));
+};
+
+void netdev_page_pool_get_ntf_free(struct netdev_page_pool_get_ntf *rsp);
+
+/* ============== NETDEV_CMD_PAGE_POOL_STATS_GET ============== */
+/* NETDEV_CMD_PAGE_POOL_STATS_GET - do */
+struct netdev_page_pool_stats_get_req {
+	struct {
+		__u32 info:1;
+	} _present;
+
+	struct netdev_page_pool_info info;
+};
+
+static inline struct netdev_page_pool_stats_get_req *
+netdev_page_pool_stats_get_req_alloc(void)
+{
+	return calloc(1, sizeof(struct netdev_page_pool_stats_get_req));
+}
+void
+netdev_page_pool_stats_get_req_free(struct netdev_page_pool_stats_get_req *req);
+
+static inline void
+netdev_page_pool_stats_get_req_set_info_id(struct netdev_page_pool_stats_get_req *req,
+					   __u64 id)
+{
+	req->_present.info = 1;
+	req->info._present.id = 1;
+	req->info.id = id;
+}
+static inline void
+netdev_page_pool_stats_get_req_set_info_ifindex(struct netdev_page_pool_stats_get_req *req,
+						__u32 ifindex)
+{
+	req->_present.info = 1;
+	req->info._present.ifindex = 1;
+	req->info.ifindex = ifindex;
+}
+
+struct netdev_page_pool_stats_get_rsp {
+	struct {
+		__u32 info:1;
+		__u32 alloc_fast:1;
+		__u32 alloc_slow:1;
+		__u32 alloc_slow_high_order:1;
+		__u32 alloc_empty:1;
+		__u32 alloc_refill:1;
+		__u32 alloc_waive:1;
+		__u32 recycle_cached:1;
+		__u32 recycle_cache_full:1;
+		__u32 recycle_ring:1;
+		__u32 recycle_ring_full:1;
+		__u32 recycle_released_refcnt:1;
+	} _present;
+
+	struct netdev_page_pool_info info;
+	__u64 alloc_fast;
+	__u64 alloc_slow;
+	__u64 alloc_slow_high_order;
+	__u64 alloc_empty;
+	__u64 alloc_refill;
+	__u64 alloc_waive;
+	__u64 recycle_cached;
+	__u64 recycle_cache_full;
+	__u64 recycle_ring;
+	__u64 recycle_ring_full;
+	__u64 recycle_released_refcnt;
+};
+
+void
+netdev_page_pool_stats_get_rsp_free(struct netdev_page_pool_stats_get_rsp *rsp);
+
+/*
+ * Get page pool statistics.
+ */
+struct netdev_page_pool_stats_get_rsp *
+netdev_page_pool_stats_get(struct ynl_sock *ys,
+			   struct netdev_page_pool_stats_get_req *req);
+
+/* NETDEV_CMD_PAGE_POOL_STATS_GET - dump */
+struct netdev_page_pool_stats_get_list {
+	struct netdev_page_pool_stats_get_list *next;
+	struct netdev_page_pool_stats_get_rsp obj __attribute__((aligned(8)));
+};
+
+void
+netdev_page_pool_stats_get_list_free(struct netdev_page_pool_stats_get_list *rsp);
+
+struct netdev_page_pool_stats_get_list *
+netdev_page_pool_stats_get_dump(struct ynl_sock *ys);
+
 #endif /* _LINUX_NETDEV_GEN_H */
diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h
index e974378e3b8c..075d868f3b57 100644
--- a/tools/net/ynl/lib/ynl.h
+++ b/tools/net/ynl/lib/ynl.h
@@ -239,7 +239,7 @@ int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg);
 #ifndef MNL_HAS_AUTO_SCALARS
 static inline uint64_t mnl_attr_get_uint(const struct nlattr *attr)
 {
-	if (mnl_attr_get_len(attr) == 4)
+	if (mnl_attr_get_payload_len(attr) == 4)
 		return mnl_attr_get_u32(attr);
 	return mnl_attr_get_u64(attr);
 }
diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore
index 2aae60c4829f..49637b26c482 100644
--- a/tools/net/ynl/samples/.gitignore
+++ b/tools/net/ynl/samples/.gitignore
@@ -1,3 +1,4 @@
 ethtool
 devlink
 netdev
+page-pool
\ No newline at end of file
diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile
index 3dbb106e87d9..1afefc266b7a 100644
--- a/tools/net/ynl/samples/Makefile
+++ b/tools/net/ynl/samples/Makefile
@@ -18,7 +18,7 @@ include $(wildcard *.d)
 
 all: $(BINS)
 
-$(BINS): ../lib/ynl.a ../generated/protos.a
+$(BINS): ../lib/ynl.a ../generated/protos.a $(SRCS)
 	@echo -e '\tCC sample $@'
 	@$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o
 	@$(LINK.c) $@.o -o $@  $(LDLIBS)
diff --git a/tools/net/ynl/samples/page-pool.c b/tools/net/ynl/samples/page-pool.c
new file mode 100644
index 000000000000..18d359713469
--- /dev/null
+++ b/tools/net/ynl/samples/page-pool.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+
+#include <ynl.h>
+
+#include <net/if.h>
+
+#include "netdev-user.h"
+
+struct stat {
+	unsigned int ifc;
+
+	struct {
+		unsigned int cnt;
+		size_t refs, bytes;
+	} live[2];
+
+	size_t alloc_slow, alloc_fast, recycle_ring, recycle_cache;
+};
+
+struct stats_array {
+	unsigned int i, max;
+	struct stat *s;
+};
+
+static struct stat *find_ifc(struct stats_array *a, unsigned int ifindex)
+{
+	unsigned int i;
+
+	for (i = 0; i < a->i; i++) {
+		if (a->s[i].ifc == ifindex)
+			return &a->s[i];
+	}
+
+	a->i++;
+	if (a->i == a->max) {
+		a->max *= 2;
+		a->s = reallocarray(a->s, a->max, sizeof(*a->s));
+	}
+	a->s[i].ifc = ifindex;
+	return &a->s[i];
+}
+
+static void count(struct stat *s, unsigned int l,
+		  struct netdev_page_pool_get_rsp *pp)
+{
+	s->live[l].cnt++;
+	if (pp->_present.inflight)
+		s->live[l].refs += pp->inflight;
+	if (pp->_present.inflight_mem)
+		s->live[l].bytes += pp->inflight_mem;
+}
+
+int main(int argc, char **argv)
+{
+	struct netdev_page_pool_stats_get_list *pp_stats;
+	struct netdev_page_pool_get_list *pools;
+	struct stats_array a = {};
+	struct ynl_error yerr;
+	struct ynl_sock *ys;
+
+	ys = ynl_sock_create(&ynl_netdev_family, &yerr);
+	if (!ys) {
+		fprintf(stderr, "YNL: %s\n", yerr.msg);
+		return 1;
+	}
+
+	a.max = 128;
+	a.s = calloc(a.max, sizeof(*a.s));
+	if (!a.s)
+		goto err_close;
+
+	pools = netdev_page_pool_get_dump(ys);
+	if (!pools)
+		goto err_free;
+
+	ynl_dump_foreach(pools, pp) {
+		struct stat *s = find_ifc(&a, pp->ifindex);
+
+		count(s, 1, pp);
+		if (pp->_present.destroyed)
+			count(s, 0, pp);
+	}
+	netdev_page_pool_get_list_free(pools);
+
+	pp_stats = netdev_page_pool_stats_get_dump(ys);
+	if (!pp_stats)
+		goto err_free;
+
+	ynl_dump_foreach(pp_stats, pp) {
+		struct stat *s = find_ifc(&a, pp->info.ifindex);
+
+		if (pp->_present.alloc_fast)
+			s->alloc_fast += pp->alloc_fast;
+		if (pp->_present.alloc_slow)
+			s->alloc_slow += pp->alloc_slow;
+		if (pp->_present.recycle_ring)
+			s->recycle_ring += pp->recycle_ring;
+		if (pp->_present.recycle_cached)
+			s->recycle_cache += pp->recycle_cached;
+	}
+	netdev_page_pool_stats_get_list_free(pp_stats);
+
+	for (unsigned int i = 0; i < a.i; i++) {
+		char ifname[IF_NAMESIZE];
+		struct stat *s = &a.s[i];
+		const char *name;
+		double recycle;
+
+		if (!s->ifc) {
+			name = "<orphan>\t";
+		} else {
+			name = if_indextoname(s->ifc, ifname);
+			if (name)
+				printf("%8s", name);
+			printf("[%d]\t", s->ifc);
+		}
+
+		printf("page pools: %u (zombies: %u)\n",
+		       s->live[1].cnt, s->live[0].cnt);
+		printf("\t\trefs: %zu bytes: %zu (refs: %zu bytes: %zu)\n",
+		       s->live[1].refs, s->live[1].bytes,
+		       s->live[0].refs, s->live[0].bytes);
+
+		/* We don't know how many pages are sitting in cache and ring
+		 * so we will under-count the recycling rate a bit.
+		 */
+		recycle = (double)(s->recycle_ring + s->recycle_cache) /
+			(s->alloc_fast + s->alloc_slow) * 100;
+		printf("\t\trecycling: %.1lf%% (alloc: %zu:%zu recycle: %zu:%zu)\n",
+		       recycle, s->alloc_slow, s->alloc_fast,
+		       s->recycle_ring, s->recycle_cache);
+	}
+
+	ynl_sock_destroy(ys);
+	return 0;
+
+err_free:
+	free(a.s);
+err_close:
+	fprintf(stderr, "YNL: %s\n", ys->err.msg);
+	ynl_sock_destroy(ys);
+	return 2;
+}
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 01/13] net: page_pool: factor out uninit
  2023-11-22  3:44 ` [PATCH net-next v3 01/13] net: page_pool: factor out uninit Jakub Kicinski
@ 2023-11-22  8:38   ` Eric Dumazet
  2023-11-22 14:15   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  8:38 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> We'll soon (next change in the series) need a fuller unwind path
> in page_pool_create() so create the inverse of page_pool_init().
>
> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 02/13] net: page_pool: id the page pools
  2023-11-22  3:44 ` [PATCH net-next v3 02/13] net: page_pool: id the page pools Jakub Kicinski
@ 2023-11-22  8:40   ` Eric Dumazet
  2023-11-22 14:16   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  8:40 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> To give ourselves the flexibility of creating netlink commands
> and ability to refer to page pool instances in uAPIs create
> IDs for page pools.
>
> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 03/13] net: page_pool: record pools per netdev
  2023-11-22  3:44 ` [PATCH net-next v3 03/13] net: page_pool: record pools per netdev Jakub Kicinski
@ 2023-11-22  8:55   ` Eric Dumazet
  2023-11-22 15:44     ` Jakub Kicinski
  2023-11-22 14:20   ` Jesper Dangaard Brouer
  1 sibling, 1 reply; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  8:55 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Link the page pools with netdevs. This needs to be netns compatible
> so we have two options. Either we record the pools per netns and
> have to worry about moving them as the netdev gets moved.
> Or we record them directly on the netdev so they move with the netdev
> without any extra work.
>
> Implement the latter option. Since pools may outlast netdev we need
> a place to store orphans. In time honored tradition use loopback
> for this purpose.
>
> Reviewed-by: Mina Almasry <almasrymina@google.com>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> v1: fix race between page pool and netdev disappearing (Simon)
> ---
>  include/linux/list.h          | 20 ++++++++
>  include/linux/netdevice.h     |  4 ++
>  include/linux/poison.h        |  2 +
>  include/net/page_pool/types.h |  4 ++
>  net/core/page_pool_user.c     | 90 +++++++++++++++++++++++++++++++++++
>  5 files changed, 120 insertions(+)
>
> diff --git a/include/linux/list.h b/include/linux/list.h
> index 1837caedf723..059aa1fff41e 100644
> --- a/include/linux/list.h
> +++ b/include/linux/list.h
> @@ -1119,6 +1119,26 @@ static inline void hlist_move_list(struct hlist_head *old,
>         old->first = NULL;
>  }
>
>

> +static void page_pool_unreg_netdev(struct net_device *netdev)
> +{
> +       struct page_pool *pool, *last;
> +       struct net_device *lo;
> +
> +       lo = __dev_get_by_index(dev_net(netdev), 1);

Any reason for not using dev_net(netdev)->loopback_dev ?

> +       if (!lo) {
> +               netdev_err_once(netdev,
> +                               "can't get lo to store orphan page pools\n");
> +               page_pool_unreg_netdev_wipe(netdev);
> +               return;
> +       }
> +

Either way :

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access
  2023-11-22  3:44 ` [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access Jakub Kicinski
@ 2023-11-22  8:57   ` Eric Dumazet
  2023-11-22 14:21   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  8:57 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> To avoid any issues with race conditions on accessing napi
> and having to think about the lifetime of NAPI objects
> in netlink GET - stash the napi_id to which page pool
> was linked at creation time.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---

Interesting... I have a patch to speedup dev_get_by_napi_id(), I will
send it today.

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers
  2023-11-22  3:44 ` [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers Jakub Kicinski
@ 2023-11-22  8:59   ` Eric Dumazet
  2023-11-22 14:22   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  8:59 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Link page pool instances to netdev for the drivers which
> already link to NAPI. Unless the driver is doing something
> very weird per-NAPI should imply per-netdev.
>
> Add netsec as well, Ilias indicates that it fits the mold.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools
  2023-11-22  3:44 ` [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools Jakub Kicinski
@ 2023-11-22  9:00   ` Eric Dumazet
  2023-11-22 14:24   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  9:00 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Add a Netlink spec in YAML for getting very basic information
> about page pools.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed
  2023-11-22  3:44 ` [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed Jakub Kicinski
@ 2023-11-22  9:02   ` Jesper Dangaard Brouer
  2023-11-22 10:21   ` Eric Dumazet
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22  9:02 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb, kernel-team



On 11/22/23 04:44, Jakub Kicinski wrote:
> Report when page pool was destroyed. Together with the inflight
> / memory use reporting this can serve as a replacement for the
> warning about leaked page pools we currently print to dmesg.
> 
> Example output for a fake leaked page pool using some hacks
> in netdevsim (one "live" pool, and one "leaked" on the same dev):
> 
> $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \
>             --dump page-pool-get
> [{'id': 2, 'ifindex': 3},
>   {'id': 1, 'ifindex': 3, 'destroyed': 133, 'inflight': 1}]
> 
> Tested-by: Dragos Tatulea<dtatulea@nvidia.com>
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   Documentation/netlink/specs/netdev.yaml | 13 +++++++++++++
>   include/net/page_pool/types.h           |  1 +
>   include/uapi/linux/netdev.h             |  1 +
>   net/core/page_pool.c                    |  1 +
>   net/core/page_pool_priv.h               |  1 +
>   net/core/page_pool_user.c               | 12 ++++++++++++
>   6 files changed, 29 insertions(+)
> 
> diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
> index 85209e19dca9..695e0e4e0d8b 100644
> --- a/Documentation/netlink/specs/netdev.yaml
> +++ b/Documentation/netlink/specs/netdev.yaml
> @@ -125,6 +125,18 @@ name: netdev
>           type: uint
>           doc: |
>             Amount of memory held by inflight pages.
> +      -
> +        name: detach-time
> +        type: uint
> +        doc: |
> +          Seconds in CLOCK_BOOTTIME of when Page Pool was detached by
> +          the driver. Once detached Page Pool can no longer be used to
> +          allocate memory.
> +          Page Pools wait for all the memory allocated from them to be freed
> +          before truly disappearing. "Detached" Page Pools cannot be
> +          "re-attached", they are just waiting to disappear.
> +          Attribute is absent if Page Pool has not been detached, and
> +          can still be used to allocate new memory.
>   

Thanks for making the adjustments. I like the new "detach" term.

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API
  2023-11-22  3:44 ` [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API Jakub Kicinski
@ 2023-11-22  9:35   ` Eric Dumazet
  2023-11-22 14:39   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  9:35 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Expose the very basic page pool information via netlink.
>
> Example using ynl-py for a system with 9 queues:
>
> $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \
>            --dump page-pool-get
> [{'id': 19, 'ifindex': 2, 'napi-id': 147},
>  {'id': 18, 'ifindex': 2, 'napi-id': 146},
>  {'id': 17, 'ifindex': 2, 'napi-id': 145},
>  {'id': 16, 'ifindex': 2, 'napi-id': 144},
>  {'id': 15, 'ifindex': 2, 'napi-id': 143},
>  {'id': 14, 'ifindex': 2, 'napi-id': 142},
>  {'id': 13, 'ifindex': 2, 'napi-id': 141},
>  {'id': 12, 'ifindex': 2, 'napi-id': 140},
>  {'id': 11, 'ifindex': 2, 'napi-id': 139},
>  {'id': 10, 'ifindex': 2, 'napi-id': 138}]
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes
  2023-11-22  3:44 ` [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes Jakub Kicinski
@ 2023-11-22  9:44   ` Eric Dumazet
  2023-11-22 14:41   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22  9:44 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Generate netlink notifications about page pool state changes.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  Documentation/netlink/specs/netdev.yaml | 20 ++++++++++++++
>  include/uapi/linux/netdev.h             |  4 +++
>  net/core/netdev-genl-gen.c              |  1 +
>  net/core/netdev-genl-gen.h              |  1 +
>  net/core/page_pool_user.c               | 36 +++++++++++++++++++++++++
>  5 files changed, 62 insertions(+)
>

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools
  2023-11-22  3:44 ` [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools Jakub Kicinski
@ 2023-11-22 10:16   ` Eric Dumazet
  2023-11-22 16:03     ` Jakub Kicinski
  2023-11-22 15:24   ` Jesper Dangaard Brouer
  1 sibling, 1 reply; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22 10:16 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Advanced deployments need the ability to check memory use
> of various system components. It makes it possible to make informed
> decisions about memory allocation and to find regressions and leaks.
>
> Report memory use of page pools. Report both number of references
> and bytes held.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  Documentation/netlink/specs/netdev.yaml | 13 +++++++++++++
>  include/uapi/linux/netdev.h             |  2 ++
>  net/core/page_pool.c                    | 13 +++++++++----
>  net/core/page_pool_priv.h               |  2 ++
>  net/core/page_pool_user.c               |  8 ++++++++
>  5 files changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
> index 82fbe81f7a49..85209e19dca9 100644
> --- a/Documentation/netlink/specs/netdev.yaml
> +++ b/Documentation/netlink/specs/netdev.yaml
> @@ -114,6 +114,17 @@ name: netdev
>          checks:
>            min: 1
>            max: u32-max
> +      -
> +        name: inflight
> +        type: uint
> +        doc: |
> +          Number of outstanding references to this page pool (allocated
> +          but yet to be freed pages).
> +      -
> +        name: inflight-mem
> +        type: uint

4GB limit seems small, should not we make this 64bit right away ?

> +        doc: |
> +          Amount of memory held by inflight pages.
>

Thanks.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed
  2023-11-22  3:44 ` [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed Jakub Kicinski
  2023-11-22  9:02   ` Jesper Dangaard Brouer
@ 2023-11-22 10:21   ` Eric Dumazet
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22 10:21 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Report when page pool was destroyed. Together with the inflight
> / memory use reporting this can serve as a replacement for the
> warning about leaked page pools we currently print to dmesg.
>
> Example output for a fake leaked page pool using some hacks
> in netdevsim (one "live" pool, and one "leaked" on the same dev):
>
> $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \
>            --dump page-pool-get
> [{'id': 2, 'ifindex': 3},
>  {'id': 1, 'ifindex': 3, 'destroyed': 133, 'inflight': 1}]
>
> Tested-by: Dragos Tatulea <dtatulea@nvidia.com>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  Documentation/netlink/specs/netdev.yaml | 13 +++++++++++++
>  include/net/page_pool/types.h           |  1 +
>  include/uapi/linux/netdev.h             |  1 +
>  net/core/page_pool.c                    |  1 +
>  net/core/page_pool_priv.h               |  1 +
>  net/core/page_pool_user.c               | 12 ++++++++++++
>  6 files changed, 29 insertions(+)
>
> diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
> index 85209e19dca9..695e0e4e0d8b 100644
> --- a/Documentation/netlink/specs/netdev.yaml
> +++ b/Documentation/netlink/specs/netdev.yaml
> @@ -125,6 +125,18 @@ name: netdev
>          type: uint
>          doc: |
>            Amount of memory held by inflight pages.
> +      -
> +        name: detach-time
> +        type: uint
> +        doc: |
> +          Seconds in CLOCK_BOOTTIME of when Page Pool was detached by
> +          the driver. Once detached Page Pool can no longer be used to
> +          allocate memory.
> +          Page Pools wait for all the memory allocated from them to be freed
> +          before truly disappearing. "Detached" Page Pools cannot be
> +          "re-attached", they are just waiting to disappear.
> +          Attribute is absent if Page Pool has not been detached, and
> +          can still be used to allocate new memory.
>
>  operations:
>    list:
> @@ -176,6 +188,7 @@ name: netdev
>              - napi-id
>              - inflight
>              - inflight-mem
> +            - detach-time
>        dump:
>          reply: *pp-reply
>        config-cond: page-pool
> diff --git a/include/net/page_pool/types.h b/include/net/page_pool/types.h
> index 7e47d7bb2c1e..ac286ea8ce2d 100644
> --- a/include/net/page_pool/types.h
> +++ b/include/net/page_pool/types.h
> @@ -193,6 +193,7 @@ struct page_pool {
>         /* User-facing fields, protected by page_pools_lock */
>         struct {
>                 struct hlist_node list;
> +               u64 detach_time;
>                 u32 napi_id;
>                 u32 id;
>         } user;
> diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
> index 26ae5bdd3187..756410274120 100644
> --- a/include/uapi/linux/netdev.h
> +++ b/include/uapi/linux/netdev.h
> @@ -70,6 +70,7 @@ enum {
>         NETDEV_A_PAGE_POOL_NAPI_ID,
>         NETDEV_A_PAGE_POOL_INFLIGHT,
>         NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
> +       NETDEV_A_PAGE_POOL_DETACH_TIME,
>
>         __NETDEV_A_PAGE_POOL_MAX,
>         NETDEV_A_PAGE_POOL_MAX = (__NETDEV_A_PAGE_POOL_MAX - 1)
> diff --git a/net/core/page_pool.c b/net/core/page_pool.c
> index 566390759294..a821fb5fe054 100644
> --- a/net/core/page_pool.c
> +++ b/net/core/page_pool.c
> @@ -953,6 +953,7 @@ void page_pool_destroy(struct page_pool *pool)
>         if (!page_pool_release(pool))
>                 return;
>
> +       page_pool_detached(pool);
>         pool->defer_start = jiffies;
>         pool->defer_warn  = jiffies + DEFER_WARN_INTERVAL;
>
> diff --git a/net/core/page_pool_priv.h b/net/core/page_pool_priv.h
> index 72fb21ea1ddc..90665d40f1eb 100644
> --- a/net/core/page_pool_priv.h
> +++ b/net/core/page_pool_priv.h
> @@ -6,6 +6,7 @@
>  s32 page_pool_inflight(const struct page_pool *pool, bool strict);
>
>  int page_pool_list(struct page_pool *pool);
> +void page_pool_detached(struct page_pool *pool);
>  void page_pool_unlist(struct page_pool *pool);
>
>  #endif
> diff --git a/net/core/page_pool_user.c b/net/core/page_pool_user.c
> index d889b347f8f4..f28ad2179f53 100644
> --- a/net/core/page_pool_user.c
> +++ b/net/core/page_pool_user.c
> @@ -134,6 +134,10 @@ page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
>             nla_put_uint(rsp, NETDEV_A_PAGE_POOL_INFLIGHT_MEM,
>                          inflight * refsz))
>                 goto err_cancel;
> +       if (pool->user.detach_time &&
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_DETACH_TIME,

You need nla_put_u64_64bit() here

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink
  2023-11-22  3:44 ` [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink Jakub Kicinski
@ 2023-11-22 10:27   ` Eric Dumazet
  2023-11-22 15:51   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22 10:27 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> 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,
> ...
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  Documentation/netlink/specs/netdev.yaml |  78 ++++++++++++++++++
>  Documentation/networking/page_pool.rst  |  10 ++-
>  include/net/page_pool/helpers.h         |   8 +-
>  include/uapi/linux/netdev.h             |  19 +++++
>  net/core/netdev-genl-gen.c              |  32 ++++++++
>  net/core/netdev-genl-gen.h              |   7 ++
>  net/core/page_pool.c                    |   2 +-
>  net/core/page_pool_user.c               | 103 ++++++++++++++++++++++++
>  8 files changed, 250 insertions(+), 9 deletions(-)
>
> diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
> index 695e0e4e0d8b..77d991738a17 100644
> --- a/Documentation/netlink/specs/netdev.yaml
> +++ b/Documentation/netlink/specs/netdev.yaml
> @@ -137,6 +137,59 @@ name: netdev
>            "re-attached", they are just waiting to disappear.
>            Attribute is absent if Page Pool has not been detached, and
>            can still be used to allocate new memory.
> +  -
> +    name: page-pool-info
> +    subset-of: page-pool
> +    attributes:
> +      -
> +        name: id
> +      -
> +        name: ifindex
> +  -
> +    name: page-pool-stats
> +    doc: |
> +      Page pool statistics, see docs for struct page_pool_stats
> +      for information about individual statistics.
> +    attributes:
> +      -
> +        name: info
> +        doc: Page pool identifying information.
> +        type: nest
> +        nested-attributes: page-pool-info
> +      -
> +        name: alloc-fast
> +        type: uint
> +        value: 8 # reserve some attr ids in case we need more metadata later
> +      -
> +        name: alloc-slow
> +        type: uint





Same remark than before, all these fields are u64

> +      -
> +        name: alloc-slow-high-order
> +        type: uint
> +      -
> +        name: alloc-empty
> +        type: uint
> +      -
> +        name: alloc-refill
> +        type: uint
> +      -
> +        name: alloc-waive
> +        type: uint
> +      -
> +        name: recycle-cached
> +        type: uint
> +      -
> +        name: recycle-cache-full
> +        type: uint
> +      -
> +        name: recycle-ring
> +        type: uint
> +      -
> +        name: recycle-ring-full
> +        type: uint
> +      -
> +        name: recycle-released-refcnt
> +        type: uint
>
>  operations:
>    list:
> @@ -210,6 +263,31 @@ name: netdev
>        notify: page-pool-get
>        mcgrp: page-pool
>        config-cond: page-pool
> +
> +       if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST,
> +                        stats.alloc_stats.fast) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,
> +                        stats.alloc_stats.slow) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,
> +                        stats.alloc_stats.slow_high_order) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,
> +                        stats.alloc_stats.empty) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,
> +                        stats.alloc_stats.refill) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,
> +                        stats.alloc_stats.waive) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,
> +                        stats.recycle_stats.cached) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,
> +                        stats.recycle_stats.cache_full) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,
> +                        stats.recycle_stats.ring) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,
> +                        stats.recycle_stats.ring_full) ||
> +           nla_put_uint(rsp, NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,
> +                        stats.recycle_stats.released_refcnt))
> +               goto err_cancel_msg;

Therefore, we should use nla_put_u64_64bit() ?

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools
  2023-11-22  3:44 ` [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools Jakub Kicinski
@ 2023-11-22 13:53   ` Eric Dumazet
  2023-11-22 16:06   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22 13:53 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 4:44 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> Mute the periodic "stalled pool shutdown" warning if the page pool
> is visible to user space. Rolling out a driver using page pools
> to just a few hundred hosts at Meta surfaces applications which
> fail to reap their broken sockets. Obviously it's best if the
> applications are fixed, but we don't generally print warnings
> for application resource leaks. Admins can now depend on the
> netlink interface for getting page pool info to detect buggy
> apps.
>
> While at it throw in the ID of the pool into the message,
> in rare cases (pools from destroyed netns) this will make
> finding the pool with a debugger easier.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  net/core/page_pool.c | 11 +++++++----
>  1 file changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/net/core/page_pool.c b/net/core/page_pool.c
> index 3d0938a60646..c2e7c9a6efbe 100644
> --- a/net/core/page_pool.c
> +++ b/net/core/page_pool.c
> @@ -897,18 +897,21 @@ static void page_pool_release_retry(struct work_struct *wq)
>  {
>         struct delayed_work *dwq = to_delayed_work(wq);
>         struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw);
> +       void *netdev;
>         int inflight;
>
>         inflight = page_pool_release(pool);
>         if (!inflight)
>                 return;
>
> -       /* Periodic warning */
> -       if (time_after_eq(jiffies, pool->defer_warn)) {
> +       /* Periodic warning for page pools the user can't see */
> +       netdev = READ_ONCE(pool->slow.netdev);
> +       if (time_after_eq(jiffies, pool->defer_warn) &&
> +           (!netdev || netdev == NET_PTR_POISON)) {
>                 int sec = (s32)((u32)jiffies - (u32)pool->defer_start) / HZ;

Orthogonal to your patch, but this probably could avoid all these casts.

long sec = (jiffies - pool->defer_start) / HZ;


>
> -               pr_warn("%s() stalled pool shutdown %d inflight %d sec\n",
> -                       __func__, inflight, sec);
> +               pr_warn("%s() stalled pool shutdown: id %u, %d inflight %d sec\n",
> +                       __func__, pool->user.id, inflight, sec);
>                 pool->defer_warn = jiffies + DEFER_WARN_INTERVAL;
>         }
>

Reviewed-by: Eric Dumazet <edumazet@google.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 01/13] net: page_pool: factor out uninit
  2023-11-22  3:44 ` [PATCH net-next v3 01/13] net: page_pool: factor out uninit Jakub Kicinski
  2023-11-22  8:38   ` Eric Dumazet
@ 2023-11-22 14:15   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:15 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> We'll soon (next change in the series) need a fuller unwind path
> in page_pool_create() so create the inverse of page_pool_init().
> 
> Reviewed-by: Ilias Apalodimas<ilias.apalodimas@linaro.org>
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   net/core/page_pool.c | 21 +++++++++++++--------
>   1 file changed, 13 insertions(+), 8 deletions(-)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 02/13] net: page_pool: id the page pools
  2023-11-22  3:44 ` [PATCH net-next v3 02/13] net: page_pool: id the page pools Jakub Kicinski
  2023-11-22  8:40   ` Eric Dumazet
@ 2023-11-22 14:16   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:16 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> To give ourselves the flexibility of creating netlink commands
> and ability to refer to page pool instances in uAPIs create
> IDs for page pools.
> 
> Reviewed-by: Ilias Apalodimas<ilias.apalodimas@linaro.org>
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   include/net/page_pool/types.h |  4 ++++
>   net/core/Makefile             |  2 +-
>   net/core/page_pool.c          | 21 +++++++++++++++-----
>   net/core/page_pool_priv.h     |  9 +++++++++
>   net/core/page_pool_user.c     | 36 +++++++++++++++++++++++++++++++++++
>   5 files changed, 66 insertions(+), 6 deletions(-)
>   create mode 100644 net/core/page_pool_priv.h
>   create mode 100644 net/core/page_pool_user.c

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 03/13] net: page_pool: record pools per netdev
  2023-11-22  3:44 ` [PATCH net-next v3 03/13] net: page_pool: record pools per netdev Jakub Kicinski
  2023-11-22  8:55   ` Eric Dumazet
@ 2023-11-22 14:20   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:20 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> Link the page pools with netdevs. This needs to be netns compatible
> so we have two options. Either we record the pools per netns and
> have to worry about moving them as the netdev gets moved.
> Or we record them directly on the netdev so they move with the netdev
> without any extra work.
> 
> Implement the latter option. Since pools may outlast netdev we need
> a place to store orphans. In time honored tradition use loopback
> for this purpose.
> 
> Reviewed-by: Mina Almasry<almasrymina@google.com>
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
> v1: fix race between page pool and netdev disappearing (Simon)
> ---
>   include/linux/list.h          | 20 ++++++++
>   include/linux/netdevice.h     |  4 ++
>   include/linux/poison.h        |  2 +
>   include/net/page_pool/types.h |  4 ++
>   net/core/page_pool_user.c     | 90 +++++++++++++++++++++++++++++++++++
>   5 files changed, 120 insertions(+)

I like it :-)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access
  2023-11-22  3:44 ` [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access Jakub Kicinski
  2023-11-22  8:57   ` Eric Dumazet
@ 2023-11-22 14:21   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:21 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb


On 11/22/23 04:44, Jakub Kicinski wrote:
> To avoid any issues with race conditions on accessing napi
> and having to think about the lifetime of NAPI objects
> in netlink GET - stash the napi_id to which page pool
> was linked at creation time.
> 
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   include/net/page_pool/types.h | 1 +
>   net/core/page_pool_user.c     | 4 +++-
>   2 files changed, 4 insertions(+), 1 deletion(-)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers
  2023-11-22  3:44 ` [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers Jakub Kicinski
  2023-11-22  8:59   ` Eric Dumazet
@ 2023-11-22 14:22   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:22 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> Link page pool instances to netdev for the drivers which
> already link to NAPI. Unless the driver is doing something
> very weird per-NAPI should imply per-netdev.
> 
> Add netsec as well, Ilias indicates that it fits the mold.
> 
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
> v3: fix netsec build
> v2: add netsec
> ---
>   drivers/net/ethernet/broadcom/bnxt/bnxt.c         | 1 +
>   drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 +
>   drivers/net/ethernet/microsoft/mana/mana_en.c     | 1 +
>   drivers/net/ethernet/socionext/netsec.c           | 2 ++
>   4 files changed, 5 insertions(+)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools
  2023-11-22  3:44 ` [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools Jakub Kicinski
  2023-11-22  9:00   ` Eric Dumazet
@ 2023-11-22 14:24   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:24 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> Add a Netlink spec in YAML for getting very basic information
> about page pools.
> 
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   Documentation/netlink/specs/netdev.yaml | 46 +++++++++++++++++++++++++
>   1 file changed, 46 insertions(+)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API
  2023-11-22  3:44 ` [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API Jakub Kicinski
  2023-11-22  9:35   ` Eric Dumazet
@ 2023-11-22 14:39   ` Jesper Dangaard Brouer
  2023-11-22 16:00     ` Jakub Kicinski
  1 sibling, 1 reply; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:39 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> Expose the very basic page pool information via netlink.
> 
> Example using ynl-py for a system with 9 queues:
> 
> $ ./cli.py --no-schema --spec netlink/specs/netdev.yaml \
>             --dump page-pool-get
> [{'id': 19, 'ifindex': 2, 'napi-id': 147},
>   {'id': 18, 'ifindex': 2, 'napi-id': 146},
>   {'id': 17, 'ifindex': 2, 'napi-id': 145},
>   {'id': 16, 'ifindex': 2, 'napi-id': 144},
>   {'id': 15, 'ifindex': 2, 'napi-id': 143},
>   {'id': 14, 'ifindex': 2, 'napi-id': 142},
>   {'id': 13, 'ifindex': 2, 'napi-id': 141},
>   {'id': 12, 'ifindex': 2, 'napi-id': 140},
>   {'id': 11, 'ifindex': 2, 'napi-id': 139},
>   {'id': 10, 'ifindex': 2, 'napi-id': 138}]
> 
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   include/uapi/linux/netdev.h |  10 +++
>   net/core/netdev-genl-gen.c  |  27 ++++++++
>   net/core/netdev-genl-gen.h  |   3 +
>   net/core/page_pool_user.c   | 127 ++++++++++++++++++++++++++++++++++++
>   4 files changed, 167 insertions(+)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>


Can we still somehow list "detached" page_pool's with ifindex==1 
(LOOPBACK_IFINDEX) ?

page_pool_unreg_netdev() does pool->slow.netdev = lo;


 > [...]
 > +page_pool_nl_fill(struct sk_buff *rsp, const struct page_pool *pool,
 > +		  const struct genl_info *info)
 > +{
 > +	void *hdr;
 > +
 > +	hdr = genlmsg_iput(rsp, info);
 > +	if (!hdr)
 > +		return -EMSGSIZE;
 > +
 > +	if (nla_put_uint(rsp, NETDEV_A_PAGE_POOL_ID, pool->user.id))
 > +		goto err_cancel;
 > +
 > +	if (pool->slow.netdev->ifindex != LOOPBACK_IFINDEX &&
 > +	    nla_put_u32(rsp, NETDEV_A_PAGE_POOL_IFINDEX,
 > +			pool->slow.netdev->ifindex))
 > +		goto err_cancel;
 > +	if (pool->user.napi_id &&
 > +	    nla_put_uint(rsp, NETDEV_A_PAGE_POOL_NAPI_ID, pool->user.napi_id))
 > +		goto err_cancel;
 > +
 > +	genlmsg_end(rsp, hdr);
 > +
 > +	return 0;
 > +err_cancel:
 > +	genlmsg_cancel(rsp, hdr);
 > +	return -EMSGSIZE;
 > +}

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes
  2023-11-22  3:44 ` [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes Jakub Kicinski
  2023-11-22  9:44   ` Eric Dumazet
@ 2023-11-22 14:41   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 14:41 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> Generate netlink notifications about page pool state changes.
> 
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   Documentation/netlink/specs/netdev.yaml | 20 ++++++++++++++
>   include/uapi/linux/netdev.h             |  4 +++
>   net/core/netdev-genl-gen.c              |  1 +
>   net/core/netdev-genl-gen.h              |  1 +
>   net/core/page_pool_user.c               | 36 +++++++++++++++++++++++++
>   5 files changed, 62 insertions(+)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools
  2023-11-22  3:44 ` [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools Jakub Kicinski
  2023-11-22 10:16   ` Eric Dumazet
@ 2023-11-22 15:24   ` Jesper Dangaard Brouer
  2023-11-22 16:06     ` Jakub Kicinski
  1 sibling, 1 reply; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 15:24 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb



On 11/22/23 04:44, Jakub Kicinski wrote:
> Advanced deployments need the ability to check memory use
> of various system components. It makes it possible to make informed
> decisions about memory allocation and to find regressions and leaks.
> 
> Report memory use of page pools. Report both number of references
> and bytes held.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>   Documentation/netlink/specs/netdev.yaml | 13 +++++++++++++
>   include/uapi/linux/netdev.h             |  2 ++
>   net/core/page_pool.c                    | 13 +++++++++----
>   net/core/page_pool_priv.h               |  2 ++
>   net/core/page_pool_user.c               |  8 ++++++++
>   5 files changed, 34 insertions(+), 4 deletions(-)
> 

I like it, but see comment/suggestion below.

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>


> diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
> index 82fbe81f7a49..85209e19dca9 100644
> --- a/Documentation/netlink/specs/netdev.yaml
> +++ b/Documentation/netlink/specs/netdev.yaml
> @@ -114,6 +114,17 @@ name: netdev
>           checks:
>             min: 1
>             max: u32-max
> +      -
> +        name: inflight
> +        type: uint
> +        doc: |
> +          Number of outstanding references to this page pool (allocated
> +          but yet to be freed pages).

Maybe it is worth explaining in this doc that these inflight references
also cover elements in (ptr) ring (and alloc-cache) ?

In a follow up patchset, we likely also want to expose the PP ring size.
As that could be relevant when assessing inflight number.

--Jesper

> +      -
> +        name: inflight-mem
> +        type: uint
> +        doc: |
> +          Amount of memory held by inflight pages.
>   
>   operations:
>     list:
> @@ -163,6 +174,8 @@ name: netdev
>               - id
>               - ifindex
>               - napi-id
> +            - inflight
> +            - inflight-mem
>         dump:
>           reply: *pp-reply
>         config-cond: page-poo

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 03/13] net: page_pool: record pools per netdev
  2023-11-22  8:55   ` Eric Dumazet
@ 2023-11-22 15:44     ` Jakub Kicinski
  0 siblings, 0 replies; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22 15:44 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, 22 Nov 2023 09:55:34 +0100 Eric Dumazet wrote:
> > +       lo = __dev_get_by_index(dev_net(netdev), 1);  
> 
> Any reason for not using dev_net(netdev)->loopback_dev ?

Incompetence :) Will change, thanks!

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink
  2023-11-22  3:44 ` [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink Jakub Kicinski
  2023-11-22 10:27   ` Eric Dumazet
@ 2023-11-22 15:51   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 15:51 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb, kernel-team



On 11/22/23 04:44, Jakub Kicinski wrote:
> 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,
> ...
> 
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   Documentation/netlink/specs/netdev.yaml |  78 ++++++++++++++++++
>   Documentation/networking/page_pool.rst  |  10 ++-
>   include/net/page_pool/helpers.h         |   8 +-
>   include/uapi/linux/netdev.h             |  19 +++++
>   net/core/netdev-genl-gen.c              |  32 ++++++++
>   net/core/netdev-genl-gen.h              |   7 ++
>   net/core/page_pool.c                    |   2 +-
>   net/core/page_pool_user.c               | 103 ++++++++++++++++++++++++
>   8 files changed, 250 insertions(+), 9 deletions(-)

Great to get stats support.

Looking forward to get feedback from my new colleagues at Cloudflare
how to consume this into our monitoring systems :-)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API
  2023-11-22 14:39   ` Jesper Dangaard Brouer
@ 2023-11-22 16:00     ` Jakub Kicinski
  2023-11-22 16:21       ` Jesper Dangaard Brouer
  0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22 16:00 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: davem, netdev, edumazet, pabeni, almasrymina, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, 22 Nov 2023 15:39:48 +0100 Jesper Dangaard Brouer wrote:
> Can we still somehow list "detached" page_pool's with ifindex==1 
> (LOOPBACK_IFINDEX) ?

Do you mean filter at the kernel level to dump just them? Or whether
they are visible at all?

They are visible, with ifindex attribute absent.

If you mean filtering - I was considering various filters but it seems
like in "production" use we dump all the page pools, anyway. 
The detached ones need to be kept in check, obviously, but the "live"
ones also have to be monitored to make sure they don't eat up too much
memory.

The code we prepared at Meta for when this gets merged logs:
 - sum(inflight-mem), not detached
 - sum(inflight-mem), detached
 - recycling rate (similar calculation to the sample in the last patch)

It may be useful in CLI to dump all detached pools but ad-hoc CLI can
just filter in user space, doesn't have to be super efficient.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools
  2023-11-22 10:16   ` Eric Dumazet
@ 2023-11-22 16:03     ` Jakub Kicinski
  2023-11-22 16:20       ` Eric Dumazet
  0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22 16:03 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, 22 Nov 2023 11:16:48 +0100 Eric Dumazet wrote:
> > +      -
> > +        name: inflight-mem
> > +        type: uint  
> 
> 4GB limit seems small, should not we make this 64bit right away ?

Yes, uint is my magic auto-sized integer which can be either 32b or 64b
depending on the value. See commit 374d345d9b5e and 7d4caf54d2e.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools
  2023-11-22 15:24   ` Jesper Dangaard Brouer
@ 2023-11-22 16:06     ` Jakub Kicinski
  2023-11-22 16:09       ` Jesper Dangaard Brouer
  0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-22 16:06 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: davem, netdev, edumazet, pabeni, almasrymina, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, 22 Nov 2023 16:24:55 +0100 Jesper Dangaard Brouer wrote:
> > +      -
> > +        name: inflight
> > +        type: uint
> > +        doc: |
> > +          Number of outstanding references to this page pool (allocated
> > +          but yet to be freed pages).  
> 
> Maybe it is worth explaining in this doc that these inflight references
> also cover elements in (ptr) ring (and alloc-cache) ?
> 
> In a follow up patchset, we likely also want to expose the PP ring size.
> As that could be relevant when assessing inflight number.

Good point, how about:

          Number of outstanding references to this page pool (allocated
          but yet to be freed pages). Allocated pages may be held in
          socket receive queues, driver receive rings, page pool recycling
          ring, the page pool cache, etc.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools
  2023-11-22  3:44 ` [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools Jakub Kicinski
  2023-11-22 13:53   ` Eric Dumazet
@ 2023-11-22 16:06   ` Jesper Dangaard Brouer
  1 sibling, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 16:06 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb, kernel-team



On 11/22/23 04:44, Jakub Kicinski wrote:
> Mute the periodic "stalled pool shutdown" warning if the page pool
> is visible to user space. Rolling out a driver using page pools
> to just a few hundred hosts at Meta surfaces applications which
> fail to reap their broken sockets. Obviously it's best if the
> applications are fixed, but we don't generally print warnings
> for application resource leaks. Admins can now depend on the
> netlink interface for getting page pool info to detect buggy
> apps.
> 

Looking at the production logs I can unfortunately see many occurrences
of these "page_pool_release_retry() stalled pool shutdown" warnings.

Digging into this it is likely a driver (bnxt_en) issue on these older
kernels. I'll check if there is a upstream fix.

My experience from the past is that this warning have helped catch
driver related bugs.
With SKB + sockets then it is obviously a lot easier to trigger this
warning, which is why it makes sense to "mute" this.


> While at it throw in the ID of the pool into the message,
> in rare cases (pools from destroyed netns) this will make
> finding the pool with a debugger easier.
> 
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>   net/core/page_pool.c | 11 +++++++----
>   1 file changed, 7 insertions(+), 4 deletions(-)

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

> diff --git a/net/core/page_pool.c b/net/core/page_pool.c
> index 3d0938a60646..c2e7c9a6efbe 100644
> --- a/net/core/page_pool.c
> +++ b/net/core/page_pool.c
> @@ -897,18 +897,21 @@ static void page_pool_release_retry(struct work_struct *wq)
>   {
>   	struct delayed_work *dwq = to_delayed_work(wq);
>   	struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw);
> +	void *netdev;
>   	int inflight;
>   
>   	inflight = page_pool_release(pool);
>   	if (!inflight)
>   		return;
>   
> -	/* Periodic warning */
> -	if (time_after_eq(jiffies, pool->defer_warn)) {
> +	/* Periodic warning for page pools the user can't see */
> +	netdev = READ_ONCE(pool->slow.netdev);
> +	if (time_after_eq(jiffies, pool->defer_warn) &&
> +	    (!netdev || netdev == NET_PTR_POISON)) {
>   		int sec = (s32)((u32)jiffies - (u32)pool->defer_start) / HZ;
>   
> -		pr_warn("%s() stalled pool shutdown %d inflight %d sec\n",
> -			__func__, inflight, sec);
> +		pr_warn("%s() stalled pool shutdown: id %u, %d inflight %d sec\n",
> +			__func__, pool->user.id, inflight, sec);
>   		pool->defer_warn = jiffies + DEFER_WARN_INTERVAL;
>   	}
>   

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools
  2023-11-22 16:06     ` Jakub Kicinski
@ 2023-11-22 16:09       ` Jesper Dangaard Brouer
  0 siblings, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 16:09 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, almasrymina, ilias.apalodimas,
	dsahern, dtatulea, willemb



On 11/22/23 17:06, Jakub Kicinski wrote:
> On Wed, 22 Nov 2023 16:24:55 +0100 Jesper Dangaard Brouer wrote:
>>> +      -
>>> +        name: inflight
>>> +        type: uint
>>> +        doc: |
>>> +          Number of outstanding references to this page pool (allocated
>>> +          but yet to be freed pages).
>>
>> Maybe it is worth explaining in this doc that these inflight references
>> also cover elements in (ptr) ring (and alloc-cache) ?
>>
>> In a follow up patchset, we likely also want to expose the PP ring size.
>> As that could be relevant when assessing inflight number.
> 
> Good point, how about:
> 
>            Number of outstanding references to this page pool (allocated
>            but yet to be freed pages). Allocated pages may be held in
>            socket receive queues, driver receive rings, page pool recycling
>            ring, the page pool cache, etc.

Sound good to me :-) - ACK

--Jesper

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 13/13] tools: ynl: add sample for getting page-pool information
  2023-11-22  3:44 ` [PATCH net-next v3 13/13] tools: ynl: add sample for getting page-pool information Jakub Kicinski
@ 2023-11-22 16:17   ` Jesper Dangaard Brouer
  0 siblings, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 16:17 UTC (permalink / raw)
  To: Jakub Kicinski, davem
  Cc: netdev, edumazet, pabeni, almasrymina, ilias.apalodimas, dsahern,
	dtatulea, willemb, kernel-team



On 11/22/23 04:44, Jakub Kicinski wrote:
> Regenerate the tools/ code after netdev spec changes.
> 
> Add sample to query page-pool info in a concise fashion:
> 
> $ ./page-pool
>      eth0[2]	page pools: 10 (zombies: 0)
> 		refs: 41984 bytes: 171966464 (refs: 0 bytes: 0)
> 		recycling: 90.3% (alloc: 656:397681 recycle: 89652:270201)
> 
> Signed-off-by: Jakub Kicinski<kuba@kernel.org>
> ---
>   tools/include/uapi/linux/netdev.h     |  36 +++
>   tools/net/ynl/generated/netdev-user.c | 419 ++++++++++++++++++++++++++
>   tools/net/ynl/generated/netdev-user.h | 171 +++++++++++
>   tools/net/ynl/lib/ynl.h               |   2 +-
>   tools/net/ynl/samples/.gitignore      |   1 +
>   tools/net/ynl/samples/Makefile        |   2 +-
>   tools/net/ynl/samples/page-pool.c     | 147 +++++++++
>   7 files changed, 776 insertions(+), 2 deletions(-)
>   create mode 100644 tools/net/ynl/samples/page-pool.c

Nice a sample tool.

Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>

Let me provide some lore links[1][2] to this, if someone want to take a
look at extracting for their own monitoring system... ;-)

[1] 
https://lore.kernel.org/netdev/20231122034420.1158898-14-kuba@kernel.org/

[2] 
https://lore.kernel.org/netdev/20231122034420.1158898-14-kuba@kernel.org/#Z31tools:net:ynl:samples:page-pool.c

[3] 
https://lore.kernel.org/netdev/20231122034420.1158898-14-kuba@kernel.org/#Z31tools:net:ynl:generated:netdev-user.c


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools
  2023-11-22 16:03     ` Jakub Kicinski
@ 2023-11-22 16:20       ` Eric Dumazet
  0 siblings, 0 replies; 49+ messages in thread
From: Eric Dumazet @ 2023-11-22 16:20 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, pabeni, almasrymina, hawk, ilias.apalodimas,
	dsahern, dtatulea, willemb

On Wed, Nov 22, 2023 at 5:03 PM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Wed, 22 Nov 2023 11:16:48 +0100 Eric Dumazet wrote:
> > > +      -
> > > +        name: inflight-mem
> > > +        type: uint
> >
> > 4GB limit seems small, should not we make this 64bit right away ?
>
> Yes, uint is my magic auto-sized integer which can be either 32b or 64b
> depending on the value. See commit 374d345d9b5e and 7d4caf54d2e.

Ah, nice ;)

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API
  2023-11-22 16:00     ` Jakub Kicinski
@ 2023-11-22 16:21       ` Jesper Dangaard Brouer
  0 siblings, 0 replies; 49+ messages in thread
From: Jesper Dangaard Brouer @ 2023-11-22 16:21 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, almasrymina, ilias.apalodimas,
	dsahern, dtatulea, willemb, kernel-team



On 11/22/23 17:00, Jakub Kicinski wrote:
> On Wed, 22 Nov 2023 15:39:48 +0100 Jesper Dangaard Brouer wrote:
>> Can we still somehow list "detached" page_pool's with ifindex==1
>> (LOOPBACK_IFINDEX) ?
> 
> Do you mean filter at the kernel level to dump just them? Or whether
> they are visible at all?
> 

I mean if they are visible.

> They are visible, with ifindex attribute absent.
> 

Okay, I thought they would be listed with ifindex==1, but good to know.

> If you mean filtering - I was considering various filters but it seems
> like in "production" use we dump all the page pools, anyway.
> The detached ones need to be kept in check, obviously, but the "live"
> ones also have to be monitored to make sure they don't eat up too much
> memory.
> 
> The code we prepared at Meta for when this gets merged logs:
>   - sum(inflight-mem), not detached
>   - sum(inflight-mem), detached
>   - recycling rate (similar calculation to the sample in the last patch)
> 
> It may be useful in CLI to dump all detached pools but ad-hoc CLI can
> just filter in user space, doesn't have to be super efficient.

I think it will be okay to let userspace filter these.

--Jesper

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection
  2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
                   ` (12 preceding siblings ...)
  2023-11-22  3:44 ` [PATCH net-next v3 13/13] tools: ynl: add sample for getting page-pool information Jakub Kicinski
@ 2023-11-25 20:57 ` Shakeel Butt
  2023-11-26 22:43   ` Jakub Kicinski
  13 siblings, 1 reply; 49+ messages in thread
From: Shakeel Butt @ 2023-11-25 20:57 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, almasrymina, hawk,
	ilias.apalodimas, dsahern, dtatulea, willemb

On Tue, Nov 21, 2023 at 07:44:07PM -0800, Jakub Kicinski wrote:
> We recently started to deploy newer kernels / drivers at Meta,
> making significant use of page pools for the first time.
> We immediately run into page pool leaks both real and false positive
> warnings. As Eric pointed out/predicted there's no guarantee that
> applications will read / close their sockets so a page pool page
> may be stuck in a socket (but not leaked) forever. This happens
> a lot in our fleet. Most of these are obviously due to application
> bugs but we should not be printing kernel warnings due to minor
> application resource leaks.
> 
> Conversely the page pool memory may get leaked at runtime, and
> we have no way to detect / track that, unless someone reconfigures
> the NIC and destroys the page pools which leaked the pages.
> 
> The solution presented here is to expose the memory use of page
> pools via netlink. This allows for continuous monitoring of memory
> used by page pools, regardless if they were destroyed or not.
> Sample in patch 15 can print the memory use and recycling
> efficiency:
> 
> $ ./page-pool
>     eth0[2]	page pools: 10 (zombies: 0)
> 		refs: 41984 bytes: 171966464 (refs: 0 bytes: 0)
> 		recycling: 90.3% (alloc: 656:397681 recycle: 89652:270201)

Hi Jakub, I am wondering if you considered to expose these metrics
through meminfo/vmstat as well, is that a bad idea or is this/netlink
more of a preference?

thanks,
Shakeel

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection
  2023-11-25 20:57 ` [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Shakeel Butt
@ 2023-11-26 22:43   ` Jakub Kicinski
  2023-11-27  6:54     ` Shakeel Butt
  0 siblings, 1 reply; 49+ messages in thread
From: Jakub Kicinski @ 2023-11-26 22:43 UTC (permalink / raw)
  To: Shakeel Butt
  Cc: davem, netdev, edumazet, pabeni, almasrymina, hawk,
	ilias.apalodimas, dsahern, dtatulea, willemb

On Sat, 25 Nov 2023 20:57:24 +0000 Shakeel Butt wrote:
> > $ ./page-pool
> >     eth0[2]	page pools: 10 (zombies: 0)
> > 		refs: 41984 bytes: 171966464 (refs: 0 bytes: 0)
> > 		recycling: 90.3% (alloc: 656:397681 recycle: 89652:270201)  
> 
> Hi Jakub, I am wondering if you considered to expose these metrics
> through meminfo/vmstat as well, is that a bad idea or is this/netlink
> more of a preference?

If that's net-namespaced we can add the basics there. We'll still need
the netlink interface, tho, it's currently per-interface and per-queue
(simplifying a bit). But internally the recycling stats are also
per-CPU, which could be of interest at some stage.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection
  2023-11-26 22:43   ` Jakub Kicinski
@ 2023-11-27  6:54     ` Shakeel Butt
  0 siblings, 0 replies; 49+ messages in thread
From: Shakeel Butt @ 2023-11-27  6:54 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: davem, netdev, edumazet, pabeni, almasrymina, hawk,
	ilias.apalodimas, dsahern, dtatulea, willemb

On Sun, Nov 26, 2023 at 02:43:00PM -0800, Jakub Kicinski wrote:
> On Sat, 25 Nov 2023 20:57:24 +0000 Shakeel Butt wrote:
> > > $ ./page-pool
> > >     eth0[2]	page pools: 10 (zombies: 0)
> > > 		refs: 41984 bytes: 171966464 (refs: 0 bytes: 0)
> > > 		recycling: 90.3% (alloc: 656:397681 recycle: 89652:270201)  
> > 
> > Hi Jakub, I am wondering if you considered to expose these metrics
> > through meminfo/vmstat as well, is that a bad idea or is this/netlink
> > more of a preference?
> 
> If that's net-namespaced we can add the basics there. We'll still need
> the netlink interface, tho, it's currently per-interface and per-queue
> (simplifying a bit). But internally the recycling stats are also
> per-CPU, which could be of interest at some stage.

Not really net-namespaced but rather system level stats in those
interfaces. Anyways if having system level makes sense then these stats
can be added later.

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2023-11-27  6:54 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-22  3:44 [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Jakub Kicinski
2023-11-22  3:44 ` [PATCH net-next v3 01/13] net: page_pool: factor out uninit Jakub Kicinski
2023-11-22  8:38   ` Eric Dumazet
2023-11-22 14:15   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 02/13] net: page_pool: id the page pools Jakub Kicinski
2023-11-22  8:40   ` Eric Dumazet
2023-11-22 14:16   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 03/13] net: page_pool: record pools per netdev Jakub Kicinski
2023-11-22  8:55   ` Eric Dumazet
2023-11-22 15:44     ` Jakub Kicinski
2023-11-22 14:20   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 04/13] net: page_pool: stash the NAPI ID for easier access Jakub Kicinski
2023-11-22  8:57   ` Eric Dumazet
2023-11-22 14:21   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 05/13] eth: link netdev to page_pools in drivers Jakub Kicinski
2023-11-22  8:59   ` Eric Dumazet
2023-11-22 14:22   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 06/13] net: page_pool: add nlspec for basic access to page pools Jakub Kicinski
2023-11-22  9:00   ` Eric Dumazet
2023-11-22 14:24   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 07/13] net: page_pool: implement GET in the netlink API Jakub Kicinski
2023-11-22  9:35   ` Eric Dumazet
2023-11-22 14:39   ` Jesper Dangaard Brouer
2023-11-22 16:00     ` Jakub Kicinski
2023-11-22 16:21       ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 08/13] net: page_pool: add netlink notifications for state changes Jakub Kicinski
2023-11-22  9:44   ` Eric Dumazet
2023-11-22 14:41   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 09/13] net: page_pool: report amount of memory held by page pools Jakub Kicinski
2023-11-22 10:16   ` Eric Dumazet
2023-11-22 16:03     ` Jakub Kicinski
2023-11-22 16:20       ` Eric Dumazet
2023-11-22 15:24   ` Jesper Dangaard Brouer
2023-11-22 16:06     ` Jakub Kicinski
2023-11-22 16:09       ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 10/13] net: page_pool: report when page pool was destroyed Jakub Kicinski
2023-11-22  9:02   ` Jesper Dangaard Brouer
2023-11-22 10:21   ` Eric Dumazet
2023-11-22  3:44 ` [PATCH net-next v3 11/13] net: page_pool: expose page pool stats via netlink Jakub Kicinski
2023-11-22 10:27   ` Eric Dumazet
2023-11-22 15:51   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 12/13] net: page_pool: mute the periodic warning for visible page pools Jakub Kicinski
2023-11-22 13:53   ` Eric Dumazet
2023-11-22 16:06   ` Jesper Dangaard Brouer
2023-11-22  3:44 ` [PATCH net-next v3 13/13] tools: ynl: add sample for getting page-pool information Jakub Kicinski
2023-11-22 16:17   ` Jesper Dangaard Brouer
2023-11-25 20:57 ` [PATCH net-next v3 00/13] net: page_pool: add netlink-based introspection Shakeel Butt
2023-11-26 22:43   ` Jakub Kicinski
2023-11-27  6:54     ` Shakeel Butt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).