* Re: [PATCHv2 net-next] net: bcmasp: handle EPROBE_DEFER for MAC retrieval
From: Justin Chen @ 2026-04-28 17:43 UTC (permalink / raw)
To: Rosen Penev, netdev
Cc: Florian Fainelli, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni,
open list:BROADCOM ASP 2.0 ETHERNET DRIVER, open list
In-Reply-To: <20260428014329.779779-1-rosenp@gmail.com>
On 4/27/26 6:43 PM, Rosen Penev wrote:
> of_get_ethdev_address can return EPROBE_DEFER when using nvmem. To
> handle this, encode the error with ERR_PTR for minimal changes. Adjust
> the only place using bcmasp_interface_create.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> v2: use dev_err_probe.
> drivers/net/ethernet/broadcom/asp2/bcmasp.c | 6 +++---
> drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c | 6 ++++--
> 2 files changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
> index 972474893a6b..e9b11b956344 100644
> --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c
> +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
> @@ -1333,10 +1333,10 @@ static int bcmasp_probe(struct platform_device *pdev)
> i = 0;
> for_each_available_child_of_node_scoped(ports_node, intf_node) {
> intf = bcmasp_interface_create(priv, intf_node, i);
> - if (!intf) {
> - dev_err(dev, "Cannot create eth interface %d\n", i);
> + if (IS_ERR(intf)) {
> of_node_put(ports_node);
> - ret = -EINVAL;
> + ret = dev_err_probe(dev, PTR_ERR(intf), "Cannot create eth interface %d\n",
> + i);
> goto err_cleanup;
> }
> list_add_tail(&intf->list, &priv->intfs);
> diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
> index ec63f50a849e..caf0e408e2f7 100644
> --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
> +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
> @@ -1254,7 +1254,7 @@ struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
> struct device *dev = &priv->pdev->dev;
> struct bcmasp_intf *intf;
> struct net_device *ndev;
> - int ch, port, ret;
> + int ch, port, ret = -EINVAL;
>
> if (of_property_read_u32(ndev_dn, "reg", &port)) {
> dev_warn(dev, "%s: invalid port number\n", ndev_dn->name);
> @@ -1314,6 +1314,8 @@ struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
> }
>
> ret = of_get_ethdev_address(ndev_dn, ndev);
> + if (ret == -EPROBE_DEFER)
> + return ERR_PTR(-EPROBE_DEFER);
Do we need to hit unwind here? i.e. goto err_deregister_fixed_link.
Thanks,
Justin
> if (ret) {
> netdev_warn(ndev, "using random Ethernet MAC\n");
> eth_hw_addr_random(ndev);
> @@ -1340,7 +1342,7 @@ struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv,
> err_free_netdev:
> free_netdev(ndev);
> err:
> - return NULL;
> + return ERR_PTR(ret);
> }
>
> void bcmasp_interface_destroy(struct bcmasp_intf *intf)
^ permalink raw reply
* RE: [EXTERNAL] [PATCH rc 04/15] RDMA/mana: Validate rx_hash_key_len
From: Long Li @ 2026-04-28 17:50 UTC (permalink / raw)
To: Jason Gunthorpe, Andrew Lunn,
Broadcom internal kernel review list, Bryan Tan, Eric Dumazet,
Junxian Huang, Konstantin Taranov, Jakub Kicinski,
Leon Romanovsky, linux-hyperv@vger.kernel.org,
linux-rdma@vger.kernel.org, netdev@vger.kernel.org, Paolo Abeni,
Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
Yishai Hadas
Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Lijun Ou,
Parav Pandit, patches@lists.linux.dev, Roland Dreier,
Roland Dreier, Sagi Grimberg, Ajay Sharma, stable@vger.kernel.org,
Tariq Toukan, Wei Hu (Xavier), Shaobo Xu, Nenglong Zhao
In-Reply-To: <4-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>
>
> Sashiko points out that rx_hash_key_len comes from a uAPI structure and is
> blindly passed to memcpy, allowing the userspace to trash kernel memory.
> Bounds check it so the memcpy cannot overflow.
>
> Cc: stable@vger.kernel.org
> Fixes: 0266a177631d ("RDMA/mana_ib: Add a driver for Microsoft Azure
> Network Adapter")
> Link:
> https://sashiko.d/
> ev%2F%23%2Fpatchset%2F0-v2-1c49eeb88c48%252B91-
> rdma_udata_rep_jgg%2540nvidia.com%3Fpart%3D1&data=05%7C02%7Clongli%
> 40microsoft.com%7C12e76b7833a74fb98a8208dea541b8cd%7C72f988bf86f141
> af91ab2d7cd011db47%7C1%7C0%7C639129898875053924%7CUnknown%7CT
> WFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4
> zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=75tKj32YfU
> uN7KdnsW63AjlwgnSLt2KXz34EUbXp2wI%3D&reserved=0
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> drivers/infiniband/hw/mana/qp.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
> index 645581359cee0b..f7bb0d1f0f8034 100644
> --- a/drivers/infiniband/hw/mana/qp.c
> +++ b/drivers/infiniband/hw/mana/qp.c
> @@ -21,6 +21,9 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev
> *dev,
>
> gc = mdev_to_gc(dev);
>
> + if (rx_hash_key_len > sizeof(req->hashkey))
> + return -EINVAL;
> +
> req_buf_size = struct_size(req, indir_tab,
> MANA_INDIRECT_TABLE_DEF_SIZE);
> req = kzalloc(req_buf_size, GFP_KERNEL);
> if (!req)
> --
> 2.43.0
^ permalink raw reply
* [RFC PATCH 0/2] net: af_unix: Useful handling of LSM denials on SCM_RIGHTS
From: Jori Koolstra @ 2026-04-28 17:51 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Eric Dumazet,
Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
David S . Miller, Jakub Kicinski, Jens Axboe, Kees Cook
Cc: Simon Horman, Andy Lutomirski, Will Drewry, Jeff Layton,
Jori Koolstra, Oleg Nesterov, Andrei Vagin, Pavel Tikhomirov,
Mateusz Guzik, Joel Granados, Charlie Mirabile, Aleksa Sarai,
linux-fsdevel, linux-kernel, netdev, io-uring
Right now if some LSM such as Smack denies an AF_UNIX socket peer to
receive an SCM_RIGHTS fd the SCM_RIGHTS fd array will be cut short at
that point, and MSG_CTRUNC is set on return of recvmsg(). This is
highly problematic behaviour, because it leaves the receiver
wondering what happened. As per man page MSG_CTRUNC is supposed to
indicate that the control buffer was sized too short, but suddenly
a permission error might result in the exact same flag being set.
Moreover, the receiver has no chance to determine how many fds got
originally sent and how many were suppressed.[1]
Add two MSG_* flags:
- MSG_RIGHTS_DENIAL is set whenever any file is rejected by the LSM
during recvmsg(2) of SCM_RIGHTS fds.
- If MSG_RIGHTS_FILTER is passed as a flag to recvmsg(), the SCM_RIGHTS
fd array is always passed in its full original size. However, any
files rejected by the LSM are replaced in this array with -EPERM
instead of an assigned fd, while keeping the original order. If the
flag is not set, the original truncate behavior is used.
I am putting this out for RFC for two reasons:
1) The MSG_* space is quite limited. We can do without MSG_RIGHTS_DENIAL
if needed.
2) Does userspace ever do anything else than bail out if MSG_CTRUNC is
found set? If not, we could maybe also get rid of MSG_RIGHTS_FILTER
and just make this the default behavior.
[1]: https://github.com/uapi-group/kernel-features#useful-handling-of-lsm-denials-on-scm_rights
Jori Koolstra (2):
net: af_unix: Useful handling of LSM denials on SCM_RIGHTS
selftest: Add tests for useful handling of LSM denials on SCM_RIGHTS
fs/file.c | 21 +-
include/linux/file.h | 4 +-
include/linux/socket.h | 3 +
include/net/scm.h | 8 +-
io_uring/openclose.c | 2 +-
kernel/pid.c | 2 +-
kernel/seccomp.c | 2 +-
net/compat.c | 7 +-
net/core/scm.c | 11 +-
.../net/af_unix/lsm_blocking/helper.h | 37 ++++
.../net/af_unix/lsm_blocking/receiver.c | 187 ++++++++++++++++++
.../net/af_unix/lsm_blocking/sender.c | 126 ++++++++++++
.../lsm_blocking/test_scm_rights_smack.sh | 172 ++++++++++++++++
13 files changed, 563 insertions(+), 19 deletions(-)
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/helper.h
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/receiver.c
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/sender.c
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/test_scm_rights_smack.sh
--
2.54.0
^ permalink raw reply
* [RFC PATCH 1/2] net: af_unix: Useful handling of LSM denials on SCM_RIGHTS
From: Jori Koolstra @ 2026-04-28 17:51 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Eric Dumazet,
Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
David S . Miller, Jakub Kicinski, Jens Axboe, Kees Cook
Cc: Simon Horman, Andy Lutomirski, Will Drewry, Jeff Layton,
Jori Koolstra, Oleg Nesterov, Andrei Vagin, Pavel Tikhomirov,
Mateusz Guzik, Joel Granados, Charlie Mirabile, Aleksa Sarai,
linux-fsdevel, linux-kernel, netdev, io-uring
In-Reply-To: <20260428175125.2705296-1-jkoolstra@xs4all.nl>
Right now if some LSM such as Smack denies an AF_UNIX socket peer to
receive an SCM_RIGHTS fd the SCM_RIGHTS fd array will be cut short at
that point, and MSG_CTRUNC is set on return of recvmsg(). This is
highly problematic behaviour, because it leaves the receiver
wondering what happened. As per man page MSG_CTRUNC is supposed to
indicate that the control buffer was sized too short, but suddenly
a permission error might result in the exact same flag being set.
Moreover, the receiver has no chance to determine how many fds got
originally sent and how many were suppressed.[1]
Add two MSG_* flags:
- MSG_RIGHTS_DENIAL is set whenever any file is rejected by the LSM
during recvmsg() of SCM_RIGHTS fds.
- If MSG_RIGHTS_FILTER is passed as a flag to recvmsg(), the SCM_RIGHTS
fd array is always passed in its full original size. However, any
files rejected by the LSM are replaced in this array with -EPERM
instead of an assigned fd, while keeping the original order. If the
flag is not set, the original truncate behavior is used.
[1]: https://github.com/uapi-group/kernel-features#useful-handling-of-lsm-denials-on-scm_rights
Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
---
fs/file.c | 21 ++++++++++++++++++---
include/linux/file.h | 4 +++-
include/linux/socket.h | 3 +++
include/net/scm.h | 8 ++++----
io_uring/openclose.c | 2 +-
kernel/pid.c | 2 +-
kernel/seccomp.c | 2 +-
net/compat.c | 7 ++++---
net/core/scm.c | 11 ++++++-----
9 files changed, 41 insertions(+), 19 deletions(-)
diff --git a/fs/file.c b/fs/file.c
index 2c81c0b162d0..cc33a1e77049 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -1370,10 +1370,11 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
}
/**
- * receive_fd() - Install received file into file descriptor table
+ * receive_fd_msg() - Install received file into file descriptor table
* @file: struct file that was received from another process
* @ufd: __user pointer to write new fd number to
* @o_flags: the O_* flags to apply to the new fd entry
+ * @msg_flags: the MSG_* flags to set for recvmsg(2)
*
* Installs a received file into the file descriptor table, with appropriate
* checks and count updates. Optionally writes the fd number to userspace, if
@@ -1384,13 +1385,21 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
*
* Returns newly install fd or -ve on error.
*/
-int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
+int receive_fd_msg(struct file *file, int __user *ufd, unsigned int o_flags,
+ unsigned int *msg_flags)
{
int error;
error = security_file_receive(file);
- if (error)
+ if (error) {
+ if (msg_flags)
+ *msg_flags |= MSG_RIGHTS_DENIAL;
+
+ if (ufd)
+ put_user(-EPERM, ufd);
+
return error;
+ }
FD_PREPARE(fdf, o_flags, file);
if (fdf.err)
@@ -1406,6 +1415,12 @@ int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
__receive_sock(fd_prepare_file(fdf));
return fd_publish(fdf);
}
+EXPORT_SYMBOL_GPL(receive_fd_msg);
+
+int receive_fd(struct file *file, unsigned int o_flags)
+{
+ return receive_fd_msg(file, NULL, o_flags, NULL);
+}
EXPORT_SYMBOL_GPL(receive_fd);
int receive_fd_replace(int new_fd, struct file *file, unsigned int o_flags)
diff --git a/include/linux/file.h b/include/linux/file.h
index 27484b444d31..38f022d997a6 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -118,7 +118,9 @@ DEFINE_FREE(fput, struct file *, if (!IS_ERR_OR_NULL(_T)) fput(_T))
extern void fd_install(unsigned int fd, struct file *file);
-int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags);
+int receive_fd_msg(struct file *file, int __user *ufd, unsigned int o_flags,
+ unsigned int *msg_flags);
+int receive_fd(struct file *file, unsigned int o_flags);
int receive_fd_replace(int new_fd, struct file *file, unsigned int o_flags);
diff --git a/include/linux/socket.h b/include/linux/socket.h
index ec4a0a025793..3809a8add2fc 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -342,6 +342,9 @@ struct ucred {
* plain text and require encryption
*/
+#define MSG_RIGHTS_DENIAL 0x200000
+#define MSG_RIGHTS_FILTER 0x400000
+
#define MSG_SOCK_DEVMEM 0x2000000 /* Receive devmem skbs as cmsg */
#define MSG_ZEROCOPY 0x4000000 /* Use user data in kernel path */
#define MSG_SPLICE_PAGES 0x8000000 /* Splice the pages from the iterator in sendmsg() */
diff --git a/include/net/scm.h b/include/net/scm.h
index c52519669349..983efa952c8e 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -50,8 +50,8 @@ struct scm_cookie {
#endif
};
-void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
-void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
+void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm, int recv_flags);
+void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm, int recv_flags);
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
void __scm_destroy(struct scm_cookie *scm);
struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
@@ -108,11 +108,11 @@ void scm_recv_unix(struct socket *sock, struct msghdr *msg,
struct scm_cookie *scm, int flags);
static inline int scm_recv_one_fd(struct file *f, int __user *ufd,
- unsigned int flags)
+ unsigned int o_flags, unsigned int *msg_flags)
{
if (!ufd)
return -EFAULT;
- return receive_fd(f, ufd, flags);
+ return receive_fd_msg(f, ufd, o_flags, msg_flags);
}
#endif /* __LINUX_NET_SCM_H */
diff --git a/io_uring/openclose.c b/io_uring/openclose.c
index c71242915dad..1b6cb05b0e3d 100644
--- a/io_uring/openclose.c
+++ b/io_uring/openclose.c
@@ -308,7 +308,7 @@ int io_install_fixed_fd(struct io_kiocb *req, unsigned int issue_flags)
int ret;
ifi = io_kiocb_to_cmd(req, struct io_fixed_install);
- ret = receive_fd(req->file, NULL, ifi->o_flags);
+ ret = receive_fd(req->file, ifi->o_flags);
if (ret < 0)
req_set_fail(req);
io_req_set_res(req, ret, 0);
diff --git a/kernel/pid.c b/kernel/pid.c
index fd5c2d4aa349..62af6874192d 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -929,7 +929,7 @@ static int pidfd_getfd(struct pid *pid, int fd)
if (IS_ERR(file))
return PTR_ERR(file);
- ret = receive_fd(file, NULL, O_CLOEXEC);
+ ret = receive_fd(file, O_CLOEXEC);
fput(file);
return ret;
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 066909393c38..ad5ab16fe2b1 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1130,7 +1130,7 @@ static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd, struct seccomp_kn
*/
list_del_init(&addfd->list);
if (!addfd->setfd)
- fd = receive_fd(addfd->file, NULL, addfd->flags);
+ fd = receive_fd(addfd->file, addfd->flags);
else
fd = receive_fd_replace(addfd->fd, addfd->file, addfd->flags);
addfd->ret = fd;
diff --git a/net/compat.c b/net/compat.c
index 2c9bd0edac99..056bce0927c4 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -287,18 +287,19 @@ static int scm_max_fds_compat(struct msghdr *msg)
return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
}
-void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
+void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm, int recv_flags)
{
struct compat_cmsghdr __user *cm =
(struct compat_cmsghdr __user *)msg->msg_control_user;
unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
+ bool filter_rights = recv_flags & MSG_RIGHTS_FILTER;
int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count);
int __user *cmsg_data = CMSG_COMPAT_DATA(cm);
int err = 0, i;
for (i = 0; i < fdmax; i++) {
- err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
- if (err < 0)
+ err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags, &msg->msg_flags);
+ if (err < 0 && !filter_rights)
break;
}
diff --git a/net/core/scm.c b/net/core/scm.c
index eec13f50ecaf..035329645d8f 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -351,10 +351,11 @@ static int scm_max_fds(struct msghdr *msg)
return (msg->msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
}
-void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
+void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm, int recv_flags)
{
struct cmsghdr __user *cm =
(__force struct cmsghdr __user *)msg->msg_control_user;
+ bool filter_rights = recv_flags & MSG_RIGHTS_FILTER;
unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
int fdmax = min_t(int, scm_max_fds(msg), scm->fp->count);
int __user *cmsg_data = CMSG_USER_DATA(cm);
@@ -365,13 +366,13 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
return;
if (msg->msg_flags & MSG_CMSG_COMPAT) {
- scm_detach_fds_compat(msg, scm);
+ scm_detach_fds_compat(msg, scm, recv_flags);
return;
}
for (i = 0; i < fdmax; i++) {
- err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
- if (err < 0)
+ err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags, &msg->msg_flags);
+ if (err < 0 && !filter_rights)
break;
}
@@ -524,7 +525,7 @@ static bool __scm_recv_common(struct sock *sk, struct msghdr *msg,
scm_passec(sk, msg, scm);
if (scm->fp)
- scm_detach_fds(msg, scm);
+ scm_detach_fds(msg, scm, flags);
return true;
}
--
2.54.0
^ permalink raw reply related
* [RFC PATCH 2/2] selftest: Add tests for useful handling of LSM denials on SCM_RIGHTS
From: Jori Koolstra @ 2026-04-28 17:51 UTC (permalink / raw)
To: Alexander Viro, Christian Brauner, Jan Kara, Eric Dumazet,
Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
David S . Miller, Jakub Kicinski, Jens Axboe, Kees Cook
Cc: Simon Horman, Andy Lutomirski, Will Drewry, Jeff Layton,
Jori Koolstra, Oleg Nesterov, Andrei Vagin, Pavel Tikhomirov,
Mateusz Guzik, Joel Granados, Charlie Mirabile, Aleksa Sarai,
linux-fsdevel, linux-kernel, netdev, io-uring
In-Reply-To: <20260428175125.2705296-1-jkoolstra@xs4all.nl>
Tests SCM_RIGHTS fd passing using Smack LSM blocking in combination with
the MSG_RIGHTS_FILTER flag.
Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
---
.../net/af_unix/lsm_blocking/helper.h | 37 ++++
.../net/af_unix/lsm_blocking/receiver.c | 187 ++++++++++++++++++
.../net/af_unix/lsm_blocking/sender.c | 126 ++++++++++++
.../lsm_blocking/test_scm_rights_smack.sh | 172 ++++++++++++++++
4 files changed, 522 insertions(+)
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/helper.h
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/receiver.c
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/sender.c
create mode 100644 tools/testing/selftests/net/af_unix/lsm_blocking/test_scm_rights_smack.sh
diff --git a/tools/testing/selftests/net/af_unix/lsm_blocking/helper.h b/tools/testing/selftests/net/af_unix/lsm_blocking/helper.h
new file mode 100644
index 000000000000..e827560ee78d
--- /dev/null
+++ b/tools/testing/selftests/net/af_unix/lsm_blocking/helper.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <unistd.h>
+#include <fcntl.h>
+
+#define MSG_RIGHTS_DENIAL 0x200000
+#define MSG_RIGHTS_FILTER 0x400000
+
+#define CMSG_IS_SCM_RIGHTS(cmsg) ({ \
+ typeof(cmsg) _cmsg = (cmsg); \
+ _cmsg && \
+ _cmsg->cmsg_level == SOL_SOCKET && \
+ _cmsg->cmsg_type == SCM_RIGHTS; \
+})
+
+#define MIN(a, b) ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a < _b ? _a : _b; \
+})
+
+#define MAX_FDS 10
+
+static inline int read_current_label(char *label, size_t size)
+{
+ int fd = open("/proc/self/attr/current", O_RDONLY);
+ if (fd < 0)
+ return fd;
+
+ ssize_t r = read(fd, label, size - 1);
+ close(fd);
+ if (r <= 0)
+ return r;
+
+ label[r] = '\0';
+
+ return 0;
+}
diff --git a/tools/testing/selftests/net/af_unix/lsm_blocking/receiver.c b/tools/testing/selftests/net/af_unix/lsm_blocking/receiver.c
new file mode 100644
index 000000000000..f5af9dcddc22
--- /dev/null
+++ b/tools/testing/selftests/net/af_unix/lsm_blocking/receiver.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * receiver.c - Receive a file descriptor over a Unix domain socket via SCM_RIGHTS
+ *
+ * Usage: ./receiver <socket_path>
+ *
+ * Listens on the given Unix socket path, accepts a connection, and
+ * attempts to receive file descriptors via SCM_RIGHTS. Reports
+ * whether the fds were delivered or blocked.
+ *
+ * Used for testing LSM (Smack) blocking of fd passing.
+ */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "helper.h"
+
+#define RECV_LOG(fmt, ...) printf("receiver: " fmt, ##__VA_ARGS__)
+#define RECV_ERR(fmt, ...) fprintf(stderr, "receiver: " fmt, ##__VA_ARGS__)
+
+static int recv_fds(int sock, int *fds)
+{
+ char buf[1];
+ char ctrl[CMSG_SPACE(MAX_FDS * sizeof(int))];
+
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = ctrl,
+ .msg_controllen = sizeof(ctrl),
+ };
+
+ ssize_t bytes_read = recvmsg(sock, &msg, MSG_RIGHTS_FILTER);
+ if (bytes_read < 0) {
+ perror("receiver: recvmsg");
+ return -1;
+ }
+ if (bytes_read == 0) {
+ RECV_ERR("connection closed, no data received\n");
+ return -1;
+ }
+
+ if (msg.msg_flags & MSG_RIGHTS_DENIAL)
+ RECV_LOG("MSG_RIGHTS_DENIAL set - some fds were blocked by the LSM!\n");
+
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ if (!CMSG_IS_SCM_RIGHTS(cmsg)) {
+ RECV_ERR("no SCM_RIGHTS in control message\n");
+ return -1;
+ }
+
+ int num_fd_slots = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+ memcpy(fds, CMSG_DATA(cmsg), num_fd_slots * sizeof(int));
+
+ RECV_LOG("got %d fd slots:", num_fd_slots);
+ for (int i = 0; i < num_fd_slots ; i++)
+ printf(" %d", fds[i]);
+ putchar('\n');
+
+ return num_fd_slots;
+}
+
+static inline int print_current_label(void)
+{
+ char label[256];
+ if (!read_current_label(label, sizeof(label))) {
+ RECV_LOG("running with Smack label '%s'\n", label);
+ return 0;
+ }
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <socket_path>\n", argv[0]);
+ return -1;
+ }
+
+ if (print_current_label()) {
+ RECV_ERR("cannot read process Smack label");
+ return -1;
+ }
+
+ int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (listen_sock < 0) {
+ perror("receiver: socket");
+ return -1;
+ }
+
+ struct sockaddr_un addr = {};
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);
+
+ /* Remove any stale socket file */
+ unlink(argv[1]);
+
+ if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror("receiver: bind");
+ return -1;
+ }
+
+ if (listen(listen_sock, 1) < 0) {
+ perror("receiver: listen");
+ return -1;
+ }
+
+ RECV_LOG("listening on '%s'\n", argv[1]);
+
+ int conn_sock = accept(listen_sock, NULL, NULL);
+ if (conn_sock < 0) {
+ perror("receiver: accept");
+ return -1;
+ }
+
+ RECV_LOG("connection accepted\n");
+
+ /* Try to receive the fds */
+ int fds[MAX_FDS];
+ int num_fds = recv_fds(conn_sock, fds);
+ if (num_fds < 0)
+ goto out_sock;
+
+ /* Try to use the received fds -- read and print their contents */
+ RECV_LOG("attempting to read from received fds...\n");
+ int i;
+ for (i = 0; i < num_fds; ++i) {
+ char readbuf[256];
+
+ if (fds[i] < 0) {
+ RECV_LOG("fd in position %i blocked\n", i);
+ continue;
+ } else if (fds[i] == 0) {
+ RECV_LOG("bad fd in position %i\n", i);
+ goto out_recv;
+ }
+
+ ssize_t n = read(fds[i], readbuf, sizeof(readbuf) - 1);
+ if (n < 0) {
+ perror("receiver: read from received fd");
+ goto out_recv;
+ }
+
+ readbuf[n] = '\0';
+ RECV_LOG("read %zd bytes from fd at position %i: '%s'\n", n, i, readbuf);
+ }
+
+ RECV_LOG("final result:\n");
+ for (int j = 0; j < num_fds; ++j) {
+ if (fds[j] < 0) {
+ printf("BLOCKED");
+ } else {
+ printf("PASSED");
+ close(fds[j]);
+ }
+ putchar(' ');
+ }
+
+ close(conn_sock);
+ close(listen_sock);
+ unlink(argv[1]);
+ return 0;
+
+out_recv:
+ for (int j = 0; j < num_fds; ++j) {
+ if (fds[j] > 0)
+ close(fds[j]);
+ }
+
+out_sock:
+ close(conn_sock);
+ close(listen_sock);
+ unlink(argv[1]);
+ return -1;
+}
diff --git a/tools/testing/selftests/net/af_unix/lsm_blocking/sender.c b/tools/testing/selftests/net/af_unix/lsm_blocking/sender.c
new file mode 100644
index 000000000000..b1c76d23b8bd
--- /dev/null
+++ b/tools/testing/selftests/net/af_unix/lsm_blocking/sender.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * sender.c - Send file descriptors over a Unix domain socket via SCM_RIGHTS
+ *
+ * Usage: ./sender <socket_path> <file_to_send> [<file_to_send>...]
+ *
+ * Opens the specified files and sends their fds to a receiver connected
+ * on the given Unix socket path. Used for testing LSM blocking of fd
+ * passing.
+ */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "helper.h"
+
+#define SEND_LOG(fmt, ...) fprintf(stdout, "sender: " fmt, ##__VA_ARGS__)
+#define SEND_ERR(fmt, ...) fprintf(stderr, "sender: " fmt, ##__VA_ARGS__)
+
+static int send_fds(int sock, int *fds, int num_fds)
+{
+ if (num_fds > MAX_FDS)
+ return -1;
+
+ char buf[1] = { 'X' };
+ char ctrl[CMSG_SPACE(MAX_FDS * sizeof(int))] = { 0 };
+
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf),
+ };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = ctrl,
+ .msg_controllen = CMSG_SPACE(num_fds * sizeof(int)),
+ };
+
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(num_fds * sizeof(int));
+ memcpy(CMSG_DATA(cmsg), fds, num_fds * sizeof(int));
+
+ ssize_t bytes_send = sendmsg(sock, &msg, 0);
+ if (bytes_send < 0) {
+ perror("sender: sendmsg");
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int print_current_label(void)
+{
+ char label[256];
+ if (!read_current_label(label, sizeof(label))) {
+ SEND_LOG("running with Smack label '%s'\n", label);
+ return 0;
+ }
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 3 || argc > 2 + MAX_FDS) {
+ fprintf(stderr, "Usage: %s <socket_path> <file_to_send> [<file_to_send>...]\\n",
+ argv[0]);
+ fprintf(stderr, "Up to a maximum of %d files", MAX_FDS);
+ return -1;
+ }
+
+ if (print_current_label()) {
+ SEND_ERR("cannot read process Smack label");
+ return -1;
+ }
+
+ int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("sender: socket");
+ return -1;
+ }
+
+ struct sockaddr_un addr = {};
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);
+
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror("sender: connect");
+ goto out_sock;
+ }
+
+ SEND_LOG("connected to '%s'\n", argv[1]);
+
+ int num_files = argc - 2;
+ int fds[MAX_FDS];
+ int i;
+ for (i = 0; i < num_files; i++) {
+ fds[i] = open(argv[2 + i], O_RDONLY);
+ if (fds[i] < 0) {
+ perror("sender: open file");
+ goto out_opened;
+ }
+ SEND_LOG("opened '%s' as fd %d\n", argv[2 + i], fds[i]);
+ }
+
+ if (send_fds(sock, fds, num_files) < 0)
+ goto out_opened;
+
+ SEND_LOG("fds successfully sent:");
+ for (int j = 0; j < num_files; j++)
+ printf(" %d", fds[j]);
+ putchar('\n');
+
+out_opened:
+ for (int j = 0; j < i; j++)
+ close(fds[j]);
+out_sock:
+ close(sock);
+ return -1;
+}
diff --git a/tools/testing/selftests/net/af_unix/lsm_blocking/test_scm_rights_smack.sh b/tools/testing/selftests/net/af_unix/lsm_blocking/test_scm_rights_smack.sh
new file mode 100644
index 000000000000..76fcfdd2cd4a
--- /dev/null
+++ b/tools/testing/selftests/net/af_unix/lsm_blocking/test_scm_rights_smack.sh
@@ -0,0 +1,172 @@
+# SPDX-License-Identifier: GPL-2.0
+
+#
+# test_scm_rights_smack.sh - Test SCM_RIGHTS fd passing using Smack LSM blocking
+#
+# Must be run as root on a kernel with Smack enabled (security=smack).
+# Requires: capsh (libcap), setfattr/getfattr (attr)
+#
+# We use the following Smack labels:
+# "Sender" - label for the sending process
+# "Receiver" - label for the receiving process
+# "SecretX" - labels for the files being passed
+#
+# Socket communication (Sender <-> Receiver) is always allowed.
+# The test controls whether Receiver can access "SecretX"-labeled fds.
+#
+
+
+readonly SOCK="/tmp/scm_test.sock"
+readonly TESTFILE1="/tmp/scm_test_secret_1"
+readonly TESTFILE2="/tmp/scm_test_secret_2"
+readonly SENDER="./sender"
+readonly RECEIVER="./receiver"
+
+set -e
+
+run_tests() {
+
+ preflight
+ setup
+
+ run_test "TEST 1" \
+ "Receiver should NOT have access to Secret1." \
+ "Receiver Secret1 ---
+Receiver Secret2 ---" \
+ "$TESTFILE1" \
+ "BLOCKED"
+
+ run_test "TEST 2" \
+ "Receiver should have access to Secret1." \
+ "Receiver Secret1 r--
+Receiver Secret2 ---" \
+ "$TESTFILE1" \
+ "PASSED"
+
+ run_test "TEST 3" \
+ "Receiver should have access to Secret2, but NOT Secret1." \
+ "Receiver Secret1 ---
+Receiver Secret2 r--" \
+ "$TESTFILE1 $TESTFILE2" \
+ "BLOCKED PASSED"
+}
+
+run_test() {
+ local name="$1"
+ local description="$2"
+ local rules="$3"
+ local files="$4"
+ local expected="$5"
+
+ echo ""
+ echo "$name: $description"
+ echo "Rules:"
+ echo "$rules"
+ echo "Expected: $expected"
+ echo ""
+
+ while IFS= read -r rule; do
+ [ -n "$rule" ] && echo "$rule" > /sys/fs/smackfs/load2
+ done <<< "$rules"
+
+ local output status last_line
+ output=$(send_fds "$SOCK" $files)
+ status=$?
+ echo "$output"
+ last_line=$(echo "$output" | tail -n 1 | xargs)
+
+ if [ "$status" -ne 0 ]; then
+ echo "TEST FAILED: receiver returned $status"
+ return 1
+ fi
+
+ if [[ "$last_line" == "$expected" ]]; then
+ echo "TEST PASSED: outcome was $expected as expected"
+ return 0
+ else
+ echo "TEST FAILED: expected $expected, got '$last_line'"
+ return 1
+ fi
+}
+
+setup() {
+
+ printf "Secret 1" > "$TESTFILE1"
+ printf "Secret 2" > "$TESTFILE2"
+
+ setfattr -n security.SMACK64 -v "Secret1" "$TESTFILE1"
+ setfattr -n security.SMACK64 -v "Secret2" "$TESTFILE2"
+ setfattr -n security.SMACK64 -v "Tmp" /tmp
+
+ echo "Sender Receiver -w-" > /sys/fs/smackfs/load2
+ echo "Receiver Sender -w-" > /sys/fs/smackfs/load2
+ echo "Sender Tmp rwx" > /sys/fs/smackfs/load2
+ echo "Receiver Tmp rwx" > /sys/fs/smackfs/load2
+ echo "Sender Secret1 r--" > /sys/fs/smackfs/load2
+ echo "Sender Secret2 r--" > /sys/fs/smackfs/load2
+}
+
+send_fds() {
+
+ local sk="$1"
+ shift
+ local files="$*"
+
+ (
+ echo "Receiver" > /proc/self/attr/current
+ exec capsh --drop=cap_mac_override,cap_mac_admin -- -c "$RECEIVER $sk"
+ ) &
+ local recv_pid=$!
+ sleep 1
+
+ (
+ echo "Sender" > /proc/self/attr/current
+ exec capsh --drop=cap_mac_override,cap_mac_admin -- -c "$SENDER $sk $files"
+ ) || true
+
+ local recv_status=0
+ wait "$recv_pid" || recv_status=$?
+
+ if [ "$recv_status" -ne 0 ]; then
+ echo "receiver exited with $recv_status"
+ fi
+ return "$recv_status"
+}
+
+preflight() {
+
+ if [ "$(id -u)" -ne 0 ]; then
+ echo "ERROR: must be run as root"
+ exit 1
+ fi
+
+ if ! grep -q smack /sys/kernel/security/lsm 2>/dev/null; then
+ echo "ERROR: Smack is not active"
+ echo " Check: cat /sys/kernel/security/lsm"
+ echo " Boot with: security=smack"
+ exit 1
+ fi
+
+ if ! mountpoint -q /sys/fs/smackfs 2>/dev/null; then
+ echo "Mounting smackfs..."
+ mount -t smackfs smackfs /sys/fs/smackfs
+ fi
+
+ if ! command -v capsh &>/dev/null; then
+ echo "ERROR: capsh not found (install libcap)"
+ exit 1
+ fi
+
+ # Build the test programs if needed
+ if [ ! -x "$SENDER" ]; then
+ echo "Building sender..."
+ gcc -Wall -o sender sender.c
+ fi
+ if [ ! -x "$RECEIVER" ]; then
+ echo "Building receiver..."
+ gcc -Wall -o receiver receiver.c
+ fi
+
+}
+
+run_tests
--
2.54.0
^ permalink raw reply related
* [RFC PATCH net-next 0/2] net: napi: Fix timer arming during busy poll timeout
From: Dragos Tatulea @ 2026-04-28 17:51 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Daniel Borkmann, Björn Töpel
Cc: Martin Karsten, dtatulea, Gal Pressman, Tariq Toukan, Joe Damato,
Frederik Deweerdt, netdev, linux-kernel
Under certain conditions a queue can be left out with interrupts
disabled and with the napi re-scheduling timer permanently stopped.
This behaviour is triggered by the napi busy poll path when
gro-flush-timeout and defer-hard-irq are set.
The first patch is a fix and has a more detailed description of how
the issue can occur.
The second patch represents an improvement which needs additional
review (hence the RFC).
The strategy for the non-RFC version is to send the first patch
as a fix to net and then send the improvement to net-next because
of the behavioral change (skipping the poll).
Is this the right way to go or should the 2 patches be squashed into
a fix for net?
[1] https://lore.kernel.org/netdev/20241105210338.5364375d@kernel.org/
Dragos Tatulea (1):
net: napi: Fix interrupts permanently disabled during busy poll
Martin Karsten (1):
net: napi: Skip poll when arming GRO timer in busy poll
net/core/dev.c | 49 ++++++++++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 21 deletions(-)
--
2.43.0
^ permalink raw reply
* [RFC PATCH net-next 1/2] net: napi: Fix interrupts permanently disabled during busy poll
From: Dragos Tatulea @ 2026-04-28 17:51 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Daniel Borkmann, Björn Töpel
Cc: Martin Karsten, dtatulea, Gal Pressman, Tariq Toukan, Joe Damato,
Frederik Deweerdt, netdev, linux-kernel
In-Reply-To: <20260428175134.1197036-2-dtatulea@nvidia.com>
Under certain conditions a queue can be left out with interrupts
disabled and with the napi re-scheduling timer permanently stopped.
This behaviour is triggered by the napi busy poll path when
gro-flush-timeout and defer-hard-irq are set. Here's a sequence of
operations:
1. Busy poll starts, NAPI_STATE_SCHED is set to avoid rescheduling napi
from the timer.
2. During napi poll, driver disables interrupts due to being in poll
mode (napi_complete_done() returns false because napi->state has
NAPIF_STATE_IN_BUSY_POLL set).
3. At the end of the busy poll (busy_poll_stop()):
3.1 napi timer is scheduled and skip_schedule is set (due to config)
3.2 napi->poll() is called:
- driver poll() processes exactly budget packets
and exits early => napi not scheduled.
(interrupts are still disabled at this point)
3.3 Since napi poll processed budget packets, __busy_poll_stop()
is called with skip_schedule set => napi is not scheduled here
either.
4. If the napi timer from 3.1 gets to be triggered due to slow napi poll
or some other reason, the timer will run with no effect (due to
NAPI_STATE_SCHED being set).
5. Busy poll finishes. Interrupts are still disabled and there is no
timer to re-schedule. Unless another busy poll call happens, the queue
will be stuck.
This patch defers the scheduling of the timer to right before
NAPI_STATE_SCHED is cleared. The timer is rescheduled and the
NAPI_STATE_SCHED bit cleared with interrupts disabled to make sure the
timer cannot fire before the bit is cleared, otherwise the
situation described in this bug can reoccur.
The timer is no longer scheduled when the napi poll returns < budget
because napi_complete_done() will re-enable the interrupts or scheduled
another napi.
Fixes: 7fd3253a7de6 ("net: Introduce preferred busy-polling")
Co-developed-by: Martin Karsten <mkarsten@uwaterloo.ca>
Signed-off-by: Martin Karsten <mkarsten@uwaterloo.ca>
Signed-off-by: Dragos Tatulea <dtatulea@nvidia.com>
---
net/core/dev.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index e59f6025067c..1487d4946dcf 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6869,9 +6869,11 @@ static void skb_defer_free_flush(void)
#if defined(CONFIG_NET_RX_BUSY_POLL)
-static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule)
+static void __busy_poll_stop(struct napi_struct *napi, unsigned long timeout)
{
- if (!skip_schedule) {
+ unsigned long flags;
+
+ if (!timeout) {
gro_normal_list(&napi->gro);
__napi_schedule(napi);
return;
@@ -6880,7 +6882,11 @@ static void __busy_poll_stop(struct napi_struct *napi, bool skip_schedule)
/* Flush too old packets. If HZ < 1000, flush all packets */
gro_flush_normal(&napi->gro, HZ >= 1000);
+ local_irq_save(flags);
+ hrtimer_start(&napi->timer, ns_to_ktime(timeout),
+ HRTIMER_MODE_REL_PINNED);
clear_bit(NAPI_STATE_SCHED, &napi->state);
+ local_irq_restore(flags);
}
enum {
@@ -6892,8 +6898,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
unsigned flags, u16 budget)
{
struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx;
- bool skip_schedule = false;
- unsigned long timeout;
+ unsigned long timeout = 0;
int rc;
/* Busy polling means there is a high chance device driver hard irq
@@ -6913,10 +6918,13 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
if (flags & NAPI_F_PREFER_BUSY_POLL) {
napi->defer_hard_irqs_count = napi_get_defer_hard_irqs(napi);
- timeout = napi_get_gro_flush_timeout(napi);
- if (napi->defer_hard_irqs_count && timeout) {
- hrtimer_start(&napi->timer, ns_to_ktime(timeout), HRTIMER_MODE_REL_PINNED);
- skip_schedule = true;
+ if (napi->defer_hard_irqs_count) {
+ /* Timer will be scheduled after napi poll to avoid
+ * firing during a slow poll which could cause the
+ * queue to get stuck with interrupts disabled and no
+ * scheduled timer.
+ */
+ timeout = napi_get_gro_flush_timeout(napi);
}
}
@@ -6931,7 +6939,7 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
trace_napi_poll(napi, rc, budget);
netpoll_poll_unlock(have_poll_lock);
if (rc == budget)
- __busy_poll_stop(napi, skip_schedule);
+ __busy_poll_stop(napi, timeout);
bpf_net_ctx_clear(bpf_net_ctx);
local_bh_enable();
}
--
2.43.0
^ permalink raw reply related
* [RFC PATCH net-next 2/2] net: napi: Skip poll when arming GRO timer in busy poll
From: Dragos Tatulea @ 2026-04-28 17:51 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman
Cc: Martin Karsten, dtatulea, Gal Pressman, Tariq Toukan, Joe Damato,
Frederik Deweerdt, netdev, linux-kernel
In-Reply-To: <20260428175134.1197036-2-dtatulea@nvidia.com>
From: Martin Karsten <mkarsten@uwaterloo.ca>
As referenced in the previous patch, having the GRO timer scheduled
while poll is running can lead to issues.
Skip the extra call to napi->poll() when the GRO timer is armed. This
removes the need for having a separate __busy_poll_stop routine and its
code is moved directly into the relevant places in busy_poll_stop.
Signed-off-by: Martin Karsten <mkarsten@uwaterloo.ca>
Co-developed-by: Dragos Tatulea <dtatulea@nvidia.com>
Signed-off-by: Dragos Tatulea <dtatulea@nvidia.com>
---
net/core/dev.c | 61 +++++++++++++++++++++++++-------------------------
1 file changed, 30 insertions(+), 31 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 1487d4946dcf..d4829c2484f5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6869,26 +6869,6 @@ static void skb_defer_free_flush(void)
#if defined(CONFIG_NET_RX_BUSY_POLL)
-static void __busy_poll_stop(struct napi_struct *napi, unsigned long timeout)
-{
- unsigned long flags;
-
- if (!timeout) {
- gro_normal_list(&napi->gro);
- __napi_schedule(napi);
- return;
- }
-
- /* Flush too old packets. If HZ < 1000, flush all packets */
- gro_flush_normal(&napi->gro, HZ >= 1000);
-
- local_irq_save(flags);
- hrtimer_start(&napi->timer, ns_to_ktime(timeout),
- HRTIMER_MODE_REL_PINNED);
- clear_bit(NAPI_STATE_SCHED, &napi->state);
- local_irq_restore(flags);
-}
-
enum {
NAPI_F_PREFER_BUSY_POLL = 1,
NAPI_F_END_ON_RESCHED = 2,
@@ -6898,14 +6878,14 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
unsigned flags, u16 budget)
{
struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx;
- unsigned long timeout = 0;
+ unsigned long timeout;
int rc;
/* Busy polling means there is a high chance device driver hard irq
* could not grab NAPI_STATE_SCHED, and that NAPI_STATE_MISSED was
* set in napi_schedule_prep().
- * Since we are about to call napi->poll() once more, we can safely
- * clear NAPI_STATE_MISSED.
+ * Since we either call napi->poll() once more or start the timer,
+ * we can safely clear NAPI_STATE_MISSED.
*
* Note: x86 could use a single "lock and ..." instruction
* to perform these two clear_bit()
@@ -6918,13 +6898,28 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
if (flags & NAPI_F_PREFER_BUSY_POLL) {
napi->defer_hard_irqs_count = napi_get_defer_hard_irqs(napi);
- if (napi->defer_hard_irqs_count) {
- /* Timer will be scheduled after napi poll to avoid
- * firing during a slow poll which could cause the
- * queue to get stuck with interrupts disabled and no
- * scheduled timer.
+ timeout = napi_get_gro_flush_timeout(napi);
+ if (napi->defer_hard_irqs_count && timeout) {
+ unsigned long flags;
+
+ /* Drop prefer-busy state as in napi_complete_done(). */
+ clear_bit(NAPI_STATE_PREFER_BUSY_POLL, &napi->state);
+ netpoll_poll_unlock(have_poll_lock);
+
+ /* Flush too old packets. If HZ < 1000, flush all
+ * packets.
+ */
+ gro_flush_normal(&napi->gro, HZ >= 1000);
+ local_irq_save(flags);
+ hrtimer_start(&napi->timer, ns_to_ktime(timeout),
+ HRTIMER_MODE_REL_PINNED);
+ clear_bit(NAPI_STATE_SCHED, &napi->state);
+ local_irq_restore(flags);
+
+ /* Timer started, so need for another call to
+ * napi->poll().
*/
- timeout = napi_get_gro_flush_timeout(napi);
+ goto out;
}
}
@@ -6938,8 +6933,12 @@ static void busy_poll_stop(struct napi_struct *napi, void *have_poll_lock,
*/
trace_napi_poll(napi, rc, budget);
netpoll_poll_unlock(have_poll_lock);
- if (rc == budget)
- __busy_poll_stop(napi, timeout);
+ if (rc == budget) {
+ gro_normal_list(&napi->gro);
+ __napi_schedule(napi);
+ }
+
+out:
bpf_net_ctx_clear(bpf_net_ctx);
local_bh_enable();
}
--
2.43.0
^ permalink raw reply related
* RE: [EXTERNAL] [PATCH rc 07/15] RDMA/mana: Fix error unwind in mana_ib_create_qp_rss()
From: Long Li @ 2026-04-28 17:53 UTC (permalink / raw)
To: Jason Gunthorpe, Andrew Lunn,
Broadcom internal kernel review list, Bryan Tan, Eric Dumazet,
Junxian Huang, Konstantin Taranov, Jakub Kicinski,
Leon Romanovsky, linux-hyperv@vger.kernel.org,
linux-rdma@vger.kernel.org, netdev@vger.kernel.org, Paolo Abeni,
Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
Yishai Hadas
Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Lijun Ou,
Parav Pandit, patches@lists.linux.dev, Roland Dreier,
Roland Dreier, Sagi Grimberg, Ajay Sharma, stable@vger.kernel.org,
Tariq Toukan, Wei Hu (Xavier), Shaobo Xu, Nenglong Zhao
In-Reply-To: <7-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>
>
> Sashiko points out that mana_ib_cfg_vport_steering() is leaked, the normal
> destroy path cleans it up.
>
> Cc: stable@vger.kernel.org
> Fixes: 0266a177631d ("RDMA/mana_ib: Add a driver for Microsoft Azure
> Network Adapter")
> Link:
> https://sashiko.d/
> ev%2F%23%2Fpatchset%2F0-v1-e911b76a94d1%252B65d95-
> rdma_udata_rep_jgg%2540nvidia.com%3Fpart%3D4&data=05%7C02%7Clongli%
> 40microsoft.com%7Cb377464abc954481e9b108dea541b646%7C72f988bf86f141
> af91ab2d7cd011db47%7C1%7C0%7C639129898856785811%7CUnknown%7CT
> WFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4
> zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=pqtgE8ULS
> pXgq%2BbpubumadArZO9lTvPki2ATvD9TnGI%3D&reserved=0
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> drivers/infiniband/hw/mana/qp.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
> index 8e1f052d0ec976..0fbcf449c134b5 100644
> --- a/drivers/infiniband/hw/mana/qp.c
> +++ b/drivers/infiniband/hw/mana/qp.c
> @@ -217,13 +217,15 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp,
> struct ib_pd *pd,
> ibdev_dbg(&mdev->ib_dev,
> "Failed to copy to udata create rss-qp, %d\n",
> ret);
> - goto fail;
> + goto err_disable_vport_rx;
> }
>
> kfree(mana_ind_table);
>
> return 0;
>
> +err_disable_vport_rx:
> + mana_disable_vport_rx(mpc);
> fail:
> while (i-- > 0) {
> ibwq = ind_tbl->ind_tbl[i];
> --
> 2.43.0
^ permalink raw reply
* RE: [EXTERNAL] [PATCH rc 06/15] RDMA/mana: Fix mana_destroy_wq_obj() cleanup in mana_ib_create_qp_rss()
From: Long Li @ 2026-04-28 17:55 UTC (permalink / raw)
To: Jason Gunthorpe, Andrew Lunn,
Broadcom internal kernel review list, Bryan Tan, Eric Dumazet,
Junxian Huang, Konstantin Taranov, Jakub Kicinski,
Leon Romanovsky, linux-hyperv@vger.kernel.org,
linux-rdma@vger.kernel.org, netdev@vger.kernel.org, Paolo Abeni,
Selvin Xavier, Chengchang Tang, Tariq Toukan, Vishnu Dasa,
Yishai Hadas
Cc: Abhijit Gangurde, Adit Ranadive, Allen Hubbe, Andrew Boyer,
Aditya Sarwade, Brad Spengler, Bryan Tan, David S. Miller,
Dexuan Cui, Doug Ledford, George Zhang, Jorgen Hansen, Jianbo Liu,
Kai Aizen, Leon Romanovsky, Leon Romanovsky, Yixian Liu, Lijun Ou,
Parav Pandit, patches@lists.linux.dev, Roland Dreier,
Roland Dreier, Sagi Grimberg, Ajay Sharma, stable@vger.kernel.org,
Tariq Toukan, Wei Hu (Xavier), Shaobo Xu, Nenglong Zhao
In-Reply-To: <6-v1-41f3135e5565+9d2-rdma_ai_fixes1_jgg@nvidia.com>
>
> Sashiko points out there are two bugs here in the error unwind flow, both related
> to how the WQ table is unwound.
>
> First there is a double i-- on the first failure path due to the while loop having a i--,
> remove it.
>
> Second if mana_ib_install_cq_cb() fails then mana_create_wq_obj() is not undone
> due to the above i--.
>
> Cc: stable@vger.kernel.org
> Fixes: c15d7802a424 ("RDMA/mana_ib: Add CQ interrupt support for RAW QP")
> Link:
> https://sashiko.d/
> ev%2F%23%2Fpatchset%2F0-v2-1c49eeb88c48%252B91-
> rdma_udata_rep_jgg%2540nvidia.com%3Fpart%3D1&data=05%7C02%7Clongli%
> 40microsoft.com%7Cd4d57c89064d4cc1781e08dea541b72a%7C72f988bf86f141
> af91ab2d7cd011db47%7C1%7C0%7C639129898849523924%7CUnknown%7CT
> WFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4
> zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=hbczVL%2F
> QTqw5zawJJPpSNkjtDrBOJNkV5Qn9vGGYbhE%3D&reserved=0
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Long Li <longli@microsoft.com>
> ---
> drivers/infiniband/hw/mana/qp.c | 9 ++++-----
> 1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
> index f7bb0d1f0f8034..8e1f052d0ec976 100644
> --- a/drivers/infiniband/hw/mana/qp.c
> +++ b/drivers/infiniband/hw/mana/qp.c
> @@ -176,11 +176,8 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp,
> struct ib_pd *pd,
>
> ret = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_RQ,
> &wq_spec, &cq_spec, &wq-
> >rx_object);
> - if (ret) {
> - /* Do cleanup starting with index i-1 */
> - i--;
> + if (ret)
> goto fail;
> - }
>
> /* The GDMA regions are now owned by the WQ object */
> wq->queue.gdma_region = GDMA_INVALID_DMA_REGION; @@
> -200,8 +197,10 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct
> ib_pd *pd,
>
> /* Create CQ table entry */
> ret = mana_ib_install_cq_cb(mdev, cq);
> - if (ret)
> + if (ret) {
> + mana_destroy_wq_obj(mpc, GDMA_RQ, wq-
> >rx_object);
> goto fail;
> + }
> }
> resp.num_entries = i;
>
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH net v4] ipv6: Implement limits on extension header parsing
From: Justin Iurman @ 2026-04-28 17:58 UTC (permalink / raw)
To: Daniel Borkmann, kuba
Cc: edumazet, dsahern, tom, willemdebruijn.kernel, idosch, pabeni,
netdev
In-Reply-To: <20260428153749.785611-1-daniel@iogearbox.net>
On 4/28/26 17:37, Daniel Borkmann wrote:
> ipv6_{skip_exthdr,find_hdr}() and ip6_{tnl_parse_tlv_enc_lim,
> protocol_deliver_rcu}() iterate over IPv6 extension headers until they
> find a non-extension-header protocol or run out of packet data. The
> loops have no iteration counter, relying solely on the packet length
> to bound them. For a crafted packet with 8-byte extension headers
> filling a 64KB jumbogram, this means a worst case of up to ~8k
> iterations with a skb_header_pointer call each. ipv6_skip_exthdr(),
> for example, is used where it parses the inner quoted packet inside
> an incoming ICMPv6 error:
>
> - icmpv6_rcv
> - checksum validation
> - case ICMPV6_DEST_UNREACH
> - icmpv6_notify
> - pskb_may_pull() <- pull inner IPv6 header
> - ipv6_skip_exthdr() <- iterates here
> - pskb_may_pull()
> - ipprot->err_handler() <- sk lookup
>
> The per-iteration cost of ipv6_skip_exthdr itself is generally
> light, but skb_header_pointer becomes more costly on reassembled
> packets: the first ~1232 bytes of the inner packet are in the skb's
> linear area, but the remaining ~63KB are in the frag_list where
> skb_copy_bits is needed to read data.
>
> Initially, the idea was to add a configurable limit via a new
> sysctl knob with default 8, in line with knobs from commit
> 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and Destination
> options"), but two reasons eventually argued against it:
>
> - It adds to UAPI that needs to be maintained forever, and
> upcoming work is restricting extension header ordering anyway,
> leaving little reason for another sysctl knob
> - exthdrs_core.c is always built-in even when CONFIG_IPV6=n,
> where struct net has no .ipv6 member, so the read site would
> need an ifdef'd fallback to a constant anyway
>
> Therefore, just use a constant (IP6_MAX_EXT_HDRS_CNT). All four
> extension header walking functions are now bound by this limit.
>
> Note that the check in ip6_protocol_deliver_rcu() happens right
> before the goto resubmit, such that we don't have to have a test
> for ipv6_ext_hdr() in the fast-path.
>
> There's an ongoing IETF draft-iurman-6man-eh-occurrences to enforce
> IPv6 extension headers ordering and occurrence. The latter also
> discusses security implications. As per RFC8200 section 4.1, the
> occurrence rules for extension headers provide a practical upper
> bound which is 8. In order to be conservative, let's define
> IP6_MAX_EXT_HDRS_CNT as 4x that to leave enough room for quirky
> setups. In the unlikely event that this is still not enough, then
> we might need to reconsider a sysctl.
>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
FWIW, I prefer v4 over v3. I didn't like the idea of a new sysctl for
several reasons I already mentioned. So, thanks for this new version,
Daniel.
However, I can't help but think 8 would pose absolutely no problem. I
would be very surprised to see someone complain. We're choosing 32 over
8 to be extra safe, at the price of security. RFC8200 provides the
following ordered list which is recommended for senders (without
normative language, though, which was a mistake):
Hop-by-Hop Options header
Destination Options header
Routing header
Fragment header
Authentication header
Encapsulating Security Payload header
Destination Options header
So this is the maximum you can have theoretically***, although you
wouldn't for instance use the Authentication header with ESP. I'm not
even talking about ordering or specific number of occurrences here, just
the total number of Extension Headers in a packet (as your patch does).
It's also worth mentioning that it's highly unlikely to see someone use
them all at the same time (in production, of course). This is why I
still think that 8 is safe too, and would provide security as expected.
***well, you also have 3 others [1] (Mobility Header, Host Identity
Protocol, Shim6 Protocol), but they're not widely used (not to say
dead). And they would probably not be used with other Extension Headers
anyway, as they are not specified to be present with a layer-4 in most
cases.
[1]
https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#extension-header
^ permalink raw reply
* [PATCH RFC] net/mlx5: check whether VFs are assigned before disabling SR-IOV
From: Max Boone via B4 Relay @ 2026-04-28 18:04 UTC (permalink / raw)
To: Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Mark Bloch,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: netdev, linux-rdma, linux-kernel, Max Boone
From: Max Boone <mboone@akamai.com>
When MLX5 cards are passed through to a VM, disabling SR-IOV by
setting the sriov_numvfs to 0 will render the machine unstable.
Other drivers (such as ixgbe, bnxt and octep) add this check to
see whether the VFs are passed through to a VM.
Signed-off-by: Max Boone <mboone@akamai.com>
---
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +-
drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 11 +++++++++--
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 1507e881d..85fe89c00 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -240,7 +240,7 @@ void mlx5_sriov_cleanup(struct mlx5_core_dev *dev);
int mlx5_sriov_attach(struct mlx5_core_dev *dev);
void mlx5_sriov_detach(struct mlx5_core_dev *dev);
int mlx5_core_sriov_configure(struct pci_dev *dev, int num_vfs);
-void mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change);
+int mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change);
int mlx5_core_sriov_set_msix_vec_count(struct pci_dev *vf, int msix_vec_count);
int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id);
int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
index bf6f631cf..07c61a73b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c
@@ -200,16 +200,23 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs)
return err;
}
-void mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change)
+int mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change)
{
struct mlx5_core_dev *dev = pci_get_drvdata(pdev);
struct devlink *devlink = priv_to_devlink(dev);
int num_vfs = pci_num_vf(dev->pdev);
+ if (pci_vfs_assigned(dev->pdev)) {
+ mlx5_core_warn(dev, "can't disable sriov, VFs are assigned\n");
+ return -EPERM;
+ }
+
pci_disable_sriov(pdev);
devl_lock(devlink);
mlx5_device_disable_sriov(dev, num_vfs, true, num_vf_change);
devl_unlock(devlink);
+
+ return 0;
}
int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs)
@@ -223,7 +230,7 @@ int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs)
if (num_vfs)
err = mlx5_sriov_enable(pdev, num_vfs);
else
- mlx5_sriov_disable(pdev, true);
+ err = mlx5_sriov_disable(pdev, true);
if (!err)
sriov->num_vfs = num_vfs;
---
base-commit: dca922e019dd758b4c1b4bec8f1d509efddeaab4
change-id: 20260428-mlx5-sriov-in-use-check-5cc2a79638e5
Best regards,
--
Max Boone <mboone@akamai.com>
^ permalink raw reply related
* Re: [PATCH 9/9] thunderbolt: Add support for USB4STREAM
From: Greg KH @ 2026-04-28 18:10 UTC (permalink / raw)
To: Mika Westerberg
Cc: linux-usb, Yehezkel Bernat, Lukas Wunner, Andreas Noever,
Alan Borzeszkowski, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, netdev
In-Reply-To: <20260428141148.GS557136@black.igk.intel.com>
On Tue, Apr 28, 2026 at 04:11:48PM +0200, Mika Westerberg wrote:
> On Tue, Apr 28, 2026 at 07:54:51AM -0600, Greg KH wrote:
> > On Tue, Apr 28, 2026 at 02:03:14PM +0200, Mika Westerberg wrote:
> > > On Tue, Apr 28, 2026 at 05:57:37AM -0600, Greg KH wrote:
> > > > On Tue, Apr 28, 2026 at 09:22:09AM +0200, Mika Westerberg wrote:
> > > > > Introduce USB4STREAM protocol and Linux implementation. This allows two
> > > > > (or more) hosts to transfer data directly over Thunderbolt/USB4 cable
> > > > > through a character device without need to go through the network stack.
> > > > >
> > > > > Any application that supports read(2) and write(2) in some form should
> > > > > be able to use the device without changes. The data is sent out to the
> > > > > other side over a tunnel inside Thunderbolt/USB4 fabric. The character
> > > > > device is called /dev/tbstreamX where X is the minor number starting
> > > > > from 0.
> > > > >
> > > > > All stream devices need to be configured first. This is done through
> > > > > ConfigFS interface. There can be multiple streams at the same time (this
> > > > > depends on number of DMA rings and available HopIDs) and a single stream
> > > > > supports traffic in both directions. For example there could be an
> > > > > application that uses one stream as control channel and another one as
> > > > > bi-directional data channel.
> > > > >
> > > > > A real use-case for this is to take a backup as a part of recovery
> > > > > initramfs tooling (no need to setup networking or have ssh or similar
> > > > > tooling as part of the initramfs). Say we want to backup the disk of
> > > > > host1 to host2. First Thunderbolt/USB4 cable is connected between the
> > > > > hosts (there can be devices in the middle too) then the receiving side
> > > > > configures the stream:
> > > > >
> > > > > host2 # mkdir /sys/kernel/config/thunderbolt/stream/0-1.0
> > > > > host2 # mkdir /sys/kernel/config/thunderbolt/stream/0-1.0/backup
> > > > > host2 # echo -1 > /sys/kernel/config/thunderbolt/stream/0-1.0/backup/in_hopid
> > > > > host2 # echo -1 > /sys/kernel/config/thunderbolt/stream/0-1.0/backup/out_hopid
> > > > >
> > > > > We use automatic HopID allocation (writing -1 to HopIDs) for simplicity.
> > > > > >From this point forward the /dev/tbstream0 can be used pretty much as
> > > > > regular file:
> > > > >
> > > > > host2 # dd if=/dev/tbstream0 of=/tmp/host1.nvme0n1.backup-$(date +%F) bs=256k
> > > > >
> > > > > The host that is being backed up then configures the stream accordingly:
> > > > >
> > > > > host1 # mkdir /sys/kernel/config/thunderbolt/stream/0-503.0
> > > > > host1 # mkdir /sys/kernel/config/thunderbolt/stream/0-503.0/backup
> > > > >
> > > > > Here we take advantage of the fact that host2 also announces the active
> > > > > streams through XDomain properties so the name "backup" gives us the
> > > > > HopIDs. It is also possible to configure them manually in the same way
> > > > > we did for host2.
> > > > >
> > > > > Then it is just a matter of copying the data over:
> > > > >
> > > > > host1 # dd if=/dev/nvme0n1 of=/dev/tbstream0 bs=256k
> > > > >
> > > > > Similarly it is possible to transfer parts of the filesystem. For
> > > > > example copy contents of mydir over to the host2:
> > > > >
> > > > > host2 # gunzip < /dev/tbstream0 | tar xf -
> > > > > host1 # tar cf - mydir | gzip > /dev/tbstream0
> > > > >
> > > > > Other end of the spectrum use-case is "borrowing" laptop (host1) camera
> > > > > to desktop (host2):
> > > > >
> > > > > host2 # gst-launch-1.0 filesrc location=/dev/tbstream0 ! jpegdec ! videoconvert ! \
> > > > > autovideosink
> > > > >
> > > > > host1 # gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=1920,height=1080 ! \
> > > > > jpegenc quality=90 ! filesink location=/dev/tbstream0
> > > > >
> > > > > Once the streams are no longer needed they can be removed:
> > > > >
> > > > > host1 # cd /sys/kernel/config/thunderbolt/stream/
> > > > > host1 # rmdir -p 0-503.0/backup
> > > > >
> > > > > host2 # cd /sys/kernel/config/thunderbolt/stream
> > > > > host2 # rmdir -p 0-1.0/backup
> > > >
> > > > Very cool, but shouldn't the above be in some documentation somewhere so
> > > > that people know how to use it?
> > >
> > > Sure, I can add it part of the Documentation/admin-guide/thunderbolt.rs for
> > > example.
> > >
> > > > And why do you need a whole major for this, why not just use a misc
> > > > device that it dynamically created for every new dev?
> > >
> > > We do use this:
> > >
> > > ret = alloc_chrdev_region(&tbstream_devt, 0, TBSTREAM_DEV_MINORS,
> > > "tbstream");
> > >
> > > that should be dynamically allocated, no?
> >
> > Yes, but you are using up a whole major number for this, and in reality
> > there's only going to be 1-2, maybe 4, different devices needed at once,
> > right? So just use the miscdev interface instead?
>
> There could be 11 per host controller in Intel hardware (we have 12 DMA
> rings, one of which is reserved for control traffic), and we have 2 host
> conrollers in recent systems. Due to the dedicated flow control we use now
> that's not possible but we are planning to make it to use shared flow
> control instead which allows more.
>
> Not sure if anybody ever will create that many, though.
Yeah, that's not many, and a bit of a waste of a full major number.
> Second thing is that we use cdev_device_add() to manage the char device and
> the stream device as they are part of the same structure. I don't think
> that can be done with miscdevice.
Not yet, but see the patches on the list for how to do that properly.
You will have issues with disconnect/open/close that you need to handle
very carefully, especially as you are a dynamic device. See this
thread:
https://lore.kernel.org/r/20260427134659.95181-1-tzungbi@kernel.org
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 5/9] thunderbolt / net: Let the service drivers configure interrupt throttling
From: Greg KH @ 2026-04-28 18:10 UTC (permalink / raw)
To: Mika Westerberg
Cc: Andrew Lunn, linux-usb, Yehezkel Bernat, Lukas Wunner,
Andreas Noever, Alan Borzeszkowski, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, netdev
In-Reply-To: <20260428172629.GW557136@black.igk.intel.com>
On Tue, Apr 28, 2026 at 07:26:29PM +0200, Mika Westerberg wrote:
> On Tue, Apr 28, 2026 at 04:59:58PM +0200, Andrew Lunn wrote:
> > On Tue, Apr 28, 2026 at 09:22:05AM +0200, Mika Westerberg wrote:
> > > Instead of the core driver programming fixed value for throttling let
> > > the service drivers to specify the interval if they need this. We also
> > > allow user to tune this through a module parameter if the default is not
> > > good fit.
> > >
> > > Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
> > > ---
> > > drivers/net/thunderbolt/main.c | 7 ++++
> > > drivers/thunderbolt/dma_test.c | 5 +++
> > > drivers/thunderbolt/nhi.c | 58 ++++++++++++++++++----------------
> > > drivers/thunderbolt/nhi_regs.h | 3 +-
> > > include/linux/thunderbolt.h | 5 +++
> > > 5 files changed, 50 insertions(+), 28 deletions(-)
> > >
> > > diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c
> > > index 49673f7e0055..8771ca807933 100644
> > > --- a/drivers/net/thunderbolt/main.c
> > > +++ b/drivers/net/thunderbolt/main.c
> > > @@ -218,6 +218,10 @@ static bool tbnet_e2e = true;
> > > module_param_named(e2e, tbnet_e2e, bool, 0444);
> > > MODULE_PARM_DESC(e2e, "USB4NET full end-to-end flow control (default: true)");
> > >
> > > +static unsigned int tbnet_throttling = 128000;
> > > +module_param_named(throttling, tbnet_throttling, uint, 0444);
> > > +MODULE_PARM_DESC(throttling, "Interrupt throttling rate in ns (default: 128000)");
> >
> > As i mentioned elsewhere, netdev does not allow module
> > parameters. They are hard to use, especially when you have lots of
> > instances of a device, or you need to set it on the kernel command
> > line because by the time the kernel has booted, it is too late, etc.
> > And they are undocumented, and every driver does it differently.
>
> Right. This was meant to be a "chicken bit" or "escape hatch" not something
> used in daily basis.
Put it in configfs if you really want it.
You shouldn't need any new module parameters.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH net v1] net/mlx5: Fix eswitch offloads cleanup on QoS init failure
From: Simon Horman @ 2026-04-28 18:11 UTC (permalink / raw)
To: Prathamesh Deshpande
Cc: saeedm, leon, kuba, tariqt, cratiu, cjubran, netdev, linux-rdma,
linux-kernel
In-Reply-To: <20260425003046.6889-1-prathameshdeshpande7@gmail.com>
On Sat, Apr 25, 2026 at 01:29:59AM +0100, Prathamesh Deshpande wrote:
> If mlx5_esw_qos_init() fails after esw_offloads_init() succeeds,
> mlx5_eswitch_init() jumps to reps_err and skips esw_offloads_cleanup(),
> leaking the offloads initialization state.
>
> Add a dedicated unwind label for QoS init failure that cleans up
> offloads before continuing the existing vport and outer eswitch cleanup.
>
> Fixes: cac7356c653d ("net/mlx5: Rework esw qos domain init and cleanup")
> Signed-off-by: Prathamesh Deshpande <prathameshdeshpande7@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* Re: [PATCH net-next 1/4] net: eth: fbnic: Fix addr validation in pcs write
From: Andrew Lunn @ 2026-04-28 18:11 UTC (permalink / raw)
To: mike.marciniszyn
Cc: Alexander Duyck, Jakub Kicinski, kernel-team, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Heiner Kallweit,
Russell King, Jacob Keller, Mohsin Bashir, netdev, linux-kernel,
stable
In-Reply-To: <20260428172810.175077-2-mike.marciniszyn@gmail.com>
On Tue, Apr 28, 2026 at 01:28:07PM -0400, mike.marciniszyn@gmail.com wrote:
> From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
>
> This patch contains a fix for addr validation in fbnic_mdio_write_pcs().
>
> Cc: stable@vger.kernel.org
> Fixes: d0ce9fd7eae0 ("fbnic: Add SW shim for MDIO interface to PMD and PCS")
> Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
Please don't mix fixed and going development work in one
patchset. They should be applied to different trees, etc.
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
Andrew
---
pw-bot: cr
^ permalink raw reply
* [PATCH] i40e: Fix i40e_debug() to use struct i40e_hw argument
From: Mohamed Khalfella @ 2026-04-28 18:14 UTC (permalink / raw)
To: Tony Nguyen, Przemek Kitszel, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Mohamed Khalfella, intel-wired-lan, netdev, linux-kernel
i40e_debug() macro takes struct i40e_hw *h as first argument. But the
macro body uses hw instead of h. This has been working so far because hw
happen to be the name of the variable in the context where the marco is
expanded. Fix the macro to use the passed argument.
Signed-off-by: Mohamed Khalfella <mkhalfella@purestorage.com>
---
drivers/net/ethernet/intel/i40e/i40e_debug.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debug.h b/drivers/net/ethernet/intel/i40e/i40e_debug.h
index e9871dfb32bd..01fd70db9086 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debug.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_debug.h
@@ -42,7 +42,7 @@ struct device *i40e_hw_to_dev(struct i40e_hw *hw);
#define i40e_debug(h, m, s, ...) \
do { \
if (((m) & (h)->debug_mask)) \
- dev_info(i40e_hw_to_dev(hw), s, ##__VA_ARGS__); \
+ dev_info(i40e_hw_to_dev(h), s, ##__VA_ARGS__); \
} while (0)
#endif /* _I40E_DEBUG_H_ */
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net-next 2/4] net: mdio: Add support for RSFEC Control register for PMA
From: Andrew Lunn @ 2026-04-28 18:15 UTC (permalink / raw)
To: mike.marciniszyn
Cc: Alexander Duyck, Jakub Kicinski, kernel-team, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Heiner Kallweit,
Russell King, Jacob Keller, Mohsin Bashir, netdev, linux-kernel
In-Reply-To: <20260428172810.175077-3-mike.marciniszyn@gmail.com>
On Tue, Apr 28, 2026 at 01:28:08PM -0400, mike.marciniszyn@gmail.com wrote:
> From: "Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>
>
> Add the constants associated with RS-FEC configuration
> and status as well as the indicated separated bits for
> DEVS1 to convey a separated PMA.
>
> Signed-off-by: Mike Marciniszyn (Meta) <mike.marciniszyn@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* Re: [PATCH net v4] ipv6: Implement limits on extension header parsing
From: Daniel Borkmann @ 2026-04-28 18:16 UTC (permalink / raw)
To: Justin Iurman, kuba
Cc: edumazet, dsahern, tom, willemdebruijn.kernel, idosch, pabeni,
netdev
In-Reply-To: <4497a340-b48e-4615-81eb-90ebc7a0b5d2@gmail.com>
On 4/28/26 7:58 PM, Justin Iurman wrote:
> On 4/28/26 17:37, Daniel Borkmann wrote:
>> ipv6_{skip_exthdr,find_hdr}() and ip6_{tnl_parse_tlv_enc_lim,
>> protocol_deliver_rcu}() iterate over IPv6 extension headers until they
>> find a non-extension-header protocol or run out of packet data. The
>> loops have no iteration counter, relying solely on the packet length
>> to bound them. For a crafted packet with 8-byte extension headers
>> filling a 64KB jumbogram, this means a worst case of up to ~8k
>> iterations with a skb_header_pointer call each. ipv6_skip_exthdr(),
>> for example, is used where it parses the inner quoted packet inside
>> an incoming ICMPv6 error:
>>
>> - icmpv6_rcv
>> - checksum validation
>> - case ICMPV6_DEST_UNREACH
>> - icmpv6_notify
>> - pskb_may_pull() <- pull inner IPv6 header
>> - ipv6_skip_exthdr() <- iterates here
>> - pskb_may_pull()
>> - ipprot->err_handler() <- sk lookup
>>
>> The per-iteration cost of ipv6_skip_exthdr itself is generally
>> light, but skb_header_pointer becomes more costly on reassembled
>> packets: the first ~1232 bytes of the inner packet are in the skb's
>> linear area, but the remaining ~63KB are in the frag_list where
>> skb_copy_bits is needed to read data.
>>
>> Initially, the idea was to add a configurable limit via a new
>> sysctl knob with default 8, in line with knobs from commit
>> 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and Destination
>> options"), but two reasons eventually argued against it:
>>
>> - It adds to UAPI that needs to be maintained forever, and
>> upcoming work is restricting extension header ordering anyway,
>> leaving little reason for another sysctl knob
>> - exthdrs_core.c is always built-in even when CONFIG_IPV6=n,
>> where struct net has no .ipv6 member, so the read site would
>> need an ifdef'd fallback to a constant anyway
>>
>> Therefore, just use a constant (IP6_MAX_EXT_HDRS_CNT). All four
>> extension header walking functions are now bound by this limit.
>>
>> Note that the check in ip6_protocol_deliver_rcu() happens right
>> before the goto resubmit, such that we don't have to have a test
>> for ipv6_ext_hdr() in the fast-path.
>>
>> There's an ongoing IETF draft-iurman-6man-eh-occurrences to enforce
>> IPv6 extension headers ordering and occurrence. The latter also
>> discusses security implications. As per RFC8200 section 4.1, the
>> occurrence rules for extension headers provide a practical upper
>> bound which is 8. In order to be conservative, let's define
>> IP6_MAX_EXT_HDRS_CNT as 4x that to leave enough room for quirky
>> setups. In the unlikely event that this is still not enough, then
>> we might need to reconsider a sysctl.
>>
>> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
>
> Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
>
> FWIW, I prefer v4 over v3. I didn't like the idea of a new sysctl for several reasons I already mentioned. So, thanks for this new version, Daniel.
>
> However, I can't help but think 8 would pose absolutely no problem. I would be very surprised to see someone complain. We're choosing 32 over 8 to be extra safe, at the price of security. RFC8200 provides the following ordered list which is recommended for senders (without normative language, though, which was a mistake):
>
> Hop-by-Hop Options header
> Destination Options header
> Routing header
> Fragment header
> Authentication header
> Encapsulating Security Payload header
> Destination Options header
>
> So this is the maximum you can have theoretically***, although you wouldn't for instance use the Authentication header with ESP. I'm not even talking about ordering or specific number of occurrences here, just the total number of Extension Headers in a packet (as your patch does). It's also worth mentioning that it's highly unlikely to see someone use them all at the same time (in production, of course). This is why I still think that 8 is safe too, and would provide security as expected.
What do you think if we fix this at 12 then to also have the exotic cases
below covered just in case to be conservative? Would still be an improvement
over 32 fwiw. I'm also fine if you think straight to 8 is the better choice.
Either option I can spin a v5, np.
Thanks,
Daniel
> ***well, you also have 3 others [1] (Mobility Header, Host Identity Protocol, Shim6 Protocol), but they're not widely used (not to say dead). And they would probably not be used with other Extension Headers anyway, as they are not specified to be present with a layer-4 in most cases.
>
> [1] https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#extension-header
^ permalink raw reply
* Re: [PATCH net v2 1/2] batman-adv: reject new tp_meter sessions during teardown
From: Simon Horman @ 2026-04-28 18:30 UTC (permalink / raw)
To: Ren Wei
Cc: b.a.t.m.a.n, netdev, marek.lindner, sw, antonio, sven, davem,
edumazet, kuba, pabeni, yuantan098, yifanwucs, tomapufckgml, bird,
tr0jan, wangjiexun2025
In-Reply-To: <20260427064338.1526762-1-n05ec@lzu.edu.cn>
On Mon, Apr 27, 2026 at 02:43:33PM +0800, Ren Wei wrote:
> From: Jiexun Wang <wangjiexun2025@gmail.com>
>
> Prevent tp_meter from starting new sender or receiver sessions after
> mesh_state has left BATADV_MESH_ACTIVE.
>
> Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
> Cc: stable@kernel.org
> Reported-by: Yuan Tan <yuantan098@gmail.com>
> Reported-by: Yifan Wu <yifanwucs@gmail.com>
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Reported-by: Xin Liu <bird@lzu.edu.cn>
> Co-developed-by: Luxing Yin <tr0jan@lzu.edu.cn>
> Signed-off-by: Luxing Yin <tr0jan@lzu.edu.cn>
> Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
> ---
> Changes in v2:
> - Split the original fix into setup-side and teardown-side patches
Hi Ren,
An AI generated review of this patch-set is available on sashiko.dev.
Could you take a look over that. I expect that some follow-up patches
are warranted.
^ permalink raw reply
* Re: [PATCH net v1 2/2] selftest: net: Add test for TCP flow failover with ECMP routes.
From: Kuniyuki Iwashima @ 2026-04-28 18:46 UTC (permalink / raw)
To: Ido Schimmel
Cc: Sagarika Sharma, David S . Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Shuah Khan, Simon Horman, netdev,
linux-kselftest
In-Reply-To: <20260428111855.GB571865@shredder>
On Tue, Apr 28, 2026 at 4:19 AM Ido Schimmel <idosch@nvidia.com> wrote:
>
> On Mon, Apr 27, 2026 at 10:42:23PM +0000, Sagarika Sharma wrote:
> > From: Kuniyuki Iwashima <kuniyu@google.com>
> >
> > Without the previous commit, TCP failed to switch to alternative
> > IPv6 routes immediately upon carrier loss.
> >
> > It would persist with the dead route until reaching the threshold
> > net.ipv4.tcp_retries1, leading to unnecessary delays in failover.
> >
> > Let's add a selftest for this scenario to ensure TCP fails over
> > immediately upon a carrier loss event.
> >
> > Before:
> > TEST: TCP IPv4 failover [ OK ]
> > TEST: TCP IPv6 failover [FAIL]
> >
> > After:
> > TEST: TCP IPv4 failover [ OK ]
> > TEST: TCP IPv6 failover [ OK ]
> >
> > Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
> > Signed-off-by: Sagarika Sharma <sharmasagarika@google.com>
>
> Thanks for the test. LGTM. A couple of nits below.
>
> [...]
>
> > diff --git a/tools/testing/selftests/net/tcp_ecmp_failover.sh b/tools/testing/selftests/net/tcp_ecmp_failover.sh
> > new file mode 100755
> > index 000000000000..f857d5db84d8
> > --- /dev/null
> > +++ b/tools/testing/selftests/net/tcp_ecmp_failover.sh
>
> [...]
>
> > +
> > +test_ipv4
> > +test_ipv6
>
> Maybe squash something like [1]? I ran the test without the first patch
> and I get:
>
> # ./tcp_ecmp_failover.sh
> TEST: TCP IPv4 failover [ OK ]
> TEST: TCP IPv6 failover [FAIL]
> # echo $?
> 0
Thanks Ido, I completely missed the exit code.
I'll fold the diff and fix some shellcheck warnings.
>
> [1]
> diff --git a/tools/testing/selftests/net/tcp_ecmp_failover.sh b/tools/testing/selftests/net/tcp_ecmp_failover.sh
> index f857d5db84d8..8b7a2d82c442 100755
> --- a/tools/testing/selftests/net/tcp_ecmp_failover.sh
> +++ b/tools/testing/selftests/net/tcp_ecmp_failover.sh
> @@ -205,5 +205,10 @@ test_ipv6()
> cleanup
> }
>
> +require_command socat
> +require_command tcpdump
> +
> test_ipv4
> test_ipv6
> +
> +exit "$EXIT_STATUS"
^ permalink raw reply
* Re: [PATCH net v4] ipv6: Implement limits on extension header parsing
From: Justin Iurman @ 2026-04-28 18:54 UTC (permalink / raw)
To: Daniel Borkmann, kuba
Cc: edumazet, dsahern, tom, willemdebruijn.kernel, idosch, pabeni,
netdev
In-Reply-To: <34f6054f-5d5d-47c8-b06d-f7b40d74c3f0@iogearbox.net>
On 4/28/26 20:16, Daniel Borkmann wrote:
> On 4/28/26 7:58 PM, Justin Iurman wrote:
>> On 4/28/26 17:37, Daniel Borkmann wrote:
>>> ipv6_{skip_exthdr,find_hdr}() and ip6_{tnl_parse_tlv_enc_lim,
>>> protocol_deliver_rcu}() iterate over IPv6 extension headers until they
>>> find a non-extension-header protocol or run out of packet data. The
>>> loops have no iteration counter, relying solely on the packet length
>>> to bound them. For a crafted packet with 8-byte extension headers
>>> filling a 64KB jumbogram, this means a worst case of up to ~8k
>>> iterations with a skb_header_pointer call each. ipv6_skip_exthdr(),
>>> for example, is used where it parses the inner quoted packet inside
>>> an incoming ICMPv6 error:
>>>
>>> - icmpv6_rcv
>>> - checksum validation
>>> - case ICMPV6_DEST_UNREACH
>>> - icmpv6_notify
>>> - pskb_may_pull() <- pull inner IPv6 header
>>> - ipv6_skip_exthdr() <- iterates here
>>> - pskb_may_pull()
>>> - ipprot->err_handler() <- sk lookup
>>>
>>> The per-iteration cost of ipv6_skip_exthdr itself is generally
>>> light, but skb_header_pointer becomes more costly on reassembled
>>> packets: the first ~1232 bytes of the inner packet are in the skb's
>>> linear area, but the remaining ~63KB are in the frag_list where
>>> skb_copy_bits is needed to read data.
>>>
>>> Initially, the idea was to add a configurable limit via a new
>>> sysctl knob with default 8, in line with knobs from commit
>>> 47d3d7ac656a ("ipv6: Implement limits on Hop-by-Hop and Destination
>>> options"), but two reasons eventually argued against it:
>>>
>>> - It adds to UAPI that needs to be maintained forever, and
>>> upcoming work is restricting extension header ordering anyway,
>>> leaving little reason for another sysctl knob
>>> - exthdrs_core.c is always built-in even when CONFIG_IPV6=n,
>>> where struct net has no .ipv6 member, so the read site would
>>> need an ifdef'd fallback to a constant anyway
>>>
>>> Therefore, just use a constant (IP6_MAX_EXT_HDRS_CNT). All four
>>> extension header walking functions are now bound by this limit.
>>>
>>> Note that the check in ip6_protocol_deliver_rcu() happens right
>>> before the goto resubmit, such that we don't have to have a test
>>> for ipv6_ext_hdr() in the fast-path.
>>>
>>> There's an ongoing IETF draft-iurman-6man-eh-occurrences to enforce
>>> IPv6 extension headers ordering and occurrence. The latter also
>>> discusses security implications. As per RFC8200 section 4.1, the
>>> occurrence rules for extension headers provide a practical upper
>>> bound which is 8. In order to be conservative, let's define
>>> IP6_MAX_EXT_HDRS_CNT as 4x that to leave enough room for quirky
>>> setups. In the unlikely event that this is still not enough, then
>>> we might need to reconsider a sysctl.
>>>
>>> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
>>
>> Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
>>
>> FWIW, I prefer v4 over v3. I didn't like the idea of a new sysctl for
>> several reasons I already mentioned. So, thanks for this new version,
>> Daniel.
>>
>> However, I can't help but think 8 would pose absolutely no problem. I
>> would be very surprised to see someone complain. We're choosing 32
>> over 8 to be extra safe, at the price of security. RFC8200 provides
>> the following ordered list which is recommended for senders (without
>> normative language, though, which was a mistake):
>>
>> Hop-by-Hop Options header
>> Destination Options header
>> Routing header
>> Fragment header
>> Authentication header
>> Encapsulating Security Payload header
>> Destination Options header
>>
>> So this is the maximum you can have theoretically***, although you
>> wouldn't for instance use the Authentication header with ESP. I'm not
>> even talking about ordering or specific number of occurrences here,
>> just the total number of Extension Headers in a packet (as your patch
>> does). It's also worth mentioning that it's highly unlikely to see
>> someone use them all at the same time (in production, of course). This
>> is why I still think that 8 is safe too, and would provide security as
>> expected.
>
> What do you think if we fix this at 12 then to also have the exotic cases
> below covered just in case to be conservative? Would still be an
> improvement
> over 32 fwiw. I'm also fine if you think straight to 8 is the better
> choice.
> Either option I can spin a v5, np.
I'm fine either way. IMO, 12 seems like a good compromise to keep
everyone happy.
^ permalink raw reply
* [PATCH net-next v3 0/4] net: dsa: mt7628 embedded switch initial support
From: Joris Vaisvila @ 2026-04-28 18:55 UTC (permalink / raw)
To: netdev
Cc: horms, pabeni, kuba, edumazet, davem, olteanv, Andrew Lunn,
devicetree, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joris Vaisvila
Hello,
This patch series adds initial support for the MediaTek MT7628 Embedded
Switch.
The driver implements the basic functionality required to operate the
switch using DSA. The hardware provides five internal Fast Ethernet user
ports and one Gigabit port connected internally to the CPU MAC.
Bridge offloading is not yet supported.
Tested on an MT7628NN-based board.
changes since v2:
- fix binding issues found in review
- fix ignored dsa_tag_8021q_register return value
- add switch teardown to clean up tag_8021q
- fix ordering issue where mdio probe fail would leak tag_8021q
Link: https://lore.kernel.org/netdev/20260330184017.766200-1-joey@tinyisr.com/t/#u
changes since v1:
- changed port 6 phy-mode to internal
- cleaned up tag_mt7628 rcv function and mask defines
- fixed sorting error in drivers/net/dsa/ Kconfig and Makefile
- fixed sorting error in net/dsa/ Kconfig and Makefile
- fixed mt7628_mii_read/write return values on error
Link: https://lore.kernel.org/netdev/20260326204413.3317584-1-joey@tinyisr.com/t/#u
Thanks,
Joris
Joris Vaisvila (4):
dt-bindings: net: dsa: add MT7628 ESW
net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet
PHYs
net: dsa: initial MT7628 tagging driver
net: dsa: initial support for MT7628 embedded switch
.../bindings/net/dsa/mediatek,mt7628-esw.yaml | 101 +++
drivers/net/dsa/Kconfig | 8 +
drivers/net/dsa/Makefile | 1 +
drivers/net/dsa/mt7628.c | 639 ++++++++++++++++++
drivers/net/phy/mediatek/Kconfig | 10 +-
drivers/net/phy/mediatek/Makefile | 1 +
drivers/net/phy/mediatek/mtk-fe-soc.c | 50 ++
include/net/dsa.h | 2 +
net/dsa/Kconfig | 6 +
net/dsa/Makefile | 1 +
net/dsa/tag_mt7628.c | 89 +++
11 files changed, 907 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/net/dsa/mediatek,mt7628-esw.yaml
create mode 100644 drivers/net/dsa/mt7628.c
create mode 100644 drivers/net/phy/mediatek/mtk-fe-soc.c
create mode 100644 net/dsa/tag_mt7628.c
--
2.54.0
^ permalink raw reply
* [PATCH net-next v3 1/4] dt-bindings: net: dsa: add MT7628 ESW
From: Joris Vaisvila @ 2026-04-28 18:55 UTC (permalink / raw)
To: netdev
Cc: horms, pabeni, kuba, edumazet, davem, olteanv, Andrew Lunn,
devicetree, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joris Vaisvila
In-Reply-To: <20260428185510.261521-1-joey@tinyisr.com>
Add bindings for MT7628 SoC's Embedded Switch.
Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
---
.../bindings/net/dsa/mediatek,mt7628-esw.yaml | 101 ++++++++++++++++++
1 file changed, 101 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/dsa/mediatek,mt7628-esw.yaml
diff --git a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7628-esw.yaml b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7628-esw.yaml
new file mode 100644
index 000000000000..a9db9057ee54
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7628-esw.yaml
@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/mediatek,mt7628-esw.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT7628 Embedded Ethernet Switch
+
+maintainers:
+ - Joris Vaisvila <joey@tinyisr.com>
+
+description:
+ The MT7628 SoC's built-in Ethernet Switch is a five port switch with
+ integrated 10/100 PHYs. The switch registers are directly mapped in the SoC's
+ memory. The switch has an internally connected 1G CPU port and 5 user ports
+ connected to the built-in Fast Ethernet PHYs.
+
+unevaluatedProperties: false
+
+allOf:
+ - $ref: dsa.yaml#/$defs/ethernet-ports
+
+properties:
+ compatible:
+ const: mediatek,mt7628-esw
+
+ reg:
+ maxItems: 1
+
+ resets:
+ items:
+ - description: internal switch block reset
+ - description: internal phy package reset
+
+ reset-names:
+ items:
+ - const: esw
+ - const: ephy
+
+ mdio:
+ $ref: /schemas/net/mdio.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - resets
+ - reset-names
+ - ethernet-ports
+
+examples:
+ - |
+ switch0: switch@10110000 {
+ compatible = "mediatek,mt7628-esw";
+
+ reg = <0x10110000 0x8000>;
+
+ resets = <&sysc 23>, <&sysc 24>;
+ reset-names = "esw", "ephy";
+
+ ethernet-ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet-port@0 {
+ reg = <0>;
+ phy-mode = "internal";
+ };
+
+ ethernet-port@1 {
+ reg = <1>;
+ phy-mode = "internal";
+ };
+
+ ethernet-port@2 {
+ reg = <2>;
+ phy-mode = "internal";
+ };
+
+ ethernet-port@3 {
+ reg = <3>;
+ phy-mode = "internal";
+ };
+
+ ethernet-port@4 {
+ reg = <4>;
+ phy-mode = "internal";
+ };
+
+ ethernet-port@6 {
+ reg = <6>;
+ phy-mode = "internal";
+ ethernet = <ðernet>;
+
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
+ };
+ };
+ };
--
2.54.0
^ permalink raw reply related
* [PATCH net-next v3 2/4] net: phy: mediatek: add phy driver for MT7628 built-in Fast Ethernet PHYs
From: Joris Vaisvila @ 2026-04-28 18:55 UTC (permalink / raw)
To: netdev
Cc: horms, pabeni, kuba, edumazet, davem, olteanv, Andrew Lunn,
devicetree, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joris Vaisvila
In-Reply-To: <20260428185510.261521-1-joey@tinyisr.com>
The Fast Ethernet PHYs present in the MT7628 SoCs require an
undocumented bit to be set before they can establish 100mbps links.
This commit adds the Kconfig option MEDIATEK_FE_SOC_PHY and the
corresponding driver mtk-fe-soc.c.
Signed-off-by: Joris Vaisvila <joey@tinyisr.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/mediatek/Kconfig | 10 +++++-
drivers/net/phy/mediatek/Makefile | 1 +
drivers/net/phy/mediatek/mtk-fe-soc.c | 50 +++++++++++++++++++++++++++
3 files changed, 60 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/phy/mediatek/mtk-fe-soc.c
diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig
index bb7dc876271e..b6a51f38c358 100644
--- a/drivers/net/phy/mediatek/Kconfig
+++ b/drivers/net/phy/mediatek/Kconfig
@@ -21,8 +21,16 @@ config MEDIATEK_GE_PHY
common operations with MediaTek SoC built-in Gigabit
Ethernet PHYs.
+config MEDIATEK_FE_SOC_PHY
+ tristate "MediaTek SoC Fast Ethernet PHYs"
+ help
+ Support for MediaTek MT7628 built-in Fast Ethernet PHYs.
+ This driver only sets an initialization bit required for the PHY
+ to establish 100 Mbps links. All other PHY operations are handled
+ by the kernel's generic PHY code.
+
config MEDIATEK_GE_SOC_PHY
- tristate "MediaTek SoC Ethernet PHYs"
+ tristate "MediaTek SoC Gigabit Ethernet PHYs"
depends on ARM64 || COMPILE_TEST
depends on ARCH_AIROHA || (ARCH_MEDIATEK && NVMEM_MTK_EFUSE) || \
COMPILE_TEST
diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile
index ac57ecc799fc..6f9cacf7f906 100644
--- a/drivers/net/phy/mediatek/Makefile
+++ b/drivers/net/phy/mediatek/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_MEDIATEK_2P5GE_PHY) += mtk-2p5ge.o
+obj-$(CONFIG_MEDIATEK_FE_SOC_PHY) += mtk-fe-soc.o
obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o
obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o
obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o
diff --git a/drivers/net/phy/mediatek/mtk-fe-soc.c b/drivers/net/phy/mediatek/mtk-fe-soc.c
new file mode 100644
index 000000000000..317944411fbe
--- /dev/null
+++ b/drivers/net/phy/mediatek/mtk-fe-soc.c
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for MT7628 Embedded Switch internal Fast Ethernet PHYs
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define MTK_FPHY_ID_MT7628 0x03a29410
+#define MTK_EXT_PAGE_ACCESS 0x1f
+
+static int mt7628_phy_read_page(struct phy_device *phydev)
+{
+ return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
+}
+
+static int mt7628_phy_write_page(struct phy_device *phydev, int page)
+{
+ return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page);
+}
+
+static int mt7628_phy_config_init(struct phy_device *phydev)
+{
+ /*
+ * This undocumented bit is required for the PHYs to be able to
+ * establish 100mbps links.
+ */
+ return phy_write_paged(phydev, 0x8000, 30, BIT(13));
+}
+
+static struct phy_driver mtk_soc_fe_phy_driver[] = {
+ {
+ PHY_ID_MATCH_EXACT(MTK_FPHY_ID_MT7628),
+ .name = "MediaTek MT7628 PHY",
+ .config_init = mt7628_phy_config_init,
+ .read_page = mt7628_phy_read_page,
+ .write_page = mt7628_phy_write_page,
+ },
+};
+
+module_phy_driver(mtk_soc_fe_phy_driver);
+static const struct mdio_device_id __maybe_unused mtk_soc_fe_phy_tbl[] = {
+ { PHY_ID_MATCH_EXACT(MTK_FPHY_ID_MT7628) },
+ { }
+};
+
+MODULE_DESCRIPTION("MediaTek SoC Fast Ethernet PHY driver");
+MODULE_AUTHOR("Joris Vaisvila <joey@tinyisr.com>");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(mdio, mtk_soc_fe_phy_tbl);
--
2.54.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