* [PATCH v4 6/7] ARM: dts: microchip: sama5d27_wlsom1: read MAC address from QSPI SFDP
From: Manikandan Muralidharan @ 2026-06-30 9:24 UTC (permalink / raw)
To: pratyush, mwalle, takahiro.kuwano, miquel.raynal, richard,
vigneshr, robh, krzk+dt, conor+dt, srini, nicolas.ferre,
alexandre.belloni, claudiu.beznea, linux, richardcochran, linusw,
arnd, michael, linux-mtd, devicetree, linux-kernel,
linux-arm-kernel, netdev
Cc: Manikandan Muralidharan
In-Reply-To: <20260630092406.150587-1-manikandan.m@microchip.com>
Describe the QSPI flash SFDP as an NVMEM provider with the
microchip,sst26vf-sfdp-eui layout, which exposes the factory-programmed
EUI-48 as a "mac-address" cell, and point macb0 at it through
nvmem-cells. This yields a stable MAC address on boards where U-Boot does
not program one, instead of falling back to a random address.
Signed-off-by: Manikandan Muralidharan <manikandan.m@microchip.com>
---
arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi | 11 +++++++++++
.../boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts | 2 ++
2 files changed, 13 insertions(+)
diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi
index 062aa02a98ed..6016d7f2a39c 100644
--- a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi
+++ b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi
@@ -240,6 +240,17 @@ qspi1_flash: flash@0 {
m25p,fast-read;
status = "disabled";
+ sfdp {
+ compatible = "jedec,sfdp";
+
+ nvmem-layout {
+ compatible = "microchip,sst26vf-sfdp-eui";
+
+ mac_address_eui48: mac-address {
+ };
+ };
+ };
+
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts
index 35a933eec573..5e87bf04bc47 100644
--- a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts
+++ b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts
@@ -97,6 +97,8 @@ uart6: serial@200 {
&macb0 {
status = "okay";
+ nvmem-cells = <&mac_address_eui48>;
+ nvmem-cell-names = "mac-address";
};
&pioA {
--
2.43.0
^ permalink raw reply related
* [PATCH v4 7/7] ARM: configs: sama5: enable Microchip/SST SFDP EUI NVMEM layout
From: Manikandan Muralidharan @ 2026-06-30 9:24 UTC (permalink / raw)
To: pratyush, mwalle, takahiro.kuwano, miquel.raynal, richard,
vigneshr, robh, krzk+dt, conor+dt, srini, nicolas.ferre,
alexandre.belloni, claudiu.beznea, linux, richardcochran, linusw,
arnd, michael, linux-mtd, devicetree, linux-kernel,
linux-arm-kernel, netdev
Cc: Manikandan Muralidharan
In-Reply-To: <20260630092406.150587-1-manikandan.m@microchip.com>
Enable CONFIG_NVMEM_LAYOUT_SST26VF_SFDP_EUI so the factory EUI-48 stored
in the SST26VF QSPI flash SFDP can be used as a MAC address on boards
such as the sama5d27_wlsom1.
Signed-off-by: Manikandan Muralidharan <manikandan.m@microchip.com>
---
arch/arm/configs/sama5_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index bd7f0b5f7d66..14dda4b0cfd0 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -220,6 +220,7 @@ CONFIG_PWM=y
CONFIG_PWM_ATMEL=y
CONFIG_PWM_ATMEL_HLCDC_PWM=y
CONFIG_PWM_ATMEL_TCB=y
+CONFIG_NVMEM_LAYOUT_SST26VF_SFDP_EUI=y
CONFIG_EXT4_FS=y
CONFIG_FANOTIFY=y
CONFIG_AUTOFS_FS=m
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v29 4/5] sfc: obtain and map cxl range using devm_cxl_probe_mem
From: Richard Cheng @ 2026-06-30 9:31 UTC (permalink / raw)
To: Alejandro Lucero Palau
Cc: alejandro.lucero-palau, linux-cxl, netdev, dan.j.williams,
edward.cree, davem, kuba, pabeni, edumazet, dave.jiang,
Edward Cree
In-Reply-To: <bde77dd7-fa7b-4d28-9a7b-3f0ce6587bf4@amd.com>
On Mon, Jun 29, 2026 at 02:20:03PM +0800, Alejandro Lucero Palau wrote:
>
> On 6/26/26 04:52, Richard Cheng wrote:
> > On Mon, Jun 22, 2026 at 01:40:09PM +0800, alejandro.lucero-palau@amd.com wrote:
> > > From: Alejandro Lucero <alucerop@amd.com>
> > >
> > > Use core API for safely obtain the CXL range linked to an HDM committed
> > > by the BIOS. Map such a range for being used as the ctpio buffer.
> > >
> > > A potential user space action through sysfs unbinding or core cxl
> > > modules remove will trigger sfc driver device detachment, with that case
> > > not racing with this mapping as this is done during driver probe and
> > > therefore protected with device lock against those user space actions.
> > >
> > > Signed-off-by: Alejandro Lucero <alucerop@amd.com>
> > > Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> > > Acked-by: Edward Cree <ecree.xilinx@gmail.com>
> > > ---
> > > drivers/net/ethernet/sfc/efx.c | 2 ++
> > > drivers/net/ethernet/sfc/efx_cxl.c | 23 +++++++++++++++++++++++
> > > drivers/net/ethernet/sfc/efx_cxl.h | 3 +++
> > > 3 files changed, 28 insertions(+)
> > >
> > > diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
> > > index 61cbb6cfc360..3806cd3dd7f4 100644
> > > --- a/drivers/net/ethernet/sfc/efx.c
> > > +++ b/drivers/net/ethernet/sfc/efx.c
> > > @@ -984,6 +984,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
> > > efx_fini_io(efx);
> > > probe_data = container_of(efx, struct efx_probe_data, efx);
> > > + efx_cxl_exit(probe_data);
> > > pci_dbg(efx->pci_dev, "shutdown successful\n");
> > > @@ -1242,6 +1243,7 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
> > > return 0;
> > > fail3:
> > > + efx_cxl_exit(probe_data);
> > > efx_fini_io(efx);
> > > fail2:
> > > efx_fini_struct(efx);
> > > diff --git a/drivers/net/ethernet/sfc/efx_cxl.c b/drivers/net/ethernet/sfc/efx_cxl.c
> > > index 18b535b3ea40..3e7c950f83e9 100644
> > > --- a/drivers/net/ethernet/sfc/efx_cxl.c
> > > +++ b/drivers/net/ethernet/sfc/efx_cxl.c
> > > @@ -18,6 +18,7 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
> > > {
> > > struct efx_nic *efx = &probe_data->efx;
> > > struct pci_dev *pci_dev = efx->pci_dev;
> > > + struct range cxl_pio_range;
> > > struct efx_cxl *cxl;
> > > u16 dvsec;
> > > int rc;
> > > @@ -73,9 +74,31 @@ int efx_cxl_init(struct efx_probe_data *probe_data)
> > > return -ENODEV;
> > > }
> > > + cxl->cxlmd = devm_cxl_probe_mem(&cxl->cxlds, &cxl_pio_range);
> > > + if (IS_ERR(cxl->cxlmd)) {
> > > + pci_err(pci_dev, "CXL accel memdev creation failed\n");
> > > + return PTR_ERR(cxl->cxlmd);
> > > + }
> > > +
> > > + cxl->ctpio_cxl = ioremap_wc(cxl_pio_range.start,
> > > + range_len(&cxl_pio_range));
> > Hi Alejandro,
> >
> > A small question here,
> > Is it possible that the FW would commit a region bigger than the range ?
>
>
> Hi Richard,
>
>
> Not really. We are using the minimum size for CXL mem, 256MB, and it is not
> configurable. If CXL is enabled by the sfc device firmware, this is the only
> possibility.
>
> It could be a good sanity check though, but I prefer to keep v29 as it is
> now ... Dan Williams is happy enough with it, so I expect Dave to merge it
> soon ...
>
>
> Maybe as a follow up path.
>
>
> Thank you,
>
> Alejandro
>
>
Hi Alejandro,
I see, thanks for the head up .
Np for me then, thanks.
--Richard
> > The committed CXL region length is never validated against the PIO window size.
> > The legacy patch sizes wc_mem_map_size to cover the VI-strided PIO offset, but
> > here we ioremap whatever the BIOS comitted and assume it's EFX_CTPIO_BUFFER_SIZE.
> >
> > Maybe adding
> > """
> > if (range_len(&cxl_pio_range) < EFX_CTPIO_BUFFER_SIZE)
> > return -EINVAL;
> > """
> > Would be worthy ?
> >
> > Let me know what you think.
> >
> > Best regards,
> > Richard Cheng
> >
> > > + if (!cxl->ctpio_cxl) {
> > > + pci_err(pci_dev, "CXL ioremap region (%pra) failed\n",
> > > + &cxl_pio_range);
> > > + return -ENOMEM;
> > > + }
> > > +
> > > probe_data->cxl = cxl;
> > > return 0;
> > > }
> > > +void efx_cxl_exit(struct efx_probe_data *probe_data)
> > > +{
> > > + if (!probe_data->cxl)
> > > + return;
> > > +
> > > + iounmap(probe_data->cxl->ctpio_cxl);
> > > +}
> > > +
> > > MODULE_IMPORT_NS("CXL");
> > > diff --git a/drivers/net/ethernet/sfc/efx_cxl.h b/drivers/net/ethernet/sfc/efx_cxl.h
> > > index 04e46278464d..3e2705cb063f 100644
> > > --- a/drivers/net/ethernet/sfc/efx_cxl.h
> > > +++ b/drivers/net/ethernet/sfc/efx_cxl.h
> > > @@ -20,10 +20,13 @@ struct efx_probe_data;
> > > struct efx_cxl {
> > > struct cxl_dev_state cxlds;
> > > struct cxl_memdev *cxlmd;
> > > + void __iomem *ctpio_cxl;
> > > };
> > > int efx_cxl_init(struct efx_probe_data *probe_data);
> > > +void efx_cxl_exit(struct efx_probe_data *probe_data);
> > > #else
> > > static inline int efx_cxl_init(struct efx_probe_data *probe_data) { return 0; }
> > > +static inline void efx_cxl_exit(struct efx_probe_data *probe_data) {}
> > > #endif
> > > #endif
> > > --
> > > 2.34.1
> > >
> > >
^ permalink raw reply
* RE: [Intel-wired-lan] [PATCH net-next v1] ice: use dev_err_probe in all appropriate places in ice_probe()
From: Loktionov, Aleksandr @ 2026-06-30 9:40 UTC (permalink / raw)
To: Rongguang Wei, netdev@vger.kernel.org,
intel-wired-lan@lists.osuosl.org
Cc: Nguyen, Anthony L, Kitszel, Przemyslaw, andrew+netdev@lunn.ch,
Rongguang Wei
In-Reply-To: <20260630032537.42605-1-clementwei90@163.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf
> Of Rongguang Wei
> Sent: Tuesday, June 30, 2026 5:26 AM
> To: netdev@vger.kernel.org; intel-wired-lan@lists.osuosl.org
> Cc: Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Kitszel,
> Przemyslaw <przemyslaw.kitszel@intel.com>; andrew+netdev@lunn.ch;
> Rongguang Wei <weirongguang@kylinos.cn>
> Subject: [Intel-wired-lan] [PATCH net-next v1] ice: use dev_err_probe
> in all appropriate places in ice_probe()
>
> From: Rongguang Wei <weirongguang@kylinos.cn>
>
> Use dev_err_probe() can conveniently combines printing an error
> message with returning the errno and also simplify the code.
>
I'd recommend to fix the commit message, like:
ice: use dev_err_probe() in ice_probe()
dev_err_probe() logs the error and returns the supplied error code, which
allows probe error paths to be written more compactly.
Use dev_err_probe() in ice_probe() for error paths that currently print an
error message and immediately return the same error code. This keeps the
existing error handling semantics while reducing open-coded logging and
return sequences.
With the best regards
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Signed-off-by: Rongguang Wei <weirongguang@kylinos.cn>
> ---
> drivers/net/ethernet/intel/ice/ice_main.c | 24 ++++++++--------------
> -
> 1 file changed, 8 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c
> b/drivers/net/ethernet/intel/ice/ice_main.c
> index e2fbe111f849..81959eaec708 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -5167,10 +5167,8 @@ ice_probe(struct pci_dev *pdev, const struct
> pci_device_id __always_unused *ent)
> struct ice_hw *hw;
> int err;
>
> - if (pdev->is_virtfn) {
> - dev_err(dev, "can't probe a virtual function\n");
> - return -EINVAL;
> - }
> + if (pdev->is_virtfn)
> + return dev_err_probe(dev, -EINVAL, "can't probe a
> virtual
> +function\n");
>
> /* when under a kdump kernel initiate a reset before enabling
> the
> * device in order to clear out any pending DMA transactions.
> These @@ -5194,10 +5192,8 @@ ice_probe(struct pci_dev *pdev, const
> struct pci_device_id __always_unused *ent)
> return err;
>
> err = pcim_iomap_regions(pdev, BIT(ICE_BAR0),
> dev_driver_string(dev));
> - if (err) {
> - dev_err(dev, "BAR0 I/O map error %d\n", err);
> - return err;
> - }
> + if (err)
> + return dev_err_probe(dev, err, "BAR0 I/O map error
> %d\n", err);
>
> pf = ice_allocate_pf(dev);
> if (!pf)
> @@ -5208,10 +5204,8 @@ ice_probe(struct pci_dev *pdev, const struct
> pci_device_id __always_unused *ent)
>
> /* set up for high or low DMA */
> err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
> - if (err) {
> - dev_err(dev, "DMA configuration failed: 0x%x\n", err);
> - return err;
> - }
> + if (err)
> + return dev_err_probe(dev, err, "DMA configuration
> failed: 0x%x\n",
> +err);
>
> pci_set_master(pdev);
> pf->pdev = pdev;
> @@ -5246,10 +5240,8 @@ ice_probe(struct pci_dev *pdev, const struct
> pci_device_id __always_unused *ent)
> return ice_probe_recovery_mode(pf);
>
> err = ice_init_hw(hw);
> - if (err) {
> - dev_err(dev, "ice_init_hw failed: %d\n", err);
> - return err;
> - }
> + if (err)
> + return dev_err_probe(dev, err, "ice_init_hw failed:
> %d\n", err);
>
> ice_init_dev_hw(pf);
>
> --
> 2.25.1
^ permalink raw reply
* Re: [PATCH net-next v4] vsock/virtio: rewrite MSG_ZEROCOPY flag handling
From: Stefano Garzarella @ 2026-06-30 9:41 UTC (permalink / raw)
To: Arseniy Krasnov
Cc: Stefan Hajnoczi, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Michael S. Tsirkin, Jason Wang, Bobby Eshleman,
Xuan Zhuo, Eugenio Pérez, Simon Horman, kvm, virtualization,
netdev, linux-kernel, oxffffaa, rulkc
In-Reply-To: <20260628182052.951760-1-avkrasnov@rulkc.org>
On Sun, Jun 28, 2026 at 09:20:52PM +0300, Arseniy Krasnov wrote:
>Logically it was based on TCP implementation, so to make further support
>easier, rewrite it in the TCP way (like in 'tcp_sendmsg_locked()'). By
>this way, patch also adds handling case when 'msg_ubuf' is already set.
Thanks for this!
IIUC the result will be similar of commit eb315a7d1396 ("tcp: support
externally provided ubufs") for tcp. Maybe I would have added it to the
commit description, anyway the patch LGTM:
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
>
>Signed-off-by: Arseniy Krasnov <avkrasnov@rulkc.org>
>---
> Changelog v1->v2:
> * Rebase on last 'net-next'. Don't need 'skb_zcopy_set()' now - it was
> already added.
> Changelog v2->v3:
> * Update commit message.
> * Remove one empty line.
> Changelog v3->v4:
> * Update commit message.
>
> net/vmw_vsock/virtio_transport_common.c | 47 ++++++++++++-------------
> 1 file changed, 22 insertions(+), 25 deletions(-)
>
>diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
>index 09475007165b..41c2a0b82a8e 100644
>--- a/net/vmw_vsock/virtio_transport_common.c
>+++ b/net/vmw_vsock/virtio_transport_common.c
>@@ -328,38 +328,35 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
> if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW)
> return pkt_len;
>
>- if (info->msg) {
>- /* If zerocopy is not enabled by 'setsockopt()', we behave as
>- * there is no MSG_ZEROCOPY flag set.
>+ if (info->msg && (info->msg->msg_flags & MSG_ZEROCOPY)) {
>+ /* If 'info->msg' is not NULL, this is only VIRTIO_VSOCK_OP_RW.
>+ * 'MSG_ZEROCOPY' flag handling here is based on the same flag
>+ * handling from 'tcp_sendmsg_locked()'.
> */
>- if (!sock_flag(sk_vsock(vsk), SOCK_ZEROCOPY))
>- info->msg->msg_flags &= ~MSG_ZEROCOPY;
>+ if (info->msg->msg_ubuf) {
>+ uarg = info->msg->msg_ubuf;
>+ can_zcopy = virtio_transport_can_zcopy(t_ops, info, pkt_len);
>+ } else if (sock_flag(sk_vsock(vsk), SOCK_ZEROCOPY)) {
>+ uarg = msg_zerocopy_realloc(sk_vsock(vsk), pkt_len,
>+ NULL, false);
>+ if (!uarg) {
>+ virtio_transport_put_credit(vvs, pkt_len);
>+ return -ENOMEM;
>+ }
>
>- if (info->msg->msg_flags & MSG_ZEROCOPY)
> can_zcopy = virtio_transport_can_zcopy(t_ops, info, pkt_len);
>+ if (!can_zcopy)
>+ uarg_to_msgzc(uarg)->zerocopy = 0;
>
>+ have_uref = true;
>+ }
>+
>+ /* 'can_zcopy' means that this transmission will be
>+ * in zerocopy way (e.g. using 'frags' array).
>+ */
> if (can_zcopy)
> max_skb_len = min_t(u32, VIRTIO_VSOCK_MAX_PKT_BUF_SIZE,
> (MAX_SKB_FRAGS * PAGE_SIZE));
>-
>- if (info->msg->msg_flags & MSG_ZEROCOPY &&
>- info->op == VIRTIO_VSOCK_OP_RW) {
>- uarg = info->msg->msg_ubuf;
>-
>- if (!uarg) {
>- uarg = msg_zerocopy_realloc(sk_vsock(vsk),
>- pkt_len, NULL, false);
>- if (!uarg) {
>- virtio_transport_put_credit(vvs, pkt_len);
>- return -ENOMEM;
>- }
>-
>- if (!can_zcopy)
>- uarg_to_msgzc(uarg)->zerocopy = 0;
>-
>- have_uref = true;
>- }
>- }
> }
>
> rest_len = pkt_len;
>--
>2.25.1
>
^ permalink raw reply
* [PATCH net-next v1] ipv4: hold a consistent view of rt->dst.dev under RCU
From: xuanqiang.luo @ 2026-06-30 9:42 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
David Ahern, Ido Schimmel
Cc: Simon Horman, Kuniyuki Iwashima, netdev, linux-kernel,
Xuanqiang Luo
From: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
rt_flush_dev() walks the per-CPU uncached route list and rewrites
rt->dst.dev in-place to blackhole_netdev under spin_lock_bh().
This lock does not exclude RCU readers, which may load rt->dst.dev
multiple times within a single rcu_read_lock() region.
ip_rt_send_redirect() is a typical example: it reads rt->dst.dev
three times to obtain in_dev, the L3 master ifindex, and net.
A concurrent device unregistration can repoint rt->dst.dev to
blackhole_netdev between those reads, making the reader combine
state from two different net_devices — for instance, an in_dev
from the real device but a netns and peer lookup from the blackhole
device, causing ICMP redirects to be issued against the wrong
namespace. ip_rt_get_source() has the same problem: it reads
rt->dst.dev four times to obtain the output ifindex, the netns,
and the source address, so a concurrent flush can cause the source
selection to mix state from different devices.
Take a single READ_ONCE() snapshot of rt->dst.dev at the start of
each affected RCU reader and use that snapshot throughout, so
concurrent flushes cannot cause mid-function inconsistency.
Publish the in-place write in rt_flush_dev() with WRITE_ONCE() to
pair with the readers.
Fixes: caacf05e5ad1a ("ipv4: Properly purge netdev references on uncached routes.")
Signed-off-by: Xuanqiang Luo <luoxuanqiang@kylinos.cn>
---
net/ipv4/route.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 3f3de5164d6e5..e14325c4929ab 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -873,6 +873,7 @@ static void ipv4_negative_advice(struct sock *sk,
void ip_rt_send_redirect(struct sk_buff *skb)
{
struct rtable *rt = skb_rtable(skb);
+ struct net_device *dev;
struct in_device *in_dev;
struct inet_peer *peer;
struct net *net;
@@ -880,15 +881,16 @@ void ip_rt_send_redirect(struct sk_buff *skb)
int vif;
rcu_read_lock();
- in_dev = __in_dev_get_rcu(rt->dst.dev);
+ dev = READ_ONCE(rt->dst.dev);
+ in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev)) {
rcu_read_unlock();
return;
}
log_martians = IN_DEV_LOG_MARTIANS(in_dev);
- vif = l3mdev_master_ifindex_rcu(rt->dst.dev);
+ vif = l3mdev_master_ifindex_rcu(dev);
- net = dev_net(rt->dst.dev);
+ net = dev_net(dev);
peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, vif);
if (!peer) {
rcu_read_unlock();
@@ -1287,29 +1289,32 @@ void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt)
{
__be32 src;
- if (rt_is_output_route(rt))
+ rcu_read_lock();
+ if (rt_is_output_route(rt)) {
src = ip_hdr(skb)->saddr;
- else {
+ } else {
struct fib_result res;
struct iphdr *iph = ip_hdr(skb);
+ struct net_device *dev = READ_ONCE(rt->dst.dev);
+ struct net *net = dev_net(dev);
struct flowi4 fl4 = {
.daddr = iph->daddr,
.saddr = iph->saddr,
.flowi4_dscp = ip4h_dscp(iph),
- .flowi4_oif = rt->dst.dev->ifindex,
+ .flowi4_oif = dev->ifindex,
.flowi4_iif = skb->dev->ifindex,
.flowi4_mark = skb->mark,
};
- rcu_read_lock();
- if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res, 0) == 0)
- src = fib_result_prefsrc(dev_net(rt->dst.dev), &res);
+ if (fib_lookup(net, &fl4, &res, 0) == 0)
+ src = fib_result_prefsrc(net, &res);
else
- src = inet_select_addr(rt->dst.dev,
+ src = inet_select_addr(dev,
rt_nexthop(rt, iph->daddr),
RT_SCOPE_UNIVERSE);
- rcu_read_unlock();
}
+ rcu_read_unlock();
+
memcpy(addr, &src, 4);
}
@@ -1565,7 +1570,7 @@ void rt_flush_dev(struct net_device *dev)
list_for_each_entry_safe(rt, safe, &ul->head, dst.rt_uncached) {
if (rt->dst.dev != dev)
continue;
- rt->dst.dev = blackhole_netdev;
+ WRITE_ONCE(rt->dst.dev, blackhole_netdev);
netdev_ref_replace(dev, blackhole_netdev,
&rt->dst.dev_tracker, GFP_ATOMIC);
list_del_init(&rt->dst.rt_uncached);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/7] samples: rust_dma: use vertical import style
From: Danilo Krummrich @ 2026-06-30 9:48 UTC (permalink / raw)
To: Guru Das Srinagesh
Cc: Miguel Ojeda, rust-for-linux, linux-kernel, Abdiel Janulgue,
Daniel Almeida, Robin Murphy, Andreas Hindborg, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
Trevor Gross, Tamir Duberstein, Alexandre Courbot,
Onur Özkan, Drew Fustini, Guo Ren, Fu Wei, Michal Wilczynski,
Uwe Kleine-König, Rafael J. Wysocki, Viresh Kumar,
Jens Axboe, FUJITA Tomonori, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, David Airlie, Simona Vetter, driver-core,
linux-riscv, linux-pwm, linux-pm, linux-block, netdev, nova-gpu,
dri-devel
In-Reply-To: <20260628-b4-rust-vertical-imports-v1-1-98bc71d4810b@gurudas.dev>
On Mon Jun 29, 2026 at 5:38 AM CEST, Guru Das Srinagesh wrote:
> page, pci,
Can you please also convert this one? Patch 7 also misses at least one case.
Thanks,
Danilo
^ permalink raw reply
* Re: [PATCH net 1/2] vsock/virtio: collapse receive queue under memory pressure
From: Paolo Abeni @ 2026-06-30 9:53 UTC (permalink / raw)
To: Stefano Garzarella, netdev
Cc: Jason Wang, Jakub Kicinski, Michael S. Tsirkin, kvm,
virtualization, Xuan Zhuo, Eric Dumazet, Simon Horman,
linux-kernel, Stefan Hajnoczi, David S. Miller,
Eugenio Pérez, stable, Brien Oberstein
In-Reply-To: <20260626134823.206676-2-sgarzare@redhat.com>
On 6/26/26 3:48 PM, Stefano Garzarella wrote:
> From: Stefano Garzarella <sgarzare@redhat.com>
>
> When many small packets accumulate in the receive queue, the skb overhead
> can exceed buf_alloc even while the payload is within bounds. This causes
> virtio_transport_inc_rx_pkt() to reject packets, leading to connection
> resets during large transfers under backpressure.
>
> The issue was reported by Brien, who has a reproducer, but it is also
> easily reproducible with iperf-vsock [1] using a small packet size:
>
> iperf3 --vsock -c $CID -l 129
>
> which fails immediately without this patch but with commit 059b7dbd20a6
> ("vsock/virtio: fix potential unbounded skb queue").
>
> Inspired by TCP's tcp_collapse() which solves a similar problem, add
> virtio_transport_collapse_rx_queue() that walks the receive queue and
> re-copies data into compact linear skbs to reduce the overhead.
>
> The collapse is triggered from virtio_transport_recv_enqueue() when
> virtio_transport_inc_rx_pkt() fails. A pre-scan counts the eligible bytes
> to size each allocation precisely, avoiding waste for isolated small
> packets. Partially consumed skbs are kept as-is to preserve
> buf_used/fwd_cnt accounting, EOM-marked skbs to maintain SEQPACKET
> message boundaries, and skbs already larger than the collapse target
> because they already have a good data-to-overhead ratio.
>
> [1] https://github.com/stefano-garzarella/iperf-vsock
>
> Fixes: 059b7dbd20a6 ("vsock/virtio: fix potential unbounded skb queue")
> Cc: stable@vger.kernel.org
> Reported-by: Brien Oberstein <brienpub@gmail.com>
> Closes: https://lore.kernel.org/netdev/618701dd023e$063de350$12b9a9f0$@gmail.com/
> Tested-by: Brien Oberstein <brienpub@gmail.com>
> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
> ---
> net/vmw_vsock/virtio_transport_common.c | 148 +++++++++++++++++++++++-
> 1 file changed, 146 insertions(+), 2 deletions(-)
>
> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> index 09475007165b..304ea424995d 100644
> --- a/net/vmw_vsock/virtio_transport_common.c
> +++ b/net/vmw_vsock/virtio_transport_common.c
> @@ -420,6 +420,137 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
> return ret;
> }
>
> +static bool virtio_transport_can_collapse(struct sk_buff *skb,
> + unsigned int size)
Why passing a `size` argument here? AFAICS the actual argument is always
a constant and IMHO rightfully so.
> +{
> + /* skbs that are partially consumed, mark a SEQPACKET message boundary,
> + * or are already large enough should not be collapsed: they either
> + * need special accounting, carry protocol state, or already have a
> + * good data-to-overhead ratio.
> + */
> + if (VIRTIO_VSOCK_SKB_CB(skb)->offset)
> + return false;
> + if (le32_to_cpu(virtio_vsock_hdr(skb)->flags) & VIRTIO_VSOCK_SEQ_EOM)
> + return false;
> + if (skb->len >= size)
> + return false;
> + return true;
> +}
> +
> +/* Iterate through the packets in the queue starting from the current skb to
> + * count the number of bytes we can collapse.
> + */
> +static unsigned int
> +virtio_transport_collapse_size(struct sk_buff *skb,
> + struct sk_buff_head *queue,
> + unsigned int max_size)
> +{
> + unsigned int target = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset;
> +
> + while ((skb = skb_peek_next(skb, queue)) &&
> + virtio_transport_can_collapse(skb, max_size)) {
> + unsigned int len = skb->len - VIRTIO_VSOCK_SKB_CB(skb)->offset;
> +
> + if (len > max_size - target)
> + return target;
> +
> + target += len;
> + }
> +
> + return target;
> +}
> +
> +/* Called under lock_sock when skb overhead exceeds the budget. */
> +static void virtio_transport_collapse_rx_queue(struct virtio_vsock_sock *vvs)
> +{
> + /* Use the same linear allocation threshold as virtio_vsock_alloc_skb()
> + * to avoid adding pressure on the page allocator.
> + */
> + unsigned int collapse_max = SKB_MAX_ORDER(VIRTIO_VSOCK_SKB_HEADROOM,
> + PAGE_ALLOC_COSTLY_ORDER);
> + struct sk_buff *skb, *next_skb, *new_skb = NULL;
> + struct sk_buff_head new_queue;
> +
> + __skb_queue_head_init(&new_queue);
> +
> + skb_queue_walk_safe(&vvs->rx_queue, skb, next_skb) {
If the queue is relevantly big, walking all of it may take a significant
amount of time/cache misses and causes traffic burstines. I think you
could add an additional stop condition, i.e. when the current queue size
is below a reasonable threshold (allowing the current packet to be
inserted plus some more slack).
/P
> + struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
> + u32 src_off = VIRTIO_VSOCK_SKB_CB(skb)->offset;
> + u32 src_len = skb->len - src_off;
> + bool keep = false;
> +
> + if (!virtio_transport_can_collapse(skb, collapse_max)) {
Minor nit, possibly something alike the following lead to more
compact/more readable code:
keep = !virtio_transport_can_collapse(skb, collapse_max);
if (keep) {
> + /* Finalize pending collapsed skb to preserve packet
> + * ordering.
> + */
> + if (new_skb) {
> + __skb_queue_tail(&new_queue, new_skb);
> + new_skb = NULL;
> + }
> + keep = true;
> + goto next;
> + }
> +
> + /* Finalize if this packet won't fit in the remaining tailroom,
> + * so we can allocate a right-sized new_skb.
> + */
> + if (new_skb && src_len > skb_tailroom(new_skb)) {
> + __skb_queue_tail(&new_queue, new_skb);
> + new_skb = NULL;
Possibly introduce an helper for the above 2 statements?
/P
^ permalink raw reply
* [PATCH bpf-next v2] selftests/bpf: Mask socket type flags in mptcpify prog
From: Guillaume Maudoux @ 2026-06-30 9:57 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau
Cc: Eduard Zingerman, Matthieu Baerts, Mat Martineau, Geliang Tang,
Shuah Khan, bpf, mptcp, netdev, linux-kselftest, linux-kernel,
Guillaume Maudoux
The mptcpify BPF prog upgrades eligible TCP sockets to MPTCP, but only
when the socket type is exactly SOCK_STREAM. Its update_socket_protocol()
hook runs on the raw type from userspace, before the socket core masks
it with SOCK_TYPE_MASK, so the type may still carry SOCK_CLOEXEC or
SOCK_NONBLOCK in its upper bits and the equality check fails.
As a result, a socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0) -- what
common libraries do by default -- is silently left as plain TCP. This
was hit in practice with curl. Since mptcpify.c is referenced as example
code for enabling MPTCP transparently, the same mistake is likely to be
copied into real deployments where it fails the same way and is hard to
diagnose.
Mask the type before comparing, mirroring the socket core. Extend the
test to also create the server with SOCK_CLOEXEC set; the same masking
is applied to start_server_addr() so a flagged type still listens.
Fixes: ddba122428a7 ("selftests/bpf: Add mptcpify test")
Signed-off-by: Guillaume Maudoux <layus.on@gmail.com>
---
Changes in v2:
- Use my real name in the Signed-off-by (the "@" broke git am).
- Add "bpf-next" to the subject prefix so the CI tests it.
- Simplify the test: drop the type[] array and loop, keep two
explicit run_mptcpify() calls (plain and SOCK_CLOEXEC).
- Tighten the commit message.
tools/testing/selftests/bpf/network_helpers.c | 4 ++--
tools/testing/selftests/bpf/network_helpers.h | 5 +++++
tools/testing/selftests/bpf/prog_tests/mptcp.c | 13 ++++++++++---
tools/testing/selftests/bpf/progs/bpf_tracing_net.h | 3 +++
tools/testing/selftests/bpf/progs/mptcpify.c | 2 +-
5 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c
index b82f572641b7..db935a9d9fc1 100644
--- a/tools/testing/selftests/bpf/network_helpers.c
+++ b/tools/testing/selftests/bpf/network_helpers.c
@@ -111,7 +111,7 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t a
if (settimeo(fd, opts->timeout_ms))
goto error_close;
- if (type == SOCK_STREAM &&
+ if ((type & SOCK_TYPE_MASK) == SOCK_STREAM &&
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
log_err("Failed to enable SO_REUSEADDR");
goto error_close;
@@ -128,7 +128,7 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t a
goto error_close;
}
- if (type == SOCK_STREAM) {
+ if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
if (listen(fd, opts->backlog ? MAX(opts->backlog, 0) : 1) < 0) {
log_err("Failed to listed on socket");
goto error_close;
diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h
index 79a010c88e11..75133119c04a 100644
--- a/tools/testing/selftests/bpf/network_helpers.h
+++ b/tools/testing/selftests/bpf/network_helpers.h
@@ -25,6 +25,11 @@ typedef __u16 __sum16;
#define VIP_NUM 5
#define MAGIC_BYTES 123
+/* include/linux/net.h */
+#ifndef SOCK_TYPE_MASK
+#define SOCK_TYPE_MASK 0xf
+#endif
+
struct network_helper_opts {
int timeout_ms;
int proto;
diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c
index 8fade8bdc451..32dfc1c511af 100644
--- a/tools/testing/selftests/bpf/prog_tests/mptcp.c
+++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c
@@ -264,7 +264,7 @@ static int verify_mptcpify(int server_fd, int client_fd)
return err;
}
-static int run_mptcpify(int cgroup_fd)
+static int run_mptcpify(int cgroup_fd, int type)
{
int server_fd, client_fd, err = 0;
struct mptcpify *mptcpify_skel;
@@ -280,7 +280,7 @@ static int run_mptcpify(int cgroup_fd)
goto out;
/* without MPTCP */
- server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);
+ server_fd = start_server(AF_INET, type, NULL, 0, 0);
if (!ASSERT_GE(server_fd, 0, "start_server")) {
err = -EIO;
goto out;
@@ -317,7 +317,14 @@ static void test_mptcpify(void)
if (!ASSERT_OK_PTR(netns, "netns_new"))
goto fail;
- ASSERT_OK(run_mptcpify(cgroup_fd), "run_mptcpify");
+ ASSERT_OK(run_mptcpify(cgroup_fd, SOCK_STREAM), "run_mptcpify");
+ /* userspace sets flags such as SOCK_CLOEXEC together with the type;
+ * the BPF prog must still upgrade the socket to MPTCP. See
+ * update_socket_protocol() in net/socket.c, which runs before the
+ * type is masked with SOCK_TYPE_MASK.
+ */
+ ASSERT_OK(run_mptcpify(cgroup_fd, SOCK_STREAM | SOCK_CLOEXEC),
+ "run_mptcpify_cloexec");
fail:
netns_free(netns);
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index d8dacef37c16..c4b438854565 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -8,6 +8,9 @@
#define AF_INET 2
#define AF_INET6 10
+/* include/linux/net.h */
+#define SOCK_TYPE_MASK 0xf
+
#define SOL_SOCKET 1
#define SO_REUSEADDR 2
#define SO_SNDBUF 7
diff --git a/tools/testing/selftests/bpf/progs/mptcpify.c b/tools/testing/selftests/bpf/progs/mptcpify.c
index cbdc730c3a47..e3f8cb54dbe9 100644
--- a/tools/testing/selftests/bpf/progs/mptcpify.c
+++ b/tools/testing/selftests/bpf/progs/mptcpify.c
@@ -15,7 +15,7 @@ int BPF_PROG(mptcpify, int family, int type, int protocol)
return protocol;
if ((family == AF_INET || family == AF_INET6) &&
- type == SOCK_STREAM &&
+ (type & SOCK_TYPE_MASK) == SOCK_STREAM &&
(!protocol || protocol == IPPROTO_TCP)) {
return IPPROTO_MPTCP;
}
--
2.54.0
^ permalink raw reply related
* Re: [PATCH net-next v3 3/5] net: af_unix: useful handling of LSM denials on SCM_RIGHTS
From: Christian Brauner @ 2026-06-30 9:58 UTC (permalink / raw)
To: Jori Koolstra
Cc: Christian Brauner, Aleksa Sarai, Kuniyuki Iwashima,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, netdev, linux-fsdevel, linux-kernel
In-Reply-To: <20260629194327.2270798-4-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 a SO_RIGHTS_NOTRUNC option to UNIX sockets to enable more useful
> handling of LSM denials when receiving SCM_RIGHTS messages: instead of
> truncating the message at the first blocked fd, keep every fd slot
> and store the LSM errno in the blocked slot.
>
> [1]: https://github.com/uapi-group/kernel-features#useful-handling-of-lsm-denials-on-scm_rights
>
> Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
>
> diff --git a/include/net/af_unix.h b/include/net/af_unix.h
> index 34f53dde65ce..bb1b3dee02e8 100644
> --- a/include/net/af_unix.h
> +++ b/include/net/af_unix.h
> @@ -49,6 +49,7 @@ struct unix_sock {
> struct scm_stat scm_stat;
> int inq_len;
> bool recvmsg_inq;
> + bool scm_rights_notrunc;
> #if IS_ENABLED(CONFIG_AF_UNIX_OOB)
> struct sk_buff *oob_skb;
> #endif
> diff --git a/include/net/scm.h b/include/net/scm.h
> index c52519669349..761cda0803fb 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, bool notrunc);
> +void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm, bool notrunc);
> 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,18 @@ 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 flags, bool notrunc)
> {
> + bool filtered;
> + int error;
> +
> if (!ufd)
> return -EFAULT;
> - return receive_fd(f, ufd, flags);
> +
> + error = receive_fd_filtered(f, ufd, flags, &filtered);
> + if (filtered && notrunc)
> + return put_user(error, ufd);
This helper makes no sense to me. The boolean return argument is just
really nasty and you need an additional put_user() as well. At this
point, just drop receive_fd() and open-code it instead of using another
custom helper. Something like the completely untested:
diff --git a/include/net/scm.h b/include/net/scm.h
index 761cda0803fb..171b5ccd0b77 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -116,10 +116,22 @@ static inline int scm_recv_one_fd(struct file *f, int __user *ufd,
if (!ufd)
return -EFAULT;
- error = receive_fd_filtered(f, ufd, flags, &filtered);
- if (filtered && notrunc)
- return put_user(error, ufd);
- return error;
+ error = security_file_receive(file);
+ if (error)
+ return notrunc ? put_user(error, ufd) : error;
+
+ FD_PREPARE(fdf, flags, f);
+ if (fdf.err)
+ return fdf.err;
+ get_file(f);
+
+ error = put_user(fd_prepare_fd(fdf), ufd);
+ if (error)
+ return error;
+
+ __receive_sock(f);
+ return fd_publish(fdf);
}
--
Christian Brauner <brauner@kernel.org>
^ permalink raw reply related
* Re: [PATCH bpf-next v5 1/3] bpf: Add BPF_FIB_LOOKUP_VLAN flag to bpf_fib_lookup() helper
From: Toke Høiland-Jørgensen @ 2026-06-30 10:00 UTC (permalink / raw)
To: David Ahern, Avinash Duduskar, ast, daniel, andrii
Cc: eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil,
john.fastabend, sdf, davem, edumazet, kuba, pabeni, horms, shuah,
hawk, yatsenko, leon.hwang, kpsingh, a.s.protopopov, ameryhung,
rongtao, eyal.birger, bpf, netdev, linux-kernel, linux-kselftest
In-Reply-To: <2ffa32dd-5c88-488a-aa23-deef13465eb9@kernel.org>
David Ahern <dsahern@kernel.org> writes:
> On 6/29/26 9:08 AM, Toke Høiland-Jørgensen wrote:
>> David Ahern <dsahern@kernel.org> writes:
>>
>>> On 6/23/26 9:05 PM, Avinash Duduskar wrote:
>>>> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
>>>> index 89b36de5fdbb..e00f0392e728 100644
>>>> --- a/include/uapi/linux/bpf.h
>>>> +++ b/include/uapi/linux/bpf.h
>>>> @@ -3532,6 +3532,29 @@ union bpf_attr {
>>>> * Use the mark present in *params*->mark for the fib lookup.
>>>> * This option should not be used with BPF_FIB_LOOKUP_DIRECT,
>>>> * as it only has meaning for full lookups.
>>>> + * **BPF_FIB_LOOKUP_VLAN**
>>>
>>> This flag should not be needed. Patches for vlan support were never
>>> submitted (I have them in some old branch). Since the vlan params are
>>> initialized to 0, no new flag should be needed. Besides, these are
>>> output parameters.
>>
>> There's no enforcement from the kernel side of the parameters being
>> zero, though? So we do need the flag for feature detection; unless we
>> expect applications to do that out of band? But then we'd need a
>> mechanism to do that which could be... the presence of the flag in the
>> ENUM (and thus in BTF)? :)
>>
>
> This is output direction - return from the fib lookup.
Ah, right, silly me.
> It does not make sense to require a flag to get lookup output. vlan
> proto of 0 is not valid, so it is a clear indication that the vlan
> output parameters were not set during the lookup.
Okay, so we could just unconditionally set the VLAN fields, but if we
start rewriting the ifindex that would be a change of the existing
behaviour that could break existing applications, no?
Specifically, if an XDP application has a table of the interfaces it
forwards between, today they'd get a VLAN interface ifindex, which would
not be in that table, and the application would return XDP_PASS. Whereas
if we change the ifindex and populate the VLAN tag, suddenly the
interface would be in the table, but because the application doesn't
read the returned VLAN tag, it will end up sending packets out without
tagging them, leading to broken forwarding.
So if we don't want the flag, we'd need some other mechanism to resolve
the parent ifindex, AFAICT? Maybe a xdp_get_parent_ifindex() kfunc, say?
That could also be made generic for other stacked interface types, I
suppose.
WDYT?
-Toke
^ permalink raw reply
* RE: [Intel-wired-lan] [PATCH net v2] idpf: handle NULL adev in idpf_idc_vdev_mtu_event
From: Andrysiak, Jakub @ 2026-06-30 10:02 UTC (permalink / raw)
To: David Carlier, Nguyen, Anthony L, Kitszel, Przemyslaw
Cc: andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
intel-wired-lan@lists.osuosl.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
In-Reply-To: <20260514183019.49527-1-devnexen@gmail.com>
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces@osuosl.org> On Behalf Of
> David Carlier
> Sent: Thursday, May 14, 2026 8:30 PM
> To: Nguyen, Anthony L <anthony.l.nguyen@intel.com>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>
> Cc: andrew+netdev@lunn.ch; davem@davemloft.net;
> edumazet@google.com; kuba@kernel.org; pabeni@redhat.com;
> horms@kernel.org; intel-wired-lan@lists.osuosl.org; netdev@vger.kernel.org;
> linux-kernel@vger.kernel.org; stable@vger.kernel.org; David Carlier
> <devnexen@gmail.com>
> Subject: [Intel-wired-lan] [PATCH net v2] idpf: handle NULL adev in
> idpf_idc_vdev_mtu_event
>
> idpf_idc_vport_dev_ctrl(adapter, false) clears vport->vdev_info->adev to NULL
> but keeps vport->vdev_info itself. An MTU change after that calls
> idpf_idc_vdev_mtu_event(), which dereferences vdev_info->adev for
> device_lock() before reaching the (!adev || ...) check.
>
> Cache vdev_info->adev once with READ_ONCE() and bail out if NULL before
> locking. Use the cached pointer on both the lock and unlock paths so the
> unlock matches the device actually acquired and cannot re-fetch a NULL slot.
>
> Fixes: ed6e1c8796a4 ("idpf: implement IDC vport aux driver MTU change
> handler")
> Cc: stable@vger.kernel.org
> Signed-off-by: David Carlier <devnexen@gmail.com>
> ---
> v2: cache vdev_info->adev with READ_ONCE() to avoid double-fetch and
> use the cached pointer on the unlock path (Alok Tiwari)
> ---
> drivers/net/ethernet/intel/idpf/idpf_idc.c | 11 +++++++----
> 1 file changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c
> b/drivers/net/ethernet/intel/idpf/idpf_idc.c
> index b7d6b08fc89e..9f764135507c 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
> @@ -162,9 +162,12 @@ void idpf_idc_vdev_mtu_event(struct
> iidc_rdma_vport_dev_info *vdev_info,
>
> set_bit(event_type, event.type);
>
> - device_lock(&vdev_info->adev->dev);
> - adev = vdev_info->adev;
> - if (!adev || !adev->dev.driver)
> + adev = READ_ONCE(vdev_info->adev);
> + if (!adev)
> + return;
> +
> + device_lock(&adev->dev);
> + if (!adev->dev.driver)
> goto unlock;
> iadrv = container_of(adev->dev.driver,
> struct iidc_rdma_vport_auxiliary_drv, @@ -172,7
> +175,7 @@ void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info
> *vdev_info,
> if (iadrv->event_handler)
> iadrv->event_handler(vdev_info, &event);
> unlock:
> - device_unlock(&vdev_info->adev->dev);
> + device_unlock(&adev->dev);
> }
>
> /**
> --
> 2.53.0
Tested-by: Jakub Andrysiak <jakub.andrysiak@intel.com>
^ permalink raw reply
* [PATCH net v4 1/1] net/sched: sch_teql: Introduce slaves_lock to avoid race condition and UAF
From: Jamal Hadi Salim @ 2026-06-30 10:02 UTC (permalink / raw)
To: netdev
Cc: davem, edumazet, kuba, pabeni, horms, jiri, victor, security,
zdi-disclosures, stable, Jamal Hadi Salim
The teql master->slaves singly linked list is not protected against
multiple writes. It can be mod'ed concurently from teql_master_xmit(),
teql_dequeue(), teql_init() and teql_destroy() without holding any list
lock or RCU protection.
zdi-disclosures@trendmicro.com has demonstrated that the qdisc is freed
after an RCU grace period, but teql_master_xmit() running on another
CPU can still hold a stale pointer into the list, resulting in a
slab-use-after-free:
BUG: KASAN: slab-use-after-free in teql_master_xmit+0xf0f/0x16b0
Read of size 8 at addr ffff888013fb0440 by task poc/332
Freed 512-byte region [ffff888013fb0400, ffff888013fb0600) (kmalloc-512)
The fix?
Add a per-master slaves_lock spinlock that serializes all mutations of
master->slaves and the NEXT_SLAVE() links in teql_destroy() and
teql_qdisc_init(). teql_master_xmit() also takes the same slaves_lock
around those updates.
Annotate master->slaves and the per-slave ->next pointer with __rcu and
use the appropriate RCU accessors everywhere they are touched:
rcu_assign_pointer() on the writer side (under slaves_lock),
rcu_dereference_protected() for the writer-side loads (also under
slaves_lock), rcu_dereference() for the loads in teql_master_xmit() and
rtnl_dereference() for the loads in teql_master_open()/teql_master_mtu(),
which run under RTNL.
Pair this with rcu_read_lock()/rcu_read_unlock() around the list
traversal in teql_master_xmit(), so that readers either observe a fully
linked list or are deferred until the in-flight mutation completes. The two
early-return paths in teql_master_xmit() are updated to release the RCU
read-side critical section before returning, since leaving it held would
keep the CPU in an RCU read-side critical section for good.
On feedback from Sashiko[1]: The core network stack already invokes
ndo_start_xmit with BH disabled, so plain rcu_read_lock() and spin_lock()
suffice in the transmit path and avoid the in_hardirq() warnings that
rcu_read_unlock_bh()/spin_unlock_bh() would trigger when xmit is reached
through netpoll or a softirq xmit path with hard IRQs disabled.
[1]https://sashiko.dev/#/patchset/20260628111229.669751-1-jhs%40mojatatu.com
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: zdi-disclosures@trendmicro.com
Tested-by: Victor Nogueira <victor@mojatatu.com>
Tested-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
---
v2->v3
1) Thanks to Simon's persistence:
The writeback in teql_master_xmit() should not blindly write NEXT_SLAVE(q)
into master->slaves. It should re-read master->slaves under slaves_lock and
only update it if q is still the current head
2) Appease sashiko by mentioning teql_dequeue() on the commit and ensuring
consistency on rcu_dereference_bh()/rcu_dereference_protected()
v3->v4 (feedback from sashiko[1])
1) Use plain rcu_read_lock()/spin_lock() in teql_master_xmit() instead of
the _bh variants, since ndo_start_xmit is already invoked with BH
disabled by the core stack and the _bh primitives can warn in_hardirq()
when xmit is reached through netpoll or a softirq xmit path with hard
IRQs disabled.
2) Fix pre-existing condition:
The list traversal in teql_master_xmit() no longer caches "start"
as the loop sentinel. If teql_destroy() concurrently unlinks that
node we end up in soft/hard lockup. To resolve, re-read master->slaves
at each iteration and terminate when q wraps around to the
current head or the list becomes empty.
[1]https://sashiko.dev/#/patchset/20260628111229.669751-1-jhs%40mojatatu.com
---
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index e7bbc9e5174d..ff0f712b8246 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -52,7 +52,8 @@
struct teql_master {
struct Qdisc_ops qops;
struct net_device *dev;
- struct Qdisc *slaves;
+ struct Qdisc __rcu *slaves;
+ spinlock_t slaves_lock; /* serializes writes to ->slaves */
struct list_head master_list;
unsigned long tx_bytes;
unsigned long tx_packets;
@@ -61,7 +62,7 @@ struct teql_master {
};
struct teql_sched_data {
- struct Qdisc *next;
+ struct Qdisc __rcu *next;
struct teql_master *m;
struct sk_buff_head q;
};
@@ -101,7 +102,9 @@ teql_dequeue(struct Qdisc *sch)
if (skb == NULL) {
struct net_device *m = qdisc_dev(q);
if (m) {
- dat->m->slaves = sch;
+ spin_lock_bh(&dat->m->slaves_lock);
+ rcu_assign_pointer(dat->m->slaves, sch);
+ spin_unlock_bh(&dat->m->slaves_lock);
netif_wake_queue(m);
}
} else {
@@ -132,34 +135,49 @@ teql_destroy(struct Qdisc *sch)
struct Qdisc *q, *prev;
struct teql_sched_data *dat = qdisc_priv(sch);
struct teql_master *master = dat->m;
+ struct netdev_queue *txq = NULL;
+ bool reset_master_queue = false;
if (!master)
return;
- prev = master->slaves;
+ spin_lock_bh(&master->slaves_lock);
+ prev = rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock));
if (prev) {
do {
- q = NEXT_SLAVE(prev);
- if (q == sch) {
- NEXT_SLAVE(prev) = NEXT_SLAVE(q);
- if (q == master->slaves) {
- master->slaves = NEXT_SLAVE(q);
- if (q == master->slaves) {
- struct netdev_queue *txq;
-
- txq = netdev_get_tx_queue(master->dev, 0);
- master->slaves = NULL;
-
- dev_reset_queue(master->dev,
- txq, NULL);
- }
- }
- skb_queue_purge(&dat->q);
- break;
+ struct Qdisc *head, *next;
+
+ q = rcu_dereference_protected(NEXT_SLAVE(prev),
+ lockdep_is_held(&master->slaves_lock));
+ if (q != sch) {
+ prev = q;
+ continue;
}
- } while ((prev = q) != master->slaves);
+ next = rcu_dereference_protected(NEXT_SLAVE(q),
+ lockdep_is_held(&master->slaves_lock));
+ rcu_assign_pointer(NEXT_SLAVE(prev), next);
+
+ head = rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock));
+ if (q == head) {
+ rcu_assign_pointer(master->slaves, next);
+ if (q == next) {
+ txq = netdev_get_tx_queue(master->dev, 0);
+ rcu_assign_pointer(master->slaves, NULL);
+ reset_master_queue = true;
+ }
+ }
+ skb_queue_purge(&dat->q);
+ break;
+ } while (prev != rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock)));
}
+ spin_unlock_bh(&master->slaves_lock);
+
+ if (reset_master_queue)
+ dev_reset_queue(master->dev, txq, NULL);
}
static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
@@ -168,6 +186,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
struct net_device *dev = qdisc_dev(sch);
struct teql_master *m = (struct teql_master *)sch->ops;
struct teql_sched_data *q = qdisc_priv(sch);
+ struct Qdisc *first;
if (dev->hard_header_len > m->dev->hard_header_len)
return -EINVAL;
@@ -184,7 +203,9 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
skb_queue_head_init(&q->q);
- if (m->slaves) {
+ spin_lock_bh(&m->slaves_lock);
+ first = rcu_dereference_protected(m->slaves, lockdep_is_held(&m->slaves_lock));
+ if (first) {
if (m->dev->flags & IFF_UP) {
if ((m->dev->flags & IFF_POINTOPOINT &&
!(dev->flags & IFF_POINTOPOINT)) ||
@@ -192,8 +213,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
!(dev->flags & IFF_BROADCAST)) ||
(m->dev->flags & IFF_MULTICAST &&
!(dev->flags & IFF_MULTICAST)) ||
- dev->mtu < m->dev->mtu)
+ dev->mtu < m->dev->mtu) {
+ spin_unlock_bh(&m->slaves_lock);
return -EINVAL;
+ }
} else {
if (!(dev->flags&IFF_POINTOPOINT))
m->dev->flags &= ~IFF_POINTOPOINT;
@@ -204,14 +227,17 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
if (dev->mtu < m->dev->mtu)
m->dev->mtu = dev->mtu;
}
- q->next = NEXT_SLAVE(m->slaves);
- NEXT_SLAVE(m->slaves) = sch;
+ rcu_assign_pointer(q->next,
+ rcu_dereference_protected(NEXT_SLAVE(first),
+ lockdep_is_held(&m->slaves_lock)));
+ rcu_assign_pointer(NEXT_SLAVE(first), sch);
} else {
- q->next = sch;
- m->slaves = sch;
+ rcu_assign_pointer(q->next, sch);
+ rcu_assign_pointer(m->slaves, sch);
m->dev->mtu = dev->mtu;
m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
}
+ spin_unlock_bh(&m->slaves_lock);
return 0;
}
@@ -279,19 +305,19 @@ static inline int teql_resolve(struct sk_buff *skb,
static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct teql_master *master = netdev_priv(dev);
- struct Qdisc *start, *q;
+ struct Qdisc *q, *head;
int busy;
int nores;
int subq = skb_get_queue_mapping(skb);
struct sk_buff *skb_res = NULL;
- start = master->slaves;
-
-restart:
+ restart:
nores = 0;
busy = 0;
- q = start;
+ rcu_read_lock();
+
+ q = rcu_dereference(master->slaves);
if (!q)
goto drop;
@@ -317,10 +343,17 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_start_xmit(skb, slave, slave_txq, false) ==
NETDEV_TX_OK) {
__netif_tx_unlock(slave_txq);
- master->slaves = NEXT_SLAVE(q);
+ spin_lock(&master->slaves_lock);
+ if (rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock)) == q)
+ rcu_assign_pointer(master->slaves,
+ rcu_dereference_protected(NEXT_SLAVE(q),
+ lockdep_is_held(&master->slaves_lock)));
+ spin_unlock(&master->slaves_lock);
netif_wake_queue(dev);
master->tx_packets++;
master->tx_bytes += length;
+ rcu_read_unlock();
return NETDEV_TX_OK;
}
__netif_tx_unlock(slave_txq);
@@ -329,45 +362,58 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
busy = 1;
break;
case 1:
- master->slaves = NEXT_SLAVE(q);
+ spin_lock(&master->slaves_lock);
+ if (rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock)) == q)
+ rcu_assign_pointer(master->slaves,
+ rcu_dereference_protected(NEXT_SLAVE(q),
+ lockdep_is_held(&master->slaves_lock)));
+ spin_unlock(&master->slaves_lock);
+ rcu_read_unlock();
return NETDEV_TX_OK;
default:
nores = 1;
break;
}
__skb_pull(skb, skb_network_offset(skb));
- } while ((q = NEXT_SLAVE(q)) != start);
+ q = rcu_dereference(NEXT_SLAVE(q));
+ head = rcu_dereference(master->slaves);
+ } while (q && head && q != head);
if (nores && skb_res == NULL) {
skb_res = skb;
+ rcu_read_unlock();
goto restart;
}
if (busy) {
netif_stop_queue(dev);
+ rcu_read_unlock();
return NETDEV_TX_BUSY;
}
master->tx_errors++;
drop:
master->tx_dropped++;
+ rcu_read_unlock();
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
static int teql_master_open(struct net_device *dev)
{
- struct Qdisc *q;
+ struct Qdisc *q, *first;
struct teql_master *m = netdev_priv(dev);
int mtu = 0xFFFE;
unsigned int flags = IFF_NOARP | IFF_MULTICAST;
- if (m->slaves == NULL)
+ first = rtnl_dereference(m->slaves);
+ if (!first)
return -EUNATCH;
flags = FMASK;
- q = m->slaves;
+ q = first;
do {
struct net_device *slave = qdisc_dev(q);
@@ -389,7 +435,7 @@ static int teql_master_open(struct net_device *dev)
flags &= ~IFF_BROADCAST;
if (!(slave->flags&IFF_MULTICAST))
flags &= ~IFF_MULTICAST;
- } while ((q = NEXT_SLAVE(q)) != m->slaves);
+ } while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first);
m->dev->mtu = mtu;
m->dev->flags = (m->dev->flags&~FMASK) | flags;
@@ -417,14 +463,15 @@ static void teql_master_stats64(struct net_device *dev,
static int teql_master_mtu(struct net_device *dev, int new_mtu)
{
struct teql_master *m = netdev_priv(dev);
- struct Qdisc *q;
+ struct Qdisc *q, *first;
- q = m->slaves;
+ first = rtnl_dereference(m->slaves);
+ q = first;
if (q) {
do {
if (new_mtu > qdisc_dev(q)->mtu)
return -EINVAL;
- } while ((q = NEXT_SLAVE(q)) != m->slaves);
+ } while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first);
}
WRITE_ONCE(dev->mtu, new_mtu);
@@ -444,6 +491,7 @@ static __init void teql_master_setup(struct net_device *dev)
struct teql_master *master = netdev_priv(dev);
struct Qdisc_ops *ops = &master->qops;
+ spin_lock_init(&master->slaves_lock);
master->dev = dev;
ops->priv_size = sizeof(struct teql_sched_data);
^ permalink raw reply related
* Re: [PATCH net] selftests: net: make busywait timeout clock portable
From: Paolo Abeni @ 2026-06-30 10:11 UTC (permalink / raw)
To: Nirmoy Das, David S. Miller, Eric Dumazet, Jakub Kicinski,
Shuah Khan
Cc: netdev, linux-kselftest, stable
In-Reply-To: <20260626144902.3214350-1-nirmoyd@nvidia.com>
On 6/26/26 4:49 PM, Nirmoy Das wrote:
> loopy_wait() expects millisecond timestamps. However, Ubuntu Resolute
> can use uutils date, where `date -u +%s%3N` returns seconds plus full
> nanoseconds instead of a 3-digit millisecond field. This makes
> busywait expire too early and can make vlan_bridge_binding.sh read a
> stale operstate.
>
> Fixes: 25ae948b4478 ("selftests/net: add lib.sh")
> Cc: stable@vger.kernel.org # 6.8+
> Link: https://github.com/uutils/coreutils/issues/11658
> Signed-off-by: Nirmoy Das <nirmoyd@nvidia.com>
> ---
> tools/testing/selftests/net/lib.sh | 19 +++++++++++++++++--
> 1 file changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/net/lib.sh b/tools/testing/selftests/net/lib.sh
> index b40694573f4c7..fcaec058be6d0 100644
> --- a/tools/testing/selftests/net/lib.sh
> +++ b/tools/testing/selftests/net/lib.sh
> @@ -70,12 +70,27 @@ ksft_exit_status_merge()
> $ksft_xfail $ksft_pass $ksft_skip $ksft_fail
> }
>
> +timestamp_ms()
> +{
> + local now=$(date -u +%s:%N)
shellcheck says:
^-^ SC2155 (warning): Declare and assign separately to avoid masking
return values.
/P
^ permalink raw reply
* Re: [PATCH net-next 1/2] tools: ynl: pyynl: re-export the library API from the package root
From: Donald Hunter @ 2026-06-30 8:38 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, sdf, gal,
jstancek, ast
In-Reply-To: <20260630001432.2204298-2-kuba@kernel.org>
Jakub Kicinski <kuba@kernel.org> writes:
> The public classes live in pyynl.lib, so users had to spell out
>
> from pyynl.lib import YnlFamily
>
> which I forget at least once a month. Re-export lib's API from
> the package __init__ so that
>
> from pyynl import YnlFamily
>
> works as well. I don't think there was a real reason not to do
> this?
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
^ permalink raw reply
* Re: [PATCH net-next 2/2] tools: ynl: pyynl: pull the --family resolution logic into the lib
From: Donald Hunter @ 2026-06-30 10:10 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, sdf, gal,
jstancek, ast
In-Reply-To: <20260630001432.2204298-3-kuba@kernel.org>
Jakub Kicinski <kuba@kernel.org> writes:
> When packaging YNL as a system level utility we added a --family
> argument which auto-resolves the full spec path from a well known
> path in /usr/share. Spelling out full YAML spec files is at this
> point only done in-tree, for example in the selftests which need
> the very latest YAML. But the selftests have their own wrapping
> classes for each family so test authors aren't really bothered
> by having to spell the paths out.
>
> Afford the same ease of use to the Python library users.
> Move the path resolution from the CLI code to the library.
> This simplifies the pyynl use by a lot:
>
> from pyynl import YnlFamily
>
> ynl = YnlFamily(family="netdev")
>
> Unless I'm missing a trick, resolving the /usr/share path
> is hard enough for most users to lean towards shelling out
> to ynl CLI with --output-json, which is sad.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> tools/net/ynl/pyynl/cli.py | 53 +++++------------------------
This breaks tools/net/ynl/tests/ethtool.py which currently imports from cli:
from cli import schema_dir, spec_dir
Otherwise, changes look good.
^ permalink raw reply
* [PATCH net-next v4] net: usb: rtl8150: handle link status read failures
From: Yousef Alhouseen @ 2026-06-30 10:12 UTC (permalink / raw)
To: Petko Manolov, Andrew Lunn
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
linux-usb, netdev, linux-kernel, Yousef Alhouseen,
syzbot+9db6c624635564ad813c
set_carrier() ignores the result of the USB control transfer and tests
the stack variable supplied as its receive buffer. If the device rejects
or aborts the request, that variable remains uninitialized and the driver
chooses an arbitrary carrier state.
Leave the existing carrier state unchanged when the link status cannot be
read. A transient USB error should not be treated as link loss.
Reported-by: syzbot+9db6c624635564ad813c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9db6c624635564ad813c
Suggested-by: Petko Manolov <petkan@nucleusys.com>
Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
---
Changes in v4:
- Target net-next and drop the Fixes tag as requested.
- Rebase onto current net-next after the 24-hour repost interval.
drivers/net/usb/rtl8150.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index c880c95c41a5..d51e43170e03 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -732,7 +732,9 @@ static void set_carrier(struct net_device *netdev)
rtl8150_t *dev = netdev_priv(netdev);
short tmp;
- get_registers(dev, CSCR, 2, &tmp);
+ if (get_registers(dev, CSCR, 2, &tmp))
+ return;
+
if (tmp & CSCR_LINK_STATUS)
netif_carrier_on(netdev);
else
--
2.54.0
^ permalink raw reply related
* [PATCH net] bnge/bng_re: fix ring ID widths
From: Vikas Gupta @ 2026-06-30 10:15 UTC (permalink / raw)
To: davem, edumazet, kuba, pabeni, andrew+netdev, horms
Cc: netdev, linux-kernel, linux-rdma, leonro, jgg, bhargava.marreddy,
rahul-rg.gupta, vsrama-krishna.nemani, rajashekar.hudumula,
ajit.khaparde, Vikas Gupta, Siva Reddy Kallam, Dharmender Garg,
Yendapally Reddy Dhananjaya Reddy
Firmware extended the TX ring ID from 16 to 32 bits to accommodate its
internal QP management. Update the HSI and the ring ID fields in the
ring alloc/free calls accordingly.
Only the TX ring ID managed by firmware is widened but RX, completion
and NQ ring IDs remain within the 16-bit range.
Fixes: 42d1c54d6248 ("bnge/bng_re: Add a new HSI")
Signed-off-by: Vikas Gupta <vikas.gupta@broadcom.com>
Reviewed-by: Siva Reddy Kallam <siva.kallam@broadcom.com>
Reviewed-by: Dharmender Garg <dharmender.garg@broadcom.com>
Reviewed-by: Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com>
---
drivers/infiniband/hw/bng_re/bng_dev.c | 6 +--
drivers/net/ethernet/broadcom/bnge/bnge.h | 1 +
.../ethernet/broadcom/bnge/bnge_hwrm_lib.c | 8 +--
.../ethernet/broadcom/bnge/bnge_hwrm_lib.h | 2 +-
.../net/ethernet/broadcom/bnge/bnge_netdev.c | 50 +++++++++----------
.../net/ethernet/broadcom/bnge/bnge_netdev.h | 4 +-
.../net/ethernet/broadcom/bnge/bnge_rmem.h | 2 +-
include/linux/bnge/hsi.h | 7 ++-
8 files changed, 39 insertions(+), 41 deletions(-)
diff --git a/drivers/infiniband/hw/bng_re/bng_dev.c b/drivers/infiniband/hw/bng_re/bng_dev.c
index 71a7ca2196ad..311c8bc93160 100644
--- a/drivers/infiniband/hw/bng_re/bng_dev.c
+++ b/drivers/infiniband/hw/bng_re/bng_dev.c
@@ -113,7 +113,7 @@ static void bng_re_fill_fw_msg(struct bnge_fw_msg *fw_msg, void *msg,
}
static int bng_re_net_ring_free(struct bng_re_dev *rdev,
- u16 fw_ring_id, int type)
+ u32 fw_ring_id, int type)
{
struct bnge_auxr_dev *aux_dev = rdev->aux_dev;
struct hwrm_ring_free_input req = {};
@@ -123,7 +123,7 @@ static int bng_re_net_ring_free(struct bng_re_dev *rdev,
bng_re_init_hwrm_hdr((void *)&req, HWRM_RING_FREE);
req.ring_type = type;
- req.ring_id = cpu_to_le16(fw_ring_id);
+ req.ring_id = cpu_to_le32(fw_ring_id);
bng_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
sizeof(resp), BNGE_DFLT_HWRM_CMD_TIMEOUT);
rc = bnge_send_msg(aux_dev, &fw_msg);
@@ -161,7 +161,7 @@ static int bng_re_net_ring_alloc(struct bng_re_dev *rdev,
sizeof(resp), BNGE_DFLT_HWRM_CMD_TIMEOUT);
rc = bnge_send_msg(aux_dev, &fw_msg);
if (!rc)
- *fw_ring_id = le16_to_cpu(resp.ring_id);
+ *fw_ring_id = (u16)le32_to_cpu(resp.ring_id);
return rc;
}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethernet/broadcom/bnge/bnge.h
index f21cff651fd4..4479ccd071f5 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge.h
@@ -36,6 +36,7 @@ struct bnge_pf_info {
};
#define INVALID_HW_RING_ID ((u16)-1)
+#define INVALID_HW_RING_ID_32BIT (U32_MAX)
enum {
BNGE_FW_CAP_SHORT_CMD = BIT_ULL(0),
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c
index 1c9cfec1b633..651c5e783516 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c
@@ -1283,7 +1283,7 @@ int bnge_hwrm_stat_ctx_alloc(struct bnge_net *bn)
int hwrm_ring_free_send_msg(struct bnge_net *bn,
struct bnge_ring_struct *ring,
- u32 ring_type, int cmpl_ring_id)
+ u32 ring_type, u32 cmpl_ring_id)
{
struct hwrm_ring_free_input *req;
struct bnge_dev *bd = bn->bd;
@@ -1295,7 +1295,7 @@ int hwrm_ring_free_send_msg(struct bnge_net *bn,
req->cmpl_ring = cpu_to_le16(cmpl_ring_id);
req->ring_type = ring_type;
- req->ring_id = cpu_to_le16(ring->fw_ring_id);
+ req->ring_id = cpu_to_le32(ring->fw_ring_id);
bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
@@ -1317,7 +1317,7 @@ int hwrm_ring_alloc_send_msg(struct bnge_net *bn,
struct hwrm_ring_alloc_output *resp;
struct hwrm_ring_alloc_input *req;
struct bnge_dev *bd = bn->bd;
- u16 ring_id, flags = 0;
+ u32 ring_id, flags = 0;
int rc;
rc = bnge_hwrm_req_init(bd, req, HWRM_RING_ALLOC);
@@ -1401,7 +1401,7 @@ int hwrm_ring_alloc_send_msg(struct bnge_net *bn,
resp = bnge_hwrm_req_hold(bd, req);
rc = bnge_hwrm_req_send(bd, req);
- ring_id = le16_to_cpu(resp->ring_id);
+ ring_id = le32_to_cpu(resp->ring_id);
bnge_hwrm_req_drop(bd, req);
exit:
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h
index 3501de7a89b9..bf452e390d5b 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.h
@@ -50,7 +50,7 @@ int bnge_hwrm_cfa_l2_set_rx_mask(struct bnge_dev *bd,
void bnge_hwrm_stat_ctx_free(struct bnge_net *bn);
int bnge_hwrm_stat_ctx_alloc(struct bnge_net *bn);
int hwrm_ring_free_send_msg(struct bnge_net *bn, struct bnge_ring_struct *ring,
- u32 ring_type, int cmpl_ring_id);
+ u32 ring_type, u32 cmpl_ring_id);
int hwrm_ring_alloc_send_msg(struct bnge_net *bn,
struct bnge_ring_struct *ring,
u32 ring_type, u32 map_index);
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
index 70768193004c..6f7ef506d4e1 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
@@ -1327,12 +1327,12 @@ static int bnge_alloc_core(struct bnge_net *bn)
return rc;
}
-u16 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr)
+u32 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr)
{
return rxr->rx_cpr->ring_struct.fw_ring_id;
}
-u16 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr)
+u32 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr)
{
return txr->tx_cpr->ring_struct.fw_ring_id;
}
@@ -1375,12 +1375,12 @@ static void bnge_init_nq_tree(struct bnge_net *bn)
struct bnge_nq_ring_info *nqr = &bn->bnapi[i]->nq_ring;
struct bnge_ring_struct *ring = &nqr->ring_struct;
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
for (j = 0; j < nqr->cp_ring_count; j++) {
struct bnge_cp_ring_info *cpr = &nqr->cp_ring_arr[j];
ring = &cpr->ring_struct;
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
}
}
@@ -1637,7 +1637,7 @@ static void bnge_init_one_rx_ring_rxbd(struct bnge_net *bn,
ring = &rxr->rx_ring_struct;
bnge_init_rxbd_pages(ring, type);
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
static void bnge_init_one_agg_ring_rxbd(struct bnge_net *bn,
@@ -1647,7 +1647,7 @@ static void bnge_init_one_agg_ring_rxbd(struct bnge_net *bn,
u32 type;
ring = &rxr->rx_agg_ring_struct;
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
if (bnge_is_agg_reqd(bn->bd)) {
type = ((u32)BNGE_RX_PAGE_SIZE << RX_BD_LEN_SHIFT) |
RX_BD_TYPE_RX_AGG_BD | RX_BD_FLAGS_SOP;
@@ -1708,7 +1708,7 @@ static void bnge_init_tx_rings(struct bnge_net *bn)
struct bnge_tx_ring_info *txr = &bn->tx_ring[i];
struct bnge_ring_struct *ring = &txr->tx_ring_struct;
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
netif_queue_set_napi(bn->netdev, i, NETDEV_QUEUE_TYPE_TX,
&txr->bnapi->napi);
@@ -1867,7 +1867,7 @@ static int bnge_hwrm_rx_agg_ring_alloc(struct bnge_net *bn,
ring->fw_ring_id);
bnge_db_write(bn->bd, &rxr->rx_agg_db, rxr->rx_agg_prod);
bnge_db_write(bn->bd, &rxr->rx_db, rxr->rx_prod);
- bn->grp_info[grp_idx].agg_fw_ring_id = ring->fw_ring_id;
+ bn->grp_info[grp_idx].agg_fw_ring_id = (u16)ring->fw_ring_id;
return 0;
}
@@ -1886,7 +1886,7 @@ static int bnge_hwrm_rx_ring_alloc(struct bnge_net *bn,
return rc;
bnge_set_db(bn, &rxr->rx_db, type, map_idx, ring->fw_ring_id);
- bn->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id;
+ bn->grp_info[map_idx].rx_fw_ring_id = (u16)ring->fw_ring_id;
return 0;
}
@@ -1916,7 +1916,7 @@ static int bnge_hwrm_ring_alloc(struct bnge_net *bn)
bnge_set_db(bn, &nqr->nq_db, type, map_idx, ring->fw_ring_id);
bnge_db_nq(bn, &nqr->nq_db, nqr->nq_raw_cons);
enable_irq(vector);
- bn->grp_info[i].nq_fw_ring_id = ring->fw_ring_id;
+ bn->grp_info[i].nq_fw_ring_id = (u16)ring->fw_ring_id;
if (!i) {
rc = bnge_hwrm_set_async_event_cr(bd, ring->fw_ring_id);
@@ -1986,15 +1986,13 @@ void bnge_fill_hw_rss_tbl(struct bnge_net *bn, struct bnge_vnic_info *vnic)
tbl_size = bnge_get_rxfh_indir_size(bd);
for (i = 0; i < tbl_size; i++) {
- u16 ring_id, j;
+ u32 j;
j = bd->rss_indir_tbl[i];
rxr = &bn->rx_ring[j];
- ring_id = rxr->rx_ring_struct.fw_ring_id;
- *ring_tbl++ = cpu_to_le16(ring_id);
- ring_id = bnge_cp_ring_for_rx(rxr);
- *ring_tbl++ = cpu_to_le16(ring_id);
+ *ring_tbl++ = cpu_to_le16(rxr->rx_ring_struct.fw_ring_id);
+ *ring_tbl++ = cpu_to_le16(bnge_cp_ring_for_rx(rxr));
}
}
@@ -2285,7 +2283,7 @@ static void bnge_disable_int(struct bnge_net *bn)
nqr = &bnapi->nq_ring;
ring = &nqr->ring_struct;
- if (ring->fw_ring_id != INVALID_HW_RING_ID)
+ if (ring->fw_ring_id != INVALID_HW_RING_ID_32BIT)
bnge_db_nq(bn, &nqr->nq_db, nqr->nq_raw_cons);
}
}
@@ -2401,7 +2399,7 @@ static void bnge_hwrm_rx_ring_free(struct bnge_net *bn,
u32 grp_idx = rxr->bnapi->index;
u32 cmpl_ring_id;
- if (ring->fw_ring_id == INVALID_HW_RING_ID)
+ if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
cmpl_ring_id = bnge_cp_ring_for_rx(rxr);
@@ -2409,7 +2407,7 @@ static void bnge_hwrm_rx_ring_free(struct bnge_net *bn,
RING_FREE_REQ_RING_TYPE_RX,
close_path ? cmpl_ring_id :
INVALID_HW_RING_ID);
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
bn->grp_info[grp_idx].rx_fw_ring_id = INVALID_HW_RING_ID;
}
@@ -2421,14 +2419,14 @@ static void bnge_hwrm_rx_agg_ring_free(struct bnge_net *bn,
u32 grp_idx = rxr->bnapi->index;
u32 cmpl_ring_id;
- if (ring->fw_ring_id == INVALID_HW_RING_ID)
+ if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
cmpl_ring_id = bnge_cp_ring_for_rx(rxr);
hwrm_ring_free_send_msg(bn, ring, RING_FREE_REQ_RING_TYPE_RX_AGG,
close_path ? cmpl_ring_id :
INVALID_HW_RING_ID);
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
bn->grp_info[grp_idx].agg_fw_ring_id = INVALID_HW_RING_ID;
}
@@ -2439,14 +2437,14 @@ static void bnge_hwrm_tx_ring_free(struct bnge_net *bn,
struct bnge_ring_struct *ring = &txr->tx_ring_struct;
u32 cmpl_ring_id;
- if (ring->fw_ring_id == INVALID_HW_RING_ID)
+ if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
cmpl_ring_id = close_path ? bnge_cp_ring_for_tx(txr) :
INVALID_HW_RING_ID;
hwrm_ring_free_send_msg(bn, ring, RING_FREE_REQ_RING_TYPE_TX,
cmpl_ring_id);
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
static void bnge_hwrm_cp_ring_free(struct bnge_net *bn,
@@ -2455,12 +2453,12 @@ static void bnge_hwrm_cp_ring_free(struct bnge_net *bn,
struct bnge_ring_struct *ring;
ring = &cpr->ring_struct;
- if (ring->fw_ring_id == INVALID_HW_RING_ID)
+ if (ring->fw_ring_id == INVALID_HW_RING_ID_32BIT)
return;
hwrm_ring_free_send_msg(bn, ring, RING_FREE_REQ_RING_TYPE_L2_CMPL,
INVALID_HW_RING_ID);
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
}
static void bnge_hwrm_ring_free(struct bnge_net *bn, bool close_path)
@@ -2496,11 +2494,11 @@ static void bnge_hwrm_ring_free(struct bnge_net *bn, bool close_path)
bnge_hwrm_cp_ring_free(bn, &nqr->cp_ring_arr[j]);
ring = &nqr->ring_struct;
- if (ring->fw_ring_id != INVALID_HW_RING_ID) {
+ if (ring->fw_ring_id != INVALID_HW_RING_ID_32BIT) {
hwrm_ring_free_send_msg(bn, ring,
RING_FREE_REQ_RING_TYPE_NQ,
INVALID_HW_RING_ID);
- ring->fw_ring_id = INVALID_HW_RING_ID;
+ ring->fw_ring_id = INVALID_HW_RING_ID_32BIT;
bn->grp_info[i].nq_fw_ring_id = INVALID_HW_RING_ID;
}
}
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
index f4636b5b0cf3..d177919c2e11 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.h
@@ -630,8 +630,8 @@ struct bnge_l2_filter {
refcount_t refcnt;
};
-u16 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr);
-u16 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr);
+u32 bnge_cp_ring_for_rx(struct bnge_rx_ring_info *rxr);
+u32 bnge_cp_ring_for_tx(struct bnge_tx_ring_info *txr);
void bnge_fill_hw_rss_tbl(struct bnge_net *bn, struct bnge_vnic_info *vnic);
int bnge_alloc_rx_data(struct bnge_net *bn, struct bnge_rx_ring_info *rxr,
u16 prod, gfp_t gfp);
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.h b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.h
index 341c7f81ed09..bb0c79a1ee60 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_rmem.h
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_rmem.h
@@ -184,7 +184,7 @@ struct bnge_ctx_mem_info {
struct bnge_ring_struct {
struct bnge_ring_mem_info ring_mem;
- u16 fw_ring_id;
+ u32 fw_ring_id;
union {
u16 grp_idx;
u16 map_idx; /* Used by NQs */
diff --git a/include/linux/bnge/hsi.h b/include/linux/bnge/hsi.h
index 8ea13d5407ee..1f7bd96415a5 100644
--- a/include/linux/bnge/hsi.h
+++ b/include/linux/bnge/hsi.h
@@ -8317,8 +8317,7 @@ struct hwrm_ring_alloc_output {
__le16 req_type;
__le16 seq_id;
__le16 resp_len;
- __le16 ring_id;
- __le16 logical_ring_id;
+ __le32 ring_id;
u8 push_buffer_index;
#define RING_ALLOC_RESP_PUSH_BUFFER_INDEX_PING_BUFFER 0x0UL
#define RING_ALLOC_RESP_PUSH_BUFFER_INDEX_PONG_BUFFER 0x1UL
@@ -8345,10 +8344,10 @@ struct hwrm_ring_free_input {
u8 flags;
#define RING_FREE_REQ_FLAGS_VIRTIO_RING_VALID 0x1UL
#define RING_FREE_REQ_FLAGS_LAST RING_FREE_REQ_FLAGS_VIRTIO_RING_VALID
- __le16 ring_id;
+ __le16 unused_1;
__le32 prod_idx;
__le32 opaque;
- __le32 unused_1;
+ __le32 ring_id;
};
/* hwrm_ring_free_output (size:128b/16B) */
--
2.47.1
^ permalink raw reply related
* [PATCH net] net/stmmac: Set Rx queue page_pool to NULL when freeing DMA resources
From: Jakub Raczynski @ 2026-06-30 10:09 UTC (permalink / raw)
To: netdev
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
linux-kernel, k.tegowski, k.domagalski, Jakub Raczynski,
Yashwant Varur
In-Reply-To: <CGME20260630101157eucas1p1b1cef0db9381391bdd9400f1d255ce49@eucas1p1.samsung.com>
When freeing RX descriptor resources, there is standard clearing of
descriptor page_pool via page_pool_destroy() which does destroy
page but does not set its pointer to NULL, which must be done by driver
calling this function.
It is not done in __free_dma_rx_desc_resources() when stopping interface,
which is generally not an issue, because __alloc_dma_rx_desc_resources() does
setup this regardless of previous state.
But above is true assuming reinitialization is successful.
In case of failure of page_pool_create() in __alloc_dma_rx_desc_resources(),
all non-NULL pages will be freed, including those already cleared.
So there is possible kernel panic due to wrong paging request at address.
Fix this by assigning NULL to page_pool pointer on free
Fixes: da5ec7f22a0f1 ("net: stmmac: refactor stmmac_init_rx_buffers for stmmac_reinit_rx_buffers")
Signed-off-by: Yashwant Varur <yashwant.v@samsung.com>
Signed-off-by: Jakub Raczynski <j.raczynski@samsung.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3591755ea30b..4b8f2814d3b5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2172,8 +2172,10 @@ static void __free_dma_rx_desc_resources(struct stmmac_priv *priv,
xdp_rxq_info_unreg(&rx_q->xdp_rxq);
kfree(rx_q->buf_pool);
- if (rx_q->page_pool)
+ if (rx_q->page_pool) {
page_pool_destroy(rx_q->page_pool);
+ rx_q->page_pool = NULL;
+ }
}
static void free_dma_rx_desc_resources(struct stmmac_priv *priv,
--
2.34.1
^ permalink raw reply related
* [PATCH v2] selftests/net/openvswitch: add output truncation test
From: Minxi Hou @ 2026-06-30 10:22 UTC (permalink / raw)
To: netdev; +Cc: Minxi Hou, aconole, echaudro, linux-kselftest
Add test_trunc exercising the OVS_ACTION_ATTR_TRUNC action. The test
verifies truncation in three steps: first confirm normal forwarding
works, then apply trunc(14) which truncates packets to the Ethernet
header and verify ping fails, then restore normal forwarding and
verify connectivity recovers.
The trunc action sets OVS_CB(skb)->cutlen, causing pskb_trim at
output time. With trunc(14) the IP payload is stripped, so the
receiver drops the frame and ICMP echo reply is never generated.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
---
.../selftests/net/openvswitch/openvswitch.sh | 66 +++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh
index 2954245129a2..fef21eb4a129 100755
--- a/tools/testing/selftests/net/openvswitch/openvswitch.sh
+++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh
@@ -32,6 +32,7 @@ tests="
dec_ttl ttl: dec_ttl decrements IP TTL
flow_set flow-set: Flow modify
action_set set: SET action rewrites fields
+ trunc trunc: output truncation
psample psample: Sampling packets with psample"
info() {
@@ -443,6 +444,71 @@ test_action_set() {
return 0
}
+test_trunc() {
+ sbx_add "test_trunc" || return $?
+ ovs_add_dp "test_trunc" trunctest || return 1
+
+ info "create namespaces"
+ for ns in client server; do
+ ovs_add_netns_and_veths "test_trunc" "trunctest" "$ns" \
+ "${ns:0:1}0" "${ns:0:1}1" || return 1
+ done
+
+ ip netns exec client ip addr add 10.0.0.1/24 dev c1
+ ip netns exec client ip link set c1 up
+ ip netns exec server ip addr add 10.0.0.2/24 dev s1
+ ip netns exec server ip link set s1 up
+
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
+
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
+
+ info "verify connectivity without truncation"
+ ovs_sbx "test_trunc" ip netns exec client ping -c 1 -W 2 \
+ 10.0.0.2 || return 1
+
+ ovs_del_flows "test_trunc" trunctest
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
+
+ info "add truncated forwarding flow"
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(1),eth(),eth_type(0x0800),ipv4()' \
+ 'trunc(14),2' || return 1
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
+
+ info "verify ping fails with truncation"
+ ovs_sbx "test_trunc" ip netns exec client ping -c 1 -W 2 \
+ 10.0.0.2 >/dev/null 2>&1 \
+ && { info "FAIL: ping should fail with trunc(14)"
+ return 1; }
+
+ ovs_del_flows "test_trunc" trunctest
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(1),eth(),eth_type(0x0806),arp()' '2' || return 1
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(2),eth(),eth_type(0x0806),arp()' '1' || return 1
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(1),eth(),eth_type(0x0800),ipv4()' '2' || return 1
+ ovs_add_flow "test_trunc" trunctest \
+ 'in_port(2),eth(),eth_type(0x0800),ipv4()' '1' || return 1
+
+ info "verify connectivity restored without truncation"
+ ovs_sbx "test_trunc" ip netns exec client ping -c 1 -W 2 \
+ 10.0.0.2 || return 1
+
+ return 0
+}
+
# psample test
# - use psample to observe packets
test_psample() {
base-commit: cef9d6804030793cf8b8796fd6936197d065dd3e
--
2.54.0
^ permalink raw reply related
* [PATCH v3] selftests/net/openvswitch: add ICMPv6 echo type match test
From: Minxi Hou @ 2026-06-30 10:22 UTC (permalink / raw)
To: netdev; +Cc: Minxi Hou, aconole, echaudro, linux-kselftest
Register OVS_KEY_ATTR_ICMPV6 in the flow key parser so that
icmpv6(type=...) can be used in flow specifications. Without this
registration the parser silently drops the token and the kernel
rejects the flow with EINVAL because the expected ICMPv6 key
attribute is missing.
While here, add convert_int() to the ovs_key_ipv6 and ovs_key_icmp
fields_map entries so that specifying a field value produces the
correct wildcard mask. The IPv6 flow label uses convert_int(20) to
produce a 20-bit mask (0x000FFFFF), matching the kernel constraint in
flow_netlink.c that rejects masks with bits 20-31 set; byte-wide
fields use convert_int(8). The ipv4 counterpart already does this via
convert_int(); the ipv6 and icmp classes were simply missing the fifth
tuple element. Existing callers that pass empty parentheses are
unaffected because convert_int("") returns (0, 0).
Add test_icmpv6 exercising the ICMPv6 echo flow key. The test uses
static neighbour entries to bypass NDP, then verifies in three steps:
install icmpv6(type=128) and icmpv6(type=129) flows and confirm ping
works, remove the flows and confirm ping fails, reinstall and confirm
recovery.
Signed-off-by: Minxi Hou <houminxi@gmail.com>
---
.../selftests/net/openvswitch/openvswitch.sh | 63 +++++++++++++++++++
.../selftests/net/openvswitch/ovs-dpctl.py | 26 +++++---
2 files changed, 82 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/net/openvswitch/openvswitch.sh b/tools/testing/selftests/net/openvswitch/openvswitch.sh
index 2954245129a2..2de01137bb50 100755
--- a/tools/testing/selftests/net/openvswitch/openvswitch.sh
+++ b/tools/testing/selftests/net/openvswitch/openvswitch.sh
@@ -32,6 +32,7 @@ tests="
dec_ttl ttl: dec_ttl decrements IP TTL
flow_set flow-set: Flow modify
action_set set: SET action rewrites fields
+ icmpv6 icmpv6: ICMPv6 echo type match
psample psample: Sampling packets with psample"
info() {
@@ -443,6 +444,68 @@ test_action_set() {
return 0
}
+test_icmpv6() {
+ sbx_add "test_icmpv6" || return $?
+ ovs_add_dp "test_icmpv6" icmpv6 || return 1
+
+ info "create namespaces"
+ for ns in client server; do
+ ovs_add_netns_and_veths "test_icmpv6" "icmpv6" \
+ "$ns" "${ns:0:1}0" "${ns:0:1}1" || return 1
+ done
+
+ ip netns exec client ip addr add fd00::1/64 dev c1 nodad
+ ip netns exec client ip link set c1 up
+ ip netns exec server ip addr add fd00::2/64 dev s1 nodad
+ ip netns exec server ip link set s1 up
+
+ local cl_mac sl_mac
+ cl_mac=$(ip netns exec client \
+ ip link show c1 | awk '/link\/ether/ {print $2}')
+ [ -z "$cl_mac" ] && \
+ { info "failed to get c1 hwaddr"; return 1; }
+ sl_mac=$(ip netns exec server \
+ ip link show s1 | awk '/link\/ether/ {print $2}')
+ [ -z "$sl_mac" ] && \
+ { info "failed to get s1 hwaddr"; return 1; }
+ ip netns exec client \
+ ip -6 neigh add fd00::2 lladdr "$sl_mac" dev c1
+ ip netns exec server \
+ ip -6 neigh add fd00::1 lladdr "$cl_mac" dev s1
+
+ ovs_add_flow "test_icmpv6" icmpv6 \
+ 'in_port(1),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6(type=128)' \
+ '2' || return 1
+ ovs_add_flow "test_icmpv6" icmpv6 \
+ 'in_port(2),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6(type=129)' \
+ '1' || return 1
+
+ info "verify ICMPv6 echo with type-specific flows"
+ ovs_sbx "test_icmpv6" ip netns exec client \
+ ping -6 -c 1 -W 2 fd00::2 || return 1
+
+ ovs_del_flows "test_icmpv6" icmpv6
+
+ info "verify ping fails without echo flows"
+ ovs_sbx "test_icmpv6" ip netns exec client \
+ ping -6 -c 1 -W 2 fd00::2 >/dev/null 2>&1 \
+ && { info "FAIL: ping should fail without flows"
+ return 1; }
+
+ ovs_add_flow "test_icmpv6" icmpv6 \
+ 'in_port(1),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6(type=128)' \
+ '2' || return 1
+ ovs_add_flow "test_icmpv6" icmpv6 \
+ 'in_port(2),eth(),eth_type(0x86dd),ipv6(proto=58),icmpv6(type=129)' \
+ '1' || return 1
+
+ info "verify connectivity restored"
+ ovs_sbx "test_icmpv6" ip netns exec client \
+ ping -6 -c 1 -W 2 fd00::2 || return 1
+
+ return 0
+}
+
# psample test
# - use psample to observe packets
test_psample() {
diff --git a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
index e1ecfad2c03e..f3edd198223f 100644
--- a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
+++ b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
@@ -1255,11 +1255,16 @@ class ovskey(nla):
lambda x: ipaddress.IPv6Address(x).packed if x else 0,
convert_ipv6,
),
- ("label", "label", "%d", lambda x: int(x) if x else 0),
- ("proto", "proto", "%d", lambda x: int(x) if x else 0),
- ("tclass", "tclass", "%d", lambda x: int(x) if x else 0),
- ("hlimit", "hlimit", "%d", lambda x: int(x) if x else 0),
- ("frag", "frag", "%d", lambda x: int(x) if x else 0),
+ ("label", "label", "%d", lambda x: int(x) if x else 0,
+ convert_int(20)),
+ ("proto", "proto", "%d", lambda x: int(x) if x else 0,
+ convert_int(8)),
+ ("tclass", "tclass", "%d", lambda x: int(x) if x else 0,
+ convert_int(8)),
+ ("hlimit", "hlimit", "%d", lambda x: int(x) if x else 0,
+ convert_int(8)),
+ ("frag", "frag", "%d", lambda x: int(x) if x else 0,
+ convert_int(8)),
)
def __init__(
@@ -1344,8 +1349,10 @@ class ovskey(nla):
)
fields_map = (
- ("type", "type", "%d", lambda x: int(x) if x else 0),
- ("code", "code", "%d", lambda x: int(x) if x else 0),
+ ("type", "type", "%d", lambda x: int(x) if x else 0,
+ convert_int(8)),
+ ("code", "code", "%d", lambda x: int(x) if x else 0,
+ convert_int(8)),
)
def __init__(
@@ -1982,6 +1989,11 @@ class ovskey(nla):
"icmp",
ovskey.ovs_key_icmp,
),
+ (
+ "OVS_KEY_ATTR_ICMPV6",
+ "icmpv6",
+ ovskey.ovs_key_icmpv6,
+ ),
(
"OVS_KEY_ATTR_TCP_FLAGS",
"tcp_flags",
base-commit: cef9d6804030793cf8b8796fd6936197d065dd3e
--
2.54.0
^ permalink raw reply related
* Re: [PATCH net-next v11 1/7] dt-bindings: phy: document the serdes PHY on sa8255p
From: Vinod Koul @ 2026-06-30 10:23 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Bartosz Golaszewski, Bjorn Andersson, Konrad Dybcio, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Maxime Coquelin,
Alexandre Torgue, Giuseppe Cavallaro, Chen-Yu Tsai,
Jernej Skrabec, Neil Armstrong, Kevin Hilman, Jerome Brunet,
Shawn Guo, Fabio Estevam, Jan Petrous, s32, Mohd Ayaan Anwar,
Romain Gantois, Magnus Damm, Maxime Ripard, Christophe Roullier,
Radu Rendec, linux-arm-msm, devicetree, linux-kernel, netdev,
linux-stm32, linux-arm-kernel, Drew Fustini, linux-sunxi,
linux-amlogic, linux-mips, imx, linux-renesas-soc, linux-rockchip,
sophgo, linux-riscv, Bartosz Golaszewski, Bartosz Golaszewski
In-Reply-To: <CAMuHMdVUBgG0EFB16OxHisbxx-sBvDKvBPNZdpyDnmBrnX4ptQ@mail.gmail.com>
On 29-06-26, 16:51, Geert Uytterhoeven wrote:
> > Russell King asked me to put the PHY logic for SCMI pm domains into the PHY
> > driver instead of the MAC driver where it was previously. Instead of cramming
> > both HLOS and firmware handling into the same driver, I figured it makes more
> > sense to have a dedicated, cleaner driver as the two share very little code (if
> > any).
>
> I think you are mixing up DT bindings and driver implementation?
Should the bindings change if we have different driver and firmware
implementations? Isn't binding supposed to be agnostic of
implementations..?
--
~Vinod
^ permalink raw reply
* Re: [PATCH net-next v11 1/7] dt-bindings: phy: document the serdes PHY on sa8255p
From: Geert Uytterhoeven @ 2026-06-30 10:18 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
Vinod Koul, Giuseppe Cavallaro, Chen-Yu Tsai, Jernej Skrabec,
Neil Armstrong, Kevin Hilman, Jerome Brunet, Shawn Guo,
Fabio Estevam, Jan Petrous, s32, Mohd Ayaan Anwar, Romain Gantois,
Magnus Damm, Maxime Ripard, Christophe Roullier, Radu Rendec,
linux-arm-msm, devicetree, linux-kernel, netdev, linux-stm32,
linux-arm-kernel, Drew Fustini, linux-sunxi, linux-amlogic,
linux-mips, imx, linux-renesas-soc, linux-rockchip, sophgo,
linux-riscv, Bartosz Golaszewski, Bartosz Golaszewski
In-Reply-To: <CAMRc=Meb58KCuLXkNSJwUq6KJUzZv0u49FBA2L4C8Vd3NVo8Cg@mail.gmail.com>
Hi Bartosz,
On Mon, 29 Jun 2026 at 18:54, Bartosz Golaszewski <brgl@kernel.org> wrote:
> On Mon, Jun 29, 2026 at 4:58 PM Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > On Mon, 29 Jun 2026 at 16:07, Bartosz Golaszewski <brgl@kernel.org> wrote:
> > > On Mon, 29 Jun 2026 15:51:31 +0200, Geert Uytterhoeven
> > > <geert@linux-m68k.org> said:
> > > > On Mon, 29 Jun 2026 at 13:29, Bartosz Golaszewski
> > > > <bartosz.golaszewski@oss.qualcomm.com> wrote:
> > > >> Describe the SGMII/SerDes PHY present on the Qualcomm sa8255p platforms.
> > > >> This is essentially the same hardware as sa8775p rev3 but the PHY is
> > > >> managed by firmware over SCMI.
> > > >
> > > > So why can't it be reuse the DT bindings, and be compatible with
> > > > qcom,sa8775p-dwmac-sgmii-phy?
> > > >
> > > >> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> > > >
> > > >> --- /dev/null
> > > >> +++ b/Documentation/devicetree/bindings/phy/qcom,sa8255p-dwmac-sgmii-phy.yaml
> > > >
> > > >> + power-domains:
> > > >> + maxItems: 1
> > > >> +
> > > >> + power-domain-names:
> > > >> + items:
> > > >> + - const: serdes
> > > >
> > > >> +examples:
> > > >> + - |
> > > >> + phy@8901000 {
> > > >> + compatible = "qcom,sa8255p-dwmac-sgmii-phy";
> > > >> + reg = <0x08901000 0xe10>;
> > > >> + #phy-cells = <0>;
> > > >> + power-domains = <&scmi7_dvfs 0>;
> > > >> + power-domain-names = "serdes";
> > > >
> > > > Ah, this uses power-domains, while the existing bindings for
> > > > qcom,sa8775p-dwmac-sgmii-phy use a clock.
> > > > I guess the clock is the correct hardware description?
> > > >
> > > > Adding to my list of examples for backing a hardware-to-SCMI remapping
> > > > driver...
> > > >
> > >
> > > Russell King asked me to put the PHY logic for SCMI pm domains into the PHY
> > > driver instead of the MAC driver where it was previously. Instead of cramming
> > > both HLOS and firmware handling into the same driver, I figured it makes more
> > > sense to have a dedicated, cleaner driver as the two share very little code (if
> > > any).
> >
> > I think you are mixing up DT bindings and driver implementation?
>
> Ah indeed, but the bindings don't share a lot of content either.
That's the (maintenance) problem: it is essentially the same hardware,
but the DT bindings (and driver) are different. Does this scale?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH] net: usb: cx82310_eth: stop parsing reboot marker as packet
From: Tianchu Chen @ 2026-06-30 10:30 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: andrew+netdev, davem, edumazet, pabeni, linux-usb, netdev
In-Reply-To: <20260629174458.6ebf647d@kernel.org>
June 30, 2026 at 8:44 AM, "Jakub Kicinski" <kuba@kernel.org mailto:kuba@kernel.org?to=%22Jakub%20Kicinski%22%20%3Ckuba%40kernel.org%3E > wrote:
>
> On Thu, 25 Jun 2026 15:32:04 +0000 Tianchu Chen wrote:
>
> >
> > From: Tianchu Chen <flynnnchen@tencent.com>
> >
> > Discovered by Atuin - Automated Vulnerability Discovery Engine.
> >
> > cx82310_rx_fixup() treats an RX length of 0xffff as a device reboot
> > marker and schedules work to re-enable ethernet mode, but then continues
> > processing the marker as a normal packet length. This is an out-of-bounds
> > heap write controlled by the usb device.
> >
> Where? Can you be more specific in the commit message? At a glance
> the accesses seem to be bound-checked with skb->len.
> --
> pw-bot: cr
>
The "len > skb->len" check bounds the source read, but the overflow is on the
destination buffer.
The buggy path is:
if (len == 0xffff) {
netdev_info(dev->net, "router was rebooted, re-enabling ethernet mode");
schedule_work(&priv->reenable_work);
/* <- BUG: missing return; 0xffff bypasses the oversized-length reject */
} else if (len > CX82310_MTU) {
netdev_err(dev->net, "RX packet too long: %d B\n", len);
return 0;
}
if (len > skb->len) {
dev->partial_len = skb->len; // skb->len is bounded by the USB transfer size (4K)
dev->partial_rem = len - skb->len;
memcpy((void *)dev->partial_data, skb->data,
dev->partial_len); /* <- TRIGGER: can copy 4K bytes into 1516-byte partial_data */
...
...
}
For normal oversized lengths, the len > CX82310_MTU branch rejects
before this copy. But 0xffff is special-cased and falls through. With a
4096-byte RX URB, after the 2-byte length header is pulled, skb->len can
be 4094, while partial_data is allocated as dev->hard_mtu
(CX82310_MTU + 2, 1516 bytes).
So the source read is bounded by skb->len; the destination write is not.
I am happy to send a v2 with this spelled out more clearly in the commit message
if needed.
Best regards,
Tianchu Chen
^ permalink raw reply
* Re: [PATCH RESEND net-next] net: airoha: Make use of the helper function dev_err_probe()
From: Lorenzo Bianconi @ 2026-06-30 10:38 UTC (permalink / raw)
To: Lei Zhu; +Cc: andrew+netdev, davem, edumazet, kuba, pabeni, netdev
In-Reply-To: <20260630015247.43322-1-zhulei_szu@163.com>
[-- Attachment #1: Type: text/plain, Size: 2262 bytes --]
> From: Lei Zhu <zhulei@kylinos.cn>
>
> Use dev_err_probe() to reduce code size and simplify the code.
>
> Signed-off-by: Lei Zhu <zhulei@kylinos.cn>
> ---
> The last submission was when net-next is closed.Resending it.
>
> drivers/net/ethernet/airoha/airoha_eth.c | 21 +++++++++------------
> 1 file changed, 9 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 31cdb11cd78d..189f64e83a46 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -3071,10 +3071,9 @@ static int airoha_probe(struct platform_device *pdev)
> eth->dev = &pdev->dev;
>
> err = dma_set_mask_and_coherent(eth->dev, DMA_BIT_MASK(32));
I do not think dma_set_mask_and_coherent() can return -EPROBE_DEFER, so there
is no point adding dev_err_probe() here.
Regards,
Lorenzo
> - if (err) {
> - dev_err(eth->dev, "failed configuring DMA mask\n");
> - return err;
> - }
> + if (err)
> + return dev_err_probe(eth->dev, err,
> + "failed configuring DMA mask\n");
>
> eth->fe_regs = devm_platform_ioremap_resource_byname(pdev, "fe");
> if (IS_ERR(eth->fe_regs))
> @@ -3087,10 +3086,9 @@ static int airoha_probe(struct platform_device *pdev)
> err = devm_reset_control_bulk_get_exclusive(eth->dev,
> ARRAY_SIZE(eth->rsts),
> eth->rsts);
> - if (err) {
> - dev_err(eth->dev, "failed to get bulk reset lines\n");
> - return err;
> - }
> + if (err)
> + return dev_err_probe(eth->dev, err,
> + "failed to get bulk reset lines\n");
>
> xsi_rsts = devm_kcalloc(eth->dev,
> eth->soc->num_xsi_rsts, sizeof(*xsi_rsts),
> @@ -3105,10 +3103,9 @@ static int airoha_probe(struct platform_device *pdev)
> err = devm_reset_control_bulk_get_exclusive(eth->dev,
> eth->soc->num_xsi_rsts,
> eth->xsi_rsts);
> - if (err) {
> - dev_err(eth->dev, "failed to get bulk xsi reset lines\n");
> - return err;
> - }
> + if (err)
> + return dev_err_probe(eth->dev, err,
> + "failed to get bulk xsi reset lines\n");
>
> eth->napi_dev = alloc_netdev_dummy(0);
> if (!eth->napi_dev)
> --
> 2.25.1
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
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