* [PATCH v9 net-next 1/5] psp: add admin/non-admin version of psp_device_get_locked
From: Wei Wang @ 2026-03-30 22:31 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Daniel Zahka, Willem de Bruijn, David Wei,
Andrew Lunn, David S . Miller, Eric Dumazet, Simon Horman
Cc: Wei Wang
In-Reply-To: <20260330223143.2394706-1-weibunny.kernel@gmail.com>
From: Wei Wang <weibunny@fb.com>
Introduce 2 versions of psp_device_get_locked:
1. psp_device_get_locked_admin(): This version is used for operations
that would change the status of the psd, and are currently used for
dev-set nad key-rotation.
2. psp_device_get_locked(): This is the non-admin version, which are
used for broader user issued operations including: dev-get, rx-assoc,
tx-assoc, get-stats.
Following commit will be implementing both of the checks.
Signed-off-by: Wei Wang <weibunny@fb.com>
---
Documentation/netlink/specs/psp.yaml | 4 ++--
net/psp/psp-nl-gen.c | 4 ++--
net/psp/psp-nl-gen.h | 2 ++
net/psp/psp.h | 2 +-
net/psp/psp_main.c | 7 +++++-
net/psp/psp_nl.c | 33 ++++++++++++++++++++--------
6 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml
index f3a57782d2cf..fe2cdc966604 100644
--- a/Documentation/netlink/specs/psp.yaml
+++ b/Documentation/netlink/specs/psp.yaml
@@ -195,7 +195,7 @@ operations:
- psp-versions-ena
reply:
attributes: []
- pre: psp-device-get-locked
+ pre: psp-device-get-locked-admin
post: psp-device-unlock
-
name: dev-change-ntf
@@ -214,7 +214,7 @@ operations:
reply:
attributes:
- id
- pre: psp-device-get-locked
+ pre: psp-device-get-locked-admin
post: psp-device-unlock
-
name: key-rotate-ntf
diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c
index 22a48d0fa378..1f5e73e7ccc1 100644
--- a/net/psp/psp-nl-gen.c
+++ b/net/psp/psp-nl-gen.c
@@ -71,7 +71,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
},
{
.cmd = PSP_CMD_DEV_SET,
- .pre_doit = psp_device_get_locked,
+ .pre_doit = psp_device_get_locked_admin,
.doit = psp_nl_dev_set_doit,
.post_doit = psp_device_unlock,
.policy = psp_dev_set_nl_policy,
@@ -80,7 +80,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
},
{
.cmd = PSP_CMD_KEY_ROTATE,
- .pre_doit = psp_device_get_locked,
+ .pre_doit = psp_device_get_locked_admin,
.doit = psp_nl_key_rotate_doit,
.post_doit = psp_device_unlock,
.policy = psp_key_rotate_nl_policy,
diff --git a/net/psp/psp-nl-gen.h b/net/psp/psp-nl-gen.h
index 599c5f1c82f2..977355455395 100644
--- a/net/psp/psp-nl-gen.h
+++ b/net/psp/psp-nl-gen.h
@@ -17,6 +17,8 @@ extern const struct nla_policy psp_keys_nl_policy[PSP_A_KEYS_SPI + 1];
int psp_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
+int psp_device_get_locked_admin(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info);
int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
void
diff --git a/net/psp/psp.h b/net/psp/psp.h
index 9f19137593a0..0f9c4e4e52cb 100644
--- a/net/psp/psp.h
+++ b/net/psp/psp.h
@@ -14,7 +14,7 @@ extern struct xarray psp_devs;
extern struct mutex psp_devs_lock;
void psp_dev_free(struct psp_dev *psd);
-int psp_dev_check_access(struct psp_dev *psd, struct net *net);
+int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin);
void psp_nl_notify_dev(struct psp_dev *psd, u32 cmd);
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 9508b6c38003..82de78a1d6bd 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -27,10 +27,15 @@ struct mutex psp_devs_lock;
* psp_dev_check_access() - check if user in a given net ns can access PSP dev
* @psd: PSP device structure user is trying to access
* @net: net namespace user is in
+ * @admin: If true, only allow access from @psd's main device's netns,
+ * for admin operations like config changes and key rotation.
+ * If false, also allow access from network namespaces that have
+ * an associated device with @psd, for read-only and association
+ * management operations.
*
* Return: 0 if PSP device should be visible in @net, errno otherwise.
*/
-int psp_dev_check_access(struct psp_dev *psd, struct net *net)
+int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin)
{
if (dev_net(psd->main_netdev) == net)
return 0;
diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
index 6afd7707ec12..eb47a9ee4438 100644
--- a/net/psp/psp_nl.c
+++ b/net/psp/psp_nl.c
@@ -41,7 +41,8 @@ static int psp_nl_reply_send(struct sk_buff *rsp, struct genl_info *info)
/* Device stuff */
static struct psp_dev *
-psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
+psp_device_get_and_lock(struct net *net, struct nlattr *dev_id,
+ bool admin)
{
struct psp_dev *psd;
int err;
@@ -56,7 +57,7 @@ psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
mutex_lock(&psd->lock);
mutex_unlock(&psp_devs_lock);
- err = psp_dev_check_access(psd, net);
+ err = psp_dev_check_access(psd, net, admin);
if (err) {
mutex_unlock(&psd->lock);
return ERR_PTR(err);
@@ -65,17 +66,31 @@ psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
return psd;
}
-int psp_device_get_locked(const struct genl_split_ops *ops,
- struct sk_buff *skb, struct genl_info *info)
+static int __psp_device_get_locked(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info,
+ bool admin)
{
if (GENL_REQ_ATTR_CHECK(info, PSP_A_DEV_ID))
return -EINVAL;
info->user_ptr[0] = psp_device_get_and_lock(genl_info_net(info),
- info->attrs[PSP_A_DEV_ID]);
+ info->attrs[PSP_A_DEV_ID],
+ admin);
return PTR_ERR_OR_ZERO(info->user_ptr[0]);
}
+int psp_device_get_locked_admin(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info)
+{
+ return __psp_device_get_locked(ops, skb, info, true);
+}
+
+int psp_device_get_locked(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info)
+{
+ return __psp_device_get_locked(ops, skb, info, false);
+}
+
void
psp_device_unlock(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info)
@@ -160,7 +175,7 @@ static int
psp_nl_dev_get_dumpit_one(struct sk_buff *rsp, struct netlink_callback *cb,
struct psp_dev *psd)
{
- if (psp_dev_check_access(psd, sock_net(rsp->sk)))
+ if (psp_dev_check_access(psd, sock_net(rsp->sk), false))
return 0;
return psp_nl_dev_fill(psd, rsp, genl_info_dump(cb));
@@ -305,7 +320,7 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
psd = psp_dev_get_for_sock(socket->sk);
if (psd) {
- err = psp_dev_check_access(psd, genl_info_net(info));
+ err = psp_dev_check_access(psd, genl_info_net(info), false);
if (err) {
psp_dev_put(psd);
psd = NULL;
@@ -330,7 +345,7 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
psp_dev_put(psd);
} else {
- psd = psp_device_get_and_lock(genl_info_net(info), id);
+ psd = psp_device_get_and_lock(genl_info_net(info), id, false);
if (IS_ERR(psd)) {
err = PTR_ERR(psd);
goto err_sock_put;
@@ -573,7 +588,7 @@ static int
psp_nl_stats_get_dumpit_one(struct sk_buff *rsp, struct netlink_callback *cb,
struct psp_dev *psd)
{
- if (psp_dev_check_access(psd, sock_net(rsp->sk)))
+ if (psp_dev_check_access(psd, sock_net(rsp->sk), false))
return 0;
return psp_nl_stats_fill(psd, rsp, genl_info_dump(cb));
--
2.52.0
^ permalink raw reply related
* [PATCH v9 net-next 2/5] psp: add new netlink cmd for dev-assoc and dev-disassoc
From: Wei Wang @ 2026-03-30 22:31 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Daniel Zahka, Willem de Bruijn, David Wei,
Andrew Lunn, David S . Miller, Eric Dumazet, Simon Horman
Cc: Wei Wang
In-Reply-To: <20260330223143.2394706-1-weibunny.kernel@gmail.com>
From: Wei Wang <weibunny@fb.com>
The main purpose of this cmd is to be able to associate a
non-psp-capable device (e.g. veth or netkit) with a psp device.
One use case is if we create a pair of veth/netkit, and assign 1 end
inside a netns, while leaving the other end within the default netns,
with a real PSP device, e.g. netdevsim or a physical PSP-capable NIC.
With this command, we could associate the veth/netkit inside the netns
with PSP device, so the virtual device could act as PSP-capable device
to initiate PSP connections, and performs PSP encryption/decryption on
the real PSP device.
Signed-off-by: Wei Wang <weibunny@fb.com>
---
Documentation/netlink/specs/psp.yaml | 67 +++++-
include/net/psp/types.h | 15 ++
include/uapi/linux/psp.h | 13 ++
net/psp/psp-nl-gen.c | 32 +++
net/psp/psp-nl-gen.h | 2 +
net/psp/psp_main.c | 21 +-
net/psp/psp_nl.c | 311 ++++++++++++++++++++++++++-
7 files changed, 449 insertions(+), 12 deletions(-)
diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml
index fe2cdc966604..336ef19155ff 100644
--- a/Documentation/netlink/specs/psp.yaml
+++ b/Documentation/netlink/specs/psp.yaml
@@ -13,6 +13,17 @@ definitions:
hdr0-aes-gmac-128, hdr0-aes-gmac-256]
attribute-sets:
+ -
+ name: assoc-dev-info
+ attributes:
+ -
+ name: ifindex
+ doc: ifindex of an associated network device.
+ type: u32
+ -
+ name: nsid
+ doc: Network namespace ID of the associated device.
+ type: s32
-
name: dev
attributes:
@@ -24,7 +35,9 @@ attribute-sets:
min: 1
-
name: ifindex
- doc: ifindex of the main netdevice linked to the PSP device.
+ doc: |
+ ifindex of the main netdevice linked to the PSP device,
+ or the ifindex to associate with the PSP device.
type: u32
-
name: psp-versions-cap
@@ -38,6 +51,28 @@ attribute-sets:
type: u32
enum: version
enum-as-flags: true
+ -
+ name: assoc-list
+ doc: List of associated virtual devices.
+ type: nest
+ nested-attributes: assoc-dev-info
+ multi-attr: true
+ -
+ name: nsid
+ doc: |
+ Network namespace ID for the device to associate/disassociate.
+ Optional for dev-assoc and dev-disassoc; if not present, the
+ device is looked up in the caller's network namespace.
+ type: s32
+ -
+ name: by-association
+ doc: |
+ Flag indicating the PSP device is an associated device from a
+ different network namespace.
+ Present when in associated namespace, absent when in primary/host
+ namespace.
+ type: flag
+
-
name: assoc
attributes:
@@ -170,6 +205,8 @@ operations:
- ifindex
- psp-versions-cap
- psp-versions-ena
+ - assoc-list
+ - by-association
pre: psp-device-get-locked
post: psp-device-unlock
dump:
@@ -271,6 +308,34 @@ operations:
post: psp-device-unlock
dump:
reply: *stats-all
+ -
+ name: dev-assoc
+ doc: Associate a network device with a PSP device.
+ attribute-set: dev
+ do:
+ request:
+ attributes:
+ - id
+ - ifindex
+ - nsid
+ reply:
+ attributes: []
+ pre: psp-device-get-locked
+ post: psp-device-unlock
+ -
+ name: dev-disassoc
+ doc: Disassociate a network device from a PSP device.
+ attribute-set: dev
+ do:
+ request:
+ attributes:
+ - id
+ - ifindex
+ - nsid
+ reply:
+ attributes: []
+ pre: psp-device-get-locked
+ post: psp-device-unlock
mcast-groups:
list:
diff --git a/include/net/psp/types.h b/include/net/psp/types.h
index 25a9096d4e7d..4bd432ed107a 100644
--- a/include/net/psp/types.h
+++ b/include/net/psp/types.h
@@ -5,6 +5,7 @@
#include <linux/mutex.h>
#include <linux/refcount.h>
+#include <net/net_trackers.h>
struct netlink_ext_ack;
@@ -43,9 +44,22 @@ struct psp_dev_config {
u32 versions;
};
+/**
+ * struct psp_assoc_dev - wrapper for associated net_device
+ * @dev_list: list node for psp_dev::assoc_dev_list
+ * @assoc_dev: the associated net_device
+ * @dev_tracker: tracker for the net_device reference
+ */
+struct psp_assoc_dev {
+ struct list_head dev_list;
+ struct net_device *assoc_dev;
+ netdevice_tracker dev_tracker;
+};
+
/**
* struct psp_dev - PSP device struct
* @main_netdev: original netdevice of this PSP device
+ * @assoc_dev_list: list of psp_assoc_dev entries associated with this PSP device
* @ops: driver callbacks
* @caps: device capabilities
* @drv_priv: driver priv pointer
@@ -67,6 +81,7 @@ struct psp_dev_config {
*/
struct psp_dev {
struct net_device *main_netdev;
+ struct list_head assoc_dev_list;
struct psp_dev_ops *ops;
struct psp_dev_caps *caps;
diff --git a/include/uapi/linux/psp.h b/include/uapi/linux/psp.h
index a3a336488dc3..1c8899cd4da5 100644
--- a/include/uapi/linux/psp.h
+++ b/include/uapi/linux/psp.h
@@ -17,11 +17,22 @@ enum psp_version {
PSP_VERSION_HDR0_AES_GMAC_256,
};
+enum {
+ PSP_A_ASSOC_DEV_INFO_IFINDEX = 1,
+ PSP_A_ASSOC_DEV_INFO_NSID,
+
+ __PSP_A_ASSOC_DEV_INFO_MAX,
+ PSP_A_ASSOC_DEV_INFO_MAX = (__PSP_A_ASSOC_DEV_INFO_MAX - 1)
+};
+
enum {
PSP_A_DEV_ID = 1,
PSP_A_DEV_IFINDEX,
PSP_A_DEV_PSP_VERSIONS_CAP,
PSP_A_DEV_PSP_VERSIONS_ENA,
+ PSP_A_DEV_ASSOC_LIST,
+ PSP_A_DEV_NSID,
+ PSP_A_DEV_BY_ASSOCIATION,
__PSP_A_DEV_MAX,
PSP_A_DEV_MAX = (__PSP_A_DEV_MAX - 1)
@@ -74,6 +85,8 @@ enum {
PSP_CMD_RX_ASSOC,
PSP_CMD_TX_ASSOC,
PSP_CMD_GET_STATS,
+ PSP_CMD_DEV_ASSOC,
+ PSP_CMD_DEV_DISASSOC,
__PSP_CMD_MAX,
PSP_CMD_MAX = (__PSP_CMD_MAX - 1)
diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c
index 1f5e73e7ccc1..114299c64423 100644
--- a/net/psp/psp-nl-gen.c
+++ b/net/psp/psp-nl-gen.c
@@ -53,6 +53,20 @@ static const struct nla_policy psp_get_stats_nl_policy[PSP_A_STATS_DEV_ID + 1] =
[PSP_A_STATS_DEV_ID] = NLA_POLICY_MIN(NLA_U32, 1),
};
+/* PSP_CMD_DEV_ASSOC - do */
+static const struct nla_policy psp_dev_assoc_nl_policy[PSP_A_DEV_NSID + 1] = {
+ [PSP_A_DEV_ID] = NLA_POLICY_MIN(NLA_U32, 1),
+ [PSP_A_DEV_IFINDEX] = { .type = NLA_U32, },
+ [PSP_A_DEV_NSID] = { .type = NLA_S32, },
+};
+
+/* PSP_CMD_DEV_DISASSOC - do */
+static const struct nla_policy psp_dev_disassoc_nl_policy[PSP_A_DEV_NSID + 1] = {
+ [PSP_A_DEV_ID] = NLA_POLICY_MIN(NLA_U32, 1),
+ [PSP_A_DEV_IFINDEX] = { .type = NLA_U32, },
+ [PSP_A_DEV_NSID] = { .type = NLA_S32, },
+};
+
/* Ops table for psp */
static const struct genl_split_ops psp_nl_ops[] = {
{
@@ -119,6 +133,24 @@ static const struct genl_split_ops psp_nl_ops[] = {
.dumpit = psp_nl_get_stats_dumpit,
.flags = GENL_CMD_CAP_DUMP,
},
+ {
+ .cmd = PSP_CMD_DEV_ASSOC,
+ .pre_doit = psp_device_get_locked,
+ .doit = psp_nl_dev_assoc_doit,
+ .post_doit = psp_device_unlock,
+ .policy = psp_dev_assoc_nl_policy,
+ .maxattr = PSP_A_DEV_NSID,
+ .flags = GENL_CMD_CAP_DO,
+ },
+ {
+ .cmd = PSP_CMD_DEV_DISASSOC,
+ .pre_doit = psp_device_get_locked,
+ .doit = psp_nl_dev_disassoc_doit,
+ .post_doit = psp_device_unlock,
+ .policy = psp_dev_disassoc_nl_policy,
+ .maxattr = PSP_A_DEV_NSID,
+ .flags = GENL_CMD_CAP_DO,
+ },
};
static const struct genl_multicast_group psp_nl_mcgrps[] = {
diff --git a/net/psp/psp-nl-gen.h b/net/psp/psp-nl-gen.h
index 977355455395..4dd0f0f23053 100644
--- a/net/psp/psp-nl-gen.h
+++ b/net/psp/psp-nl-gen.h
@@ -33,6 +33,8 @@ int psp_nl_rx_assoc_doit(struct sk_buff *skb, struct genl_info *info);
int psp_nl_tx_assoc_doit(struct sk_buff *skb, struct genl_info *info);
int psp_nl_get_stats_doit(struct sk_buff *skb, struct genl_info *info);
int psp_nl_get_stats_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
+int psp_nl_dev_assoc_doit(struct sk_buff *skb, struct genl_info *info);
+int psp_nl_dev_disassoc_doit(struct sk_buff *skb, struct genl_info *info);
enum {
PSP_NLGRP_MGMT,
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 82de78a1d6bd..178b848989f1 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -37,8 +37,18 @@ struct mutex psp_devs_lock;
*/
int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin)
{
+ struct psp_assoc_dev *entry;
+
if (dev_net(psd->main_netdev) == net)
return 0;
+
+ if (!admin) {
+ list_for_each_entry(entry, &psd->assoc_dev_list, dev_list) {
+ if (dev_net(entry->assoc_dev) == net)
+ return 0;
+ }
+ }
+
return -ENOENT;
}
@@ -74,6 +84,7 @@ psp_dev_create(struct net_device *netdev,
return ERR_PTR(-ENOMEM);
psd->main_netdev = netdev;
+ INIT_LIST_HEAD(&psd->assoc_dev_list);
psd->ops = psd_ops;
psd->caps = psd_caps;
psd->drv_priv = priv_ptr;
@@ -121,6 +132,7 @@ void psp_dev_free(struct psp_dev *psd)
*/
void psp_dev_unregister(struct psp_dev *psd)
{
+ struct psp_assoc_dev *entry, *entry_tmp;
struct psp_assoc *pas, *next;
mutex_lock(&psp_devs_lock);
@@ -140,6 +152,14 @@ void psp_dev_unregister(struct psp_dev *psd)
list_for_each_entry_safe(pas, next, &psd->stale_assocs, assocs_list)
psp_dev_tx_key_del(psd, pas);
+ list_for_each_entry_safe(entry, entry_tmp, &psd->assoc_dev_list,
+ dev_list) {
+ list_del(&entry->dev_list);
+ rcu_assign_pointer(entry->assoc_dev->psp_dev, NULL);
+ netdev_put(entry->assoc_dev, &entry->dev_tracker);
+ kfree(entry);
+ }
+
rcu_assign_pointer(psd->main_netdev->psp_dev, NULL);
psd->ops = NULL;
@@ -361,5 +381,4 @@ static int __init psp_init(void)
return genl_register_family(&psp_nl_family);
}
-
subsys_initcall(psp_init);
diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
index eb47a9ee4438..8a70848c74d7 100644
--- a/net/psp/psp_nl.c
+++ b/net/psp/psp_nl.c
@@ -2,6 +2,7 @@
#include <linux/ethtool.h>
#include <linux/skbuff.h>
+#include <linux/net_namespace.h>
#include <linux/xarray.h>
#include <net/genetlink.h>
#include <net/psp.h>
@@ -38,6 +39,73 @@ static int psp_nl_reply_send(struct sk_buff *rsp, struct genl_info *info)
return genlmsg_reply(rsp, info);
}
+/**
+ * psp_nl_multicast_per_ns() - multicast a notification to each unique netns
+ * @psd: PSP device (must be locked)
+ * @group: multicast group
+ * @build_ntf: callback to build an skb for a given netns, or NULL on failure
+ * @ctx: opaque context passed to @build_ntf
+ *
+ * Iterates all unique network namespaces from the associated device list
+ * plus the main device's netns. For each unique netns, calls @build_ntf
+ * to construct a notification skb and multicasts it.
+ */
+static void psp_nl_multicast_per_ns(struct psp_dev *psd, unsigned int group,
+ struct sk_buff *(*build_ntf)(struct psp_dev *,
+ struct net *,
+ void *),
+ void *ctx)
+{
+ struct psp_assoc_dev *entry;
+ struct xarray sent_nets;
+ struct net *main_net;
+ struct sk_buff *ntf;
+
+ main_net = dev_net(psd->main_netdev);
+ xa_init(&sent_nets);
+
+ list_for_each_entry(entry, &psd->assoc_dev_list, dev_list) {
+ struct net *assoc_net = dev_net(entry->assoc_dev);
+ int ret;
+
+ if (net_eq(assoc_net, main_net))
+ continue;
+
+ ret = xa_insert(&sent_nets, (unsigned long)assoc_net, assoc_net,
+ GFP_KERNEL);
+ if (ret == -EBUSY)
+ continue;
+
+ ntf = build_ntf(psd, assoc_net, ctx);
+ if (!ntf)
+ continue;
+
+ genlmsg_multicast_netns(&psp_nl_family, assoc_net, ntf, 0,
+ group, GFP_KERNEL);
+ }
+ xa_destroy(&sent_nets);
+
+ /* Send to main device netns */
+ ntf = build_ntf(psd, main_net, ctx);
+ if (!ntf)
+ return;
+ genlmsg_multicast_netns(&psp_nl_family, main_net, ntf, 0, group,
+ GFP_KERNEL);
+}
+
+static struct sk_buff *psp_nl_clone_ntf(struct psp_dev *psd, struct net *net,
+ void *ctx)
+{
+ return skb_clone(ctx, GFP_KERNEL);
+}
+
+static void psp_nl_multicast_all_ns(struct psp_dev *psd, struct sk_buff *ntf,
+ unsigned int group)
+{
+ psp_nl_multicast_per_ns(psd, group, psp_nl_clone_ntf, ntf);
+ nlmsg_free(ntf);
+}
+
/* Device stuff */
static struct psp_dev *
@@ -103,11 +171,74 @@ psp_device_unlock(const struct genl_split_ops *ops, struct sk_buff *skb,
sockfd_put(socket);
}
+static bool psp_has_assoc_dev_in_ns(struct psp_dev *psd, struct net *net)
+{
+ struct psp_assoc_dev *entry;
+
+ list_for_each_entry(entry, &psd->assoc_dev_list, dev_list) {
+ if (dev_net(entry->assoc_dev) == net)
+ return true;
+ }
+
+ return false;
+}
+
+static int psp_nl_fill_assoc_dev_list(struct psp_dev *psd, struct sk_buff *rsp,
+ struct net *cur_net,
+ struct net *filter_net)
+{
+ struct psp_assoc_dev *entry;
+ struct net *dev_net_ns;
+ struct nlattr *nest;
+ int nsid;
+
+ list_for_each_entry(entry, &psd->assoc_dev_list, dev_list) {
+ dev_net_ns = dev_net(entry->assoc_dev);
+
+ if (filter_net && dev_net_ns != filter_net)
+ continue;
+
+ /* When filtering by namespace, all devices are in the caller's
+ * namespace so nsid is always NETNSA_NSID_NOT_ASSIGNED (-1).
+ * Otherwise, calculate the nsid relative to cur_net.
+ */
+ nsid = filter_net ? NETNSA_NSID_NOT_ASSIGNED :
+ peernet2id_alloc(cur_net, dev_net_ns,
+ GFP_KERNEL);
+
+ nest = nla_nest_start(rsp, PSP_A_DEV_ASSOC_LIST);
+ if (!nest)
+ return -1;
+
+ if (nla_put_u32(rsp, PSP_A_ASSOC_DEV_INFO_IFINDEX,
+ entry->assoc_dev->ifindex) ||
+ nla_put_s32(rsp, PSP_A_ASSOC_DEV_INFO_NSID, nsid)) {
+ nla_nest_cancel(rsp, nest);
+ return -1;
+ }
+
+ nla_nest_end(rsp, nest);
+ }
+
+ return 0;
+}
+
static int
psp_nl_dev_fill(struct psp_dev *psd, struct sk_buff *rsp,
const struct genl_info *info)
{
+ struct net *cur_net;
void *hdr;
+ int err;
+
+ cur_net = genl_info_net(info);
+
+ /* Skip this device if we're in an associated netns but have no
+ * associated devices in cur_net
+ */
+ if (cur_net != dev_net(psd->main_netdev) &&
+ !psp_has_assoc_dev_in_ns(psd, cur_net))
+ return 0;
hdr = genlmsg_iput(rsp, info);
if (!hdr)
@@ -119,6 +250,22 @@ psp_nl_dev_fill(struct psp_dev *psd, struct sk_buff *rsp,
nla_put_u32(rsp, PSP_A_DEV_PSP_VERSIONS_ENA, psd->config.versions))
goto err_cancel_msg;
+ if (cur_net == dev_net(psd->main_netdev)) {
+ /* Primary device - dump assoc list */
+ err = psp_nl_fill_assoc_dev_list(psd, rsp, cur_net, NULL);
+ if (err)
+ goto err_cancel_msg;
+ } else {
+ /* In netns: set by-association flag and dump filtered
+ * assoc list containing only devices in cur_net
+ */
+ if (nla_put_flag(rsp, PSP_A_DEV_BY_ASSOCIATION))
+ goto err_cancel_msg;
+ err = psp_nl_fill_assoc_dev_list(psd, rsp, cur_net, cur_net);
+ if (err)
+ goto err_cancel_msg;
+ }
+
genlmsg_end(rsp, hdr);
return 0;
@@ -127,27 +274,34 @@ psp_nl_dev_fill(struct psp_dev *psd, struct sk_buff *rsp,
return -EMSGSIZE;
}
-void psp_nl_notify_dev(struct psp_dev *psd, u32 cmd)
+static struct sk_buff *psp_nl_build_dev_ntf(struct psp_dev *psd,
+ struct net *net, void *ctx)
{
+ u32 cmd = *(u32 *)ctx;
struct genl_info info;
struct sk_buff *ntf;
- if (!genl_has_listeners(&psp_nl_family, dev_net(psd->main_netdev),
- PSP_NLGRP_MGMT))
- return;
+ if (!genl_has_listeners(&psp_nl_family, net, PSP_NLGRP_MGMT))
+ return NULL;
ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!ntf)
- return;
+ return NULL;
genl_info_init_ntf(&info, &psp_nl_family, cmd);
+ genl_info_net_set(&info, net);
if (psp_nl_dev_fill(psd, ntf, &info)) {
nlmsg_free(ntf);
- return;
+ return NULL;
}
- genlmsg_multicast_netns(&psp_nl_family, dev_net(psd->main_netdev), ntf,
- 0, PSP_NLGRP_MGMT, GFP_KERNEL);
+ return ntf;
+}
+
+void psp_nl_notify_dev(struct psp_dev *psd, u32 cmd)
+{
+ psp_nl_multicast_per_ns(psd, PSP_NLGRP_MGMT,
+ psp_nl_build_dev_ntf, &cmd);
}
int psp_nl_dev_get_doit(struct sk_buff *req, struct genl_info *info)
@@ -281,8 +435,9 @@ int psp_nl_key_rotate_doit(struct sk_buff *skb, struct genl_info *info)
psd->stats.rotations++;
nlmsg_end(ntf, (struct nlmsghdr *)ntf->data);
- genlmsg_multicast_netns(&psp_nl_family, dev_net(psd->main_netdev), ntf,
- 0, PSP_NLGRP_USE, GFP_KERNEL);
+
+ psp_nl_multicast_all_ns(psd, ntf, PSP_NLGRP_USE);
+
return psp_nl_reply_send(rsp, info);
err_free_ntf:
@@ -292,6 +447,140 @@ int psp_nl_key_rotate_doit(struct sk_buff *skb, struct genl_info *info)
return err;
}
+int psp_nl_dev_assoc_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ struct psp_dev *psd = info->user_ptr[0];
+ struct psp_assoc_dev *psp_assoc_dev;
+ struct net_device *assoc_dev;
+ u32 assoc_ifindex;
+ struct sk_buff *rsp;
+ struct net *net;
+ int nsid;
+
+ if (GENL_REQ_ATTR_CHECK(info, PSP_A_DEV_IFINDEX))
+ return -EINVAL;
+
+ if (info->attrs[PSP_A_DEV_NSID]) {
+ nsid = nla_get_s32(info->attrs[PSP_A_DEV_NSID]);
+
+ net = get_net_ns_by_id(genl_info_net(info), nsid);
+ if (!net) {
+ NL_SET_BAD_ATTR(info->extack,
+ info->attrs[PSP_A_DEV_NSID]);
+ return -EINVAL;
+ }
+ } else {
+ net = get_net(genl_info_net(info));
+ }
+
+ psp_assoc_dev = kzalloc(sizeof(*psp_assoc_dev), GFP_KERNEL);
+ if (!psp_assoc_dev) {
+ put_net(net);
+ return -ENOMEM;
+ }
+
+ assoc_ifindex = nla_get_u32(info->attrs[PSP_A_DEV_IFINDEX]);
+ assoc_dev = netdev_get_by_index(net, assoc_ifindex,
+ &psp_assoc_dev->dev_tracker,
+ GFP_KERNEL);
+ if (!assoc_dev) {
+ put_net(net);
+ kfree(psp_assoc_dev);
+ NL_SET_BAD_ATTR(info->extack, info->attrs[PSP_A_DEV_IFINDEX]);
+ return -ENODEV;
+ }
+
+ /* Check if device is already associated with a PSP device */
+ if (cmpxchg(&assoc_dev->psp_dev, NULL, psd)) {
+ NL_SET_ERR_MSG(info->extack,
+ "Device already associated with a PSP device");
+ netdev_put(assoc_dev, &psp_assoc_dev->dev_tracker);
+ put_net(net);
+ kfree(psp_assoc_dev);
+ return -EBUSY;
+ }
+
+ psp_assoc_dev->assoc_dev = assoc_dev;
+ rsp = psp_nl_reply_new(info);
+ if (!rsp) {
+ rcu_assign_pointer(assoc_dev->psp_dev, NULL);
+ netdev_put(assoc_dev, &psp_assoc_dev->dev_tracker);
+ put_net(net);
+ kfree(psp_assoc_dev);
+ return -ENOMEM;
+ }
+
+ list_add_tail(&psp_assoc_dev->dev_list, &psd->assoc_dev_list);
+
+ put_net(net);
+
+ psp_nl_notify_dev(psd, PSP_CMD_DEV_CHANGE_NTF);
+
+ return psp_nl_reply_send(rsp, info);
+}
+
+int psp_nl_dev_disassoc_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ struct psp_assoc_dev *entry, *found = NULL;
+ struct psp_dev *psd = info->user_ptr[0];
+ u32 assoc_ifindex;
+ struct sk_buff *rsp;
+ struct net *net;
+ int nsid;
+
+ if (GENL_REQ_ATTR_CHECK(info, PSP_A_DEV_IFINDEX))
+ return -EINVAL;
+
+ if (info->attrs[PSP_A_DEV_NSID]) {
+ nsid = nla_get_s32(info->attrs[PSP_A_DEV_NSID]);
+
+ net = get_net_ns_by_id(genl_info_net(info), nsid);
+ if (!net) {
+ NL_SET_BAD_ATTR(info->extack,
+ info->attrs[PSP_A_DEV_NSID]);
+ return -EINVAL;
+ }
+ } else {
+ net = get_net(genl_info_net(info));
+ }
+
+ assoc_ifindex = nla_get_u32(info->attrs[PSP_A_DEV_IFINDEX]);
+
+ /* Search the association list by ifindex and netns */
+ list_for_each_entry(entry, &psd->assoc_dev_list, dev_list) {
+ if (entry->assoc_dev->ifindex == assoc_ifindex &&
+ dev_net(entry->assoc_dev) == net) {
+ found = entry;
+ break;
+ }
+ }
+
+ if (!found) {
+ put_net(net);
+ NL_SET_BAD_ATTR(info->extack, info->attrs[PSP_A_DEV_IFINDEX]);
+ return -ENODEV;
+ }
+
+ rsp = psp_nl_reply_new(info);
+ if (!rsp) {
+ put_net(net);
+ return -ENOMEM;
+ }
+
+ /* Notify before removal */
+ psp_nl_notify_dev(psd, PSP_CMD_DEV_CHANGE_NTF);
+
+ /* Remove from the association list */
+ list_del(&found->dev_list);
+ rcu_assign_pointer(found->assoc_dev->psp_dev, NULL);
+ netdev_put(found->assoc_dev, &found->dev_tracker);
+ kfree(found);
+
+ put_net(net);
+
+ return psp_nl_reply_send(rsp, info);
+}
+
/* Key etc. */
int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
@@ -320,7 +609,9 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
psd = psp_dev_get_for_sock(socket->sk);
if (psd) {
+ mutex_lock(&psd->lock);
err = psp_dev_check_access(psd, genl_info_net(info), false);
+ mutex_unlock(&psd->lock);
if (err) {
psp_dev_put(psd);
psd = NULL;
--
2.52.0
^ permalink raw reply related
* [PATCH v9 net-next 0/5] psp: Add support for dev-assoc/disassoc
From: Wei Wang @ 2026-03-30 22:31 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Daniel Zahka, Willem de Bruijn, David Wei,
Andrew Lunn, David S . Miller, Eric Dumazet, Simon Horman
Cc: Wei Wang
From: Wei Wang <weibunny@fb.com>
The main purpose of this feature is to associate virtual devices like
veth or netkit with a real PSP device, so we could provide PSP
functionality to the application running with virtual devices.
A typical deployment that works with this feature is as follows:
Host Namespace:
psp_dev_local ←──physically linked──→ psp_dev_peer
(PSP device)
│
│ BPF on psp_dev_local ingress: bpf_redirect_peer() to nk_guest
│
nk_host / veth_host
│
│ BPF on nk_host ingress: bpf_redirect_neigh() to psp_dev_local
│
Guest Namespace (netns):
│
nk_guest / veth_guest
★ PSP application run here
Remote Namespace (_netns):
psp_dev_peer
★ PSP server application runs here
Note:
The general requirement for this feature to work:
For PSP to work correctly, the egress device at validate_xmit_skb()
time must have psp_dev matching the association's psd. Any device
stacking or traffic redirection that changes the egress device will
cause either:
1. TX validation failure (SKB_DROP_REASON_PSP_OUTPUT) - fail-safe
2. RX policy failure after tx-assoc - packets without PSP extension
are rejected by receiver expecting encrypted traffic
Here are a few examples that this feature would not work:
- Bonding with load balancing in round-robin, XOR, 802.3ad mode across
multiple PSP devices, or mixed PSP and non-PSP devices
- Bonding with active-backup mode might work without PSP migration for
failover case.
- ipvlan/macvlan in bridge mode would not work given packets are
loopbacked locally without going through the PSP device.
Changes since v8:
- Rebase
Changes since v7:
- Refactor in patch 1 to have a common helper for
psp_device_get_locked_admin() and psp_device_get_locked()
- Take psd->lock in psp_assoc_device_get_locked() before
psp_dev_check_access() in patch 2
- Use cmpxchg() for assoc_dev->psp_dev assignment when doing dev-assoc
in patch 2
- Check for err for register_netdevice_notifier() in patch 3
- Call psp_attach_netdev_notifier() in pre_doit handler for dev-assoc to
avoid releasing of psd->lock in patch 3
Changes since v6:
- Remove the unused remote_addr, nk_guest_addr and import cmd in patch 5
Changes since v5:
- Remove module_exit() in patch 3
Changes since v4:
- Address compilation warning in patch 3
- Removed the call to psp_nl_has_listeners_any_ns() and check listeners
when looping through netns in psp_nl_notify_dev() in patch 2. This
makes sure we only send notification to netns that has listeners.
Changes since v3:
- Make nsid optional for dev-assoc/dev-disassoc operation, and use
the ns user is in when it's not specified. Also added a test for this.
- Fix psp_nl_notify_dev() to compute the correct nsid relative to the
listener's netns.
- Only register the new netdev event for psp dev cleanup upon the first
successful dev-assoc operation.
- Change the following in selftest:
- Add CONFIG_NETKIT to driver/net's config
- Fall back to NetDrvEpEnv and run basic test cases if NetDrvContEnv
does not load
- Use ksft_variants instead of psp_ip_ver_test_builder
Changes since v2:
- Change the newly added parameter to psp_device_get_and_lock() to
admin in patch 1. Introduce 2 device check functions:
- psp_device_get_locked_admin() for dev-set and key-rotate
- psp_device_get_locked() for all other operations
Flip the logic for checking the dev_assoc_list accordingly in patch 2.
- Move psp_nl_notify_dev() before removing the dev from assoc_dev_list
in psp_nl_dev_disassoc_doit() and correct the typo in commit msg in
patch 2.
- Remove the threading and subprocess and some comment updates in patch 5.
Changes since v1:
- Update the first 4 patches to reflect the latest changes in
https://lore.kernel.org/netdev/20260302053315.1919859-1-dw@davidwei.uk/
- Update patch 9 to add a param to NetDrvContEnv to control the loading
of the tx forwarding bpf program
Wei Wang (5):
psp: add admin/non-admin version of psp_device_get_locked
psp: add new netlink cmd for dev-assoc and dev-disassoc
psp: add a new netdev event for dev unregister
selftests/net: Add bpf skb forwarding program
selftest/net: psp: Add test for dev-assoc/disassoc
Documentation/netlink/specs/psp.yaml | 71 ++-
include/net/psp/types.h | 15 +
include/uapi/linux/psp.h | 13 +
net/psp/psp-nl-gen.c | 36 +-
net/psp/psp-nl-gen.h | 7 +
net/psp/psp.h | 3 +-
net/psp/psp_main.c | 96 +++-
net/psp/psp_nl.c | 352 ++++++++++++-
tools/testing/selftests/drivers/net/config | 1 +
.../drivers/net/hw/nk_redirect.bpf.c | 60 +++
.../selftests/drivers/net/lib/py/env.py | 54 +-
tools/testing/selftests/drivers/net/psp.py | 492 ++++++++++++++++--
12 files changed, 1140 insertions(+), 60 deletions(-)
create mode 100644 tools/testing/selftests/drivers/net/hw/nk_redirect.bpf.c
--
2.52.0
^ permalink raw reply
* Re: [PATCH v8 net-next 0/5] psp: Add support for dev-assoc/disassoc
From: Wei Wang @ 2026-03-30 22:26 UTC (permalink / raw)
To: Jakub Kicinski
Cc: netdev, Daniel Zahka, Willem de Bruijn, David Wei, Andrew Lunn,
David S . Miller, Eric Dumazet, Simon Horman, Wei Wang
In-Reply-To: <20260329111240.67e6f097@kernel.org>
On Sun, Mar 29, 2026 at 11:12 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Sat, 28 Mar 2026 21:19:16 -0700 Wei Wang wrote:
> > The main purpose of this feature is to associate virtual devices like
> > veth or netkit with a real PSP device, so we could provide PSP
> > functionality to the application running with virtual devices.
>
> Does not apply to net-next.
Sorry, rebased and will resend
^ permalink raw reply
* Re: [PATCH v7 1/3] PCI: AtomicOps: Do not enable requests by RCiEPs
From: Jason Gunthorpe @ 2026-03-30 22:26 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Gerd Bayer, Alex Deucher, Christian König, Selvin Xavier,
Kalesh AP, Leon Romanovsky, Michal Kalderon, Saeed Mahameed,
Tariq Toukan, Mark Bloch, Bjorn Helgaas, Jay Cornwall,
Felix Kuehling, Ilpo Järvinen, Christian Borntraeger,
Niklas Schnelle, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Alexander Gordeev, Sven Schnelle, Alexander Schmidt, linux-s390,
linux-pci, linux-kernel, netdev, linux-rdma
In-Reply-To: <20260330214253.GA92498@bhelgaas>
On Mon, Mar 30, 2026 at 04:42:53PM -0500, Bjorn Helgaas wrote:
> [+to amdgpu, bnxe_re, mlx5 IB, qedr, mlx5 maintainers]
>
> On Mon, Mar 30, 2026 at 03:09:44PM +0200, Gerd Bayer wrote:
> > Since root complex integrated end points (RCiEPs) attach to a bus that
> > has no bridge device describing the root port, the capability to
> > complete AtomicOps requests cannot be determined with PCIe methods.
> >
> > Change default of pci_enable_atomic_ops_to_root() to not enable
> > AtomicOps requests on RCiEPs.
>
> I know I suggested this because there's nothing explicit that tells us
> whether the RC supports atomic ops from RCiEPs [1]. But I'm concerned
> that GPUs, infiniband HCAs, and NICs that use atomic ops may be
> implemented as RCiEPs and would be broken by this.
AFAIK none of the NICs are integrated into root complexes in their
topology model..
Jason
^ permalink raw reply
* Re: [PATCH net-next v4] net: mana: Expose hardware diagnostic info via debugfs
From: Jakub Kicinski @ 2026-03-30 22:23 UTC (permalink / raw)
To: Erni Sri Satya Vennela
Cc: kys, haiyangz, wei.liu, decui, longli, andrew+netdev, davem,
edumazet, pabeni, kotaranov, horms, shradhagupta, shirazsaleem,
dipayanroy, yury.norov, kees, ssengar, gargaditya, linux-hyperv,
netdev, linux-kernel, linux-rdma
In-Reply-To: <acrKgG0USsGABqYT@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net>
On Mon, 30 Mar 2026 12:09:52 -0700 Erni Sri Satya Vennela wrote:
> Just a quick follow‑up on this. Since these issues were pre‑existing and
> not introduced by this patch, would you prefer that I send them as a
> separate fix patch, or fold the fixes into the current patch?
Anything that's pre-existing should be a separate patch, before any new
code. If the bug exists only in net-next - earlier in the same series,
if the bug exists in net - posted separately for the net tree.
^ permalink raw reply
* Re: [PATCH bpf-next v2 1/2] net: clear the dst when performing encap / decap
From: patchwork-bot+netdevbpf @ 2026-03-30 22:20 UTC (permalink / raw)
To: Jakub Kicinski
Cc: bpf, netdev, davem, edumazet, pabeni, andrew+netdev, horms, maze,
willemdebruijn.kernel, ast, daniel, andrii, martin.lau, eddyz87,
song, yonghong.song, john.fastabend, kpsingh, sdf, haoluo, jolsa
In-Reply-To: <20260329180428.2657785-1-kuba@kernel.org>
Hello:
This series was applied to bpf/bpf-next.git (net)
by Martin KaFai Lau <martin.lau@kernel.org>:
On Sun, 29 Mar 2026 11:04:27 -0700 you wrote:
> Commit ba9db6f907ac ("net: clear the dst when changing skb protocol")
> added dst clearing when a BPF program changes the skb protocol
> (e.g. IPv4 to IPv6). Since that was a fix we only cleared the dst when
> the L3 protocol actually changes to keep it minimal. As suggested during
> the discussion (see Link) encap or decap operation which wraps or unwraps
> a same-protocol header may also render the existing dst incorrect - even
> if that doesn't result in a crash, just the wrong route for the now-outermost
> IP dst.
>
> [...]
Here is the summary with links:
- [bpf-next,v2,1/2] net: clear the dst when performing encap / decap
https://git.kernel.org/bpf/bpf-next/c/648c1bc05997
- [bpf-next,v2,2/2] selftests/bpf: test that dst is cleared on same-protocol encap
https://git.kernel.org/bpf/bpf-next/c/660735c4182c
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net v3 04/11] list: Move on_list_rcu() to list.h and add on_list() also
From: Linus Torvalds @ 2026-03-30 22:14 UTC (permalink / raw)
To: David Howells
Cc: Jakub Kicinski, netdev, Marc Dionne, David S. Miller,
Eric Dumazet, Paolo Abeni, linux-afs, linux-kernel,
Mathieu Desnoyers, John Johansen, Minas Harutyunyan, Simon Horman,
apparmor, linux-usb, stable
In-Reply-To: <1179840.1774867765@warthog.procyon.org.uk>
On Mon, 30 Mar 2026 at 03:49, David Howells <dhowells@redhat.com> wrote:
>
> Anyway, I'll find a different way to do this, not involving checking the prev
> pointer. What I don't want to do is hard code "prev == LIST_POISON2" into my
> stuff. Anything like that really needs to be in list.h.
So i think the proper model is:
(a) normal and good list users should never *use* this kind of "is
this entry on a list or not".
Dammit, you should *KNOW* that already from core logic. Not with a
flag, not with a function to ask, but from how things work. The whole
"am I on a list or not" should not be a list issue, it should be
obvious.
(b) if the code in question really doesn't know what the ^%&%^ it did,
and has lost sight of what it has done to a list entry, and really
wants some kind of "did I remove this entry already" logic, I would
encourage such uses to either re-consider, or just use the
"__list_del_clearprev()" function when removing entries.
Because I really don't want the core list handling to cater to code
that doesn't know what the hell it has done.
Linus
^ permalink raw reply
* Re: [PATCH net-next v3 3/6] net: bcmgenet: add basic XDP support (PASS/DROP)
From: Florian Fainelli @ 2026-03-30 22:06 UTC (permalink / raw)
To: Nicolai Buchwitz, Mohsin Bashir
Cc: netdev, Doug Berger, Broadcom internal kernel review list,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Alexei Starovoitov, Daniel Borkmann,
Jesper Dangaard Brouer, John Fastabend, Stanislav Fomichev,
linux-kernel, bpf
In-Reply-To: <56270d59e5e5e79fcd3d104817679d70@tipi-net.de>
On 3/30/26 15:01, Nicolai Buchwitz wrote:
> On 30.3.2026 20:15, Mohsin Bashir wrote:
>>> +static int bcmgenet_xdp_setup(struct net_device *dev,
>>> + struct netdev_bpf *xdp)
>>> +{
>>> + struct bcmgenet_priv *priv = netdev_priv(dev);
>>> + struct bpf_prog *old_prog;
>>> + struct bpf_prog *prog = xdp->prog;
>>> +
>>> + if (prog && dev->mtu > PAGE_SIZE - GENET_RX_HEADROOM -
>>> + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) {
>>> + NL_SET_ERR_MSG_MOD(xdp->extack,
>>> + "MTU too large for single-page XDP buffer");
>>> + return -EOPNOTSUPP;
>>> + }
>>
>> The MTU check here is great. But I do not see support
>> for .ndo_change_mtu. This would allow users to change MTU size AFTER
>> the program is attached.
>
> Good point. I had planned to add ndo_change_mtu in a follow-up series,
> but this leaves a gap where MTU can be changed while XDP is attached.
>
> Options:
> 1. Add a minimal ndo_change_mtu to this series that only rejects MTU
> changes incompatible with XDP, default behavior otherwise
Option 1 seems to be the simplest yet getting you a path through merging
XDP support.
> 2. Reject any MTU change while XDP is attached
> 3. Defer to the ndo_change_mtu follow-up series
>
> Thoughts?
>
> Thanks
> Nicolai
--
Florian
^ permalink raw reply
* Re: [PATCH] net: renesas: rswitch: Fix memory leak in rswitch_phy_device_init()
From: kernel test robot @ 2026-03-30 22:01 UTC (permalink / raw)
To: Ma Ke, yoshihiro.shimoda.uh, andrew+netdev, davem, edumazet, kuba,
pabeni, niklas.soderlund+renesas, michael.dege, nikita.yoush,
yury.norov, geert+renesas
Cc: llvm, oe-kbuild-all, netdev, linux-renesas-soc, linux-kernel,
Ma Ke, stable
In-Reply-To: <20260330073541.2871414-1-make24@iscas.ac.cn>
Hi Ma,
kernel test robot noticed the following build warnings:
[auto build test WARNING on net-next/main]
[also build test WARNING on net/main linus/master v7.0-rc6 next-20260327]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Ma-Ke/net-renesas-rswitch-Fix-memory-leak-in-rswitch_phy_device_init/20260330-214200
base: net-next/main
patch link: https://lore.kernel.org/r/20260330073541.2871414-1-make24%40iscas.ac.cn
patch subject: [PATCH] net: renesas: rswitch: Fix memory leak in rswitch_phy_device_init()
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20260331/202603310514.S572gcNU-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260331/202603310514.S572gcNU-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603310514.S572gcNU-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/net/ethernet/renesas/rswitch_main.c:1480:2: warning: variable 'phydev' is uninitialized when used here [-Wuninitialized]
1480 | phydev->mac_managed_pm = true;
| ^~~~~~
drivers/net/ethernet/renesas/rswitch_main.c:1462:27: note: initialize the variable 'phydev' to silence this warning
1462 | struct phy_device *phydev, *tmp_phydev;
| ^
| = NULL
1 warning generated.
vim +/phydev +1480 drivers/net/ethernet/renesas/rswitch_main.c
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1459
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1460 static int rswitch_phy_device_init(struct rswitch_device *rdev)
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1461 {
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1462 struct phy_device *phydev, *tmp_phydev;
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1463 struct device_node *phy;
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1464 int err = -ENOENT;
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1465
b46f1e5793298c drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1466 if (!rdev->np_port)
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1467 return -ENODEV;
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1468
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1469 phy = of_parse_phandle(rdev->np_port, "phy-handle", 0);
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1470 if (!phy)
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1471 return -ENODEV;
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1472
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1473 /* Set phydev->host_interfaces before calling of_phy_connect() to
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1474 * configure the PHY with the information of host_interfaces.
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1475 */
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1476 tmp_phydev = of_phy_find_device(phy);
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1477 if (!tmp_phydev)
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1478 goto out;
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1479 __set_bit(rdev->etha->phy_interface, tmp_phydev->host_interfaces);
35b78409e1c7ff drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-10-17 @1480 phydev->mac_managed_pm = true;
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1481
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1482 phydev = of_phy_connect(rdev->ndev, phy, rswitch_adjust_link, 0,
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1483 rdev->etha->phy_interface);
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1484
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1485 /* Release the temporary reference obtained by of_phy_find_device() */
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1486 phy_device_free(tmp_phydev);
142f4caaa41b9c drivers/net/ethernet/renesas/rswitch_main.c Ma Ke 2026-03-30 1487
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1488 if (!phydev)
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1489 goto out;
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1490
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1491 phy_set_max_speed(phydev, SPEED_2500);
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1492 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1493 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1494 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1495 phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1496 rswitch_phy_remove_link_mode(rdev, phydev);
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1497
c16a5033f77b9e drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1498 phy_attached_info(phydev);
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1499
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1500 err = 0;
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1501 out:
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1502 of_node_put(phy);
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1503
0df024d0f1d3e5 drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2023-02-01 1504 return err;
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1505 }
3590918b5d07aa drivers/net/ethernet/renesas/rswitch.c Yoshihiro Shimoda 2022-10-31 1506
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH net-next v2] net: phy: bcm84881: add BCM84891/BCM84892 support
From: Florian Fainelli @ 2026-03-30 22:01 UTC (permalink / raw)
To: Daniel Wagner, netdev
Cc: Andrew Lunn, Heiner Kallweit, Russell King,
bcm-kernel-feedback-list, Jakub Kicinski, Eric Dumazet,
Paolo Abeni
In-Reply-To: <20260324190601.1616343-1-wagner.daniel.t@gmail.com>
On 3/24/26 12:06, Daniel Wagner wrote:
> The BCM84891 and BCM84892 are 10GBASE-T PHYs in the same family as the
> BCM84881, sharing the register map and most callbacks. They add USXGMII
> as a host interface mode.
>
> bcm8489x_config_init() is separate from bcm84881_config_init(): it
> allows only USXGMII (the only host mode available on the tested
> hardware) and clears MDIO_CTRL1_LPOWER, which is set at boot on the
> tested platform. Does not recur on ifdown/ifup, cable events, or
> link-partner advertisement changes, so config_init is sufficient.
>
> For USXGMII, read_status() skips the 0x4011 host-mode register: it
> returns the same value regardless of negotiated copper speed (USXGMII
> symbol replication). Speed comes from phy_resolve_aneg_linkmode() via
> standard C45 AN resolution.
>
> Tested on TRENDnet TEG-S750 (RTL9303 + 1x BCM84891 + 4x BCM84892)
> running OpenWrt, where the MDIO controller driver is currently
> OpenWrt-specific. Link verified at 100M, 1G, 2.5G, 10G.
>
> Signed-off-by: Daniel Wagner <wagner.daniel.t@gmail.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply
* Re: [PATCH net-next v3 3/6] net: bcmgenet: add basic XDP support (PASS/DROP)
From: Nicolai Buchwitz @ 2026-03-30 22:01 UTC (permalink / raw)
To: Mohsin Bashir
Cc: netdev, Doug Berger, Florian Fainelli,
Broadcom internal kernel review list, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, linux-kernel, bpf
In-Reply-To: <1d551008-3c42-4b7b-9507-03072740a54a@gmail.com>
On 30.3.2026 20:15, Mohsin Bashir wrote:
>> +static int bcmgenet_xdp_setup(struct net_device *dev,
>> + struct netdev_bpf *xdp)
>> +{
>> + struct bcmgenet_priv *priv = netdev_priv(dev);
>> + struct bpf_prog *old_prog;
>> + struct bpf_prog *prog = xdp->prog;
>> +
>> + if (prog && dev->mtu > PAGE_SIZE - GENET_RX_HEADROOM -
>> + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) {
>> + NL_SET_ERR_MSG_MOD(xdp->extack,
>> + "MTU too large for single-page XDP buffer");
>> + return -EOPNOTSUPP;
>> + }
>
> The MTU check here is great. But I do not see support for
> .ndo_change_mtu. This would allow users to change MTU size AFTER the
> program is attached.
Good point. I had planned to add ndo_change_mtu in a follow-up series,
but this leaves a gap where MTU can be changed while XDP is attached.
Options:
1. Add a minimal ndo_change_mtu to this series that only rejects MTU
changes incompatible with XDP, default behavior otherwise
2. Reject any MTU change while XDP is attached
3. Defer to the ndo_change_mtu follow-up series
Thoughts?
Thanks
Nicolai
^ permalink raw reply
* [PATCH net-next v3 4/4] selftests/bpf: Ensure dst addr/port are preserved after socket abort
From: Jordan Rife @ 2026-03-30 21:57 UTC (permalink / raw)
To: netdev
Cc: Jordan Rife, bpf, Willem de Bruijn, Eric Dumazet, Daniel Borkmann,
Martin KaFai Lau, Stanislav Fomichev, Andrii Nakryiko,
Yusuke Suzuki, Jakub Kicinski, Kuniyuki Iwashima
In-Reply-To: <20260330215707.2374657-1-jrife@google.com>
Ensure that sock_release hooks see the original dst_ip4, dst_ip6, and
dst_port values for connected UDP and TCP sockets following a socket
abort.
Signed-off-by: Jordan Rife <jrife@google.com>
---
.../bpf/prog_tests/sock_destroy_release.c | 180 ++++++++++++++++++
.../bpf/progs/sock_destroy_release.c | 56 ++++++
2 files changed, 236 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_destroy_release.c
create mode 100644 tools/testing/selftests/bpf/progs/sock_destroy_release.c
diff --git a/tools/testing/selftests/bpf/prog_tests/sock_destroy_release.c b/tools/testing/selftests/bpf/prog_tests/sock_destroy_release.c
new file mode 100644
index 000000000000..022031332b83
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/sock_destroy_release.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include "network_helpers.h"
+#include "sock_destroy_release.skel.h"
+
+#define TEST_NS "sock_destroy_release_netns"
+#define BIND_ADDR4 "127.0.0.1"
+#define BIND_ADDR6 "::1"
+#define ANY_ADDR4 "0.0.0.0"
+#define ANY_ADDR6 "::"
+
+static __u64 socket_cookie(int fd)
+{
+ __u64 cookie;
+ socklen_t cookie_len = sizeof(cookie);
+
+ if (!ASSERT_OK(getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie,
+ &cookie_len), "getsockopt(SO_COOKIE)"))
+ return 0;
+ return cookie;
+}
+
+static void destroy(struct sock_destroy_release *skel, int fd, int sock_type)
+{
+ __u64 cookie = socket_cookie(fd);
+ struct bpf_link *link = NULL;
+ int iter_fd = -1;
+ int nread;
+ __u64 out;
+
+ skel->bss->abort_cookie = cookie;
+
+ link = bpf_program__attach_iter(sock_type == SOCK_STREAM ?
+ skel->progs.abort_tcp :
+ skel->progs.abort_udp, NULL);
+ if (!ASSERT_OK_PTR(link, "bpf_program__attach_iter"))
+ goto done;
+
+ iter_fd = bpf_iter_create(bpf_link__fd(link));
+ if (!ASSERT_OK_FD(iter_fd, "bpf_iter_create"))
+ goto done;
+
+ /* Delete matching socket. */
+ nread = read(iter_fd, &out, sizeof(out));
+ ASSERT_GE(nread, 0, "nread");
+ if (nread)
+ ASSERT_EQ(out, cookie, "cookie matches");
+done:
+ if (iter_fd >= 0)
+ close(iter_fd);
+ bpf_link__destroy(link);
+}
+
+static void do_test(struct sock_destroy_release *skel, int sock_type,
+ int family, const char *bind_addr_str, const int bind_port)
+{
+ const char *addr = family == AF_INET ? BIND_ADDR4 : BIND_ADDR6;
+ int listen_fd = -1, connect_fd = -1, accept_fd = -1;
+ struct sockaddr_storage bind_addr;
+ static const int port = 10001;
+ socklen_t bind_addr_len;
+
+ listen_fd = start_server(family, sock_type, addr, port, 0);
+ if (!ASSERT_OK_FD(listen_fd, "start_server"))
+ goto cleanup;
+
+ connect_fd = client_socket(family, sock_type, NULL);
+ if (!ASSERT_OK_FD(connect_fd, "client_socket"))
+ goto cleanup;
+
+ if (bind_addr_str) {
+ if (!ASSERT_OK(make_sockaddr(family, bind_addr_str, bind_port,
+ &bind_addr, &bind_addr_len),
+ "make_sockaddr"))
+ goto cleanup;
+ if (!ASSERT_OK(bind(connect_fd, (struct sockaddr *)&bind_addr,
+ bind_addr_len), "bind"))
+ goto cleanup;
+ }
+
+ if (!ASSERT_OK(connect_fd_to_fd(connect_fd, listen_fd, 0),
+ "connect_fd_to_fd"))
+ goto cleanup;
+
+ memset(&skel->bss->sk, 0, sizeof(skel->bss->sk));
+ destroy(skel, connect_fd, sock_type);
+ close(connect_fd);
+ connect_fd = -1;
+ ASSERT_EQ(ntohs(skel->bss->sk.dst_port), port, "dst_port");
+ if (family == AF_INET) {
+ ASSERT_EQ(ntohl(skel->bss->sk.dst_ip4), 0x7f000001, "dst_ip4");
+ } else {
+ ASSERT_EQ(skel->bss->sk.dst_ip6[0], 0, "dst_ip6[0]");
+ ASSERT_EQ(skel->bss->sk.dst_ip6[1], 0, "dst_ip6[1]");
+ ASSERT_EQ(skel->bss->sk.dst_ip6[2], 0, "dst_ip6[2]");
+ ASSERT_EQ(ntohl(skel->bss->sk.dst_ip6[3]), 0x1, "dst_ip6[3]");
+ }
+cleanup:
+ if (connect_fd >= 0)
+ close(connect_fd);
+ if (accept_fd >= 0)
+ close(accept_fd);
+ if (listen_fd >= 0)
+ close(listen_fd);
+}
+
+static void do_tests(struct sock_destroy_release *skel, int sock_type,
+ int family, const char * const *bind_addrs,
+ size_t bind_addrs_len, const int *bind_ports,
+ size_t bind_ports_len)
+{
+ const char *protocol_name = sock_type == SOCK_STREAM ? "tcp" : "udp";
+ const char *family_name = family == AF_INET ? "ipv4" : "ipv6";
+ char name[256];
+
+ for (size_t i = 0; i < bind_addrs_len; i++) {
+ for (size_t j = 0; j < bind_ports_len; j++) {
+ snprintf(name, sizeof(name), "%s/%s/destroy/%s:%d",
+ protocol_name, family_name, bind_addrs[i],
+ bind_ports[j]);
+ if (test__start_subtest(name))
+ do_test(skel, sock_type, family, bind_addrs[i],
+ bind_ports[j]);
+ }
+ }
+}
+
+void test_sock_destroy_release(void)
+{
+ static const char * const bind4_addresses[] = {NULL, ANY_ADDR4,
+ BIND_ADDR4};
+ static const char * const bind6_addresses[] = {NULL, ANY_ADDR6,
+ BIND_ADDR6};
+ static const int bind_ports[] = {0, 10002};
+ struct sock_destroy_release *skel = NULL;
+ struct nstoken *nstoken = NULL;
+ int cgroup_fd = -1;
+
+ skel = sock_destroy_release__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "open_and_load"))
+ goto done;
+
+ cgroup_fd = test__join_cgroup("/sock_destroy_release");
+ if (!ASSERT_OK_FD(cgroup_fd, "join_cgroup"))
+ goto done;
+
+ skel->links.sock_release = bpf_program__attach_cgroup(
+ skel->progs.sock_release, cgroup_fd);
+ if (!ASSERT_OK_PTR(skel->links.sock_release, "attach_cgroup"))
+ goto done;
+
+ SYS_NOFAIL("ip netns del " TEST_NS);
+ SYS(done, "ip netns add %s", TEST_NS);
+ SYS(done, "ip -net %s link set dev lo up", TEST_NS);
+
+ nstoken = open_netns(TEST_NS);
+ if (!ASSERT_OK_PTR(nstoken, "open_netns"))
+ goto done;
+
+ do_tests(skel, SOCK_STREAM, AF_INET, bind4_addresses,
+ ARRAY_SIZE(bind4_addresses), bind_ports,
+ ARRAY_SIZE(bind_ports));
+ do_tests(skel, SOCK_STREAM, AF_INET6, bind6_addresses,
+ ARRAY_SIZE(bind6_addresses), bind_ports,
+ ARRAY_SIZE(bind_ports));
+ do_tests(skel, SOCK_DGRAM, AF_INET, bind4_addresses,
+ ARRAY_SIZE(bind4_addresses), bind_ports,
+ ARRAY_SIZE(bind_ports));
+ do_tests(skel, SOCK_DGRAM, AF_INET6, bind6_addresses,
+ ARRAY_SIZE(bind6_addresses), bind_ports,
+ ARRAY_SIZE(bind_ports));
+done:
+ if (nstoken)
+ close_netns(nstoken);
+ if (cgroup_fd >= 0)
+ close(cgroup_fd);
+ SYS_NOFAIL("ip netns del " TEST_NS);
+ sock_destroy_release__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/sock_destroy_release.c b/tools/testing/selftests/bpf/progs/sock_destroy_release.c
new file mode 100644
index 000000000000..5389f79226f9
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/sock_destroy_release.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+
+volatile __u64 abort_cookie;
+
+void maybe_abort(struct sock_common *sk, struct seq_file *seq)
+{
+ __u64 sock_cookie;
+
+ if (!sk)
+ return;
+
+ sock_cookie = bpf_get_socket_cookie(sk);
+ if (sock_cookie != abort_cookie)
+ return;
+
+ bpf_sock_destroy(sk);
+ bpf_seq_write(seq, &sock_cookie, sizeof(sock_cookie));
+}
+
+SEC("iter/udp")
+int abort_udp(struct bpf_iter__udp *ctx)
+{
+ maybe_abort((struct sock_common *)ctx->udp_sk,
+ ctx->meta->seq);
+
+ return 0;
+}
+
+SEC("iter/tcp")
+int abort_tcp(struct bpf_iter__tcp *ctx)
+{
+ maybe_abort((struct sock_common *)ctx->sk_common,
+ ctx->meta->seq);
+
+ return 0;
+}
+
+struct bpf_sock sk = {};
+
+SEC("cgroup/sock_release")
+int sock_release(struct bpf_sock *ctx)
+{
+ sk.dst_ip4 = ctx->dst_ip4;
+ sk.dst_ip6[0] = ctx->dst_ip6[0];
+ sk.dst_ip6[1] = ctx->dst_ip6[1];
+ sk.dst_ip6[2] = ctx->dst_ip6[2];
+ sk.dst_ip6[3] = ctx->dst_ip6[3];
+ sk.dst_port = ctx->dst_port;
+
+ return 1;
+}
+
+char _license[] SEC("license") = "GPL";
--
2.53.0.1118.gaef5881109-goog
^ permalink raw reply related
* [PATCH net-next v3 3/4] udp: Preserve destination address info after abort
From: Jordan Rife @ 2026-03-30 21:57 UTC (permalink / raw)
To: netdev
Cc: Jordan Rife, bpf, Willem de Bruijn, Eric Dumazet, Daniel Borkmann,
Martin KaFai Lau, Stanislav Fomichev, Andrii Nakryiko,
Yusuke Suzuki, Jakub Kicinski, Kuniyuki Iwashima
In-Reply-To: <20260330215707.2374657-1-jrife@google.com>
For explicit disconnections using connect(AF_UNSPEC) behavior remains
unchanged while udp_abort now avoids clearing inet_daddr and inet_dport.
This is safe to do without changing behavior elsewhere, since lookups
only consult these fields if the socket is currently connected (sk_state
== TCP_ESTABLISHED). The behavior of getpeername doesn't change w.r.t.
aborted sockets, since it returns -ENOTCONN as long as sk_state ==
TCP_CLOSE. Behavior of BPF socket iterators and /proc/net/udp /do/
change with both now seeing the non-cleared daddr+dport pair after
an abort. Behavior of BPF socket lookup helpers which invoke
__udp*_lib_lookup don't change, since the result of compute_score should
be the same as before.
Reported-by: Yusuke Suzuki <yusuke.suzuki@isovalent.com>
Signed-off-by: Jordan Rife <jrife@google.com>
---
net/ipv4/udp.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 6e5ba2ce9314..043496a249ca 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2207,7 +2207,7 @@ static int udp_connect(struct sock *sk, struct sockaddr_unsized *uaddr,
return res;
}
-int __udp_disconnect(struct sock *sk, int flags)
+static int ___udp_disconnect(struct sock *sk, int flags, bool clear_dest)
{
struct inet_sock *inet = inet_sk(sk);
/*
@@ -2215,8 +2215,10 @@ int __udp_disconnect(struct sock *sk, int flags)
*/
sk->sk_state = TCP_CLOSE;
- inet->inet_daddr = 0;
- inet->inet_dport = 0;
+ if (clear_dest) {
+ inet->inet_daddr = 0;
+ inet->inet_dport = 0;
+ }
sock_rps_reset_rxhash(sk);
sk->sk_bound_dev_if = 0;
if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) {
@@ -2233,14 +2235,19 @@ int __udp_disconnect(struct sock *sk, int flags)
sk_dst_reset(sk);
return 0;
}
+
+int __udp_disconnect(struct sock *sk, int flags)
+{
+ return ___udp_disconnect(sk, flags, true);
+}
EXPORT_SYMBOL(__udp_disconnect);
-static int udp_disconnect_unhash4(struct sock *sk, int flags)
+static int udp_disconnect_unhash4(struct sock *sk, int flags, bool clear_dest)
{
struct udp_table *udptable = udp_get_table_prot(sk);
udp_unhash4(udptable, sk);
- __udp_disconnect(sk, flags);
+ ___udp_disconnect(sk, flags, clear_dest);
return 0;
}
@@ -2248,7 +2255,7 @@ static int udp_disconnect_unhash4(struct sock *sk, int flags)
int udp_disconnect(struct sock *sk, int flags)
{
lock_sock(sk);
- udp_disconnect_unhash4(sk, flags);
+ udp_disconnect_unhash4(sk, flags, true);
release_sock(sk);
return 0;
}
@@ -3264,7 +3271,7 @@ int udp_abort(struct sock *sk, int err)
sk->sk_err = err;
sk_error_report(sk);
- udp_disconnect_unhash4(sk, 0);
+ udp_disconnect_unhash4(sk, 0, false);
out:
if (!has_current_bpf_ctx())
--
2.53.0.1118.gaef5881109-goog
^ permalink raw reply related
* [PATCH net-next v3 2/4] udp: Remove disconnected sockets from the 4-tuple hash
From: Jordan Rife @ 2026-03-30 21:57 UTC (permalink / raw)
To: netdev
Cc: Jordan Rife, bpf, Willem de Bruijn, Eric Dumazet, Daniel Borkmann,
Martin KaFai Lau, Stanislav Fomichev, Andrii Nakryiko,
Yusuke Suzuki, Jakub Kicinski, Kuniyuki Iwashima
In-Reply-To: <20260330215707.2374657-1-jrife@google.com>
Currently, previously connected sockets stay in the 4-tuple hash after
__udp_disconnect if the socket was bound to a specific port or port:addr
pair. This is benign if inet_daddr/inet_dport are cleared as well, since
lookups matching the old 4-tuple will not find this socket in the hash.
To maintain the same behavior as before if inet_daddr/inet_dport are not
cleared in __udp_disconnect, always remove a socket from the hash on
disconnect or abort to prevent a lookup for the original 4-tuple from
finding the socket.
Signed-off-by: Jordan Rife <jrife@google.com>
---
net/ipv4/udp.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d91c587c3657..6e5ba2ce9314 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2235,10 +2235,20 @@ int __udp_disconnect(struct sock *sk, int flags)
}
EXPORT_SYMBOL(__udp_disconnect);
+static int udp_disconnect_unhash4(struct sock *sk, int flags)
+{
+ struct udp_table *udptable = udp_get_table_prot(sk);
+
+ udp_unhash4(udptable, sk);
+ __udp_disconnect(sk, flags);
+
+ return 0;
+}
+
int udp_disconnect(struct sock *sk, int flags)
{
lock_sock(sk);
- __udp_disconnect(sk, flags);
+ udp_disconnect_unhash4(sk, flags);
release_sock(sk);
return 0;
}
@@ -3254,7 +3264,7 @@ int udp_abort(struct sock *sk, int err)
sk->sk_err = err;
sk_error_report(sk);
- __udp_disconnect(sk, 0);
+ udp_disconnect_unhash4(sk, 0);
out:
if (!has_current_bpf_ctx())
--
2.53.0.1118.gaef5881109-goog
^ permalink raw reply related
* [PATCH net-next v3 1/4] udp: Only compare daddr/dport when sk_state == TCP_ESTABLISHED
From: Jordan Rife @ 2026-03-30 21:57 UTC (permalink / raw)
To: netdev
Cc: Jordan Rife, bpf, Willem de Bruijn, Eric Dumazet, Daniel Borkmann,
Martin KaFai Lau, Stanislav Fomichev, Andrii Nakryiko,
Yusuke Suzuki, Jakub Kicinski, Kuniyuki Iwashima
In-Reply-To: <20260330215707.2374657-1-jrife@google.com>
Adjust lookups and scoring to keep their results equivalent to before
even if inet_daddr+inet_dport are left intact after disconnecting a
socket (sk_state == TCP_CLOSE). sk_state == TCP_ESTABLISHED implies that
*daddr is non-zero, so remove redundant checks for that at the same
time. Note that __udp6_lib_demux_lookup already checks if sk_state ==
TCP_ESTABLISHED, so no change was needed there [1].
I could find no discernible difference in performance in
udp4_lib_lookup2 before and after the change in compute_score.
(AMD Ryzen 9 9900X)
kprobe:udp4_lib_lookup2 {
@start[cpu] = nsecs;
}
kretprobe:udp4_lib_lookup2 {
@lookup[cpu] = hist(nsecs - @start[cpu], 2);
}
BEFORE
======
@lookup[11]:
[80, 96) 1387077 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[96, 112) 364973 |@@@@@@@@@@@@@ |
[112, 128) 34261 |@ |
[128, 160) 7246 | |
[160, 192) 215 | |
[192, 224) 126 | |
AFTER
=====
@lookup[11]:
[80, 96) 1408594 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[96, 112) 340568 |@@@@@@@@@@@@ |
[112, 128) 30753 |@ |
[128, 160) 8019 | |
[160, 192) 231 | |
[192, 224) 157 | |
[1]: https://lore.kernel.org/netdev/20170623222537.130493-1-tracywwnj@gmail.com/
Signed-off-by: Jordan Rife <jrife@google.com>
---
net/ipv4/udp.c | 20 +++++++++++---------
net/ipv6/udp.c | 18 +++++++++---------
2 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index b60fad393e18..d91c587c3657 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -385,16 +385,16 @@ static int compute_score(struct sock *sk, const struct net *net,
score = (sk->sk_family == PF_INET) ? 2 : 1;
inet = inet_sk(sk);
- if (inet->inet_daddr) {
+ if (sk->sk_state == TCP_ESTABLISHED) {
if (inet->inet_daddr != saddr)
return -1;
score += 4;
- }
- if (inet->inet_dport) {
- if (inet->inet_dport != sport)
- return -1;
- score += 4;
+ if (inet->inet_dport) {
+ if (inet->inet_dport != sport)
+ return -1;
+ score += 4;
+ }
}
dev_match = udp_sk_bound_dev_eq(net, sk->sk_bound_dev_if,
@@ -796,8 +796,9 @@ static inline bool __udp_is_mcast_sock(struct net *net, const struct sock *sk,
if (!net_eq(sock_net(sk), net) ||
udp_sk(sk)->udp_port_hash != hnum ||
- (inet->inet_daddr && inet->inet_daddr != rmt_addr) ||
- (inet->inet_dport != rmt_port && inet->inet_dport) ||
+ (sk->sk_state == TCP_ESTABLISHED &&
+ (inet->inet_daddr != rmt_addr ||
+ (inet->inet_dport != rmt_port && inet->inet_dport))) ||
(inet->inet_rcv_saddr && inet->inet_rcv_saddr != loc_addr) ||
ipv6_only_sock(sk) ||
!udp_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif))
@@ -2854,7 +2855,8 @@ static struct sock *__udp4_lib_demux_lookup(struct net *net,
ports = INET_COMBINED_PORTS(rmt_port, hnum);
udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) {
- if (inet_match(net, sk, acookie, ports, dif, sdif))
+ if (sk->sk_state == TCP_ESTABLISHED &&
+ inet_match(net, sk, acookie, ports, dif, sdif))
return sk;
/* Only check first socket in chain */
break;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 010b909275dd..b93a9a3e7678 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -147,16 +147,16 @@ static int compute_score(struct sock *sk, const struct net *net,
score = 0;
inet = inet_sk(sk);
- if (inet->inet_dport) {
+ if (sk->sk_state == TCP_ESTABLISHED) {
if (inet->inet_dport != sport)
return -1;
score++;
- }
- if (!ipv6_addr_any(&sk->sk_v6_daddr)) {
- if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr))
- return -1;
- score++;
+ if (!ipv6_addr_any(&sk->sk_v6_daddr)) {
+ if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr))
+ return -1;
+ score++;
+ }
}
bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
@@ -949,9 +949,9 @@ static bool __udp_v6_is_mcast_sock(struct net *net, const struct sock *sk,
if (udp_sk(sk)->udp_port_hash != hnum ||
sk->sk_family != PF_INET6 ||
- (inet->inet_dport && inet->inet_dport != rmt_port) ||
- (!ipv6_addr_any(&sk->sk_v6_daddr) &&
- !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) ||
+ (sk->sk_state == TCP_ESTABLISHED &&
+ ((inet->inet_dport && inet->inet_dport != rmt_port) ||
+ !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr))) ||
!udp_sk_bound_dev_eq(net, READ_ONCE(sk->sk_bound_dev_if), dif, sdif) ||
(!ipv6_addr_any(&sk->sk_v6_rcv_saddr) &&
!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)))
--
2.53.0.1118.gaef5881109-goog
^ permalink raw reply related
* [PATCH net-next v3 0/4] udp: Preserve UDP socket addresses on abort
From: Jordan Rife @ 2026-03-30 21:57 UTC (permalink / raw)
To: netdev
Cc: Jordan Rife, bpf, Willem de Bruijn, Eric Dumazet, Daniel Borkmann,
Martin KaFai Lau, Stanislav Fomichev, Andrii Nakryiko,
Yusuke Suzuki, Jakub Kicinski, Kuniyuki Iwashima
BPF cgroup/sock_release hooks can be useful for performing cleanup,
map maintenance, or other bookkeeping when sockets are released. Cilium
uses cgroup/sock_release hooks to do just that, cleaning up maps keyed
by socket destination addresses. This works fine for TCP and connected
UDP sockets when they're closed gracefully, but Yusuke reported in [1]
that behavior is inconsistent following a socket abort.
From the perspective of a BPF sock_release hook, the state of sockets
following a socket abort (udp_abort, tcp_abort) is inconsistent and
surprising. After a sequence like the following,
1. connect(127.0.0.1:10001) or connect(::1:10001)
2. abort (diag_destroy() -> tcp_abort() or udp_abort())
3. close() -> sock_release hook runs
, the state of the sock_release program context differs depending on the
protocol and IP version.
+--------------------------------------------------------------+
| Configuration | ctx fields |
+------+----------+-----------+-----------+---------+----------+
| Case | Protocol | IP Family | dst_ip4 | dst_ip6 | dst_port |
+------+----------+-----------+-----------+---------+----------+
| 1 | TCP | IPv4 | 127.0.0.1 | - | 10001 |
| 2 | TCP | IPv6 | - | ::1 | 10001 |
| 3 | UDP | IPv4 | 0 | - | 0 |
| 4 | UDP | IPv6 | - | ::1 | 0 |
+------+----------+-----------+-----------+---------+----------+
For TCP, the state of dst_ip4/dst_ip6/dst_port are preserved. In the
case of UDP, both dst_ip4 and dst_port are cleared for IPv4 while
dst_ip6 remains intact for IPv6. This can be confusing for users of BPF
like Cilium where a sock_release hook makes use of these fields and
expects them to match a socket's state prior to abort. This series aims
to make the behavior consistent across the board to eliminate this
pitfall by preserving the state of dst_ip4 and dst_port after an abort.
[1]: https://github.com/cilium/cilium/issues/42649
v2: https://lore.kernel.org/netdev/20260303170106.129698-1-jrife@google.com/
CHANGES
=======
v2 -> v3:
* Expand selftests to add coverage for scenarios where a socket is bound
and connected.
* Simply unhashing a socket in udp_abort() as in v2 immediately releases
any ports the socket is bound to. Instead, the socket should hold onto
its port until it is closed just as before (Kuniyuki). v3 employs a
new strategy where inet_daddr and inet_dport are left intact in
__udp_disconnect during udp_abort and bound sockets remain in the
primary and portaddr hashes just as before. At the same time, the
logic in hash lookups is adjusted so that inet_daddr/inet_dport are
ignored unless the socket is currently connected (sk_state ==
TCP_ESTABLISHED).
Kuniyuki mentioned that performance may be a concern with changes to
logic in the fast path. I've tried to address these concerns by
testing the performance of udp4_lib_lookup2 before and after making
the changes.
v1 -> v2:
* Set connect_fd back to -1 after calling destroy() in the selftest
(Jakub).
Jordan Rife (4):
udp: Only compare daddr/dport when sk_state == TCP_ESTABLISHED
udp: Remove disconnected sockets from the 4-tuple hash
udp: Preserve destination address info after abort
selftests/bpf: Ensure dst addr/port are preserved after socket abort
net/ipv4/udp.c | 47 +++--
net/ipv6/udp.c | 18 +-
.../bpf/prog_tests/sock_destroy_release.c | 180 ++++++++++++++++++
.../bpf/progs/sock_destroy_release.c | 56 ++++++
4 files changed, 278 insertions(+), 23 deletions(-)
create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_destroy_release.c
create mode 100644 tools/testing/selftests/bpf/progs/sock_destroy_release.c
--
2.53.0.1118.gaef5881109-goog
^ permalink raw reply
* Re: [PATCH v7 1/3] PCI: AtomicOps: Do not enable requests by RCiEPs
From: Bjorn Helgaas @ 2026-03-30 21:42 UTC (permalink / raw)
To: Gerd Bayer, Alex Deucher, Christian König, Selvin Xavier,
Kalesh AP, Jason Gunthorpe, Leon Romanovsky, Michal Kalderon,
Saeed Mahameed, Tariq Toukan, Mark Bloch
Cc: Bjorn Helgaas, Jay Cornwall, Felix Kuehling, Ilpo Järvinen,
Christian Borntraeger, Niklas Schnelle, Gerald Schaefer,
Heiko Carstens, Vasily Gorbik, Alexander Gordeev, Sven Schnelle,
Alexander Schmidt, linux-s390, linux-pci, linux-kernel, netdev,
linux-rdma
In-Reply-To: <20260330-fix_pciatops-v7-1-f601818417e8@linux.ibm.com>
[+to amdgpu, bnxe_re, mlx5 IB, qedr, mlx5 maintainers]
On Mon, Mar 30, 2026 at 03:09:44PM +0200, Gerd Bayer wrote:
> Since root complex integrated end points (RCiEPs) attach to a bus that
> has no bridge device describing the root port, the capability to
> complete AtomicOps requests cannot be determined with PCIe methods.
>
> Change default of pci_enable_atomic_ops_to_root() to not enable
> AtomicOps requests on RCiEPs.
I know I suggested this because there's nothing explicit that tells us
whether the RC supports atomic ops from RCiEPs [1]. But I'm concerned
that GPUs, infiniband HCAs, and NICs that use atomic ops may be
implemented as RCiEPs and would be broken by this.
These drivers use pci_enable_atomic_ops_to_root():
amdgpu
bnxt_re (infiniband)
mlx5 (infinband)
qedr (infiniband)
mlx5 (ethernet)
Maybe we should assume that because RCiEPs are directly integrated
into the RC, the RCiEP would only allow AtomicOp Requester Enable to
be set if the RC supports atomic ops?
I don't like making assumptions like that, but it'd be worse to break
these devices.
[1] https://lore.kernel.org/all/20260326164002.GA1325368@bhelgaas
> Signed-off-by: Gerd Bayer <gbayer@linux.ibm.com>
> ---
> drivers/pci/pci.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 8479c2e1f74f1044416281aba11bf071ea89488a..135e5b591df405e87e7f520a618d7e2ccba55ce1 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -3692,15 +3692,14 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
>
> /*
> * Per PCIe r4.0, sec 6.15, endpoints and root ports may be
> - * AtomicOp requesters. For now, we only support endpoints as
> - * requesters and root ports as completers. No endpoints as
> + * AtomicOp requesters. For now, we only support (legacy) endpoints
> + * as requesters and root ports as completers. No endpoints as
> * completers, and no peer-to-peer.
> */
>
> switch (pci_pcie_type(dev)) {
> case PCI_EXP_TYPE_ENDPOINT:
> case PCI_EXP_TYPE_LEG_END:
> - case PCI_EXP_TYPE_RC_END:
> break;
> default:
> return -EINVAL;
>
> --
> 2.51.0
>
^ permalink raw reply
* Re: [PATCH] netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT absent
From: kernel test robot @ 2026-03-30 21:34 UTC (permalink / raw)
To: Qi Tang, Pablo Neira Ayuso, Florian Westphal
Cc: oe-kbuild-all, Phil Sutter, netfilter-devel, coreteam, netdev,
Qi Tang
In-Reply-To: <20260329165217.241038-1-tpluszz77@gmail.com>
Hi Qi,
kernel test robot noticed the following build errors:
[auto build test ERROR on netfilter-nf/main]
[also build test ERROR on linus/master nf-next/master horms-ipvs/master v7.0-rc6 next-20260327]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Qi-Tang/netfilter-ctnetlink-zero-expect-NAT-fields-when-CTA_EXPECT_NAT-absent/20260330-195347
base: https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git main
patch link: https://lore.kernel.org/r/20260329165217.241038-1-tpluszz77%40gmail.com
patch subject: [PATCH] netfilter: ctnetlink: zero expect NAT fields when CTA_EXPECT_NAT absent
config: sh-randconfig-001-20260331 (https://download.01.org/0day-ci/archive/20260331/202603310541.XVM8V7WG-lkp@intel.com/config)
compiler: sh4-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260331/202603310541.XVM8V7WG-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603310541.XVM8V7WG-lkp@intel.com/
All errors (new ones prefixed by >>):
net/netfilter/nf_conntrack_netlink.c: In function 'ctnetlink_alloc_expect':
>> net/netfilter/nf_conntrack_netlink.c:3592:28: error: 'struct nf_conntrack_expect' has no member named 'saved_addr'
3592 | memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
| ^~
net/netfilter/nf_conntrack_netlink.c:3592:55: error: 'struct nf_conntrack_expect' has no member named 'saved_addr'
3592 | memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
| ^~
>> net/netfilter/nf_conntrack_netlink.c:3593:28: error: 'struct nf_conntrack_expect' has no member named 'saved_proto'
3593 | memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
| ^~
net/netfilter/nf_conntrack_netlink.c:3593:56: error: 'struct nf_conntrack_expect' has no member named 'saved_proto'
3593 | memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
| ^~
>> net/netfilter/nf_conntrack_netlink.c:3594:20: error: 'struct nf_conntrack_expect' has no member named 'dir'
3594 | exp->dir = 0;
| ^~
vim +3592 net/netfilter/nf_conntrack_netlink.c
3528
3529 static struct nf_conntrack_expect *
3530 ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
3531 struct nf_conntrack_helper *helper,
3532 struct nf_conntrack_tuple *tuple,
3533 struct nf_conntrack_tuple *mask)
3534 {
3535 struct net *net = read_pnet(&ct->ct_net);
3536 struct nf_conntrack_expect *exp;
3537 struct nf_conn_help *help;
3538 u32 class = 0;
3539 int err;
3540
3541 help = nfct_help(ct);
3542 if (!help)
3543 return ERR_PTR(-EOPNOTSUPP);
3544
3545 if (cda[CTA_EXPECT_CLASS] && helper) {
3546 class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
3547 if (class > helper->expect_class_max)
3548 return ERR_PTR(-EINVAL);
3549 }
3550 exp = nf_ct_expect_alloc(ct);
3551 if (!exp)
3552 return ERR_PTR(-ENOMEM);
3553
3554 if (cda[CTA_EXPECT_FLAGS]) {
3555 exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
3556 exp->flags &= ~NF_CT_EXPECT_USERSPACE;
3557 } else {
3558 exp->flags = 0;
3559 }
3560 if (cda[CTA_EXPECT_FN]) {
3561 const char *name = nla_data(cda[CTA_EXPECT_FN]);
3562 struct nf_ct_helper_expectfn *expfn;
3563
3564 expfn = nf_ct_helper_expectfn_find_by_name(name);
3565 if (expfn == NULL) {
3566 err = -EINVAL;
3567 goto err_out;
3568 }
3569 exp->expectfn = expfn->expectfn;
3570 } else
3571 exp->expectfn = NULL;
3572
3573 exp->class = class;
3574 exp->master = ct;
3575 write_pnet(&exp->net, net);
3576 #ifdef CONFIG_NF_CONNTRACK_ZONES
3577 exp->zone = ct->zone;
3578 #endif
3579 if (!helper)
3580 helper = rcu_dereference(help->helper);
3581 rcu_assign_pointer(exp->helper, helper);
3582 exp->tuple = *tuple;
3583 exp->mask.src.u3 = mask->src.u3;
3584 exp->mask.src.u.all = mask->src.u.all;
3585
3586 if (cda[CTA_EXPECT_NAT]) {
3587 err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
3588 exp, nf_ct_l3num(ct));
3589 if (err < 0)
3590 goto err_out;
3591 } else {
> 3592 memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
> 3593 memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
> 3594 exp->dir = 0;
3595 }
3596 return exp;
3597 err_out:
3598 nf_ct_expect_put(exp);
3599 return ERR_PTR(err);
3600 }
3601
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH] ppp: dead code cleanup in Kconfig
From: Julian Braha @ 2026-03-30 21:32 UTC (permalink / raw)
To: andrew+netdev, pabeni, davem, kuba; +Cc: netdev, linux-kernel, Julian Braha
There is already an 'if PPP' condition wrapping several config options
e.g. PPP_MPPE and PPPOE, making the 'depends on PPP' statement for each of
these a duplicate dependency (dead code).
I propose leaving the outer 'if PPP...endif' and removing the individual
'depends on PPP' statement from each option.
This dead code was found by kconfirm, a static analysis tool for Kconfig.
Signed-off-by: Julian Braha <julianbraha@gmail.com>
---
drivers/net/ppp/Kconfig | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig
index a1806b4b84be..f57fba84fe55 100644
--- a/drivers/net/ppp/Kconfig
+++ b/drivers/net/ppp/Kconfig
@@ -37,7 +37,6 @@ if PPP
config PPP_BSDCOMP
tristate "PPP BSD-Compress compression"
- depends on PPP
help
Support for the BSD-Compress compression method for PPP, which uses
the LZW compression method to compress each PPP packet before it is
@@ -56,7 +55,6 @@ config PPP_BSDCOMP
config PPP_DEFLATE
tristate "PPP Deflate compression"
- depends on PPP
select ZLIB_INFLATE
select ZLIB_DEFLATE
help
@@ -71,7 +69,6 @@ config PPP_DEFLATE
config PPP_FILTER
bool "PPP filtering"
- depends on PPP
help
Say Y here if you want to be able to filter the packets passing over
PPP interfaces. This allows you to control which packets count as
@@ -84,7 +81,6 @@ config PPP_FILTER
config PPP_MPPE
tristate "PPP MPPE compression (encryption)"
- depends on PPP
select CRYPTO_LIB_ARC4
select CRYPTO_LIB_SHA1
help
@@ -96,7 +92,6 @@ config PPP_MPPE
config PPP_MULTILINK
bool "PPP multilink support"
- depends on PPP
help
PPP multilink is a protocol (defined in RFC 1990) which allows you
to combine several (logical or physical) lines into one logical PPP
@@ -109,7 +104,7 @@ config PPP_MULTILINK
config PPPOATM
tristate "PPP over ATM"
- depends on ATM && PPP
+ depends on ATM
help
Support PPP (Point to Point Protocol) encapsulated in ATM frames.
This implementation does not yet comply with section 8 of RFC2364,
@@ -118,7 +113,6 @@ config PPPOATM
config PPPOE
tristate "PPP over Ethernet"
- depends on PPP
help
Support for PPP over Ethernet.
@@ -164,7 +158,7 @@ config PPPOE_HASH_BITS
config PPTP
tristate "PPP over IPv4 (PPTP)"
- depends on PPP && NET_IPGRE_DEMUX
+ depends on NET_IPGRE_DEMUX
help
Support for PPP over IPv4.(Point-to-Point Tunneling Protocol)
@@ -175,7 +169,7 @@ config PPTP
config PPPOL2TP
tristate "PPP over L2TP"
- depends on L2TP && PPP
+ depends on L2TP
help
Support for PPP-over-L2TP socket family. L2TP is a protocol
used by ISPs and enterprises to tunnel PPP traffic over UDP
@@ -184,7 +178,6 @@ if TTY
config PPP_ASYNC
tristate "PPP support for async serial ports"
- depends on PPP
select CRC_CCITT
help
Say Y (or M) here if you want to be able to use PPP over standard
@@ -198,7 +191,6 @@ config PPP_ASYNC
config PPP_SYNC_TTY
tristate "PPP support for sync tty ports"
- depends on PPP
help
Say Y (or M) here if you want to be able to use PPP over synchronous
(HDLC) tty devices, such as the SyncLink adapter. These devices
--
2.51.2
^ permalink raw reply related
* Re: [PATCH net-next v3 4/6] net: bcmgenet: add XDP_TX support
From: Nicolai Buchwitz @ 2026-03-30 21:28 UTC (permalink / raw)
To: Mohsin Bashir
Cc: netdev, Doug Berger, Florian Fainelli,
Broadcom internal kernel review list, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexei Starovoitov, Daniel Borkmann, Jesper Dangaard Brouer,
John Fastabend, Stanislav Fomichev, linux-kernel, bpf
In-Reply-To: <c79a7b7e-9e1c-4b3b-8ef0-2d4144dccc25@gmail.com>
On 30.3.2026 20:15, Mohsin Bashir wrote:
>> +static bool
>> +bcmgenet_xdp_xmit_frame(struct bcmgenet_priv *priv,
>> + struct xdp_frame *xdpf, bool dma_map)
>> +{
>> + struct bcmgenet_tx_ring *ring = &priv->tx_rings[DESC_INDEX];
>> + struct device *kdev = &priv->pdev->dev;
>> + struct enet_cb *tx_cb_ptr;
>> + dma_addr_t mapping;
>> + unsigned int dma_len;
>> + u32 len_stat;
>> +
>> + spin_lock(&ring->lock);
>> +
>
> So we acquire lock on per-packet basis on the XDP_TX path? Do you think
> we can batch this?
Patch 4 only has one caller so the lock inside was fine. Patch 5
adds ndo_xdp_xmit which needs batching, so it moves the lock out
to the callers. XDP_TX processes one frame at a time in NAPI context
so batching doesn't apply there.
Note: v5 of this series was posted two days ago [1].
[1]
https://lore.kernel.org/netdev/20260328230513.415790-1-nb@tipi-net.de/
Thanks
Nicolai
^ permalink raw reply
* Re: [PATCH v2 1/2] iov: Bypass usercopy hardening for copy_to_iter()
From: David Laight @ 2026-03-30 21:11 UTC (permalink / raw)
To: Chuck Lever
Cc: Al Viro, Kees Cook, Gustavo A. R. Silva, linux-hardening,
linux-block, linux-fsdevel, netdev, Chuck Lever
In-Reply-To: <20260330-bypass-user-copy-v2-1-f236179e7fd6@oracle.com>
On Mon, 30 Mar 2026 10:36:30 -0400
Chuck Lever <cel@kernel.org> wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
>
> Profiling NFSD under an iozone workload showed that hardened
> usercopy checks consume roughly 1.3% of CPU in the TCP receive
> path. The runtime check in check_object_size() validates that
> copy buffers reside in expected kernel memory regions (slab,
> stack, and non-text), which is meaningful when data crosses
> the user/kernel boundary but adds no value when both source
> and destination are kernel addresses.
I thought the purpose was to avoid accidental overwrites when
the allocated buffer was the wrong size.
This is pretty much likely to affect user copies as kernel ones.
OTOH the overhead for some socket paths is really horrid.
IIRC sendmsg/recvmsg does copies where the length depends on
whether it is a 64bit or compat system call.
These go through the full horrors of user copy hardening even
thought there is no way they can ever fail.
That is the 'control pane' copies - well before you get to
any actual data.
David
^ permalink raw reply
* Re: [PATCH net-next v3 1/6] net: bcmgenet: convert RX path to page_pool
From: Nicolai Buchwitz @ 2026-03-30 21:03 UTC (permalink / raw)
To: Mohsin Bashir
Cc: netdev, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Doug Berger, Florian Fainelli,
Broadcom internal kernel review list, Vikas Gupta,
Rajashekar Hudumula, Bhargava Marreddy, Eric Biggers,
Arnd Bergmann, linux-kernel
In-Reply-To: <aeaa44fc-d7e2-425e-a7f5-703bc8539f82@gmail.com>
On 30.3.2026 20:15, Mohsin Bashir wrote:
>> if (priv->crc_fwd_en) {
>> - skb_trim(skb, len - ETH_FCS_LEN);
>> + skb_trim(skb, skb->len - ETH_FCS_LEN);
>> len -= ETH_FCS_LEN;
>
> Looks like 'len' update here is unnecessary since we are overwriting it
> later anyway?
Good catch, the len = skb->len assignment added in this patch makes len
-= ETH_FCS_LEN dead code since skb_trim already removed the FCS. Will
fix in v6.
Thanks
Nicolai
>
>> }
>> + /* Set up checksum offload */
>> + if (dev->features & NETIF_F_RXCSUM) {
>> + rx_csum = (__force __be16)(status->rx_csum & 0xffff);
>> + if (rx_csum) {
>> + skb->csum = (__force __wsum)ntohs(rx_csum);
>> + skb->ip_summed = CHECKSUM_COMPLETE;
>> + }
>> + }
>> +
>> + len = skb->len;
^ permalink raw reply
* [PATCH net-next,v4] net: mana: Force full-page RX buffers via ethtool private flag
From: Dipayaan Roy @ 2026-03-30 21:01 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, dipayanroy
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().
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
---
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.
---
drivers/net/ethernet/microsoft/mana/mana_en.c | 22 ++-
.../ethernet/microsoft/mana/mana_ethtool.c | 159 +++++++++++++++---
include/net/mana/mana.h | 8 +
3 files changed, 159 insertions(+), 30 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 6a4b42fe0944..9f7393b71a34 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -133,58 +133,91 @@ 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);
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);
+ case ETH_SS_PRIV_FLAGS:
+ return MANA_PRIV_FLAG_MAX;
+ default:
return -EINVAL;
+ }
+}
+
+static void mana_get_strings_priv_flags(u8 **data)
+{
+ int i;
- 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);
+ 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)
+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_PRIV_FLAGS:
+ mana_get_strings_priv_flags(&data);
+ break;
+
+ case ETH_SS_STATS:
+ mana_get_strings_stats(apc, &data);
+ break;
}
}
@@ -573,6 +606,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,
@@ -591,4 +692,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
* [PATCH net] tipc: fix UAF in tipc_buf_append via tipc_msg_validate
From: nicholas @ 2026-03-30 20:53 UTC (permalink / raw)
To: netdev; +Cc: Jon Maloy, Nicholas Carlini, stable
From: Nicholas Carlini <nicholas@carlini.com>
tipc_buf_append() passes the address of a local variable `head` to
tipc_msg_validate(). When the flow-control ratio check in
tipc_msg_validate() fires, it frees the original skb and updates
*_skb to point to a new copy -- but this only updates the local
`head`, not *headbuf. If validation subsequently fails (e.g. the
reassembled message has an invalid TIPC version), the err path
calls kfree_skb(*headbuf) on the already-freed skb. The replacement
skb is also leaked.
A remote attacker with an established TIPC link over a UDP bearer
can trigger this by sending a sequence of MSG_FRAGMENTER packets
crafted to inflate the reassembled skb's truesize relative to its
length past the ratio threshold, with an invalid version field in
the inner message.
Fix by passing headbuf directly to tipc_msg_validate() so the
pointer update propagates correctly.
Fixes: d618d09a68e4 ("tipc: enforce valid ratio between skb truesize and contents")
Cc: stable@vger.kernel.org
Signed-off-by: Nicholas Carlini <nicholas@carlini.com>
---
net/tipc/msg.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 76284fc53..9f4f612ee 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -177,8 +177,9 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
if (fragid == LAST_FRAGMENT) {
TIPC_SKB_CB(head)->validated = 0;
- if (unlikely(!tipc_msg_validate(&head)))
+ if (unlikely(!tipc_msg_validate(headbuf)))
goto err;
+ head = *headbuf;
*buf = head;
TIPC_SKB_CB(head)->tail = NULL;
*headbuf = NULL;
--
2.43.0
^ 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