* [PATCH net-next V5 08/12] selftest: netdevsim: Add devlink port resource doit test
From: Tariq Toukan @ 2026-04-07 19:41 UTC (permalink / raw)
To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller
Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Shuah Khan, Matthieu Baerts (NGI0), Chuck Lever,
Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
Daniel Zahka, Shahar Shitrit, Cosmin Ratiu, Jacob Keller,
Parav Pandit, Adithya Jayachandran, Shay Drori, Kees Cook,
Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
linux-kselftest, Gal Pressman
In-Reply-To: <20260407194107.148063-1-tariqt@nvidia.com>
From: Or Har-Toov <ohartoov@nvidia.com>
Tests that querying a specific port handle returns the expected
resource name and size.
Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../drivers/net/netdevsim/devlink.sh | 29 ++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
index 1b529ccaf050..31d1cef54898 100755
--- a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
+++ b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
@@ -5,7 +5,8 @@ lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="fw_flash_test params_test \
params_default_test regions_test reload_test \
- netns_reload_test resource_test dev_info_test \
+ netns_reload_test resource_test \
+ port_resource_doit_test dev_info_test \
empty_reporter_test dummy_reporter_test rate_test"
NUM_NETIFS=0
source $lib_dir/lib.sh
@@ -768,6 +769,32 @@ rate_node_del()
devlink port function rate del $handle
}
+port_resource_doit_test()
+{
+ RET=0
+
+ local port_handle="${DL_HANDLE}/0"
+ local name
+ local size
+
+ if ! devlink resource help 2>&1 | grep -q "PORT_INDEX"; then
+ echo "SKIP: devlink resource show with port not supported"
+ return
+ fi
+
+ name=$(cmd_jq "devlink resource show $port_handle -j" \
+ '.[][][].name')
+ [ "$name" == "test_resource" ]
+ check_err $? "wrong port resource name (got $name)"
+
+ size=$(cmd_jq "devlink resource show $port_handle -j" \
+ '.[][][].size')
+ [ "$size" == "20" ]
+ check_err $? "wrong port resource size (got $size)"
+
+ log_test "port resource doit test"
+}
+
rate_test()
{
RET=0
--
2.44.0
^ permalink raw reply related
* [PATCH net-next V5 09/12] devlink: Document port-level resources and full dump
From: Tariq Toukan @ 2026-04-07 19:41 UTC (permalink / raw)
To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller
Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Shuah Khan, Matthieu Baerts (NGI0), Chuck Lever,
Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
Daniel Zahka, Shahar Shitrit, Cosmin Ratiu, Jacob Keller,
Parav Pandit, Adithya Jayachandran, Shay Drori, Kees Cook,
Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
linux-kselftest, Gal Pressman, Jiri Pirko
In-Reply-To: <20260407194107.148063-1-tariqt@nvidia.com>
From: Or Har-Toov <ohartoov@nvidia.com>
Document the port-level resource support and the option to dump all
resources, including both device-level and port-level entries.
Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Shay Drori <shayd@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../networking/devlink/devlink-resource.rst | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/Documentation/networking/devlink/devlink-resource.rst b/Documentation/networking/devlink/devlink-resource.rst
index 3d5ae51e65a2..9839c1661315 100644
--- a/Documentation/networking/devlink/devlink-resource.rst
+++ b/Documentation/networking/devlink/devlink-resource.rst
@@ -74,3 +74,38 @@ attribute, which represents the pending change in size. For example:
Note that changes in resource size may require a device reload to properly
take effect.
+
+Port-level Resources and Full Dump
+==================================
+
+In addition to device-level resources, ``devlink`` also supports port-level
+resources. These resources are associated with a specific devlink port rather
+than the device as a whole.
+
+To list resources for all devlink devices and ports:
+
+.. code:: shell
+
+ $ devlink resource show
+ pci/0000:03:00.0:
+ name max_local_SFs size 128 unit entry dpipe_tables none
+ name max_external_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.0/196608:
+ name max_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.0/196609:
+ name max_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.1:
+ name max_local_SFs size 128 unit entry dpipe_tables none
+ name max_external_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.1/196708:
+ name max_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.1/196709:
+ name max_SFs size 128 unit entry dpipe_tables none
+
+To show resources for a specific port:
+
+.. code:: shell
+
+ $ devlink resource show pci/0000:03:00.0/196608
+ pci/0000:03:00.0/196608:
+ name max_SFs size 128 unit entry dpipe_tables none
--
2.44.0
^ permalink raw reply related
* [PATCH net-next V5 10/12] devlink: Add resource scope filtering to resource dump
From: Tariq Toukan @ 2026-04-07 19:41 UTC (permalink / raw)
To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller
Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Shuah Khan, Matthieu Baerts (NGI0), Chuck Lever,
Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
Daniel Zahka, Shahar Shitrit, Cosmin Ratiu, Jacob Keller,
Parav Pandit, Adithya Jayachandran, Shay Drori, Kees Cook,
Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
linux-kselftest, Gal Pressman
In-Reply-To: <20260407194107.148063-1-tariqt@nvidia.com>
From: Or Har-Toov <ohartoov@nvidia.com>
Allow filtering the resource dump to device-level or port-level
resources using the 'scope' option.
Example - dump only device-level resources:
$ devlink resource show scope dev
pci/0000:03:00.0:
name max_local_SFs size 128 unit entry dpipe_tables none
name max_external_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1:
name max_local_SFs size 128 unit entry dpipe_tables none
name max_external_SFs size 128 unit entry dpipe_tables none
Example - dump only port-level resources:
$ devlink resource show scope port
pci/0000:03:00.0/196608:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.0/196609:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1/196708:
name max_SFs size 128 unit entry dpipe_tables none
pci/0000:03:00.1/196709:
name max_SFs size 128 unit entry dpipe_tables none
Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
Documentation/netlink/specs/devlink.yaml | 24 +++++++++++++++++++++++-
include/uapi/linux/devlink.h | 11 +++++++++++
net/devlink/netlink_gen.c | 5 +++--
net/devlink/resource.c | 19 ++++++++++++++++++-
4 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index 34aa81ba689e..247b147d689f 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -157,6 +157,14 @@ definitions:
entries:
-
name: entry
+ -
+ type: enum
+ name: resource-scope
+ entries:
+ -
+ name: dev
+ -
+ name: port
-
type: enum
name: reload-action
@@ -873,6 +881,16 @@ attribute-sets:
doc: Unique devlink instance index.
checks:
max: u32-max
+ -
+ name: resource-scope-mask
+ type: u32
+ enum: resource-scope
+ enum-as-flags: true
+ doc: |
+ Bitmask selecting which resource classes to include in a
+ resource-dump response. Bit 0 (dev) selects device-level
+ resources; bit 1 (port) selects port-level resources.
+ When absent all classes are returned.
-
name: dl-dev-stats
subset-of: devlink
@@ -1775,7 +1793,11 @@ operations:
- resource-list
dump:
request:
- attributes: *dev-id-attrs
+ attributes:
+ - bus-name
+ - dev-name
+ - index
+ - resource-scope-mask
reply: *resource-dump-reply
-
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 7de2d8cc862f..0b165eac7619 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -645,6 +645,7 @@ enum devlink_attr {
DEVLINK_ATTR_PARAM_RESET_DEFAULT, /* flag */
DEVLINK_ATTR_INDEX, /* uint */
+ DEVLINK_ATTR_RESOURCE_SCOPE_MASK, /* u32 */
/* Add new attributes above here, update the spec in
* Documentation/netlink/specs/devlink.yaml and re-generate
@@ -704,6 +705,16 @@ enum devlink_resource_unit {
DEVLINK_RESOURCE_UNIT_ENTRY,
};
+enum devlink_resource_scope {
+ DEVLINK_RESOURCE_SCOPE_DEV_BIT,
+ DEVLINK_RESOURCE_SCOPE_PORT_BIT,
+};
+
+#define DEVLINK_RESOURCE_SCOPE_DEV \
+ _BITUL(DEVLINK_RESOURCE_SCOPE_DEV_BIT)
+#define DEVLINK_RESOURCE_SCOPE_PORT \
+ _BITUL(DEVLINK_RESOURCE_SCOPE_PORT_BIT)
+
enum devlink_port_fn_attr_cap {
DEVLINK_PORT_FN_ATTR_CAP_ROCE_BIT,
DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT,
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index 9cc372d9ee41..81899786fd98 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -313,10 +313,11 @@ static const struct nla_policy devlink_resource_dump_do_nl_policy[DEVLINK_ATTR_I
};
/* DEVLINK_CMD_RESOURCE_DUMP - dump */
-static const struct nla_policy devlink_resource_dump_dump_nl_policy[DEVLINK_ATTR_INDEX + 1] = {
+static const struct nla_policy devlink_resource_dump_dump_nl_policy[DEVLINK_ATTR_RESOURCE_SCOPE_MASK + 1] = {
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
[DEVLINK_ATTR_INDEX] = NLA_POLICY_FULL_RANGE(NLA_UINT, &devlink_attr_index_range),
+ [DEVLINK_ATTR_RESOURCE_SCOPE_MASK] = NLA_POLICY_MASK(NLA_U32, 0x3),
};
/* DEVLINK_CMD_RELOAD - do */
@@ -974,7 +975,7 @@ const struct genl_split_ops devlink_nl_ops[75] = {
.cmd = DEVLINK_CMD_RESOURCE_DUMP,
.dumpit = devlink_nl_resource_dump_dumpit,
.policy = devlink_resource_dump_dump_nl_policy,
- .maxattr = DEVLINK_ATTR_INDEX,
+ .maxattr = DEVLINK_ATTR_RESOURCE_SCOPE_MASK,
.flags = GENL_CMD_CAP_DUMP,
},
{
diff --git a/net/devlink/resource.c b/net/devlink/resource.c
index bf5221fb3e64..3d2f42bc2fb5 100644
--- a/net/devlink/resource.c
+++ b/net/devlink/resource.c
@@ -398,11 +398,25 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
struct netlink_callback *cb, int flags)
{
struct devlink_nl_dump_state *state = devlink_dump_state(cb);
+ const struct genl_info *info = genl_info_dump(cb);
struct devlink_port *devlink_port;
+ struct nlattr *scope_attr = NULL;
unsigned long port_idx;
+ u32 scope = 0;
int err;
- if (!state->port_ctx.index_valid) {
+ if (info->attrs && info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]) {
+ scope_attr = info->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK];
+ scope = nla_get_u32(scope_attr);
+ if (!scope) {
+ NL_SET_ERR_MSG_ATTR(info->extack, scope_attr,
+ "empty resource scope selection");
+ return -EINVAL;
+ }
+ }
+
+ if (!state->port_ctx.index_valid &&
+ (!scope || (scope & DEVLINK_RESOURCE_SCOPE_DEV))) {
err = devlink_resource_dump_fill_one(skb, devlink, NULL,
cb, flags, &state->idx);
if (err)
@@ -410,6 +424,8 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
state->idx = 0;
}
+ if (scope && !(scope & DEVLINK_RESOURCE_SCOPE_PORT))
+ goto out;
/* Check in case port was removed between dump callbacks. */
if (state->port_ctx.index_valid &&
!xa_load(&devlink->ports, state->port_ctx.index))
@@ -425,6 +441,7 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
}
state->idx = 0;
}
+out:
state->port_ctx.index_valid = false;
state->port_ctx.index = 0;
return 0;
--
2.44.0
^ permalink raw reply related
* [PATCH net-next V5 11/12] selftest: netdevsim: Add resource dump and scope filter test
From: Tariq Toukan @ 2026-04-07 19:41 UTC (permalink / raw)
To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller
Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Shuah Khan, Matthieu Baerts (NGI0), Chuck Lever,
Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
Daniel Zahka, Shahar Shitrit, Cosmin Ratiu, Jacob Keller,
Parav Pandit, Adithya Jayachandran, Shay Drori, Kees Cook,
Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
linux-kselftest, Gal Pressman
In-Reply-To: <20260407194107.148063-1-tariqt@nvidia.com>
From: Or Har-Toov <ohartoov@nvidia.com>
Add resource_dump_test() which verifies dumping resources for all
devices and ports, and tests that scope=dev returns only device-level
resources and scope=port returns only port resources.
Skip if userspace does not support the scope parameter.
Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../drivers/net/netdevsim/devlink.sh | 52 ++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
index 31d1cef54898..22a626c6cde3 100755
--- a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
+++ b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh
@@ -5,7 +5,7 @@ lib_dir=$(dirname $0)/../../../net/forwarding
ALL_TESTS="fw_flash_test params_test \
params_default_test regions_test reload_test \
- netns_reload_test resource_test \
+ netns_reload_test resource_test resource_dump_test \
port_resource_doit_test dev_info_test \
empty_reporter_test dummy_reporter_test rate_test"
NUM_NETIFS=0
@@ -483,6 +483,56 @@ resource_test()
log_test "resource test"
}
+resource_dump_test()
+{
+ RET=0
+
+ local port_jq
+ local dev_jq
+ local dl_jq
+ local count
+
+ dl_jq="with_entries(select(.key | startswith(\"$DL_HANDLE\")))"
+ port_jq="[.[] | $dl_jq | keys |"
+ port_jq+=" map(select(test(\"/.+/\"))) | length] | add"
+ dev_jq="[.[] | $dl_jq | keys |"
+ dev_jq+=" map(select(test(\"/.+/\")|not)) | length] | add"
+
+ if ! devlink resource help 2>&1 | grep -q "scope"; then
+ echo "SKIP: devlink resource show not supported"
+ return
+ fi
+
+ devlink resource show > /dev/null 2>&1
+ check_err $? "Failed to dump all resources"
+
+ count=$(cmd_jq "devlink resource show -j" "$port_jq")
+ [ "$count" -gt "0" ]
+ check_err $? "missing port resources in resource dump"
+
+ count=$(cmd_jq "devlink resource show -j" "$dev_jq")
+ [ "$count" -gt "0" ]
+ check_err $? "missing device resources in resource dump"
+
+ count=$(cmd_jq "devlink resource show scope dev -j" "$dev_jq")
+ [ "$count" -gt "0" ]
+ check_err $? "dev scope missing device resources"
+
+ count=$(cmd_jq "devlink resource show scope dev -j" "$port_jq")
+ [ "$count" -eq "0" ]
+ check_err $? "dev scope returned port resources"
+
+ count=$(cmd_jq "devlink resource show scope port -j" "$port_jq")
+ [ "$count" -gt "0" ]
+ check_err $? "port scope missing port resources"
+
+ count=$(cmd_jq "devlink resource show scope port -j" "$dev_jq")
+ [ "$count" -eq "0" ]
+ check_err $? "port scope returned device resources"
+
+ log_test "resource dump test"
+}
+
info_get()
{
local name=$1
--
2.44.0
^ permalink raw reply related
* [PATCH net-next V5 12/12] devlink: Document resource scope filtering
From: Tariq Toukan @ 2026-04-07 19:41 UTC (permalink / raw)
To: Eric Dumazet, Jakub Kicinski, Paolo Abeni, Andrew Lunn,
David S. Miller
Cc: Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
Shuah Khan, Saeed Mahameed, Leon Romanovsky, Tariq Toukan,
Mark Bloch, Shuah Khan, Matthieu Baerts (NGI0), Chuck Lever,
Carolina Jubran, Or Har-Toov, Moshe Shemesh, Dragos Tatulea,
Daniel Zahka, Shahar Shitrit, Cosmin Ratiu, Jacob Keller,
Parav Pandit, Adithya Jayachandran, Shay Drori, Kees Cook,
Daniel Jurgens, netdev, linux-kernel, linux-doc, linux-rdma,
linux-kselftest, Gal Pressman
In-Reply-To: <20260407194107.148063-1-tariqt@nvidia.com>
From: Or Har-Toov <ohartoov@nvidia.com>
Document the scope parameter for devlink resource show, which allows
filtering the dump to device-level or port-level resources only.
Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
---
.../networking/devlink/devlink-resource.rst | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/Documentation/networking/devlink/devlink-resource.rst b/Documentation/networking/devlink/devlink-resource.rst
index 9839c1661315..47eec8f875b4 100644
--- a/Documentation/networking/devlink/devlink-resource.rst
+++ b/Documentation/networking/devlink/devlink-resource.rst
@@ -109,3 +109,38 @@ To show resources for a specific port:
$ devlink resource show pci/0000:03:00.0/196608
pci/0000:03:00.0/196608:
name max_SFs size 128 unit entry dpipe_tables none
+
+Resource Scope Filtering
+========================
+
+When dumping resources for all devices, ``devlink resource show`` accepts
+an optional ``scope`` parameter to restrict the response to device-level
+resources, port-level resources, or both (the default).
+
+To dump only device-level resources across all devices:
+
+.. code:: shell
+
+ $ devlink resource show scope dev
+ pci/0000:03:00.0:
+ name max_local_SFs size 128 unit entry dpipe_tables none
+ name max_external_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.1:
+ name max_local_SFs size 128 unit entry dpipe_tables none
+ name max_external_SFs size 128 unit entry dpipe_tables none
+
+To dump only port-level resources across all devices:
+
+.. code:: shell
+
+ $ devlink resource show scope port
+ pci/0000:03:00.0/196608:
+ name max_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.0/196609:
+ name max_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.1/196708:
+ name max_SFs size 128 unit entry dpipe_tables none
+ pci/0000:03:00.1/196709:
+ name max_SFs size 128 unit entry dpipe_tables none
+
+Note that port-level resources are read-only.
--
2.44.0
^ permalink raw reply related
* Re: [PATCH][next] Bluetooth: hci.h: Avoid a couple -Wflex-array-member-not-at-end warnings
From: Gustavo A. R. Silva @ 2026-04-07 19:57 UTC (permalink / raw)
To: Gustavo A. R. Silva, Marcel Holtmann, Johan Hedberg,
Luiz Augusto von Dentz, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: linux-bluetooth, netdev, linux-kernel, linux-hardening
In-Reply-To: <aZ1FrL8qvvKuktBF@kspp>
Hi all,
Friendly ping: who can take this, please?
Thanks
-Gustavo
On 2/24/26 00:31, Gustavo A. R. Silva wrote:
> -Wflex-array-member-not-at-end was introduced in GCC-14, and we are
> getting ready to enable it, globally.
>
> struct hci_std_codecs and struct hci_std_codecs_v2 are flexible
> structures, this is structures that contain a flexible-array member
> (__u8 codec[]; and struct hci_std_codec_v2 codec[];, correspondingly.)
>
> Since struct hci_rp_read_local_supported_codecs and struct
> hci_rp_read_local_supported_codecs_v2 are defined by hardware, we
> create the new struct hci_std_codecs_hdr and struct hci_std_codecs_v2_hdr
> types, and use them to replace the object types causing trouble in
> struct hci_rp_read_local_supported_codecs and struct
> hci_rp_read_local_supported_codecs_v2, namely struct hci_std_codecs
> std_codecs; and struct hci_std_codecs_v2_hdr std_codecs;.
>
> Also, once -fms-extensions is enabled, we can use transparent struct
> members in both struct hci_std_codecs and struct hci_std_codecs_v2_hdr.
>
> Notice that the newly created types does not contain the flex-array
> member `codec`, which is the object causing the -Wfamnae warnings.
>
> After these changes, the size of struct hci_rp_read_local_supported_codecs
> and struct hci_rp_read_local_supported_codecs_v2, along with their
> member's offsets remain the same, hence the memory layouts don't
> change:
>
> Before changes:
> struct hci_rp_read_local_supported_codecs {
> __u8 status; /* 0 1 */
> struct hci_std_codecs std_codecs; /* 1 1 */
> struct hci_vnd_codecs vnd_codecs; /* 2 1 */
>
> /* size: 3, cachelines: 1, members: 3 */
> /* last cacheline: 3 bytes */
> } __attribute__((__packed__));
>
> struct hci_rp_read_local_supported_codecs_v2 {
> __u8 status; /* 0 1 */
> struct hci_std_codecs_v2 std_codecs; /* 1 1 */
> struct hci_vnd_codecs_v2 vendor_codecs; /* 2 1 */
>
> /* size: 3, cachelines: 1, members: 3 */
> /* last cacheline: 3 bytes */
> } __attribute__((__packed__));
>
> After changes:
> struct hci_rp_read_local_supported_codecs {
> __u8 status; /* 0 1 */
> struct hci_std_codecs_hdr std_codecs; /* 1 1 */
> struct hci_vnd_codecs vnd_codecs; /* 2 1 */
>
> /* size: 3, cachelines: 1, members: 3 */
> /* last cacheline: 3 bytes */
> } __attribute__((__packed__));
>
> struct hci_rp_read_local_supported_codecs_v2 {
> __u8 status; /* 0 1 */
> struct hci_std_codecs_v2_hdr std_codecs; /* 1 1 */
> struct hci_vnd_codecs_v2 vendor_codecs; /* 2 1 */
>
> /* size: 3, cachelines: 1, members: 3 */
> /* last cacheline: 3 bytes */
> } __attribute__((__packed__));
>
> With these changes fix the following warnings:
>
> include/net/bluetooth/hci.h:1490:31: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> include/net/bluetooth/hci.h:1525:34: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
>
> Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
> ---
> include/net/bluetooth/hci.h | 16 ++++++++++++----
> 1 file changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index 89ad9470fa71..572b1c620c5d 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1468,8 +1468,12 @@ struct hci_rp_read_data_block_size {
> } __packed;
>
> #define HCI_OP_READ_LOCAL_CODECS 0x100b
> -struct hci_std_codecs {
> +struct hci_std_codecs_hdr {
> __u8 num;
> +} __packed;
> +
> +struct hci_std_codecs {
> + struct hci_std_codecs_hdr;
> __u8 codec[];
> } __packed;
>
> @@ -1487,7 +1491,7 @@ struct hci_vnd_codecs {
>
> struct hci_rp_read_local_supported_codecs {
> __u8 status;
> - struct hci_std_codecs std_codecs;
> + struct hci_std_codecs_hdr std_codecs;
> struct hci_vnd_codecs vnd_codecs;
> } __packed;
>
> @@ -1504,8 +1508,12 @@ struct hci_std_codec_v2 {
> __u8 transport;
> } __packed;
>
> -struct hci_std_codecs_v2 {
> +struct hci_std_codecs_v2_hdr {
> __u8 num;
> +} __packed;
> +
> +struct hci_std_codecs_v2 {
> + struct hci_std_codecs_v2_hdr;
> struct hci_std_codec_v2 codec[];
> } __packed;
>
> @@ -1522,7 +1530,7 @@ struct hci_vnd_codecs_v2 {
>
> struct hci_rp_read_local_supported_codecs_v2 {
> __u8 status;
> - struct hci_std_codecs_v2 std_codecs;
> + struct hci_std_codecs_v2_hdr std_codecs;
> struct hci_vnd_codecs_v2 vendor_codecs;
> } __packed;
>
^ permalink raw reply
* [PATCH net-next v6 0/2] net: mana: add ethtool private flag for full-page RX buffers
From: Dipayaan Roy @ 2026-04-07 19:59 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, leitao, kees, john.fastabend,
hawk, bpf, daniel, ast, sdf, dipayanroy
On some ARM64 platforms with 4K PAGE_SIZE, utilizing page_pool
fragments for allocation in the RX refill path (~2kB buffer per fragment)
causes 15-20% throughput regression under high connection counts
(>16 TCP streams at 180+ Gbps). Using full-page buffers on these
platforms shows no regression and restores line-rate performance.
This behavior is observed on a single platform; other platforms
perform better with page_pool fragments, indicating this is not a
page_pool issue but platform-specific.
This series adds an ethtool private flag "full-page-rx" to let the
user opt in to one RX buffer per page:
ethtool --set-priv-flags eth0 full-page-rx on
There is no behavioral change by default. The flag can be persisted
via udev rule for affected platforms.
Changes in v6:
- Added missed maintainers.
Changes in v5:
- Split prep refactor into separate patch (patch 1/2)
Changes in v4:
- Dropping the smbios string parsing and add ethtool priv flag
to reconfigure the queues with full page rx buffers.
Changes in v3:
- changed u8* to char*
Changes in v2:
- separate reading string index and the string, remove inline.
Dipayaan Roy (2):
net: mana: refactor mana_get_strings() and mana_get_sset_count() to
use switch
net: mana: force full-page RX buffers via ethtool private flag
drivers/net/ethernet/microsoft/mana/mana_en.c | 22 ++-
.../ethernet/microsoft/mana/mana_ethtool.c | 164 ++++++++++++++----
include/net/mana/mana.h | 8 +
3 files changed, 163 insertions(+), 31 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH net-next v6 1/2] net: mana: refactor mana_get_strings() and mana_get_sset_count() to use switch
From: Dipayaan Roy @ 2026-04-07 19:59 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, leitao, kees, john.fastabend,
hawk, bpf, daniel, ast, sdf, dipayanroy
In-Reply-To: <20260407200216.272659-1-dipayanroy@linux.microsoft.com>
Refactor mana_get_strings() and mana_get_sset_count() from if/else to
switch statements in preparation for adding ethtool private flags
support which requires handling ETH_SS_PRIV_FLAGS.
No functional change.
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
.../ethernet/microsoft/mana/mana_ethtool.c | 75 ++++++++++++-------
1 file changed, 46 insertions(+), 29 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 6a4b42fe0944..a28ca461c135 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -138,53 +138,70 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
struct mana_port_context *apc = netdev_priv(ndev);
unsigned int num_queues = apc->num_queues;
- if (stringset != ETH_SS_STATS)
+ switch (stringset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(mana_eth_stats) +
+ ARRAY_SIZE(mana_phy_stats) +
+ ARRAY_SIZE(mana_hc_stats) +
+ num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
+ default:
return -EINVAL;
-
- return ARRAY_SIZE(mana_eth_stats) + ARRAY_SIZE(mana_phy_stats) + ARRAY_SIZE(mana_hc_stats) +
- num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
+ }
}
-static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
{
- struct mana_port_context *apc = netdev_priv(ndev);
unsigned int num_queues = apc->num_queues;
int i, j;
- if (stringset != ETH_SS_STATS)
- return;
for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++)
- ethtool_puts(&data, mana_eth_stats[i].name);
+ ethtool_puts(data, mana_eth_stats[i].name);
for (i = 0; i < ARRAY_SIZE(mana_hc_stats); i++)
- ethtool_puts(&data, mana_hc_stats[i].name);
+ ethtool_puts(data, mana_hc_stats[i].name);
for (i = 0; i < ARRAY_SIZE(mana_phy_stats); i++)
- ethtool_puts(&data, mana_phy_stats[i].name);
+ ethtool_puts(data, mana_phy_stats[i].name);
for (i = 0; i < num_queues; i++) {
- ethtool_sprintf(&data, "rx_%d_packets", i);
- ethtool_sprintf(&data, "rx_%d_bytes", i);
- ethtool_sprintf(&data, "rx_%d_xdp_drop", i);
- ethtool_sprintf(&data, "rx_%d_xdp_tx", i);
- ethtool_sprintf(&data, "rx_%d_xdp_redirect", i);
- ethtool_sprintf(&data, "rx_%d_pkt_len0_err", i);
+ ethtool_sprintf(data, "rx_%d_packets", i);
+ ethtool_sprintf(data, "rx_%d_bytes", i);
+ ethtool_sprintf(data, "rx_%d_xdp_drop", i);
+ ethtool_sprintf(data, "rx_%d_xdp_tx", i);
+ ethtool_sprintf(data, "rx_%d_xdp_redirect", i);
+ ethtool_sprintf(data, "rx_%d_pkt_len0_err", i);
for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
- ethtool_sprintf(&data, "rx_%d_coalesced_cqe_%d", i, j + 2);
+ ethtool_sprintf(data,
+ "rx_%d_coalesced_cqe_%d",
+ i,
+ j + 2);
}
for (i = 0; i < num_queues; i++) {
- ethtool_sprintf(&data, "tx_%d_packets", i);
- ethtool_sprintf(&data, "tx_%d_bytes", i);
- ethtool_sprintf(&data, "tx_%d_xdp_xmit", i);
- ethtool_sprintf(&data, "tx_%d_tso_packets", i);
- ethtool_sprintf(&data, "tx_%d_tso_bytes", i);
- ethtool_sprintf(&data, "tx_%d_tso_inner_packets", i);
- ethtool_sprintf(&data, "tx_%d_tso_inner_bytes", i);
- ethtool_sprintf(&data, "tx_%d_long_pkt_fmt", i);
- ethtool_sprintf(&data, "tx_%d_short_pkt_fmt", i);
- ethtool_sprintf(&data, "tx_%d_csum_partial", i);
- ethtool_sprintf(&data, "tx_%d_mana_map_err", i);
+ ethtool_sprintf(data, "tx_%d_packets", i);
+ ethtool_sprintf(data, "tx_%d_bytes", i);
+ ethtool_sprintf(data, "tx_%d_xdp_xmit", i);
+ ethtool_sprintf(data, "tx_%d_tso_packets", i);
+ ethtool_sprintf(data, "tx_%d_tso_bytes", i);
+ ethtool_sprintf(data, "tx_%d_tso_inner_packets", i);
+ ethtool_sprintf(data, "tx_%d_tso_inner_bytes", i);
+ ethtool_sprintf(data, "tx_%d_long_pkt_fmt", i);
+ ethtool_sprintf(data, "tx_%d_short_pkt_fmt", i);
+ ethtool_sprintf(data, "tx_%d_csum_partial", i);
+ ethtool_sprintf(data, "tx_%d_mana_map_err", i);
+ }
+}
+
+static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+{
+ struct mana_port_context *apc = netdev_priv(ndev);
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ mana_get_strings_stats(apc, &data);
+ break;
+ default:
+ break;
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v6 2/2] net: mana: force full-page RX buffers via ethtool private flag
From: Dipayaan Roy @ 2026-04-07 19:59 UTC (permalink / raw)
To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
kuba, pabeni, leon, longli, kotaranov, horms, shradhagupta,
ssengar, ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, leitao, kees, john.fastabend,
hawk, bpf, daniel, ast, sdf, dipayanroy
In-Reply-To: <20260407200216.272659-1-dipayanroy@linux.microsoft.com>
On some ARM64 platforms with 4K PAGE_SIZE, page_pool fragment
allocation in the RX refill path can cause 15-20% throughput
regression under high connection counts (>16 TCP streams).
Add an ethtool private flag "full-page-rx" that allows the user to
force one RX buffer per page, bypassing the page_pool fragment path.
This restores line-rate (180+ Gbps) performance on affected platforms.
Usage:
ethtool --set-priv-flags eth0 full-page-rx on
There is no behavioral change by default. The flag must be explicitly
enabled by the user or udev rule.
The existing single-buffer-per-page logic for XDP and jumbo frames is
consolidated into a new helper mana_use_single_rxbuf_per_page() which
is now the single decision point for both the automatic and
user-controlled paths.
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 22 ++++-
.../ethernet/microsoft/mana/mana_ethtool.c | 89 +++++++++++++++++++
include/net/mana/mana.h | 8 ++
3 files changed, 117 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 49c65cc1697c..59a1626c2be1 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -744,6 +744,25 @@ static void *mana_get_rxbuf_pre(struct mana_rxq *rxq, dma_addr_t *da)
return va;
}
+static bool
+mana_use_single_rxbuf_per_page(struct mana_port_context *apc, u32 mtu)
+{
+ /* On some platforms with 4K PAGE_SIZE, page_pool fragment allocation
+ * in the RX refill path (~2kB buffer) can cause significant throughput
+ * regression under high connection counts. Allow user to force one RX
+ * buffer per page via ethtool private flag to bypass the fragment
+ * path.
+ */
+ if (apc->priv_flags & BIT(MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF))
+ return true;
+
+ /* For xdp and jumbo frames make sure only one packet fits per page. */
+ if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc))
+ return true;
+
+ return false;
+}
+
/* Get RX buffer's data size, alloc size, XDP headroom based on MTU */
static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
int mtu, u32 *datasize, u32 *alloc_size,
@@ -754,8 +773,7 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc,
/* Calculate datasize first (consistent across all cases) */
*datasize = mtu + ETH_HLEN;
- /* For xdp and jumbo frames make sure only one packet fits per page */
- if (mtu + MANA_RXBUF_PAD > PAGE_SIZE / 2 || mana_xdp_get(apc)) {
+ if (mana_use_single_rxbuf_per_page(apc, mtu)) {
if (mana_xdp_get(apc)) {
*headroom = XDP_PACKET_HEADROOM;
*alloc_size = PAGE_SIZE;
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index a28ca461c135..0547c903f613 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -133,6 +133,10 @@ static const struct mana_stats_desc mana_phy_stats[] = {
{ "hc_tc7_tx_pause_phy", offsetof(struct mana_ethtool_phy_stats, tx_pause_tc7_phy) },
};
+static const char mana_priv_flags[MANA_PRIV_FLAG_MAX][ETH_GSTRING_LEN] = {
+ [MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF] = "full-page-rx"
+};
+
static int mana_get_sset_count(struct net_device *ndev, int stringset)
{
struct mana_port_context *apc = netdev_priv(ndev);
@@ -144,6 +148,10 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
ARRAY_SIZE(mana_phy_stats) +
ARRAY_SIZE(mana_hc_stats) +
num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
+
+ case ETH_SS_PRIV_FLAGS:
+ return MANA_PRIV_FLAG_MAX;
+
default:
return -EINVAL;
}
@@ -192,6 +200,14 @@ static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
}
}
+static void mana_get_strings_priv_flags(u8 **data)
+{
+ int i;
+
+ for (i = 0; i < MANA_PRIV_FLAG_MAX; i++)
+ ethtool_puts(data, mana_priv_flags[i]);
+}
+
static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
{
struct mana_port_context *apc = netdev_priv(ndev);
@@ -200,6 +216,9 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
case ETH_SS_STATS:
mana_get_strings_stats(apc, &data);
break;
+ case ETH_SS_PRIV_FLAGS:
+ mana_get_strings_priv_flags(&data);
+ break;
default:
break;
}
@@ -590,6 +609,74 @@ static int mana_get_link_ksettings(struct net_device *ndev,
return 0;
}
+static u32 mana_get_priv_flags(struct net_device *ndev)
+{
+ struct mana_port_context *apc = netdev_priv(ndev);
+
+ return apc->priv_flags;
+}
+
+static int mana_set_priv_flags(struct net_device *ndev, u32 priv_flags)
+{
+ struct mana_port_context *apc = netdev_priv(ndev);
+ u32 changed = apc->priv_flags ^ priv_flags;
+ u32 old_priv_flags = apc->priv_flags;
+ bool schedule_port_reset = false;
+ int err = 0;
+
+ if (!changed)
+ return 0;
+
+ /* Reject unknown bits */
+ if (priv_flags & ~GENMASK(MANA_PRIV_FLAG_MAX - 1, 0))
+ return -EINVAL;
+
+ if (changed & BIT(MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF)) {
+ apc->priv_flags = priv_flags;
+
+ if (!apc->port_is_up) {
+ /* Port is down, flag updated to apply on next up
+ * so just return.
+ */
+ return 0;
+ }
+
+ /* Pre-allocate buffers to prevent failure in mana_attach
+ * later
+ */
+ err = mana_pre_alloc_rxbufs(apc, ndev->mtu, apc->num_queues);
+ if (err) {
+ netdev_err(ndev,
+ "Insufficient memory for new allocations\n");
+ apc->priv_flags = old_priv_flags;
+ return err;
+ }
+
+ err = mana_detach(ndev, false);
+ if (err) {
+ netdev_err(ndev, "mana_detach failed: %d\n", err);
+ apc->priv_flags = old_priv_flags;
+ goto out;
+ }
+
+ err = mana_attach(ndev);
+ if (err) {
+ netdev_err(ndev, "mana_attach failed: %d\n", err);
+ apc->priv_flags = old_priv_flags;
+ schedule_port_reset = true;
+ }
+ }
+
+out:
+ mana_pre_dealloc_rxbufs(apc);
+
+ if (err && schedule_port_reset)
+ queue_work(apc->ac->per_port_queue_reset_wq,
+ &apc->queue_reset_work);
+
+ return err;
+}
+
const struct ethtool_ops mana_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES,
.get_ethtool_stats = mana_get_ethtool_stats,
@@ -608,4 +695,6 @@ const struct ethtool_ops mana_ethtool_ops = {
.set_ringparam = mana_set_ringparam,
.get_link_ksettings = mana_get_link_ksettings,
.get_link = ethtool_op_get_link,
+ .get_priv_flags = mana_get_priv_flags,
+ .set_priv_flags = mana_set_priv_flags,
};
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 3336688fed5e..fd87e3d6c1f4 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -30,6 +30,12 @@ enum TRI_STATE {
TRI_STATE_TRUE = 1
};
+/* MANA ethtool private flag bit positions */
+enum mana_priv_flag_bits {
+ MANA_PRIV_FLAG_USE_FULL_PAGE_RXBUF = 0,
+ MANA_PRIV_FLAG_MAX,
+};
+
/* Number of entries for hardware indirection table must be in power of 2 */
#define MANA_INDIRECT_TABLE_MAX_SIZE 512
#define MANA_INDIRECT_TABLE_DEF_SIZE 64
@@ -531,6 +537,8 @@ struct mana_port_context {
u32 rxbpre_headroom;
u32 rxbpre_frag_count;
+ u32 priv_flags;
+
struct bpf_prog *bpf_prog;
/* Create num_queues EQs, SQs, SQ-CQs, RQs and RQ-CQs, respectively. */
--
2.43.0
^ permalink raw reply related
* Re: [PATCH][next] Bluetooth: hci.h: Avoid a couple -Wflex-array-member-not-at-end warnings
From: Luiz Augusto von Dentz @ 2026-04-07 20:06 UTC (permalink / raw)
To: Gustavo A. R. Silva
Cc: Gustavo A. R. Silva, Marcel Holtmann, Johan Hedberg,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, linux-bluetooth, netdev, linux-kernel,
linux-hardening
In-Reply-To: <d04e11af-5c1b-44a2-aebc-a0ee4fb79802@embeddedor.com>
Hi Gustavo,
On Tue, Apr 7, 2026 at 3:58 PM Gustavo A. R. Silva
<gustavo@embeddedor.com> wrote:
>
> Hi all,
>
> Friendly ping: who can take this, please?
Just resend as this is no longer available via patchwork.
> Thanks
> -Gustavo
>
> On 2/24/26 00:31, Gustavo A. R. Silva wrote:
> > -Wflex-array-member-not-at-end was introduced in GCC-14, and we are
> > getting ready to enable it, globally.
> >
> > struct hci_std_codecs and struct hci_std_codecs_v2 are flexible
> > structures, this is structures that contain a flexible-array member
> > (__u8 codec[]; and struct hci_std_codec_v2 codec[];, correspondingly.)
> >
> > Since struct hci_rp_read_local_supported_codecs and struct
> > hci_rp_read_local_supported_codecs_v2 are defined by hardware, we
> > create the new struct hci_std_codecs_hdr and struct hci_std_codecs_v2_hdr
> > types, and use them to replace the object types causing trouble in
> > struct hci_rp_read_local_supported_codecs and struct
> > hci_rp_read_local_supported_codecs_v2, namely struct hci_std_codecs
> > std_codecs; and struct hci_std_codecs_v2_hdr std_codecs;.
> >
> > Also, once -fms-extensions is enabled, we can use transparent struct
> > members in both struct hci_std_codecs and struct hci_std_codecs_v2_hdr.
> >
> > Notice that the newly created types does not contain the flex-array
> > member `codec`, which is the object causing the -Wfamnae warnings.
> >
> > After these changes, the size of struct hci_rp_read_local_supported_codecs
> > and struct hci_rp_read_local_supported_codecs_v2, along with their
> > member's offsets remain the same, hence the memory layouts don't
> > change:
> >
> > Before changes:
> > struct hci_rp_read_local_supported_codecs {
> > __u8 status; /* 0 1 */
> > struct hci_std_codecs std_codecs; /* 1 1 */
> > struct hci_vnd_codecs vnd_codecs; /* 2 1 */
> >
> > /* size: 3, cachelines: 1, members: 3 */
> > /* last cacheline: 3 bytes */
> > } __attribute__((__packed__));
> >
> > struct hci_rp_read_local_supported_codecs_v2 {
> > __u8 status; /* 0 1 */
> > struct hci_std_codecs_v2 std_codecs; /* 1 1 */
> > struct hci_vnd_codecs_v2 vendor_codecs; /* 2 1 */
> >
> > /* size: 3, cachelines: 1, members: 3 */
> > /* last cacheline: 3 bytes */
> > } __attribute__((__packed__));
> >
> > After changes:
> > struct hci_rp_read_local_supported_codecs {
> > __u8 status; /* 0 1 */
> > struct hci_std_codecs_hdr std_codecs; /* 1 1 */
> > struct hci_vnd_codecs vnd_codecs; /* 2 1 */
> >
> > /* size: 3, cachelines: 1, members: 3 */
> > /* last cacheline: 3 bytes */
> > } __attribute__((__packed__));
> >
> > struct hci_rp_read_local_supported_codecs_v2 {
> > __u8 status; /* 0 1 */
> > struct hci_std_codecs_v2_hdr std_codecs; /* 1 1 */
> > struct hci_vnd_codecs_v2 vendor_codecs; /* 2 1 */
> >
> > /* size: 3, cachelines: 1, members: 3 */
> > /* last cacheline: 3 bytes */
> > } __attribute__((__packed__));
> >
> > With these changes fix the following warnings:
> >
> > include/net/bluetooth/hci.h:1490:31: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> > include/net/bluetooth/hci.h:1525:34: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> >
> > Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
> > ---
> > include/net/bluetooth/hci.h | 16 ++++++++++++----
> > 1 file changed, 12 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index 89ad9470fa71..572b1c620c5d 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -1468,8 +1468,12 @@ struct hci_rp_read_data_block_size {
> > } __packed;
> >
> > #define HCI_OP_READ_LOCAL_CODECS 0x100b
> > -struct hci_std_codecs {
> > +struct hci_std_codecs_hdr {
> > __u8 num;
> > +} __packed;
> > +
> > +struct hci_std_codecs {
> > + struct hci_std_codecs_hdr;
> > __u8 codec[];
> > } __packed;
> >
> > @@ -1487,7 +1491,7 @@ struct hci_vnd_codecs {
> >
> > struct hci_rp_read_local_supported_codecs {
> > __u8 status;
> > - struct hci_std_codecs std_codecs;
> > + struct hci_std_codecs_hdr std_codecs;
> > struct hci_vnd_codecs vnd_codecs;
> > } __packed;
> >
> > @@ -1504,8 +1508,12 @@ struct hci_std_codec_v2 {
> > __u8 transport;
> > } __packed;
> >
> > -struct hci_std_codecs_v2 {
> > +struct hci_std_codecs_v2_hdr {
> > __u8 num;
> > +} __packed;
> > +
> > +struct hci_std_codecs_v2 {
> > + struct hci_std_codecs_v2_hdr;
> > struct hci_std_codec_v2 codec[];
> > } __packed;
> >
> > @@ -1522,7 +1530,7 @@ struct hci_vnd_codecs_v2 {
> >
> > struct hci_rp_read_local_supported_codecs_v2 {
> > __u8 status;
> > - struct hci_std_codecs_v2 std_codecs;
> > + struct hci_std_codecs_v2_hdr std_codecs;
> > struct hci_vnd_codecs_v2 vendor_codecs;
> > } __packed;
> >
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH RESEND][next] Bluetooth: hci.h: Avoid a couple -Wflex-array-member-not-at-end warnings
From: Gustavo A. R. Silva @ 2026-04-07 20:16 UTC (permalink / raw)
To: Marcel Holtmann, Johan Hedberg, Luiz Augusto von Dentz,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman
Cc: linux-bluetooth, netdev, linux-kernel, Gustavo A. R. Silva,
linux-hardening
-Wflex-array-member-not-at-end was introduced in GCC-14, and we are
getting ready to enable it, globally.
struct hci_std_codecs and struct hci_std_codecs_v2 are flexible
structures, this is structures that contain a flexible-array member
(__u8 codec[]; and struct hci_std_codec_v2 codec[];, correspondingly.)
Since struct hci_rp_read_local_supported_codecs and struct
hci_rp_read_local_supported_codecs_v2 are defined by hardware, we
create the new struct hci_std_codecs_hdr and struct hci_std_codecs_v2_hdr
types, and use them to replace the object types causing trouble in
struct hci_rp_read_local_supported_codecs and struct
hci_rp_read_local_supported_codecs_v2, namely struct hci_std_codecs
std_codecs; and struct hci_std_codecs_v2_hdr std_codecs;.
Also, once -fms-extensions is enabled, we can use transparent struct
members in both struct hci_std_codecs and struct hci_std_codecs_v2_hdr.
Notice that the newly created types does not contain the flex-array
member `codec`, which is the object causing the -Wfamnae warnings.
After these changes, the size of struct hci_rp_read_local_supported_codecs
and struct hci_rp_read_local_supported_codecs_v2, along with their
member's offsets remain the same, hence the memory layouts don't
change:
Before changes:
struct hci_rp_read_local_supported_codecs {
__u8 status; /* 0 1 */
struct hci_std_codecs std_codecs; /* 1 1 */
struct hci_vnd_codecs vnd_codecs; /* 2 1 */
/* size: 3, cachelines: 1, members: 3 */
/* last cacheline: 3 bytes */
} __attribute__((__packed__));
struct hci_rp_read_local_supported_codecs_v2 {
__u8 status; /* 0 1 */
struct hci_std_codecs_v2 std_codecs; /* 1 1 */
struct hci_vnd_codecs_v2 vendor_codecs; /* 2 1 */
/* size: 3, cachelines: 1, members: 3 */
/* last cacheline: 3 bytes */
} __attribute__((__packed__));
After changes:
struct hci_rp_read_local_supported_codecs {
__u8 status; /* 0 1 */
struct hci_std_codecs_hdr std_codecs; /* 1 1 */
struct hci_vnd_codecs vnd_codecs; /* 2 1 */
/* size: 3, cachelines: 1, members: 3 */
/* last cacheline: 3 bytes */
} __attribute__((__packed__));
struct hci_rp_read_local_supported_codecs_v2 {
__u8 status; /* 0 1 */
struct hci_std_codecs_v2_hdr std_codecs; /* 1 1 */
struct hci_vnd_codecs_v2 vendor_codecs; /* 2 1 */
/* size: 3, cachelines: 1, members: 3 */
/* last cacheline: 3 bytes */
} __attribute__((__packed__));
With these changes fix the following warnings:
include/net/bluetooth/hci.h:1490:31: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
include/net/bluetooth/hci.h:1525:34: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
include/net/bluetooth/hci.h | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 89ad9470fa71..572b1c620c5d 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1468,8 +1468,12 @@ struct hci_rp_read_data_block_size {
} __packed;
#define HCI_OP_READ_LOCAL_CODECS 0x100b
-struct hci_std_codecs {
+struct hci_std_codecs_hdr {
__u8 num;
+} __packed;
+
+struct hci_std_codecs {
+ struct hci_std_codecs_hdr;
__u8 codec[];
} __packed;
@@ -1487,7 +1491,7 @@ struct hci_vnd_codecs {
struct hci_rp_read_local_supported_codecs {
__u8 status;
- struct hci_std_codecs std_codecs;
+ struct hci_std_codecs_hdr std_codecs;
struct hci_vnd_codecs vnd_codecs;
} __packed;
@@ -1504,8 +1508,12 @@ struct hci_std_codec_v2 {
__u8 transport;
} __packed;
-struct hci_std_codecs_v2 {
+struct hci_std_codecs_v2_hdr {
__u8 num;
+} __packed;
+
+struct hci_std_codecs_v2 {
+ struct hci_std_codecs_v2_hdr;
struct hci_std_codec_v2 codec[];
} __packed;
@@ -1522,7 +1530,7 @@ struct hci_vnd_codecs_v2 {
struct hci_rp_read_local_supported_codecs_v2 {
__u8 status;
- struct hci_std_codecs_v2 std_codecs;
+ struct hci_std_codecs_v2_hdr std_codecs;
struct hci_vnd_codecs_v2 vendor_codecs;
} __packed;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next v2 4/5] dt-bindings: dpll: add ref-sync-sources property
From: Rob Herring @ 2026-04-07 20:18 UTC (permalink / raw)
To: Ivan Vecera
Cc: netdev, Petr Oros, Prathosh Satish, Arkadiusz Kubalewski,
Jiri Pirko, Michal Schmidt, Simon Horman, Vadim Fedorenko,
linux-kernel, Conor Dooley, Krzysztof Kozlowski, devicetree,
Pasi Vaananen
In-Reply-To: <20260328080624.593916-5-ivecera@redhat.com>
On Sat, Mar 28, 2026 at 09:06:23AM +0100, Ivan Vecera wrote:
> Add ref-sync-sources phandle-array property to the dpll-pin schema
> allowing board designers to declare which input pins can serve as
> sync sources in a Reference-Sync pair. A Ref-Sync pair consists of
> a clock reference and a low-frequency sync signal where the DPLL locks
> to the clock but phase-aligns to the sync reference.
>
> Update both examples in the Microchip ZL3073x binding to demonstrate
> the new property with a 1 PPS sync source paired to a clock source.
>
> Reviewed-by: Petr Oros <poros@redhat.com>
> Reviewed-by: Prathosh Satish <Prathosh.Satish@microchip.com>
> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
> ---
> .../devicetree/bindings/dpll/dpll-pin.yaml | 11 +++++++
> .../bindings/dpll/microchip,zl30731.yaml | 30 ++++++++++++++-----
> 2 files changed, 34 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/dpll/dpll-pin.yaml b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
> index 51db93b77306f..7084f102e274c 100644
> --- a/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
> +++ b/Documentation/devicetree/bindings/dpll/dpll-pin.yaml
> @@ -36,6 +36,17 @@ properties:
> description: String exposed as the pin board label
> $ref: /schemas/types.yaml#/definitions/string
>
> + ref-sync-sources:
> + description: |
> + List of phandles to input pins that can serve as the sync source
> + in a Reference-Sync pair with this pin acting as the clock source.
> + A Ref-Sync pair consists of a clock reference and a low-frequency
> + sync signal. The DPLL locks to the clock reference but
> + phase-aligns to the sync reference.
> + Only valid for input pins. Each referenced pin must be a
> + different input pin on the same device.
> + $ref: /schemas/types.yaml#/definitions/phandle-array
phandle-array is really a matrix. As there are no arg cells here, for
a list of phandles you need:
items:
maxItems: 1
With that,
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Rob
^ permalink raw reply
* [syzbot] Monthly bridge report (Apr 2026)
From: syzbot @ 2026-04-07 20:34 UTC (permalink / raw)
To: bridge, idosch, linux-kernel, netdev, razor, syzkaller-bugs
Hello bridge maintainers/developers,
This is a 31-day syzbot report for the bridge subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/bridge
During the period, 0 new issues were detected and 0 were fixed.
In total, 4 issues are still open and 42 have already been fixed.
Some of the still happening issues:
Ref Crashes Repro Title
<1> 59 Yes possible deadlock in br_multicast_rcv (3)
https://syzkaller.appspot.com/bug?extid=d7b7f1412c02134efa6d
<2> 6 Yes WARNING in nf_ct_bridge_post
https://syzkaller.appspot.com/bug?extid=a8ba738fe2db6b4bb27f
<3> 2 Yes INFO: task hung in br_ioctl_stub (2)
https://syzkaller.appspot.com/bug?extid=6bdeba54c73aa6a6219d
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders
To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem
You may send multiple commands in a single email message.
^ permalink raw reply
* Re: [PATCH v9 02/10] x86/bhi: Make clear_bhb_loop() effective on newer CPUs
From: Jim Mattson @ 2026-04-07 20:53 UTC (permalink / raw)
To: Pawan Gupta
Cc: x86, Jon Kohler, Nikolay Borisov, H. Peter Anvin, Josh Poimboeuf,
David Kaplan, Sean Christopherson, Borislav Petkov, Dave Hansen,
Peter Zijlstra, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, KP Singh, Jiri Olsa, David S. Miller,
David Laight, Andy Lutomirski, Thomas Gleixner, Ingo Molnar,
David Ahern, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, John Fastabend, Stanislav Fomichev, Hao Luo,
Paolo Bonzini, Jonathan Corbet, linux-kernel, kvm, Asit Mallick,
Tao Zhang, bpf, netdev, linux-doc, chao.gao
In-Reply-To: <20260407191128.b2hr2ttkdpyunhrr@desk>
On Tue, Apr 7, 2026 at 12:11 PM Pawan Gupta
<pawan.kumar.gupta@linux.intel.com> wrote:
>
> On Tue, Apr 07, 2026 at 11:40:57AM -0700, Jim Mattson wrote:
> > My proposal is as follows:
> >
> > 1. The (advanced) hypervisor can advertise to the guest (via CPUID bit
> > or MSR bit) that the short BHB clearing sequence is adequate. This may
> > mean either that the VM will only be hosted on pre-Alder Lake hardware
> > or that the hypervisor will set BHI_DIS_S behind the back of the
> > guest. Presumably, this bit would not be reported if BHI_CTRL is
> > advertised to the guest.
> > 2. If the guest sees this bit, then it can use the short sequence. If
> > it doesn't see this bit, it must use the long sequence.
>
> Thats a good middle ground. Let me check with folks internally what they
> think about defining a new software-only bit.
>
> Third case, for a guest that doesn't want BHI_DIS_S, userspace should be
> allowed to override setting BHI_DIS_S. Then this proposed bit can indicate
> that long sequence is required.
That case can be handled by the paravirtual mitigation MSRs, right?
^ permalink raw reply
* Re: [PATCH] net: lpc_eth: Fix a possible memory leak in lpc_mii_probe()
From: Vladimir Zapolskiy @ 2026-04-07 20:58 UTC (permalink / raw)
To: Ma Ke
Cc: alexandre.belloni, andrew+netdev, davem, edumazet, kuba,
linux-arm-kernel, linux-kernel, netdev, pabeni, piotr.wojtaszczyk,
stable
In-Reply-To: <20260401131813.139167-1-make24@iscas.ac.cn>
Hello Ma Ke.
On 4/1/26 16:18, Ma Ke wrote:
> On 3/30/26 13:04, Vladimir Zapolskiy wrote:
>> On 3/30/26 11:16, Ma Ke wrote:
>>> lpc_mii_probe() calls of_phy_find_device() to obtain a phy_device
>>> pointer. of_phy_find_device() increments the refcount of the device.
>>> The current implementation does not decrement the refcount after using
>>> the pointer, which leads to a memory leak.
>>
>> this is correct, there is an actual detected bug.
>>
>>>
>>> Add phy_device_free() to balance the refcount.
>>
>> But this does not sound right, you shoud use of_node_put(pldat->phy_node).
>>
>>>
>>> Found by code review.
>>>
>>> Signed-off-by: Ma Ke <make24@iscas.ac.cn>
>>> Cc: stable@vger.kernel.org
>>> Fixes: 3503bf024b3e ("net: lpc_eth: parse phy nodes from device tree")
>>> ---
>>> drivers/net/ethernet/nxp/lpc_eth.c | 11 ++++++-----
>>> 1 file changed, 6 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
>>> index 8b9a3e3bba30..8ce7c9bb6dd6 100644
>>> --- a/drivers/net/ethernet/nxp/lpc_eth.c
>>> +++ b/drivers/net/ethernet/nxp/lpc_eth.c
>>> @@ -751,7 +751,7 @@ static void lpc_handle_link_change(struct net_device *ndev)
>>> static int lpc_mii_probe(struct net_device *ndev)
>>> {
>>> struct netdata_local *pldat = netdev_priv(ndev);
>>> - struct phy_device *phydev;
>>> + struct phy_device *phydev, *phydev_tmp;
>>>
>>> /* Attach to the PHY */
>>> if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
>>> @@ -760,17 +760,18 @@ static int lpc_mii_probe(struct net_device *ndev)
>>> netdev_info(ndev, "using RMII interface\n");
>>>
>>> if (pldat->phy_node)
>>> - phydev = of_phy_find_device(pldat->phy_node);
>>> + phydev_tmp = of_phy_find_device(pldat->phy_node);
>>> else
>>> - phydev = phy_find_first(pldat->mii_bus);
>>> - if (!phydev) {
>>> + phydev_tmp = phy_find_first(pldat->mii_bus);
>>> + if (!phydev_tmp) {
>>
>> I didn't get it, why the new phydev_tmp is needed above, please
>> restore the original code above.
>>
>>> netdev_err(ndev, "no PHY found\n");
>>> return -ENODEV;
>>> }
>>>
>>> - phydev = phy_connect(ndev, phydev_name(phydev),
>>> + phydev = phy_connect(ndev, phydev_name(phydev_tmp),
>>> &lpc_handle_link_change,
>>> lpc_phy_interface_mode(&pldat->pdev->dev));
>>> + phy_device_free(phydev_tmp);
>>
>> This is plainly wrong and has to be dropped or changed to
>>
>> if (pldat->phy_node)
>> of_node_put(pldat->phy_node);
>>
>>> if (IS_ERR(phydev)) {
>>> netdev_err(ndev, "Could not attach to PHY\n");
>>> return PTR_ERR(phydev);
>>
>> Is it AI generated fix or what?.. The change looks bad, it introduces
>> more severe issues than it fixes.
>>
>> If you think you cannot create a proper change, let me know.
>>
> Thank you very much for your detailed review and guidance.
>
> Now I think your point probably is: you are saying that the real leak
> is not from of_phy_find_device(), but from the device node
I was pretty indelicate in my comment, let's split the change into parts.
1) I still do not understand, why phydev_tmp is introduced, please explain
or remove this part of the change;
2) phydev = of_phy_find_device() requires phy_device_free(phydev), but
I do not see why phy_find_first() requires it, while it was added in your
change.
Let's start from resolving these two points.
> pldat->phy_node which was obtained earlier (probably by
> of_parse_phandle()) and never freed by of_node_put(). And you suggest
> to add of_node_put(pldat->phy_node) instead of my wrong
> phy_device_free().
>
> However, I am still a little confused. In lpc_mii_probe(),
> of_phy_find_device() is called. From my understanding, this function
> increases the reference count of the device. To balance it, I thought
> phy_device_free() (which calls put_device()) should be used.
>
> Could you please kindly advise the correct patch? I will follow your
> guidance and submit a proper fix.
>
> I apologize again for my previous wrong patch. Thank you very much for
> your help.
--
Best wishes,
Vladimir
^ permalink raw reply
* Re: [PATCH net-next] net: bcmasp: Switch to page pool for RX path
From: Nicolai Buchwitz @ 2026-04-07 21:04 UTC (permalink / raw)
To: Florian Fainelli
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Justin Chen, Vikas Gupta,
Bhargava Marreddy, Rajashekar Hudumula, Arnd Bergmann,
Eric Biggers, Markus Blöchl, Heiner Kallweit,
Fernando Fernandez Mancera, linux-kernel,
bcm-kernel-feedback-list
In-Reply-To: <20260407162658.4056141-1-florian.fainelli@broadcom.com>
On 7.4.2026 18:26, Florian Fainelli wrote:
> This shows an improvement of 1.9% in reducing the CPU cycles and data
> cache misses.
>
> Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
> ---
> [...]
>
> -static int bcmasp_alloc_buffers(struct bcmasp_intf *intf)
> +static struct page_pool *
> +bcmasp_rx_page_pool_create(struct bcmasp_intf *intf)
> +{
> + struct page_pool_params pp_params = {
> + .order = 0,
> + /* Pages are CPU-side copy targets; no DMA mapping needed. */
> + .flags = 0,
> + .pool_size = NUM_4K_BUFFERS,
> + .nid = NUMA_NO_NODE,
> + .dev = &intf->parent->pdev->dev,
> + .dma_dir = DMA_FROM_DEVICE,
Nit: .dma_dir has AFAIK no effect without PP_FLAG_DMA_MAP, so
it's a bit misleading next to the "no DMA mapping needed" comment.
> + .offset = 0,
> + .max_len = PAGE_SIZE,
> + };
Other Broadcom page pool drivers set .napi and .netdev. Adding those
here would enable direct recycling and expose pool stats in ethtool -S.
> [...]
Thanks
Nicolai
^ permalink raw reply
* Re: [PATCH net-next v2 3/4] bpf-timestamp: keep track of the skb when wait_for_space occurs
From: Willem de Bruijn @ 2026-04-07 21:17 UTC (permalink / raw)
To: Jason Xing, Willem de Bruijn
Cc: davem, edumazet, kuba, pabeni, horms, willemb, martin.lau, netdev,
bpf, Jason Xing, Yushan Zhou
In-Reply-To: <CAL+tcoCctfs=d9zz5ei1S999S94HmUDSToriZ8NJiLT8MmpQTA@mail.gmail.com>
Jason Xing wrote:
> On Tue, Apr 7, 2026 at 11:33 AM Jason Xing <kerneljasonxing@gmail.com> wrote:
> >
> > On Mon, Apr 6, 2026 at 10:37 PM Willem de Bruijn
> > <willemdebruijn.kernel@gmail.com> wrote:
> > >
> > > Jason Xing wrote:
> > > > On Mon, Apr 6, 2026 at 10:28 AM Willem de Bruijn
> > > > <willemdebruijn.kernel@gmail.com> wrote:
> > > > >
> > > > > Jason Xing wrote:
> > > > > > From: Jason Xing <kernelxing@tencent.com>
> > > > > >
> > > > > > The patch is the 1/2 part of push-level granularity feature.
> > > > > >
> > > > > > Tag the skb in tcp_sendmsg_locked() when wait_for_space occurs even
> > > > > > though it might not carry the last byte of the sendmsg.
> > > > > >
> > > > > > Prior to the patch, BPF timestamping cannot cover this case:
> > > > > > The following steps reproduce this:
> > > > > > 1) skb A is the current last skb before entering wait_for_space process
> > > > > > 2) tcp_push() pushes A without any tag
> > > > > > 3) A is transmitted from TCP to driver without putting any skb carrying
> > > > > > timestamps in the error queue, like SCHED, DRV/HARDWARE.
> > > > > > 4) sk_stream_wait_memory() sleeps for a while and then returns with an
> > > > > > error code. Note that the socket lock is released.
> > > > > > 5) skb A finally gets acked and removed from the rtx queue.
> > > > > > 6) continue with the rest of tcp_sendmsg_locked(): it will jump to(goto)
> > > > > > 'do_error' label and then 'out' label.
> > > > > > 7) at this moment, skb A turns out to be the last one in this send
> > > > > > syscall, and miss the following tcp_bpf_tx_timestamp() opportunity
> > > > > > before the final tcp_push()
> > > > > > 8) BPF script fails to see any timestamps this time
> > > > > >
> > > > > > Signed-off-by: Yushan Zhou <katrinzhou@tencent.com>
> > > > > > Signed-off-by: Jason Xing <kernelxing@tencent.com>
> > > > > > ---
> > > > > > net/ipv4/tcp.c | 4 +++-
> > > > > > 1 file changed, 3 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> > > > > > index c603b90057f6..7d030a11d004 100644
> > > > > > --- a/net/ipv4/tcp.c
> > > > > > +++ b/net/ipv4/tcp.c
> > > > > > @@ -1400,9 +1400,11 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
> > > > > > wait_for_space:
> > > > > > set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
> > > > > > tcp_remove_empty_skb(sk);
> > > > > > - if (copied)
> > > > > > + if (copied) {
> > > > > > + tcp_bpf_tx_timestamp(sk);
> > > > > > tcp_push(sk, flags & ~MSG_MORE, mss_now,
> > > > > > TCP_NAGLE_PUSH, size_goal);
> > > > >
> > > > > Now the number of skbs that will be tracked will be unpredictable,
> > > > > varying based on memory pressure.
> > > >
> > > > Right, I put some effort into writing a selftests to check how many
> > > > push functions get called at one time and failed to do so.
> > > >
> > > > >
> > > > > That sounds hard to use to me. Especially if these extra pushes
> > > > > cannot be identified as such.
> > > > >
> > > > > Perhaps if all skbs from the same sendmsg call can be identified,
> > > > > that would help explain pattern in data resulting from these
> > > > > uncommon extra data points.
> > > >
> > > > You meant move tcp_bpf_tx_timestamp before tcp_skb_entail()? That is
> > > > close to packet basis without considering fragmentation of skb :)
> > >
> > > No, I meant somehow in the notification having a way to identify all
> > > the skbs belonging to the same sendmsg call, to allow filtering on
> > > that. But I also don't immediately see how to do that (without adding
> > > yet another counter say).
> >
> > If we don't build the relationship between skb and sendmsg (just like
> > the SENDMSG sock option), we will have no clue on how to calculate. If
> > we only take care of the skb from the view of the syscall layer, it's
> > fine by moving tcp_bpf_tx_timestamp() before tcp_skb_entail(). But in
> > terms of per skb even generated beneath TCP due to gso/tso, there is
> > only one way to correlate: adding an additional member in the skb
> > structure to store its sendmsg time. This discussion is only suitable
> > for use cases like net_timestamping.
> >
> > Well, my key point is that, I have to admit, the above (including
> > existing bpf script net_timestamping) is a less effective way which
> > definitely harms the performance because of the extremely frequent
> > look-up process. It's not suitable for 7x24 observability in
> > production. What we've done internally is make the kernel layer as
> > lightweight/easy as possible and let the timestamping feature throw
> > each record into a ring buffer that the application can read, sort and
> > calculate. This arch survives the performance. But that's simply what
> > the design of the kernel module is, given the fast deployment in
> > production. I suppose in the future we could build a userspace tool
> > like blktrace to monitor efficiently instead of the selftest sample.
> > Honestly I don't like look-up action.
> >
> > Since we're modifying the kernel, how about adding a new member to
> > record sendmsg time which bpf script is able to read. The whole
> > scenario looks like this:
> > 1) in tcp_sendmsg_locked(), record the sendmsg time for each skb
> > 2) in either tso_fragment() or tcp_gso_tstamp(), each new skb will get
> > a copy of its original skb
> > 3) in each stage, bpf script reads the skb's sendmsg time and the
> > current time, and then effortlessly do the math.
> >
> > At this point, what I had in mind is we have two options:
> > 1) only handle the skb from the view of the send syscall layer, which
> > is, for sure, very simple but not thorough.
> > 2) stick to a pure authentic packet basis, then adding a new member
> > seems inevitable. so the question would be where to add? The space of
> > the skb structure is very precious :(
>
> Finding a suitable place to put this timestamp is really hard. IIRC,
> we can't expand the size of struct skb_shared_info so easily since
> it's a global effect.
>
> I'm wondering if we can turn the per-packet mode into a non-compatible
> feature by reusing 'u32 tskey' to store a microsecond timestamp of
> sendmsg.
Agreed that an extra field is hard. We should avoid that.
If the purpose is to group skbs by sendmsg call (e.g., to filter out
all but the last one), it is probably also unnecessary.
From a process PoV, since the process knows the sendmsg len and each
skb has a tskey in byte offset, it can correlate the skb with a given
sendmsg buffer.
The BPF program is under control of a third-party admin. So that does
not follow directly. But it can be passed additional metadata.
I thought about passing the offset of the skb from the start of the
sendmsg buffer to identify all consecutive skbs for a sendmsg call,
as each new buffer will start with an skb with offset 0 ..
.. but that won't work as there is no guarantee that a sendmsg call
will not append to an existing outstanding skb.
Anyway, the general idea is to pass to the BPF program through
bpf_skops_tx_timestamping some relevant signal , without having to
expand either skb or sk itself.
I hear you on that measuring every skb is too frequent. But is calling
the BPF program and letting it decide whether to measure too? BPF
program invocation itself should be cheap.
If per-push is preferable, with a filter ability like the above, it
seems more useful to me already.
^ permalink raw reply
* Re: [PATCH 0/8] smb: add kernel internal IPPROTO_SMBDIRECT
From: Steve French @ 2026-04-07 21:18 UTC (permalink / raw)
To: Stefan Metzmacher
Cc: linux-cifs, samba-technical, Tom Talpey, Long Li, Namjae Jeon,
David Howells, Henrique Carvalho, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Kuniyuki Iwashima,
Willem de Bruijn, netdev, Xin Long, quic, linux-rdma,
linux-kernel, Mark Brown, linux-next
In-Reply-To: <cover.1775571957.git.metze@samba.org>
merged the first 4 into smb3-kernel ksmbd-for-next
On Tue, Apr 7, 2026 at 9:47 AM Stefan Metzmacher <metze@samba.org> wrote:
>
> Hi,
>
> as the work to unify the smbdirect code
> between cifs.ko and ksmbd.ko into an smbdirect.ko
> is in linux-next for a while this is the next
> step to also share the code with userspace
> e.g. Samba as client and server.
>
> The SMBDIRECT protocol, defined in [MS-SMBD] by Microsoft.
> It is used as wrapper around RDMA in order to provide a transport for SMB3,
> but Microsoft also uses it as transport for other protocols.
>
> SMBDIRECT works over Infiniband, RoCE and iWarp. RoCEv2 is based on IP/UDP
> and iWarp is based on IP/TCP, so these use IP addresses natively.
> Infiniband and RoCEv1 require IPOIB in order to be used for SMBDIRECT.
>
> So instead of adding a PF_SMBDIRECT, which would only use AF_INET[6],
> we use IPPROTO_SMBDIRECT instead, this uses a number not
> allocated from IANA, as it would not appear in an IP header.
>
> This is similar to IPPROTO_SMC, IPPROTO_MPTCP and IPPROTO_QUIC,
> which are linux specific values for the socket() syscall.
>
> socket(AF_INET, SOCK_STREAM, IPPROTO_SMBDIRECT);
> socket(AF_INET6, SOCK_STREAM, IPPROTO_SMBDIRECT);
>
> This will allow the existing smbdirect code used by
> cifs.ko and ksmbd.ko to be moved behind the socket layer [1],
> so that there's less special handling. Only sock_sendmsg()
> sock_recvmsg() are used, so that the main stream handling
> is done all the same for tcp, smbdirect and later also quic.
>
> The special RDMA read/write handling will be via direct
> function calls as they are currently done for the in kernel
> consumers.
>
> As a start __sock_create(kern=0)/sk->sk_kern_sock == 0 will
> still cause a -EPROTONOSUPPORT. So only in kernel consumers
> will be supported for now.
>
> For now the core smbdirect code still supports both
> modes, direct calls in indirect via the socket layer.
> The core code uses if (sc->sk.sk_family) as indication
> for the new socket mode. Once cifs.ko and ksmbd.ko
> are converted we can remove the old mode slowly,
> but I'll deferr that to a future patchset.
>
> There's still a way to go in order to make this
> as generic as tcp and quic e.g. adding MSG_SPLICE_PAGES support or
> splice_read/read_sock/read_skb.
>
> But it's a good start, which will make changes much easier.
>
> This patchset is based on top of the smbdirect.ko patches
> in ksmbd-for-next and it's also based on netdev-next
> because it needs this commit from there:
> 8341c989ac77d712c7d6e2bce29e8a4bcb2eeae4
> "net: remove addr_len argument of recvmsg() handlers"
>
> Patches 1-4 are some preparation fixes for the
> existing smbdirect.ko patchset. We may
> squash them into the existing patches before
> sending them to Linus. But for now I kept
> them separately. I also don't cc the network and rdma
> people on these...
>
> Patch 5 defines IPPROTO_SMBDIRECT and SOL_SMBDIRECT
> constants (and also reserve the number 288 for SOL_QUIC
> as applications are already using that and we don't
> want to conflict)
>
> Patch 6 adds basic IPPROTO_SMBDIRECT layering
> on top of the existing smbdirect code.
> This is just enough in order to let cifs.ko
> and ksmbd.ko use it in the following commits,
> so userspace still sees -EPROTONOSUPPORT.
>
> Patch 7 converts cifs.ko to use IPPROTO_SMBDIRECT
> as much as currently possible.
> Using sock_sendmsg is not yet possible, because of the
> tcp_sock_set_cork usage, but that will change in future.
>
> Patch 8 converts ksmbd.ko to use IPPROTO_SMBDIRECT.
>
> Because of the need for netdev-next commit
> 8341c989ac77d712c7d6e2bce29e8a4bcb2eeae4
> "net: remove addr_len argument of recvmsg() handlers"
> it's a bit tricky to prepare something that would not
> cause problems in linux-next.
>
> We could merge in netdev-next completely,
> but I saw commit 00f03539e3d97af925abf42992d8c46167d54243
> in next-20260406, indicates some resolved conflicts
> with (at least) the rdma tree, which comes
> just before netdev-next, while ksmbd-for-next is merged
> before all of them. So merging netdev-next into
> ksmbd-for-next changes the order of netdev-next vs. rdma.
>
> Or we add a new branch smbdirect-for-next that's
> merged into linux-next after netdev-next.
>
> Or a bit hacky but likely easier, ksmbd-for-next
> just cherry-picks 8341c989ac77d712c7d6e2bce29e8a4bcb2eeae4
> "net: remove addr_len argument of recvmsg() handlers"
> and that cherry picked commit is reverted as
> last commit in ksmbd-for-next, or only in linux-next
> right before netdev-next is merged.
>
> For now I have the patches in a branch with a
> cherry picked version of the needed commit only, see
> for-7.1/ipproto-smbdirect-20260407-v1 at commit:
> e1972e6f1fda9842c5724b7daf4a2aa7779901a5
> git fetch https://git.samba.org/metze/linux/wip.git for-7.1/ipproto-smbdirect-20260407-v1
> https://git.samba.org/?p=metze/linux/wip.git;a=shortlog;h=refs/heads/for-7.1/ipproto-smbdirect-20260407-v1
>
> It would be great to get this somehow into linux-next soon :-)
>
> Stefan Metzmacher (8):
> smb: smbdirect: change
> smbdirect_socket_parameters.{initiator_depth,responder_resources} to
> __u16
> smb: smbdirect: fix copyright header of smbdirect.h
> smb: smbdirect: fix the logic in smbdirect_socket_destroy_sync()
> without an error
> smb: smbdirect: let smbdirect_connection_deregister_mr_io unlock while
> waiting
> net: define IPPROTO_SMBDIRECT and SOL_SMBDIRECT constants
> smb: smbdirect: add in kernel only support for IPPROTO_SMBDIRECT
> smb: client: make use of IPPROTO_SMBDIRECT sockets
> smb: server: make use of IPPROTO_SMBDIRECT sockets
>
> fs/smb/client/cifs_debug.c | 2 +-
> fs/smb/client/cifsfs.c | 2 +-
> fs/smb/client/cifsglob.h | 7 +-
> fs/smb/client/connect.c | 123 +-
> fs/smb/client/file.c | 8 +-
> fs/smb/client/sess.c | 4 +-
> fs/smb/client/smb2ops.c | 8 +-
> fs/smb/client/smb2pdu.c | 10 +-
> fs/smb/client/smbdirect.c | 275 +--
> fs/smb/client/smbdirect.h | 27 +-
> fs/smb/client/transport.c | 2 +-
> fs/smb/common/smbdirect/Makefile | 1 +
> fs/smb/common/smbdirect/smbdirect.h | 69 +-
> fs/smb/common/smbdirect/smbdirect_accept.c | 14 +-
> .../common/smbdirect/smbdirect_connection.c | 58 +
> fs/smb/common/smbdirect/smbdirect_devices.c | 2 +-
> fs/smb/common/smbdirect/smbdirect_internal.h | 59 +-
> fs/smb/common/smbdirect/smbdirect_listen.c | 49 +-
> fs/smb/common/smbdirect/smbdirect_main.c | 45 +
> fs/smb/common/smbdirect/smbdirect_mr.c | 18 +
> fs/smb/common/smbdirect/smbdirect_proto.c | 1549 +++++++++++++++++
> fs/smb/common/smbdirect/smbdirect_public.h | 3 +
> fs/smb/common/smbdirect/smbdirect_rw.c | 29 +-
> fs/smb/common/smbdirect/smbdirect_socket.c | 180 +-
> fs/smb/common/smbdirect/smbdirect_socket.h | 26 +-
> fs/smb/server/transport_rdma.c | 119 +-
> include/linux/socket.h | 2 +
> include/uapi/linux/in.h | 2 +
> 28 files changed, 2320 insertions(+), 373 deletions(-)
> create mode 100644 fs/smb/common/smbdirect/smbdirect_proto.c
>
> --
> 2.43.0
>
--
Thanks,
Steve
^ permalink raw reply
* [PATCH v3 net-next 00/15] ip6mr: No RTNL for RTNL_FAMILY_IP6MR rtnetlink.
From: Kuniyuki Iwashima @ 2026-04-07 21:19 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
This series is the IPv6 version of
https://lore.kernel.org/netdev/20260228221800.1082070-1-kuniyu@google.com/
and removes RTNL from ip6mr rtnetlink handlers.
After this series, there are a few RTNL left in net/ipv6/ipmr.c
and such users will be converted to per-netns RTNL in another
series.
Patch 1 extends the ipmr selftest to exercise most of the RTNL
paths in net/ipv6/ipmr.c
Patch 2 is misc cleanup.
Patch 3 - 7 converts RTM_GETROUTE handlers to RCU.
Patch 8 removes struct fib_dump_filter.rtnl_held.
Patch 9 - 11 converts ->exit_batch() to ->exit_rtnl() to
save one RTNL in cleanup_net().
Patch 12 - 13 removes unnecessary RTNL during setup_net()
failure.
Patch 14 is cleanup.
Patch 15 drops RTNL for MRT6_(ADD|DEL)_MFC(_PROXY)?.
Kuniyuki Iwashima (15):
selftest: net: Extend ipmr.c for IP6MR.
ipmr: Convert mr_table.cache_resolve_queue_len to u32.
ip6mr: Annotate access to mrt->mroute_do_{pim,assert,wrvifwhole}.
ip6mr: Use MAXMIFS in mr6_msgsize().
ip6mr: Allocate skb earlier in ip6mr_rtm_getroute().
ip6mr: Convert ip6mr_rtm_getroute() to RCU.
ip6mr: Convert ip6mr_rtm_dumproute() to RCU.
net: Remove rtnl_held of struct fib_dump_filter.
ip6mr: Move unregister_netdevice_many() out of mroute_clean_tables().
ip6mr: Move unregister_netdevice_many() out of ip6mr_free_table().
ip6mr: Convert ip6mr_net_exit_batch() to ->exit_rtnl().
ip6mr: Remove RTNL in ip6mr_rules_init() and ip6mr_net_init().
ip6mr: Call fib_rules_unregister() without RTNL.
ip6mr: Define net->ipv6.{ip6mr_notifier_ops,ipmr_seq} under
CONFIG_IP_MROUTE.
ip6mr: Replace RTNL with a dedicated mutex for MFC.
include/linux/mroute_base.h | 2 +-
include/net/ip_fib.h | 1 -
include/net/netns/ipv6.h | 5 +-
net/ipv4/fib_frontend.c | 19 +-
net/ipv4/ipmr.c | 22 +-
net/ipv6/ip6_fib.c | 1 -
net/ipv6/ip6mr.c | 195 +++++++++++-------
net/mpls/af_mpls.c | 6 +-
tools/testing/selftests/net/forwarding/ipmr.c | 163 ++++++++++-----
9 files changed, 252 insertions(+), 162 deletions(-)
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply
* [PATCH v3 net-next 01/15] selftest: net: Extend ipmr.c for IP6MR.
From: Kuniyuki Iwashima @ 2026-04-07 21:19 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260407212001.2368593-1-kuniyu@google.com>
This commit extends most test cases in ipmr.c for IPV6MR.
Note that IP6MR does not provide rtnetlink interface for MFC,
so such tests will be skipped.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
tools/testing/selftests/net/forwarding/ipmr.c | 163 ++++++++++++------
1 file changed, 110 insertions(+), 53 deletions(-)
diff --git a/tools/testing/selftests/net/forwarding/ipmr.c b/tools/testing/selftests/net/forwarding/ipmr.c
index df870aad9ead..cfd00173bcd6 100644
--- a/tools/testing/selftests/net/forwarding/ipmr.c
+++ b/tools/testing/selftests/net/forwarding/ipmr.c
@@ -2,7 +2,9 @@
/* Copyright 2026 Google LLC */
#include <linux/if.h>
+#include <linux/in6.h>
#include <linux/mroute.h>
+#include <linux/mroute6.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/socket.h>
@@ -17,6 +19,14 @@ FIXTURE(ipmr)
int netlink_sk;
int raw_sk;
int veth_ifindex;
+ union {
+ struct vifctl vif;
+ struct mif6ctl vif6;
+ };
+ union {
+ struct mfcctl mfc;
+ struct mf6cctl mfc6;
+ };
};
FIXTURE_VARIANT(ipmr)
@@ -25,6 +35,11 @@ FIXTURE_VARIANT(ipmr)
int protocol;
int level;
int opts[MRT_MAX - MRT_BASE + 1];
+ int vif_size;
+ char vif_check_cmd_pimreg[64];
+ char vif_check_cmd_veth[64];
+ int mfc_size;
+ char mfc_check_cmd[1024];
};
FIXTURE_VARIANT_ADD(ipmr, ipv4)
@@ -47,6 +62,39 @@ FIXTURE_VARIANT_ADD(ipmr, ipv4)
MRT_DEL_MFC_PROXY,
MRT_FLUSH,
},
+ .vif_size = sizeof(struct vifctl),
+ .vif_check_cmd_pimreg = "cat /proc/net/ip_mr_vif | grep -q pimreg",
+ .vif_check_cmd_veth = "cat /proc/net/ip_mr_vif | grep -q veth",
+ .mfc_size = sizeof(struct mfcctl),
+ .mfc_check_cmd = "cat /proc/net/ip_mr_cache | grep -q '00000000 00000000'",
+};
+
+FIXTURE_VARIANT_ADD(ipmr, ipv6)
+{
+ .family = AF_INET6,
+ .protocol = IPPROTO_ICMPV6,
+ .level = IPPROTO_IPV6,
+ .opts = {
+ MRT6_INIT,
+ MRT6_DONE,
+ MRT6_ADD_MIF,
+ MRT6_DEL_MIF,
+ MRT6_ADD_MFC,
+ MRT6_DEL_MFC,
+ MRT6_VERSION,
+ MRT6_ASSERT,
+ MRT6_PIM,
+ MRT6_TABLE,
+ MRT6_ADD_MFC_PROXY,
+ MRT6_DEL_MFC_PROXY,
+ MRT_FLUSH,
+ },
+ .vif_size = sizeof(struct mif6ctl),
+ .vif_check_cmd_pimreg = "cat /proc/net/ip6_mr_vif | grep -q pim6reg",
+ .vif_check_cmd_veth = "cat /proc/net/ip6_mr_vif | grep -q veth",
+ .mfc_size = sizeof(struct mf6cctl),
+ .mfc_check_cmd = "cat /proc/net/ip6_mr_cache | "
+ "grep -q '0000:0000:0000:0000:0000:0000:0000:0000 0000:0000:0000:0000:0000:0000:0000:0000'",
};
struct mfc_attr {
@@ -144,6 +192,18 @@ FIXTURE_SETUP(ipmr)
ASSERT_EQ(0, err);
self->veth_ifindex = ifr.ifr_ifindex;
+
+ if (variant->family == AF_INET) {
+ self->vif = (struct vifctl){
+ .vifc_flags = VIFF_USE_IFINDEX,
+ .vifc_lcl_ifindex = self->veth_ifindex,
+ };
+ } else {
+ self->vif6 = (struct mif6ctl){
+ .mif6c_flags = 0,
+ .mif6c_pifi = self->veth_ifindex,
+ };
+ }
}
FIXTURE_TEARDOWN(ipmr)
@@ -169,41 +229,39 @@ TEST_F(ipmr, mrt_init)
TEST_F(ipmr, mrt_add_vif_register)
{
- struct vifctl vif = {
- .vifc_vifi = 0,
- .vifc_flags = VIFF_REGISTER,
- };
int err;
+ memset(&self->vif, 0, variant->vif_size);
+
+ if (variant->family == AF_INET)
+ self->vif.vifc_flags = VIFF_REGISTER;
+ else
+ self->vif6.mif6c_flags = MIFF_REGISTER;
+
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(0, err);
- err = system("cat /proc/net/ip_mr_vif | grep -q pimreg");
+ err = system(variant->vif_check_cmd_pimreg);
ASSERT_EQ(0, err);
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_DEL_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(0, err);
}
TEST_F(ipmr, mrt_del_vif_unreg)
{
- struct vifctl vif = {
- .vifc_vifi = 0,
- .vifc_flags = VIFF_USE_IFINDEX,
- .vifc_lcl_ifindex = self->veth_ifindex,
- };
int err;
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(0, err);
- err = system("cat /proc/net/ip_mr_vif | grep -q veth0");
+ err = system(variant->vif_check_cmd_veth);
ASSERT_EQ(0, err);
/* VIF is removed along with its device. */
@@ -213,23 +271,18 @@ TEST_F(ipmr, mrt_del_vif_unreg)
/* mrt->vif_table[veth_ifindex]->dev is NULL. */
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_DEL_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(-1, err);
ASSERT_EQ(EADDRNOTAVAIL, errno);
}
TEST_F(ipmr, mrt_del_vif_netns_dismantle)
{
- struct vifctl vif = {
- .vifc_vifi = 0,
- .vifc_flags = VIFF_USE_IFINDEX,
- .vifc_lcl_ifindex = self->veth_ifindex,
- };
int err;
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(0, err);
/* Let cleanup_net() remove veth0 and VIF. */
@@ -237,49 +290,49 @@ TEST_F(ipmr, mrt_del_vif_netns_dismantle)
TEST_F(ipmr, mrt_add_mfc)
{
- struct mfcctl mfc = {};
int err;
/* MRT_ADD_MFC / MRT_ADD_MFC_PROXY does not need vif to exist (unlike netlink). */
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_MFC - MRT_BASE],
- &mfc, sizeof(mfc));
+ &self->mfc, variant->mfc_size);
ASSERT_EQ(0, err);
/* (0.0.0.0 -> 0.0.0.0) */
- err = system("cat /proc/net/ip_mr_cache | grep -q '00000000 00000000' ");
+ err = system(variant->mfc_check_cmd);
ASSERT_EQ(0, err);
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_DEL_MFC - MRT_BASE],
- &mfc, sizeof(mfc));
+ &self->mfc, variant->mfc_size);
}
TEST_F(ipmr, mrt_add_mfc_proxy)
{
- struct mfcctl mfc = {};
int err;
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_MFC_PROXY - MRT_BASE],
- &mfc, sizeof(mfc));
+ &self->mfc, variant->mfc_size);
ASSERT_EQ(0, err);
- err = system("cat /proc/net/ip_mr_cache | grep -q '00000000 00000000' ");
+ err = system(variant->mfc_check_cmd);
ASSERT_EQ(0, err);
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_DEL_MFC_PROXY - MRT_BASE],
- &mfc, sizeof(mfc));
+ &self->mfc, variant->mfc_size);
}
+#define SKIP_IPV6() \
+ do { \
+ if (variant->family == AF_INET6) \
+ SKIP(return, \
+ "no netlink MFC interface"); \
+ } while (0)
+
TEST_F(ipmr, mrt_add_mfc_netlink)
{
- struct vifctl vif = {
- .vifc_vifi = 0,
- .vifc_flags = VIFF_USE_IFINDEX,
- .vifc_lcl_ifindex = self->veth_ifindex,
- };
struct mfc_attr mfc_attr = {
.table = RT_TABLE_DEFAULT,
.origin = 0,
@@ -289,15 +342,17 @@ TEST_F(ipmr, mrt_add_mfc_netlink)
};
int err;
+ SKIP_IPV6();
+
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(0, err);
err = nl_sendmsg_mfc(_metadata, self, RTM_NEWROUTE, &mfc_attr);
ASSERT_EQ(0, err);
- err = system("cat /proc/net/ip_mr_cache | grep -q '00000000 00000000' ");
+ err = system(variant->mfc_check_cmd);
ASSERT_EQ(0, err);
err = nl_sendmsg_mfc(_metadata, self, RTM_DELROUTE, &mfc_attr);
@@ -306,11 +361,6 @@ TEST_F(ipmr, mrt_add_mfc_netlink)
TEST_F(ipmr, mrt_add_mfc_netlink_proxy)
{
- struct vifctl vif = {
- .vifc_vifi = 0,
- .vifc_flags = VIFF_USE_IFINDEX,
- .vifc_lcl_ifindex = self->veth_ifindex,
- };
struct mfc_attr mfc_attr = {
.table = RT_TABLE_DEFAULT,
.origin = 0,
@@ -320,15 +370,17 @@ TEST_F(ipmr, mrt_add_mfc_netlink_proxy)
};
int err;
+ SKIP_IPV6();
+
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(0, err);
err = nl_sendmsg_mfc(_metadata, self, RTM_NEWROUTE, &mfc_attr);
ASSERT_EQ(0, err);
- err = system("cat /proc/net/ip_mr_cache | grep -q '00000000 00000000' ");
+ err = system(variant->mfc_check_cmd);
ASSERT_EQ(0, err);
err = nl_sendmsg_mfc(_metadata, self, RTM_DELROUTE, &mfc_attr);
@@ -345,6 +397,8 @@ TEST_F(ipmr, mrt_add_mfc_netlink_no_vif)
};
int err;
+ SKIP_IPV6();
+
/* netlink always requires RTA_IIF of an existing vif. */
mfc_attr.ifindex = 0;
err = nl_sendmsg_mfc(_metadata, self, RTM_NEWROUTE, &mfc_attr);
@@ -378,6 +432,8 @@ TEST_F(ipmr, mrt_del_mfc_netlink_netns_dismantle)
};
int i, err;
+ SKIP_IPV6();
+
for (i = 0; i < 2; i++) {
/* Create 2 VIFs just to avoid -ENFILE later. */
err = setsockopt(self->raw_sk,
@@ -390,7 +446,7 @@ TEST_F(ipmr, mrt_del_mfc_netlink_netns_dismantle)
err = nl_sendmsg_mfc(_metadata, self, RTM_NEWROUTE, &mfc_attr);
ASSERT_EQ(0, err);
- err = system("cat /proc/net/ip_mr_cache | grep -q '00000000 00000000' ");
+ err = system(variant->mfc_check_cmd);
ASSERT_EQ(0, err);
/* Remove mrt->vif_table[0]. */
@@ -398,7 +454,7 @@ TEST_F(ipmr, mrt_del_mfc_netlink_netns_dismantle)
ASSERT_EQ(0, err);
/* MFC entry is NOT removed even if the tied VIF is removed... */
- err = system("cat /proc/net/ip_mr_cache | grep -q '00000000 00000000' ");
+ err = system(variant->mfc_check_cmd);
ASSERT_EQ(0, err);
/* ... and netlink is not capable of removing such an entry
@@ -412,11 +468,6 @@ TEST_F(ipmr, mrt_del_mfc_netlink_netns_dismantle)
TEST_F(ipmr, mrt_table_flush)
{
- struct vifctl vif = {
- .vifc_vifi = 0,
- .vifc_flags = VIFF_USE_IFINDEX,
- .vifc_lcl_ifindex = self->veth_ifindex,
- };
struct mfc_attr mfc_attr = {
.origin = 0,
.group = 0,
@@ -436,11 +487,17 @@ TEST_F(ipmr, mrt_table_flush)
err = setsockopt(self->raw_sk,
variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
- &vif, sizeof(vif));
+ &self->vif, variant->vif_size);
ASSERT_EQ(0, err);
- mfc_attr.table = table_id;
- err = nl_sendmsg_mfc(_metadata, self, RTM_NEWROUTE, &mfc_attr);
+ if (variant->family == AF_INET) {
+ mfc_attr.table = table_id;
+ err = nl_sendmsg_mfc(_metadata, self, RTM_NEWROUTE, &mfc_attr);
+ } else {
+ err = setsockopt(self->raw_sk,
+ variant->level, variant->opts[MRT_ADD_MFC - MRT_BASE],
+ &self->mfc, variant->mfc_size);
+ }
ASSERT_EQ(0, err);
/* Flush mrt->vif_table[] and all caches. */
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 net-next 02/15] ipmr: Convert mr_table.cache_resolve_queue_len to u32.
From: Kuniyuki Iwashima @ 2026-04-07 21:19 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260407212001.2368593-1-kuniyu@google.com>
mr_table.cache_resolve_queue_len is always updated under
spin_lock_bh(&mfc_unres_lock).
Let's convert it to u32.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/linux/mroute_base.h | 2 +-
net/ipv4/ipmr.c | 18 ++++++++++--------
net/ipv6/ip6mr.c | 11 +++++++----
3 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h
index cf3374580f74..3341acca002f 100644
--- a/include/linux/mroute_base.h
+++ b/include/linux/mroute_base.h
@@ -254,7 +254,7 @@ struct mr_table {
struct rhltable mfc_hash;
struct list_head mfc_cache_list;
int maxvif;
- atomic_t cache_resolve_queue_len;
+ u32 cache_resolve_queue_len;
bool mroute_do_assert;
bool mroute_do_pim;
bool mroute_do_wrvifwhole;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 8a08d09b4c30..2566b4a1f80b 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -756,7 +756,8 @@ static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
struct sk_buff *skb;
struct nlmsgerr *e;
- atomic_dec(&mrt->cache_resolve_queue_len);
+ WRITE_ONCE(mrt->cache_resolve_queue_len,
+ mrt->cache_resolve_queue_len - 1);
while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved))) {
if (ip_hdr(skb)->version == 0) {
@@ -1178,11 +1179,12 @@ static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
return err;
}
- atomic_inc(&mrt->cache_resolve_queue_len);
+ WRITE_ONCE(mrt->cache_resolve_queue_len,
+ mrt->cache_resolve_queue_len + 1);
list_add(&c->_c.list, &mrt->mfc_unres_queue);
mroute_netlink_event(mrt, c, RTM_NEWROUTE);
- if (atomic_read(&mrt->cache_resolve_queue_len) == 1)
+ if (mrt->cache_resolve_queue_len == 1)
mod_timer(&mrt->ipmr_expire_timer,
c->_c.mfc_un.unres.expires);
}
@@ -1287,7 +1289,8 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
if (uc->mfc_origin == c->mfc_origin &&
uc->mfc_mcastgrp == c->mfc_mcastgrp) {
list_del(&_uc->list);
- atomic_dec(&mrt->cache_resolve_queue_len);
+ WRITE_ONCE(mrt->cache_resolve_queue_len,
+ mrt->cache_resolve_queue_len - 1);
found = true;
break;
}
@@ -1346,7 +1349,7 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags,
}
if (flags & MRT_FLUSH_MFC) {
- if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
+ if (READ_ONCE(mrt->cache_resolve_queue_len)) {
spin_lock_bh(&mfc_unres_lock);
list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
list_del(&c->list);
@@ -2954,10 +2957,9 @@ static int ipmr_rtm_route(struct sk_buff *skb, struct nlmsghdr *nlh,
static bool ipmr_fill_table(struct mr_table *mrt, struct sk_buff *skb)
{
- u32 queue_len = atomic_read(&mrt->cache_resolve_queue_len);
-
if (nla_put_u32(skb, IPMRA_TABLE_ID, mrt->id) ||
- nla_put_u32(skb, IPMRA_TABLE_CACHE_RES_QUEUE_LEN, queue_len) ||
+ nla_put_u32(skb, IPMRA_TABLE_CACHE_RES_QUEUE_LEN,
+ READ_ONCE(mrt->cache_resolve_queue_len)) ||
nla_put_s32(skb, IPMRA_TABLE_MROUTE_REG_VIF_NUM,
READ_ONCE(mrt->mroute_reg_vif_num)) ||
nla_put_u8(skb, IPMRA_TABLE_MROUTE_DO_ASSERT,
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 85010ff21c98..5755244e226c 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -792,7 +792,8 @@ static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c)
struct net *net = read_pnet(&mrt->net);
struct sk_buff *skb;
- atomic_dec(&mrt->cache_resolve_queue_len);
+ WRITE_ONCE(mrt->cache_resolve_queue_len,
+ mrt->cache_resolve_queue_len - 1);
while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) {
if (ipv6_hdr(skb)->version == 0) {
@@ -1205,7 +1206,8 @@ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi,
return err;
}
- atomic_inc(&mrt->cache_resolve_queue_len);
+ WRITE_ONCE(mrt->cache_resolve_queue_len,
+ mrt->cache_resolve_queue_len + 1);
list_add(&c->_c.list, &mrt->mfc_unres_queue);
mr6_netlink_event(mrt, c, RTM_NEWROUTE);
@@ -1510,7 +1512,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
list_del(&_uc->list);
- atomic_dec(&mrt->cache_resolve_queue_len);
+ WRITE_ONCE(mrt->cache_resolve_queue_len,
+ mrt->cache_resolve_queue_len - 1);
found = true;
break;
}
@@ -1568,7 +1571,7 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags)
}
if (flags & MRT6_FLUSH_MFC) {
- if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
+ if (READ_ONCE(mrt->cache_resolve_queue_len)) {
spin_lock_bh(&mfc_unres_lock);
list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) {
list_del(&c->list);
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 net-next 03/15] ip6mr: Annotate access to mrt->mroute_do_{pim,assert,wrvifwhole}.
From: Kuniyuki Iwashima @ 2026-04-07 21:19 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260407212001.2368593-1-kuniyu@google.com>
These fields in struct mr_table are updated in ip6_mroute_setsockopt()
under RTNL:
* mroute_do_pim
* mroute_do_assert
* mroute_do_wrvifwhole
However, ip6_mroute_getsockopt() does not hold RTNL and read the first
two fields locklessly, and ip6_mr_forward() reads all the three under
RCU.
Let's use WRITE_ONCE() and READ_ONCE() for them.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv6/ip6mr.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 5755244e226c..5d368ee39b28 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1783,7 +1783,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
return -EINVAL;
if (copy_from_sockptr(&v, optval, sizeof(v)))
return -EFAULT;
- mrt->mroute_do_assert = v;
+ WRITE_ONCE(mrt->mroute_do_assert, v);
return 0;
}
@@ -1803,9 +1803,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
rtnl_lock();
ret = 0;
if (v != mrt->mroute_do_pim) {
- mrt->mroute_do_pim = v;
- mrt->mroute_do_assert = v;
- mrt->mroute_do_wrvifwhole = do_wrmifwhole;
+ WRITE_ONCE(mrt->mroute_do_pim, v);
+ WRITE_ONCE(mrt->mroute_do_assert, v);
+ WRITE_ONCE(mrt->mroute_do_wrvifwhole, do_wrmifwhole);
}
rtnl_unlock();
return ret;
@@ -1873,11 +1873,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,
break;
#ifdef CONFIG_IPV6_PIMSM_V2
case MRT6_PIM:
- val = mrt->mroute_do_pim;
+ val = READ_ONCE(mrt->mroute_do_pim);
break;
#endif
case MRT6_ASSERT:
- val = mrt->mroute_do_assert;
+ val = READ_ONCE(mrt->mroute_do_assert);
break;
default:
return -ENOPROTOOPT;
@@ -2180,20 +2180,20 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
if (rcu_access_pointer(mrt->vif_table[vif].dev) != dev) {
atomic_long_inc(&c->_c.mfc_un.res.wrong_if);
- if (true_vifi >= 0 && mrt->mroute_do_assert &&
+ if (true_vifi >= 0 && READ_ONCE(mrt->mroute_do_assert) &&
/* pimsm uses asserts, when switching from RPT to SPT,
so that we cannot check that packet arrived on an oif.
It is bad, but otherwise we would need to move pretty
large chunk of pimd to kernel. Ough... --ANK
*/
- (mrt->mroute_do_pim ||
+ (READ_ONCE(mrt->mroute_do_pim) ||
c->_c.mfc_un.res.ttls[true_vifi] < 255) &&
time_after(jiffies,
c->_c.mfc_un.res.last_assert +
MFC_ASSERT_THRESH)) {
c->_c.mfc_un.res.last_assert = jiffies;
ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
- if (mrt->mroute_do_wrvifwhole)
+ if (READ_ONCE(mrt->mroute_do_wrvifwhole))
ip6mr_cache_report(mrt, skb, true_vifi,
MRT6MSG_WRMIFWHOLE);
}
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 net-next 04/15] ip6mr: Use MAXMIFS in mr6_msgsize().
From: Kuniyuki Iwashima @ 2026-04-07 21:19 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260407212001.2368593-1-kuniyu@google.com>
mr6_msgsize() calculates skb size needed for ip6mr_fill_mroute().
The size differs based on mrt->maxvif.
We will drop RTNL for ip6mr_rtm_getroute() and mrt->maxvif may
change under RCU.
To avoid -EMSGSIZE, let's calculate the size with the maximum
value of mrt->maxvif, MAXMIFS.
struct rtnexthop is 8 bytes and MAXMIFS is 32, so the maximum delta
is 256 bytes, which is small enough.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv6/ip6mr.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 5d368ee39b28..4d78041276c1 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -2542,7 +2542,7 @@ static int _ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
cmd, flags);
}
-static int mr6_msgsize(bool unresolved, int maxvif)
+static int mr6_msgsize(bool unresolved)
{
size_t len =
NLMSG_ALIGN(sizeof(struct rtmsg))
@@ -2555,7 +2555,7 @@ static int mr6_msgsize(bool unresolved, int maxvif)
len = len
+ nla_total_size(4) /* RTA_IIF */
+ nla_total_size(0) /* RTA_MULTIPATH */
- + maxvif * NLA_ALIGN(sizeof(struct rtnexthop))
+ + MAXMIFS * NLA_ALIGN(sizeof(struct rtnexthop))
/* RTA_MFC_STATS */
+ nla_total_size_64bit(sizeof(struct rta_mfc_stats))
;
@@ -2570,8 +2570,7 @@ static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
struct sk_buff *skb;
int err = -ENOBUFS;
- skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif),
- GFP_ATOMIC);
+ skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS), GFP_ATOMIC);
if (!skb)
goto errout;
@@ -2727,7 +2726,7 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
return -ENOENT;
}
- skb = nlmsg_new(mr6_msgsize(false, mrt->maxvif), GFP_KERNEL);
+ skb = nlmsg_new(mr6_msgsize(false), GFP_KERNEL);
if (!skb)
return -ENOBUFS;
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 net-next 05/15] ip6mr: Allocate skb earlier in ip6mr_rtm_getroute().
From: Kuniyuki Iwashima @ 2026-04-07 21:19 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260407212001.2368593-1-kuniyu@google.com>
We will convert ip6mr_rtm_getroute() to RCU in the following patch,
where __ip6mr_get_table() will be called under RCU.
nlmsg_new() uses GFP_KERNEL and needs to be called before holding
rcu_read_lock().
As a prep, let's move nlmsg_new() before __ip6mr_get_table().
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv6/ip6mr.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 4d78041276c1..db7376cbcc01 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -2705,6 +2705,10 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
if (err < 0)
return err;
+ skb = nlmsg_new(mr6_msgsize(false), GFP_KERNEL);
+ if (!skb)
+ return -ENOBUFS;
+
if (tb[RTA_SRC])
src = nla_get_in6_addr(tb[RTA_SRC]);
if (tb[RTA_DST])
@@ -2714,7 +2718,8 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
mrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
if (!mrt) {
NL_SET_ERR_MSG_MOD(extack, "MR table does not exist");
- return -ENOENT;
+ err = -ENOENT;
+ goto err;
}
/* entries are added/deleted only under RTNL */
@@ -2723,21 +2728,20 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
rcu_read_unlock();
if (!cache) {
NL_SET_ERR_MSG_MOD(extack, "MR cache entry not found");
- return -ENOENT;
+ err = -ENOENT;
+ goto err;
}
- skb = nlmsg_new(mr6_msgsize(false), GFP_KERNEL);
- if (!skb)
- return -ENOBUFS;
-
err = ip6mr_fill_mroute(mrt, skb, NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, cache, RTM_NEWROUTE, 0);
- if (err < 0) {
- kfree_skb(skb);
- return err;
- }
+ if (err < 0)
+ goto err;
return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
+
+err:
+ kfree_skb(skb);
+ return err;
}
static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v3 net-next 06/15] ip6mr: Convert ip6mr_rtm_getroute() to RCU.
From: Kuniyuki Iwashima @ 2026-04-07 21:19 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev
In-Reply-To: <20260407212001.2368593-1-kuniyu@google.com>
ip6mr_rtm_getroute() calls __ip6mr_get_table(), ip6mr_cache_find(),
and ip6mr_fill_mroute().
Once created, struct mr_table is not freed until netns dismantle,
so it's safe under RCU.
ip6mr_cache_find() iterates mrt->mfc_hash with rhl_for_each_entry_rcu().
struct mr_mfc is freed with call_rcu(), so this is also safe under
RCU.
ip6mr_fill_mroute() calls mr_fill_mroute(), which properly uses
RCU helpers.
Let's call them under RCU and register ip6mr_rtm_getroute() with
RTNL_FLAG_DOIT_UNLOCKED.
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv6/ip6mr.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index db7376cbcc01..389471e740bc 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1390,7 +1390,8 @@ static struct pernet_operations ip6mr_net_ops = {
static const struct rtnl_msg_handler ip6mr_rtnl_msg_handlers[] __initconst_or_module = {
{.owner = THIS_MODULE, .protocol = RTNL_FAMILY_IP6MR,
.msgtype = RTM_GETROUTE,
- .doit = ip6mr_rtm_getroute, .dumpit = ip6mr_rtm_dumproute},
+ .doit = ip6mr_rtm_getroute, .dumpit = ip6mr_rtm_dumproute,
+ .flags = RTNL_FLAG_DOIT_UNLOCKED},
};
int __init ip6_mr_init(void)
@@ -2715,6 +2716,8 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
grp = nla_get_in6_addr(tb[RTA_DST]);
tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
+ rcu_read_lock();
+
mrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT);
if (!mrt) {
NL_SET_ERR_MSG_MOD(extack, "MR table does not exist");
@@ -2722,10 +2725,7 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
goto err;
}
- /* entries are added/deleted only under RTNL */
- rcu_read_lock();
cache = ip6mr_cache_find(mrt, &src, &grp);
- rcu_read_unlock();
if (!cache) {
NL_SET_ERR_MSG_MOD(extack, "MR cache entry not found");
err = -ENOENT;
@@ -2737,9 +2737,12 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
if (err < 0)
goto err;
+ rcu_read_unlock();
+
return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
err:
+ rcu_read_unlock();
kfree_skb(skb);
return err;
}
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox