From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:09
As the page pool functionality grows we will be increasingly
constrained by the lack of any uAPI. This series is a first
step towards such a uAPI, it creates a way for users to query
information about page pools and associated statistics.
I'm purposefully exposing only the information which I'd
find useful when monitoring production workloads.
For the SET part (which to be clear isn't addressed by this
series at all) I think we'll need to turn to something more
along the lines of "netdev-level policy". Instead of configuring
page pools, which are somewhat ephemeral, and hard to change
at runtime, we should set the "expected page pool parameters"
at the netdev level, and have the driver consult those when
instantiating pools. My ramblings from yesterday about Queue API
may make this more or less clear...
https://lore.kernel.org/all/20230815171638.4c057dcd@kernel.org/
Jakub Kicinski (13):
net: page_pool: split the page_pool_params into fast and slow
net: page_pool: avoid touching slow on the fastpath
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 pp
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 when page pool was destroyed
net: page_pool: expose page pool stats via netlink
tools: netdev: regen after page pool changes
Documentation/netlink/specs/netdev.yaml | 158 +++++++
Documentation/networking/page_pool.rst | 5 +-
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 +
include/linux/list.h | 20 +
include/linux/netdevice.h | 4 +
include/net/page_pool/helpers.h | 8 +-
include/net/page_pool/types.h | 43 +-
include/uapi/linux/netdev.h | 37 ++
net/core/Makefile | 2 +-
net/core/netdev-genl-gen.c | 41 ++
net/core/netdev-genl-gen.h | 11 +
net/core/page_pool.c | 56 ++-
net/core/page_pool_priv.h | 12 +
net/core/page_pool_user.c | 409 +++++++++++++++++
tools/include/uapi/linux/netdev.h | 37 ++
tools/net/ynl/generated/netdev-user.c | 415 ++++++++++++++++++
tools/net/ynl/generated/netdev-user.h | 169 +++++++
19 files changed, 1391 insertions(+), 39 deletions(-)
create mode 100644 net/core/page_pool_priv.h
create mode 100644 net/core/page_pool_user.c
--
2.41.0
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:09
struct page_pool is rather performance critical and we use
16B of the first cache line to store 2 pointers used only
by test code. Future patches will add more informational
(non-fast path) attributes.
It's convenient for the user of the API to not have to worry
which fields are fast and which are slow path. Use struct
groups to split the params into the two categories internally.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
include/net/page_pool/types.h | 31 +++++++++++++++++++------------
net/core/page_pool.c | 7 ++++---
2 files changed, 23 insertions(+), 15 deletions(-)
@@ -56,18 +56,22 @@ struct pp_alloc_cache {*@offset:DMAsyncaddressoffsetforPP_FLAG_DMA_SYNC_DEV*/structpage_pool_params{-unsignedintflags;-unsignedintorder;-unsignedintpool_size;-intnid;-structdevice*dev;-structnapi_struct*napi;-enumdma_data_directiondma_dir;-unsignedintmax_len;-unsignedintoffset;+struct_group_tagged(page_pool_params_fast,fast,+unsignedintflags;+unsignedintorder;+unsignedintpool_size;+intnid;+structdevice*dev;+structnapi_struct*napi;+enumdma_data_directiondma_dir;+unsignedintmax_len;+unsignedintoffset;+);+struct_group_tagged(page_pool_params_slow,slow,/* private: used by test code only */-void(*init_callback)(structpage*page,void*arg);-void*init_arg;+void(*init_callback)(structpage*page,void*arg);+void*init_arg;+);};#ifdef CONFIG_PAGE_POOL_STATS
@@ -173,7 +173,8 @@ static int page_pool_init(struct page_pool *pool,{unsignedintring_qsize=1024;/* Default */-memcpy(&pool->p,params,sizeof(pool->p));+memcpy(&pool->p,¶ms->fast,sizeof(pool->p));+memcpy(&pool->slow,¶ms->slow,sizeof(pool->slow));/* Validate only known flags were used */if(pool->p.flags&~(PP_FLAG_ALL))
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:10
To fully benefit from previous commit add one byte of state
in the first cache line recording if we need to look at
the slow part.
The packing isn't all that impressive right now, we create
a 7B hole. I'm expecting Olek's rework will reshuffle this,
anyway.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
include/net/page_pool/types.h | 2 ++
net/core/page_pool.c | 4 +++-
2 files changed, 5 insertions(+), 1 deletion(-)
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:11
We'll soon need a fuller unwind path in page_pool_create()
so create the inverse of page_pool_init().
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
net/core/page_pool.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
@@ -264,13 +266,21 @@ struct page_pool *page_pool_create(const struct page_pool_params *params)returnERR_PTR(-ENOMEM);err=page_pool_init(pool,params);-if(err<0){-pr_warn("%s() gave up with errno %d\n",__func__,err);-kfree(pool);-returnERR_PTR(err);-}+if(err<0)+gotoerr_free;++err=page_pool_list(pool);+if(err)+gotoerr_uninit;returnpool;++err_uninit:+page_pool_uninit(pool);+err_free:+pr_warn("%s() gave up with errno %d\n",__func__,err);+kfree(pool);+returnERR_PTR(err);}EXPORT_SYMBOL(page_pool_create);
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:12
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.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
include/linux/list.h | 20 ++++++++
include/linux/netdevice.h | 4 ++
include/net/page_pool/types.h | 4 ++
net/core/page_pool_user.c | 86 +++++++++++++++++++++++++++++++++++
4 files changed, 114 insertions(+)
@@ -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
@@ -68,6 +70,7 @@ struct page_pool_params {unsignedintoffset;);struct_group_tagged(page_pool_params_slow,slow,+structnet_device*netdev;/* private: used by test code only */void(*init_callback)(structpage*page,void*arg);void*init_arg;
@@ -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"staticDEFINE_XARRAY_FLAGS(page_pools,XA_FLAGS_ALLOC1);+/* Protects: page_pools, netdevice->page_pools, pool->slow.netdev, pool->user.+*Ordering:insidertnl_lock+*/staticDEFINE_MUTEX(page_pools_lock);+/* Page pools are only reachable from user space (via netlink) if they are+*linkedtoanetdevatcreationtime.Followingpagepool"visibility"+*statesarepossible:+*-normal+*-user.list:linkedtorealnetdev,netdev:realnetdev+*-orphaned-realnetdevhasdisappeared+*-user.list:linkedtolo,netdev:lo+*-invisible-either(a)createdwithoutnetdevlinking,(b)unlisteddue+*toerror,or(c)theentirenamespacewhichownedthispooldisappeared+*-user.list:unhashed,netdev:unknown+*/+intpage_pool_list(structpage_pool*pool){staticu32id_alloc_next;
@@ -20,6 +37,10 @@ int page_pool_list(struct page_pool *pool)if(err<0)gotoerr_unlock;+if(pool->slow.netdev)+hlist_add_head(&pool->user.list,+&pool->slow.netdev->page_pools);+mutex_unlock(&page_pools_lock);return0;
@@ -32,5 +53,70 @@ 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);}++staticvoidpage_pool_unreg_netdev_wipe(structnet_device*netdev)+{+structhlist_node*c,*n;++mutex_lock(&page_pools_lock);+hlist_for_each_safe(c,n,&netdev->page_pools)+hlist_del_init(c);+mutex_unlock(&page_pools_lock);+}++staticvoidpage_pool_unreg_netdev(structnet_device*netdev)+{+structpage_pool*pool,*last;+structnet_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);+hlist_for_each_entry(pool,&netdev->page_pools,user.list){+pool->slow.netdev=lo;+last=pool;+}++hlist_splice_init(&netdev->page_pools,&last->user.list,+&lo->page_pools);+mutex_unlock(&page_pools_lock);+}++staticint+page_pool_netdevice_event(structnotifier_block*nb,+unsignedlongevent,void*ptr)+{+structnet_device*netdev=netdev_notifier_info_to_dev(ptr);++if(event!=NETDEV_UNREGISTER)+returnNOTIFY_DONE;++if(hlist_empty(&netdev->page_pools))+returnNOTIFY_OK;++if(netdev->ifindex!=1)+page_pool_unreg_netdev(netdev);+else+page_pool_unreg_netdev_wipe(netdev);+returnNOTIFY_OK;+}++staticstructnotifier_blockpage_pool_netdevice_nb={+.notifier_call=page_pool_netdevice_event,+};++staticint__initpage_pool_user_init(void)+{+returnregister_netdevice_notifier(&page_pool_netdevice_nb);+}++subsys_initcall(page_pool_user_init);
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:12
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(-)
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:13
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.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
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 +
3 files changed, 3 insertions(+)
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:14
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 | 41 +++++++++++++++++++++++++
1 file changed, 41 insertions(+)
@@ -68,6 +68,30 @@ name: netdevtype:u32checks:min:1+-+name:page-pool+attributes:+-+name:id+doc:Unique ID of a Page Pool instance.+type:u32+checks:+min:1+-+name:pad+type:pad+-+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+-+name:napi-id+doc:Id of NAPI using this Page Pool instance.+type:u32operations:list:
@@ -101,6 +125,23 @@ name: netdevdoc:Notification about device configuration being changed.notify:dev-getmcgrp: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-replymcast-groups:list:
@@ -142,8 +142,25 @@ name: netdev-napi-iddump:reply:*pp-reply+-+name:page-pool-add-ntf+doc:Notification about page pool appearing.+notify:page-pool-get+mcgrp:page-pool+-+name:page-pool-del-ntf+doc:Notification about page pool disappearing.+notify:page-pool-get+mcgrp:page-pool+-+name:page-pool-change-ntf+doc:Notification about page pool configuration being changed.+notify:page-pool-get+mcgrp:page-poolmcast-groups:list:-name:mgmt+-+name:page-pool
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-16 23:43:16
Report when page pool was destroyed and number of inflight
references. This allows user to proactively check for dead
page pools without waiting to see if errors messages will
be printed in dmesg.
Only provide inflight for pools which were already "destroyed".
inflight information could also be interesting for "live"
pools but we don't want to have to deal with the potential
negative values due to races.
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}]
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
Documentation/netlink/specs/netdev.yaml | 16 ++++++++++++++++
include/net/page_pool/types.h | 1 +
include/uapi/linux/netdev.h | 2 ++
net/core/page_pool.c | 3 ++-
net/core/page_pool_priv.h | 3 +++
net/core/page_pool_user.c | 16 ++++++++++++++++
6 files changed, 40 insertions(+), 1 deletion(-)
@@ -92,6 +92,20 @@ name: netdevname:napi-iddoc:Id of NAPI using this Page Pool instance.type:u32+-+name:destroyed+type:u64+doc:|+Seconds in CLOCK_BOOTTIME of when Page Pool was destroyed.+Page Pools wait for all the memory allocated from them to be freed+before truly disappearing.+Absent if Page Pool hasn't been destroyed.+-+name:inflight+type:u32+doc:|+Number of outstanding references to this page pool (allocated+but yet to be freed pages).operations:list:
@@ -106,6 +106,66 @@ name: netdevdoc:|Number of outstanding references to this page pool (allocatedbut yet to be freed pages).+-+name:page-pool-info+subset-of:page-pool+attributes:+-+name:id+type:u32+checks:+min:1+-+name:ifindex+type:u32+-+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:pad+type:pad+-+name:alloc-fast+type:u64+value:8# reserve some attr ids in case we need more metadata later+-+name:alloc-slow+type:u64+-+name:alloc-slow-high-order+type:u64+-+name:alloc-empty+type:u64+-+name:alloc-refill+type:u64+-+name:alloc-waive+type:u64+-+name:recycle-cached+type:u64+-+name:recycle-cache-full+type:u64+-+name:recycle-ring+type:u64+-+name:recycle-ring-full+type:u64+-+name:recycle-released-refcnt+type:u64operations:list:
@@ -173,6 +233,30 @@ name: netdevdoc:Notification about page pool configuration being changed.notify:page-pool-getmcgrp: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-replymcast-groups:list:
@@ -105,8 +105,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
@@ -106,6 +107,111 @@ netdev_nl_page_pool_get_dump(struct sk_buff *skb, struct netlink_callback *cb,returnerr;}+staticint+page_pool_nl_stats_fill(structsk_buff*rsp,conststructpage_pool*pool,+conststructgenl_info*info)+{+#ifdef CONFIG_PAGE_POOL_STATS+constu32pad=NETDEV_A_PAGE_POOL_STATS_PAD;+structpage_pool_statsstats={};+structnlattr*nest;+void*hdr;++if(!page_pool_get_stats(pool,&stats))+return0;++hdr=genlmsg_iput(rsp,info);+if(!hdr)+return-EMSGSIZE;++nest=nla_nest_start(rsp,NETDEV_A_PAGE_POOL_STATS_INFO);++if(nla_put_u32(rsp,NETDEV_A_PAGE_POOL_ID,pool->user.id)||+(pool->slow.netdev->ifindex!=1&&+nla_put_u32(rsp,NETDEV_A_PAGE_POOL_IFINDEX,+pool->slow.netdev->ifindex)))+gotoerr_cancel_nest;++nla_nest_end(rsp,nest);++if(nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_ALLOC_FAST,+stats.alloc_stats.fast,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW,+stats.alloc_stats.slow,pad)||+nla_put_u64_64bit(rsp,+NETDEV_A_PAGE_POOL_STATS_ALLOC_SLOW_HIGH_ORDER,+stats.alloc_stats.slow_high_order,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_ALLOC_EMPTY,+stats.alloc_stats.empty,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_ALLOC_REFILL,+stats.alloc_stats.refill,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_ALLOC_WAIVE,+stats.alloc_stats.waive,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHED,+stats.recycle_stats.cached,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_RECYCLE_CACHE_FULL,+stats.recycle_stats.cache_full,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING,+stats.recycle_stats.ring,pad)||+nla_put_u64_64bit(rsp,NETDEV_A_PAGE_POOL_STATS_RECYCLE_RING_FULL,+stats.recycle_stats.ring_full,pad)||+nla_put_u64_64bit(rsp,+NETDEV_A_PAGE_POOL_STATS_RECYCLE_RELEASED_REFCNT,+stats.recycle_stats.released_refcnt,pad))+gotoerr_cancel_msg;++genlmsg_end(rsp,hdr);++return0;+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+}++intnetdev_nl_page_pool_stats_get_doit(structsk_buff*skb,+structgenl_info*info)+{+structnlattr*tb[ARRAY_SIZE(netdev_page_pool_info_nl_policy)];+structnlattr*nest;+interr;+u32id;++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)+returnerr;++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_u32(tb[NETDEV_A_PAGE_POOL_ID]);++returnnetdev_nl_page_pool_get_do(info,id,page_pool_nl_stats_fill);+}++intnetdev_nl_page_pool_stats_get_dumpit(structsk_buff*skb,+structnetlink_callback*cb)+{+returnnetdev_nl_page_pool_get_dump(skb,cb,page_pool_nl_stats_fill);+}+staticintpage_pool_nl_fill(structsk_buff*rsp,conststructpage_pool*pool,conststructgenl_info*info)
From: Simon Horman <horms@kernel.org> Date: 2023-08-17 07:26:13
On Wed, Aug 16, 2023 at 04:42:54PM -0700, 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.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
I am not sure I am following the reasoning here. The only extra thing
page_pool_free() does is disconnect the pool. So I assume no one will
call page_pool_uninit() directly. Do you expect page_pool_free() to
grow in the future, so factoring out the uninit makes the code easier
to read?
Thanks
/Ilias
quoted hunk
+
/**
* page_pool_create() - create a page pool.
* @params: parameters, see struct page_pool_params
struct page_pool is rather performance critical and we use
16B of the first cache line to store 2 pointers used only
by test code. Future patches will add more informational
(non-fast path) attributes.
It's convenient for the user of the API to not have to worry
which fields are fast and which are slow path. Use struct
groups to split the params into the two categories internally.
Signed-off-by: Jakub Kicinski<kuba@kernel.org>
---
include/net/page_pool/types.h | 31 +++++++++++++++++++------------
net/core/page_pool.c | 7 ++++---
2 files changed, 23 insertions(+), 15 deletions(-)
With changes in 2/13 where you add a bool to avoid accessing "slow":
Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>
To fully benefit from previous commit add one byte of state
in the first cache line recording if we need to look at
the slow part.
The packing isn't all that impressive right now, we create
a 7B hole. I'm expecting Olek's rework will reshuffle this,
anyway.
Signed-off-by: Jakub Kicinski<kuba@kernel.org>
---
include/net/page_pool/types.h | 2 ++
net/core/page_pool.c | 4 +++-
2 files changed, 5 insertions(+), 1 deletion(-)
As followup to 1/13 LGTM
Acked-by: Jesper Dangaard Brouer <hawk@kernel.org>
Hi Jakub,
On Thu, 17 Aug 2023 at 02:43, Jakub Kicinski [off-list ref] wrote:
struct page_pool is rather performance critical and we use
16B of the first cache line to store 2 pointers used only
by test code. Future patches will add more informational
(non-fast path) attributes.
It's convenient for the user of the API to not have to worry
which fields are fast and which are slow path. Use struct
groups to split the params into the two categories internally.
LGTM and valuable, since we've been struggling to explain where new
variables should be placed, in order to affect the cache line
placement as little as possible.
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
@@ -56,18 +56,22 @@ struct pp_alloc_cache {*@offset:DMAsyncaddressoffsetforPP_FLAG_DMA_SYNC_DEV*/structpage_pool_params{-unsignedintflags;-unsignedintorder;-unsignedintpool_size;-intnid;-structdevice*dev;-structnapi_struct*napi;-enumdma_data_directiondma_dir;-unsignedintmax_len;-unsignedintoffset;+struct_group_tagged(page_pool_params_fast,fast,+unsignedintflags;+unsignedintorder;+unsignedintpool_size;+intnid;+structdevice*dev;+structnapi_struct*napi;+enumdma_data_directiondma_dir;+unsignedintmax_len;+unsignedintoffset;+);+struct_group_tagged(page_pool_params_slow,slow,/* private: used by test code only */-void(*init_callback)(structpage*page,void*arg);-void*init_arg;+void(*init_callback)(structpage*page,void*arg);+void*init_arg;+);};#ifdef CONFIG_PAGE_POOL_STATS
@@ -173,7 +173,8 @@ static int page_pool_init(struct page_pool *pool,{unsignedintring_qsize=1024;/* Default */-memcpy(&pool->p,params,sizeof(pool->p));+memcpy(&pool->p,¶ms->fast,sizeof(pool->p));+memcpy(&pool->slow,¶ms->slow,sizeof(pool->slow));/* Validate only known flags were used */if(pool->p.flags&~(PP_FLAG_ALL))
On Thu, 17 Aug 2023 at 02:43, Jakub Kicinski [off-list ref] wrote:
quoted hunk
To fully benefit from previous commit add one byte of state
in the first cache line recording if we need to look at
the slow part.
The packing isn't all that impressive right now, we create
a 7B hole. I'm expecting Olek's rework will reshuffle this,
anyway.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
include/net/page_pool/types.h | 2 ++
net/core/page_pool.c | 4 +++-
2 files changed, 5 insertions(+), 1 deletion(-)
I am not sure I am following the reasoning here. The only extra thing
page_pool_free() does is disconnect the pool. So I assume no one will
call page_pool_uninit() directly. Do you expect page_pool_free() to
grow in the future, so factoring out the uninit makes the code easier
to read?
I'm calling it from the unwind patch of page_pool_create() in the next
patch, because I'm adding another setup state after page_pool_init().
I can't put the free into _uninit() because on the unwind path of
_create() that's an individual step.
I am not sure I am following the reasoning here. The only extra thing
page_pool_free() does is disconnect the pool. So I assume no one will
call page_pool_uninit() directly. Do you expect page_pool_free() to
grow in the future, so factoring out the uninit makes the code easier
to read?
I'm calling it from the unwind patch of page_pool_create() in the next
patch, because I'm adding another setup state after page_pool_init().
I can't put the free into _uninit() because on the unwind path of
_create() that's an individual step.
Yea fair enough, I went through that patch a few minutes ago, so this
one makes sense
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
From: Mina Almasry <hidden> Date: 2023-08-17 21:21:40
On Wed, Aug 16, 2023 at 4:43 PM Jakub Kicinski [off-list ref] wrote:
As the page pool functionality grows we will be increasingly
constrained by the lack of any uAPI. This series is a first
step towards such a uAPI, it creates a way for users to query
information about page pools and associated statistics.
I'm purposefully exposing only the information which I'd
find useful when monitoring production workloads.
For the SET part (which to be clear isn't addressed by this
series at all) I think we'll need to turn to something more
along the lines of "netdev-level policy". Instead of configuring
page pools, which are somewhat ephemeral, and hard to change
at runtime, we should set the "expected page pool parameters"
at the netdev level, and have the driver consult those when
instantiating pools. My ramblings from yesterday about Queue API
may make this more or less clear...
https://lore.kernel.org/all/20230815171638.4c057dcd@kernel.org/
The patches themselves look good to me, and I'll provide Reviewed-by
for the ones I feel I understand well enough to review, but I'm a bit
unsure about exposing specifically page_pool stats to the user. Isn't
it better to expose rx-queue stats (slightly more generic) to the
user? In my mind, the advantages:
- we could implement better SET apis that allocate, delete, or
reconfigure rx-queues. APIs that allocate or delete page-pool make
less sense semantically maybe? The page-pool doesn't decide to
instantiate itself.
- The api can be extended for non-page-pool stats (per rx-queue
dropped packets maybe, or something like that).
- The api maybe can be extended to non-page-pool drivers. The driver
may be able to implement their own function to provide equivalent
stats (although this one may not be that important).
- rx-queue GET API fits in nicely with what you described yesterday
[1]. At the moment I'm a bit unsure because the SET api you described
yesterday sounded per-rx-queue to me. But the GET api here is
per-page-pool based. Maybe the distinction doesn't matter? Maybe
you're thinking they're unrelated APIs?
[1] https://lore.kernel.org/all/20230815171638.4c057dcd@kernel.org/
Jakub Kicinski (13):
net: page_pool: split the page_pool_params into fast and slow
net: page_pool: avoid touching slow on the fastpath
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 pp
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 when page pool was destroyed
net: page_pool: expose page pool stats via netlink
tools: netdev: regen after page pool changes
Documentation/netlink/specs/netdev.yaml | 158 +++++++
Documentation/networking/page_pool.rst | 5 +-
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 +
include/linux/list.h | 20 +
include/linux/netdevice.h | 4 +
include/net/page_pool/helpers.h | 8 +-
include/net/page_pool/types.h | 43 +-
include/uapi/linux/netdev.h | 37 ++
net/core/Makefile | 2 +-
net/core/netdev-genl-gen.c | 41 ++
net/core/netdev-genl-gen.h | 11 +
net/core/page_pool.c | 56 ++-
net/core/page_pool_priv.h | 12 +
net/core/page_pool_user.c | 409 +++++++++++++++++
tools/include/uapi/linux/netdev.h | 37 ++
tools/net/ynl/generated/netdev-user.c | 415 ++++++++++++++++++
tools/net/ynl/generated/netdev-user.h | 169 +++++++
19 files changed, 1391 insertions(+), 39 deletions(-)
create mode 100644 net/core/page_pool_priv.h
create mode 100644 net/core/page_pool_user.c
--
2.41.0
From: Mina Almasry <hidden> Date: 2023-08-17 21:29:06
On Wed, Aug 16, 2023 at 4:43 PM Jakub Kicinski [off-list ref] wrote:
struct page_pool is rather performance critical and we use
16B of the first cache line to store 2 pointers used only
by test code. Future patches will add more informational
(non-fast path) attributes.
It's convenient for the user of the API to not have to worry
which fields are fast and which are slow path. Use struct
groups to split the params into the two categories internally.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
@@ -56,18 +56,22 @@ struct pp_alloc_cache {*@offset:DMAsyncaddressoffsetforPP_FLAG_DMA_SYNC_DEV*/structpage_pool_params{-unsignedintflags;-unsignedintorder;-unsignedintpool_size;-intnid;-structdevice*dev;-structnapi_struct*napi;-enumdma_data_directiondma_dir;-unsignedintmax_len;-unsignedintoffset;+struct_group_tagged(page_pool_params_fast,fast,+unsignedintflags;+unsignedintorder;+unsignedintpool_size;+intnid;+structdevice*dev;+structnapi_struct*napi;+enumdma_data_directiondma_dir;+unsignedintmax_len;+unsignedintoffset;+);+struct_group_tagged(page_pool_params_slow,slow,/* private: used by test code only */-void(*init_callback)(structpage*page,void*arg);-void*init_arg;+void(*init_callback)(structpage*page,void*arg);+void*init_arg;+);};#ifdef CONFIG_PAGE_POOL_STATS
@@ -173,7 +173,8 @@ static int page_pool_init(struct page_pool *pool,{unsignedintring_qsize=1024;/* Default */-memcpy(&pool->p,params,sizeof(pool->p));+memcpy(&pool->p,¶ms->fast,sizeof(pool->p));+memcpy(&pool->slow,¶ms->slow,sizeof(pool->slow));/* Validate only known flags were used */if(pool->p.flags&~(PP_FLAG_ALL))
From: Mina Almasry <hidden> Date: 2023-08-17 21:31:59
On Wed, Aug 16, 2023 at 4:43 PM Jakub Kicinski [off-list ref] wrote:
quoted hunk
To fully benefit from previous commit add one byte of state
in the first cache line recording if we need to look at
the slow part.
The packing isn't all that impressive right now, we create
a 7B hole. I'm expecting Olek's rework will reshuffle this,
anyway.
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
include/net/page_pool/types.h | 2 ++
net/core/page_pool.c | 4 +++-
2 files changed, 5 insertions(+), 1 deletion(-)
Nit: I wonder if it's slightly more appropriate for this to be
has_slow, given how I understand the intent of usage, but it doesn't
really matter. Either way,:
Reviewed-by: Mina Almasry <redacted>
quoted hunk
long frag_users;
struct page *frag_page;
unsigned int frag_offset;
From: Mina Almasry <hidden> Date: 2023-08-17 21:56:28
On Wed, Aug 16, 2023 at 4:43 PM Jakub Kicinski [off-list ref] 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.
Sorry maybe I'm missing something, but it's a bit curious to me that
this ID is needed. An rx queue can only ever have 1 page-pool
associated with it at a time, right? Could you instead add a pointer
to the page_pool into 'struct netdev_rx_queue', and then page-pool can
be referred to by the netdev id & the rx-queue number? Wouldn't that
make the implementation much simpler? I also believe the userspace
refers to the rx-queue by its index number for the ethtool APIs like
adding flow steering rules, so extending that to here maybe makes
sense.
@@ -264,13 +266,21 @@ struct page_pool *page_pool_create(const struct page_pool_params *params)returnERR_PTR(-ENOMEM);err=page_pool_init(pool,params);-if(err<0){-pr_warn("%s() gave up with errno %d\n",__func__,err);-kfree(pool);-returnERR_PTR(err);-}+if(err<0)+gotoerr_free;++err=page_pool_list(pool);+if(err)+gotoerr_uninit;returnpool;++err_uninit:+page_pool_uninit(pool);+err_free:+pr_warn("%s() gave up with errno %d\n",__func__,err);+kfree(pool);+returnERR_PTR(err);}EXPORT_SYMBOL(page_pool_create);
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-18 00:08:49
On Thu, 17 Aug 2023 14:56:01 -0700 Mina Almasry wrote:
Sorry maybe I'm missing something, but it's a bit curious to me that
this ID is needed.
Right.. now I realize that I haven't explained the queue side.
I expect a similar API will be added to dump queue info, and then page
pool ID will be added to the queue object, to link which queue is being
fed from which page pool. I guess I should have said that in the cover
letter...
An rx queue can only ever have 1 page-pool
associated with it at a time, right? Could you instead add a pointer
to the page_pool into 'struct netdev_rx_queue',
100% my intention, which is why I moved the location of that struct
recently :)
and then page-pool can be referred to by the netdev id & the rx-queue
number?
And use/type (headers vs payloads). And then nothing stops a driver from
using one page pool for multiple queues of the same type within a NAPI.
And then the page pools can die and linger (see patch 11).
Wouldn't that make the implementation much simpler? I also believe
the userspace refers to the rx-queue by its index number for the
ethtool APIs like adding flow steering rules, so extending that to
here maybe makes sense.
From: Jakub Kicinski <kuba@kernel.org> Date: 2023-08-18 00:13:05
On Thu, 17 Aug 2023 14:21:26 -0700 Mina Almasry wrote:
- rx-queue GET API fits in nicely with what you described yesterday
[1]. At the moment I'm a bit unsure because the SET api you described
yesterday sounded per-rx-queue to me. But the GET api here is
per-page-pool based. Maybe the distinction doesn't matter? Maybe
you're thinking they're unrelated APIs?
Right, they aren't unrelated but I do somehow prefer the more flexible
model where each object type has its own API and the objects can refer
to each other.
I think there's too much of a risk that the mapping between page pools
to queues will become n:m and then having them tied together will be
a problem.