Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next] gtp: annotate PDP lookups under RTNL
From: Simon Horman @ 2026-07-08 19:04 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: Pablo Neira Ayuso, Runyu Xiao, laforge, andrew+netdev, davem,
	edumazet, kuba, osmocom-net-gprs, netdev, linux-kernel,
	jianhao.xu
In-Reply-To: <20260708183252.GL1364329@horms.kernel.org>

On Wed, Jul 08, 2026 at 07:32:52PM +0100, Simon Horman wrote:
> On Wed, Jul 08, 2026 at 01:10:58PM +0200, Paolo Abeni wrote:
> > On 7/8/26 12:35 PM, Simon Horman wrote:
> > > On Tue, Jul 07, 2026 at 04:51:12PM +0200, Pablo Neira Ayuso wrote:

...

> > >> I think this patch is not correct.
> > > 
> > > Hi Pablo,
> > > 
> > > Of course you are correct.
> > > Sorry for not realising this earlier.
> > 
> > Human slop here made me wrongly apply this patch. Could either of you
> > please share a formal revert?
> 
> Sure, will do.

- [PATCH net-next] Revert "gtp: annotate PDP lookups under RTNL"
  https://lore.kernel.org/netdev/20260708-gtp-rtnl-v1-1-218091f171bc@kernel.org/T/

^ permalink raw reply

* Re: [PATCH v12 nf-next 7/7] netfilter: nft_flow_offload: Add bridgeflow to nft_flow_offload_eval()
From: Eric Woudstra @ 2026-07-08 19:14 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Florian Westphal, Phil Sutter,
	Nikolay Aleksandrov, Ido Schimmel, Kuniyuki Iwashima,
	Stanislav Fomichev, Samiullah Khawaja, Hangbin Liu, Krishna Kumar,
	Martin Karsten, netdev, netfilter-devel, bridge
In-Reply-To: <ak4d89hkh0Jvcp2W@chamomile>



On 7/8/26 11:52 AM, Pablo Neira Ayuso wrote:
> Hi,
> 
> On Tue, Jul 07, 2026 at 11:10:45AM +0200, Eric Woudstra wrote:
>> Edit nft_flow_offload_eval() to make it possible to handle a flowtable of
>> the nft bridge family.
>>
>> Use nft_flow_offload_bridge_init() to fill the flow tuples. It uses
>> nft_dev_fill_bridge_path() in each direction.
> 
> I decided to add a bit more boiler plate in my proposal to detach the
> inet and bridge flowtable dataplanes.
> 
> More comments below.
> 
>> Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
>> ---
>>  include/net/netfilter/nf_flow_table.h |   5 +
>>  net/netfilter/nf_flow_table_path.c    | 126 ++++++++++++++++++++++++++
>>  net/netfilter/nft_flow_offload.c      |  20 +++-
>>  3 files changed, 146 insertions(+), 5 deletions(-)
>>
>> diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
>> index 5c6e3b65ae85b..a109eda5250c7 100644
>> --- a/include/net/netfilter/nf_flow_table.h
>> +++ b/include/net/netfilter/nf_flow_table.h
>> @@ -305,6 +305,11 @@ nf_flow_table_offload_del_cb(struct nf_flowtable *flow_table,
>>  void flow_offload_route_init(struct flow_offload *flow,
>>  			     struct nf_flow_route *route);
>>  
>> +int flow_offload_bridge_init(struct flow_offload *flow,
>> +			     const struct nft_pktinfo *pkt,
>> +			     enum ip_conntrack_dir dir,
>> +			     struct nft_flowtable *ft);
>> +
>>  int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
>>  void flow_offload_refresh(struct nf_flowtable *flow_table,
>>  			  struct flow_offload *flow, bool force);
>> diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
>> index 2b6ebb594a9ee..cdd6a822cb811 100644
>> --- a/net/netfilter/nf_flow_table_path.c
>> +++ b/net/netfilter/nf_flow_table_path.c
>> @@ -1,6 +1,7 @@
>>  // SPDX-License-Identifier: GPL-2.0-only
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>> +#include <linux/if_vlan.h>
>>  #include <linux/init.h>
>>  #include <linux/etherdevice.h>
>>  #include <linux/netlink.h>
>> @@ -365,3 +366,128 @@ int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
>>  	return -ENOENT;
>>  }
>>  EXPORT_SYMBOL_GPL(nft_flow_route);
>> +
>> +static int nft_dev_fill_bridge_path(struct flow_offload *flow,
>> +				    struct nft_flowtable *ft,
>> +				    enum ip_conntrack_dir dir,
>> +				    const struct net_device *src_dev,
>> +				    const struct net_device *dst_dev,
>> +				    unsigned char *src_ha,
>> +				    unsigned char *dst_ha)
>> +{
>> +	struct flow_offload_tuple_rhash *th = flow->tuplehash;
>> +	struct net_device_path_ctx ctx = {};
>> +	struct net_device_path_stack stack;
>> +	struct nft_forward_info info = {};
>> +	int i, j = 0;
>> +
>> +	for (i = th[dir].tuple.encap_num - 1; i >= 0 ; i--) {
>> +		if (info.num_encaps >= NF_FLOW_TABLE_ENCAP_MAX)
>> +			return -1;
>> +
>> +		if (th[dir].tuple.in_vlan_ingress & BIT(i))
>> +			continue;
>> +
>> +		info.encap[info.num_encaps].id = th[dir].tuple.encap[i].id;
>> +		info.encap[info.num_encaps].proto = th[dir].tuple.encap[i].proto;
>> +		info.num_encaps++;
>> +
>> +		if (th[dir].tuple.encap[i].proto == htons(ETH_P_PPP_SES))
>> +			continue;
>> +
>> +		if (ctx.num_vlans >= NET_DEVICE_PATH_VLAN_MAX)
>> +			return -1;
>> +		ctx.vlan[ctx.num_vlans].id = th[dir].tuple.encap[i].id;
>> +		ctx.vlan[ctx.num_vlans].proto = th[dir].tuple.encap[i].proto;
>> +		ctx.num_vlans++;
>> +	}
> 
> I am not sure why this is needed, in my approach I simplified this,
> but maybe I broke bridge vlan filtering. I am not sure what test
> coverage you made.
> 

This part is used for handling packets that are incoming with encaps.
Previously I got the encaps from the skb and stored them in
th[dir].tuple.encap. I understand you want to do this differently.
It is also why I'm starting in the opposite direction as in you patch-set.

The code above then reads th[dir].tuple.encap and starts filling info
and ctx with encaps. It also handles encaps marked with a
in_vlan_ingress bit. Once info and ctx are filled with the encaps from
the skb, it can continue with dev_fill_bridge_path().

My selftest script bridge_fastpath.sh tests this code thoroughly in many
different scenarios. Incoming vlan, q-in-q, ad, pppoe, pppoe-in-q. Also
on a dsa-port with the in_vlan_ingress bit set.

>> +	ctx.dev = src_dev;
>> +	ether_addr_copy(ctx.daddr, dst_ha);
>> +
>> +	if (dev_fill_bridge_path(&ctx, &stack) < 0)
>> +		return -1;
>> +
>> +	nft_dev_path_info(&stack, &info, dst_ha, &ft->data);
>> +
>> +	if (!info.indev || info.indev != dst_dev)
>> +		return -1;
>> +
>> +	th[!dir].tuple.iifidx = info.indev->ifindex;
>> +	for (i = info.num_encaps - 1; i >= 0; i--) {
>> +		th[!dir].tuple.encap[j].id = info.encap[i].id;
>> +		th[!dir].tuple.encap[j].proto = info.encap[i].proto;
>> +		if (info.ingress_vlans & BIT(i))
>> +			th[!dir].tuple.in_vlan_ingress |= BIT(j);
>> +		j++;
>> +	}
>> +	th[!dir].tuple.encap_num = info.num_encaps;
>> +
>> +	th[dir].tuple.mtu = dst_dev->mtu;
>> +	ether_addr_copy(th[dir].tuple.out.h_source, src_ha);
>> +	ether_addr_copy(th[dir].tuple.out.h_dest, dst_ha);
>> +	th[dir].tuple.out.ifidx = info.outdev->ifindex;
>> +	th[dir].tuple.xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
>> +
>> +	return 0;
>> +}
>> +
>> +int flow_offload_bridge_init(struct flow_offload *flow,
>> +			     const struct nft_pktinfo *pkt,
>> +			     enum ip_conntrack_dir dir,
>> +			     struct nft_flowtable *ft)
>> +{
>> +	const struct net_device *in_dev, *out_dev;
>> +	struct ethhdr *eth = eth_hdr(pkt->skb);
>> +	struct flow_offload_tuple *tuple;
>> +	int err, i = 0;
>> +
>> +	in_dev = nft_in(pkt);
>> +	if (!in_dev || !nft_flowtable_find_dev(in_dev, ft))
>> +		return -1;
>> +
>> +	out_dev = nft_out(pkt);
>> +	if (!out_dev || !nft_flowtable_find_dev(out_dev, ft))
>> +		return -1;
>> +
>> +	tuple =  &flow->tuplehash[!dir].tuple;
>> +
>> +	if (skb_vlan_tag_present(pkt->skb)) {
>> +		tuple->encap[i].id = skb_vlan_tag_get(pkt->skb);
>> +		tuple->encap[i].proto = pkt->skb->vlan_proto;
>> +		i++;
>> +	}
>> +
>> +	switch (eth_hdr(pkt->skb)->h_proto) {
>> +	case htons(ETH_P_8021Q): {
>> +		struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb_mac_header(pkt->skb)
>> +					 + sizeof(struct ethhdr));
>> +		tuple->encap[i].id = ntohs(vhdr->h_vlan_TCI);
>> +		tuple->encap[i].proto = htons(ETH_P_8021Q);
>> +		i++;
>> +		break;
>> +	}
>> +	case htons(ETH_P_PPP_SES): {
>> +		struct pppoe_hdr *phdr = (struct pppoe_hdr *)(skb_mac_header(pkt->skb)
>> +					  + sizeof(struct ethhdr));
>> +
>> +		tuple->encap[i].id = ntohs(phdr->sid);
>> +		tuple->encap[i].proto = htons(ETH_P_PPP_SES);
>> +		i++;
>> +		break;
>> +	}
>> +	}
>> +	tuple->encap_num = i;
> 
> I am not sure these lines above can work. The VLAN tag might be
> already gone by when the packet is observed from the bridge/forward
> hook. I think populating the encap fields of the tuple by using the
> observed packet is not good to go.
> 

I have not experienced this, but I understand that this is no guarantee
that it does not happen at all.

>> +	err = nft_dev_fill_bridge_path(flow, ft, !dir, out_dev, in_dev,
>> +				       eth->h_dest, eth->h_source);
>> +	if (err < 0)
>> +		return err;
>> +
>> +	err = nft_dev_fill_bridge_path(flow, ft, dir, in_dev, out_dev,
>> +				       eth->h_source, eth->h_dest);
>> +	if (err < 0)
>> +		return err;
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(flow_offload_bridge_init);
>> diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
>> index 0be62841155b6..d0d63ef7cecd5 100644
>> --- a/net/netfilter/nft_flow_offload.c
>> +++ b/net/netfilter/nft_flow_offload.c
>> @@ -53,6 +53,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
>>  {
>>  	struct nft_flow_offload *priv = nft_expr_priv(expr);
>>  	struct nf_flowtable *flowtable = &priv->flowtable->data;
>> +	bool routing = flowtable->type->family != NFPROTO_BRIDGE;
>>  	struct tcphdr _tcph, *tcph = NULL;
>>  	struct nf_flow_route route = {};
>>  	enum ip_conntrack_info ctinfo;
>> @@ -109,14 +110,21 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
>>  		goto out;
>>  
>>  	dir = CTINFO2DIR(ctinfo);
>> -	if (nft_flow_route(pkt, ct, &route, dir, priv->flowtable) < 0)
>> -		goto err_flow_route;
>> +	if (routing) {
>> +		if (nft_flow_route(pkt, ct, &route, dir, priv->flowtable) < 0)
>> +			goto err_flow_route;
>> +	}
> 
> As said, I am leaning towards adding a bit more boilerplate code to
> separate the bridge and inet flowtable datapaths.
> 
>>  	flow = flow_offload_alloc(ct);
>>  	if (!flow)
>>  		goto err_flow_alloc;
>>  
>> -	flow_offload_route_init(flow, &route);
>> +	if (routing)
>> +		flow_offload_route_init(flow, &route);
>> +	else
>> +		if (flow_offload_bridge_init(flow, pkt, dir, priv->flowtable) < 0)
>> +			goto err_flow_add;
>> +
>>  	if (tcph)
>>  		flow_offload_ct_tcp(ct);
>>  
>> @@ -164,8 +172,10 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
>>  err_flow_add:
>>  	flow_offload_free(flow);
>>  err_flow_alloc:
>> -	dst_release(route.tuple[dir].dst);
>> -	dst_release(route.tuple[!dir].dst);
>> +	if (routing) {
>> +		dst_release(route.tuple[dir].dst);
>> +		dst_release(route.tuple[!dir].dst);
>> +	}
>>  err_flow_route:
>>  	clear_bit(IPS_OFFLOAD_BIT, &ct->status);
>>  out:
>> -- 
>> 2.53.0
>>


^ permalink raw reply

* Re: [PATCH net-next] net/mlx5e: bound TX CQ poll softirq residency with a time budget
From: Jose Fernandez (Anthropic) @ 2026-07-08 19:32 UTC (permalink / raw)
  To: Dragos Tatulea
  Cc: Saeed Mahameed, Tariq Toukan, Mark Bloch, Leon Romanovsky,
	Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, netdev, linux-rdma, linux-kernel, Ben Cressey
In-Reply-To: <5557a08f-6d53-4425-8004-b7f0bbcd8a50@nvidia.com>

Hi Dragos,

Thanks for the review.

On Mon, Jul 06, 2026 at 01:48:41PM +0200, Dragos Tatulea wrote:
> This is interesting. I can think of 2 cases here which can overlap:
>
> 1) Packets are sent with xmit_more which trigger this many WQEs per
>   CQE scenario.
>
> 2) TSO packets can have many fragments so even a single WQE will have
>    more than one DMA unmap. For the default GSO size of 64K each TSO
>    skb will have 2 fragments on your platform. If the GSO is bumped to
>    256K then you usually get ~5 fragments.
>
> Let's first understand if this is a case of 1) (small packets sent
> with xmit_more) or 2) (many TSO packets) or 1+2) (many TSO packets sent
> with xmit_more).

Likely both, mostly 1). The workload is bursty bulk transfers, and
the stalls hit while processing a burst's completions: one CQE covers
a whole xmit_more batch, each TSO skb adds its 2 frag unmaps, so the
CQE budget bounds entries but not the unmap work behind them.

I don't have the tx_xmit_more / tx_tso_packets ratios handy. I'll
collect them across a burst window and report back.

> If xmit_more is used then you can actually tune the BQL to avoid this
> behavior which seems to wreak havoc on your configuration.

We considered that. BQL bounds bytes in flight, but bytes only
translate into poll time at some assumed per-unmap cost, and that
cost is the unstable part here: a few us normally, ~100x worse when
many CPUs contend on the shared SMMU command queue. A BQL setting
small enough for the worst case would hurt throughput the rest of
the time.

> The bounded poll is faster because it is interrupted earlier or is
> it faster because it results in less contention on the IOMMU?

Both, and we tried to separate them. Sweeping the yield cadence
barely moves the numbers, so it is not just doing less per poll. And
in A/B runs with the budget armed, the competing side's per-unmap
cost drops 15-20%, so there is a real contention reduction on top of
the transmit path getting the core back sooner.

> This change is too invasive in the driver for all the other cases. We have to figure
> another way to go about this issue.

Fair enough, and the module parameter should not have been there anyway.
The direction I would rather take: fix the cost instead of capping it,
by converting the mlx5e TX path to the tso_dma_map helpers (as bnxt
did), so a TSO skb maps as one IOVA range where the DMA IOVA API is
available, completing with one sync instead of one per frag.

Once the counters confirm the frag-unmap volume I will prototype that,
unless you or Tariq/Saeed see a problem with the direction. Happy to
test on the affected boxes. We have a repro harness.

Thanks,
Jose

^ permalink raw reply

* Re: [PATCH net-next v5 1/4] dt-bindings: net: pse-pd: add bindings for Realtek/Broadcom PSE MCU
From: Jonas Jelonek @ 2026-07-08 19:44 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Oleksij Rempel, Kory Maincent, Andrew Lunn, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
	linux-kernel, Daniel Golle, Bjørn Mork
In-Reply-To: <20260708-lyrically-footrest-10963a12145f@spud>

Hi Conor,

On 08.07.26 18:56, Conor Dooley wrote:
> On Tue, Jul 07, 2026 at 10:50:21PM +0200, Jonas Jelonek wrote:
>> [...]
>> Ok, I hope I put this together correctly. A concrete proposal:
>>
>> "realtek,pse-mcu-gen1"                        (Protocol Gen 1, UART)
>> "realtek,pse-mcu-gen1-smbus"            (Protocol Gen 1, SMBus)
>> "realtek,pse-mcu-gen2"                        (Protocol Gen 2, UART)
>> "realtek,pse-mcu-gen2-i2c"                  (Protocol Gen 2, raw I2C)
>> "realtek,pse-mcu-gen2-smbus"            (Protocol Gen 2, SMBus)
>>
>> This uniquely identifies the protocol used: first generation and second
>> generation. As Rob mentioned before [1], this also pulls in the raw I2C
>> vs. SMBus framing in contrast to having it in a property. The framing
>> suffix appears only on I2C attachments because it doesn't apply to
>> UART transport, and this is given by the parent serial@ node.
>>
>> Though I'm still open for suggestions regarding the protocol
>> identification if "-gen1"/"-gen2" is not acceptable.
> This seems reasonable enough.
>
>> [...]
>>
>> It would also be an exception to the other PSE-PD bindings. They describe
>> controllers used across many switches too, yet none encode the
> The difference is those cases (for what few pse-psd bindings there are)
> the compatibles correspond to individual devices. Here you have
> compatibles you're going to use to cover multiple devices (with device
> corresponding to a combination of mcu/firmware/hardware behind the mcu).
> That lack of a 1:1 mapping is why I'm asking for something different from
> you than you see with the existing pse-pd devices. The switch the device
> is integrated on seems to be the only thing that reasonably makes sense
> to use.
>
>
>> switch/enclosure. Board-specific compatibles might still be added later in
>> case a device really has a variation or quirk that genuinely needs its own
>> compatible.
> And in doing so, have to retrofit that compatible to all devicetrees
> that use it. This is one of the reasons that we generally demand
> device-specific compatibles.
>
> You could add switch-specific compatibles that fall back to the ones you
> provide above, with the driver only using the ones above unless
> something crops up in the future?

Thank you for the thorough explanation. I think I got your point now and
understand why it's required that way.

I'll rework this for the next version.

> Cheers,
> Conor.

Best regards,
Jonas

^ permalink raw reply

* Re: [PATCH RFC net-next 2/3] net: dsa: mxl862xx: add SMDIO clause-22 register access
From: Daniel Golle @ 2026-07-08 19:45 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, netdev
In-Reply-To: <96c362d3-59d2-43c4-b2aa-c12dfeb6fcca@lunn.ch>

On Wed, Jul 08, 2026 at 07:22:49PM +0200, Andrew Lunn wrote:
> On Tue, Jul 07, 2026 at 04:16:07PM +0200, Daniel Golle wrote:
> > Add mxl862xx_smdio_read() and mxl862xx_smdio_write() for clause-22
> > SMDIO register access. MCUboot rescue mode only exposes clause-22
> > registers; the existing clause-45 MMD interface is unavailable during
> > firmware transfer. The MDIO bus lock is held per-transaction (not
> > across polls) so that SB PDI polling during flash erase does not
> > starve other MDIO users.
> 
> What other MDIO users are there? It sounds like once the switch is in
> rescue mode, switch management is dead. So how can there be users?

The MDIO bus lock refers to the host bus which is used to connect
the switch management interface. The same bus can also be used to
connect other unrelated PHYs (eg. to provide a WAN or management
interface independent of the switch).
Especially because this "other" interface can be used to connect
to the host via SSH and perform the firmware update on the switch
holding the MDIO bus lock may impact PHY polling and impair the
link used to conduct the update.
At least that was my thought when implementing this.

^ permalink raw reply

* Re: [PATCH 0/3] SM8450 IPA support
From: Alex Elder @ 2026-07-08 19:49 UTC (permalink / raw)
  To: Esteban Urrutia, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Alex Elder
  Cc: linux-arm-msm, devicetree, linux-kernel, netdev
In-Reply-To: <48c624c3-5408-4862-b4ec-9321ad279bf9@proton.me>

On 6/23/26 8:57 PM, Esteban Urrutia wrote:
> On 6/23/26 11:56 AM, Alex Elder wrote:
>> I assume you have implemented this based on what you found in
>> some downstream code.  And if so, could you please indicate
>> where to find that (so I can do some cross-referencing myself).
>> I no longer have access to any Qualcomm internal documentation.
> 
> Hello. Yes, that would be the case. What I used goes as follows.

Thank you very much for sharing this information.

> 1. My personal findings regarding IPA:
> https://gist.github.com/esteuwu/bd49ed67ed9290f41612bdae1cacb5bc

This was interesting to see.  It's something I should probably
document better.  Most everything maps to the downstream code,
but it's not always completely obvious how, because the upstream
driver has evolved substantially.

> Note that these may be subject to errors since I mostly cross-checked
> values to get here.
> 
> 2. SM8450 downstream device tree:
> https://github.com/LineageOS/android_kernel_qcom_sm8450-devicetrees/blob/lineage-20/qcom/waipio.dtsi#L3304
> 
> 3. SM8475 downstream device tree:
> https://github.com/LineageOS/android_kernel_qcom_sm8450-devicetrees/blob/lineage-20/qcom/cape.dtsi#L2624
> 
> It's worth mentioning that between SM8450 and SM8475, IPA SRAM size is
> different, so I used the smaller SRAM size to support SM8475 as well. Hence
> the reason why I included SM8475's downstream device tree as well.

This means that the SRAM size (ipa_mem_data->smem_size) should
possibly be defined in devicetree (as the IMEM address and size
now are).

The SMEM region is used for "IPA filter tables", and access to
it is shared between the AP and the modem.  Unlike the other
(host) memory regions, the size used is *not* included in the
ipa_init_modem_driver_req message that communicates from the
AP to the modem where the regions are, and their sizes.

So it's possible that the size used must actually match what
is expected by both the AP and modem.  If that is the case,
using the smaller size might have problems on whichever
platform (SM8450?) expects the larger one.

So I'm not sure whether using the smaller size for both
platforms is OK; someone from Qualcomm might be able to
answer that question.

> 4. SM8450/SM8475 downstream IPA driver:
> https://github.com/LineageOS/android_kernel_qcom_sm8450-modules/tree/lineage-20/qcom/opensource/dataipa
> 
> Most of my cross-checking came from the source code in this folder.

Yes, "ipa_utils.c" contains a great deal of the information
needed.

> 
> Finally, for some values such as qmap, aggregation, tre_count and
> event_count, I had to cross-check on the same folder that all
> ipa_data-vX.Y.c files reside, since I couldn't find any reference to these
> values in downstream code.

I'll try to explain those things separately.

					-Alex

> Regards,
> Esteban
> 


^ permalink raw reply

* Re: [PATCH RFC net-next 3/3] net: dsa: mxl862xx: add devlink flash_update and info_get
From: Daniel Golle @ 2026-07-08 20:02 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, netdev
In-Reply-To: <42792433-a95c-431f-ba0c-dc0644dcbdb5@lunn.ch>

On Wed, Jul 08, 2026 at 07:27:21PM +0200, Andrew Lunn wrote:
> > + * The flash process takes approximately 15 minutes. Progress is
> > + * reported via devlink status notifications. After a successful (or
> > + * failed) flash the driver reprobes the device automatically.
> 
> Have you tested the failed use case?
> 
> I assume if the firmware in the flash is invalid, the bootloader does
> not boot it, and it remains in the bootloader waiting for another
> attempt. Does this DSA driver still load, so devlink can be used to
> try again?

No. Without a running the firmware the driver doesn't probe and only
a special rescue tool allows to recover the hardware.
Having the DSA driver detect the presence of the switch stuck in
mcuboot mode and probe without registering any user or CPU ports
also isn't straight forward.

^ permalink raw reply

* Re: [PATCH 3/3] net: ipa: Add IPA v5.1 data
From: Alex Elder @ 2026-07-08 20:06 UTC (permalink / raw)
  To: esteuwu, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Alex Elder
  Cc: linux-arm-msm, devicetree, linux-kernel, netdev
In-Reply-To: <20260622-sm8450-ipa-v1-3-532f0299f96e@proton.me>

On 6/22/26 8:44 PM, Esteban Urrutia via B4 Relay wrote:
> From: Esteban Urrutia <esteuwu@proton.me>
> 
> Add the required ipa_data-v5.1.c file for IPA v5.1 along with changes
> that declare IPA v5.1 support.
> This version of IPA is used in both SM8450 and SM8475 SoCs.
> 
> Signed-off-by: Esteban Urrutia <esteuwu@proton.me>

OK I'm finally reviewing this.  Thank you again for sharing links to
the resources you used and developed while doing this work.


For the most part this looks entirely correct.  There is one
pair of memory table entries that I think should not be there,
otherwise everything looks just about perfect.

I'm not totally sure that reducing the SMEM size will work
correctly.


I'm taking this opportunity to explain a LOT of things about
IPA and the driver code.  It's much more than what's typical
for a review, but I thought this provided a good chance to
explain some things in context.  You can add it to your notes
file if you like...

> ---
>   drivers/net/ipa/Makefile             |   2 +-
>   drivers/net/ipa/data/ipa_data-v5.1.c | 477 +++++++++++++++++++++++++++++++++++
>   drivers/net/ipa/gsi_reg.c            |   1 +
>   drivers/net/ipa/ipa_data.h           |   1 +
>   drivers/net/ipa/ipa_main.c           |   4 +
>   drivers/net/ipa/ipa_reg.c            |   1 +
>   6 files changed, 485 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ipa/Makefile b/drivers/net/ipa/Makefile
> index e148ec3c1a10..d4995c2e8ca0 100644
> --- a/drivers/net/ipa/Makefile
> +++ b/drivers/net/ipa/Makefile
> @@ -7,7 +7,7 @@ IPA_REG_VERSIONS	:=	3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.5
>   # Some IPA versions can reuse another set of GSI register definitions.
>   GSI_REG_VERSIONS	:=	3.1 3.5.1 4.0 4.5 4.9 4.11 5.0
>   
> -IPA_DATA_VERSIONS	:=	3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.2 5.5
> +IPA_DATA_VERSIONS	:=	3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.1 5.2 5.5
>   
>   obj-$(CONFIG_QCOM_IPA)	+=	ipa.o
>   
> diff --git a/drivers/net/ipa/data/ipa_data-v5.1.c b/drivers/net/ipa/data/ipa_data-v5.1.c
> new file mode 100644
> index 000000000000..85b21efa1224
> --- /dev/null
> +++ b/drivers/net/ipa/data/ipa_data-v5.1.c
> @@ -0,0 +1,477 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/* Copyright (C) 2023-2024 Linaro Ltd. */
> +/* Copyright (C) 2026 Esteban Urrutia <esteuwu@proton.me> */
> +
> +#include <linux/array_size.h>
> +#include <linux/log2.h>
> +
> +#include "../ipa_data.h"
> +#include "../ipa_endpoint.h"
> +#include "../ipa_mem.h"
> +#include "../ipa_version.h"
> +
> +/** enum ipa_resource_type - IPA resource types for an SoC having IPA v5.1 */
> +enum ipa_resource_type {
> +	/* Source resource types; first must have value 0 */
> +	IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS		= 0,
> +	IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
> +	IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
> +	IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
> +	IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
> +
> +	/* Destination resource types; first must have value 0 */
> +	IPA_RESOURCE_TYPE_DST_DATA_SECTORS		= 0,
> +	IPA_RESOURCE_TYPE_DST_DPS_DMARS,
> +	IPA_RESOURCE_TYPE_DST_ULSO_SEGMENTS,
> +};

The above looks correct to me.  They come from downstream
"ipa_utils.c", in the ipa3_rsrc_src_grp_config[IPA_5_1][][]
array and the ipa3_rsrc_dst_grp_config[IPA_5_1][][] array.

The *_SRC_* symbols are the index values used in the
ipa_resource_src[] array upstream, and the *_DST_* symbols
are indexes in the upstream ipa_resource_dst[] array.

> +/* Resource groups used for an SoC having IPA v5.1 */
> +enum ipa_rsrc_group_id {
> +	/* Source resource group identifiers */
> +	IPA_RSRC_GROUP_SRC_UL				= 0,
> +	IPA_RSRC_GROUP_SRC_DL,
> +	IPA_RSRC_GROUP_SRC_UNUSED_2,
> +	IPA_RSRC_GROUP_SRC_UNUSED_3,
> +	IPA_RSRC_GROUP_SRC_URLLC,
> +	IPA_RSRC_GROUP_SRC_U_RX_QC,
> +	IPA_RSRC_GROUP_SRC_COUNT,	/* Last in set; not a source group */
> +
> +	/* Destination resource group identifiers */
> +	IPA_RSRC_GROUP_DST_UL				= 0,
> +	IPA_RSRC_GROUP_DST_DL,
> +	IPA_RSRC_GROUP_DST_UNUSED_2,
> +	IPA_RSRC_GROUP_DST_UNUSED_3,
> +	IPA_RSRC_GROUP_DST_UNUSED_4,
> +	IPA_RSRC_GROUP_DST_UC,
> +	IPA_RSRC_GROUP_DST_DRB_IP,
> +	IPA_RSRC_GROUP_DST_COUNT,	/* Last; not a destination group */
> +};

These look correct.  They correspond to the second index values
in the downstream arrays mentioned earlier, and are used as
indexes into the limits[] array within an ipa_resource structure.

As you probably now know, the symbols correspond to these comments
in the downstream code:
                 /* UL  DL  unused  unused  URLLC UC_RX_Q N/A */
                 /* UL  DL  unused  unused unused  UC_RX_Q DRBIP N/A */
> +/* QSB configuration data for an SoC having IPA v5.1 */
> +static const struct ipa_qsb_data ipa_qsb_data[] = {
> +	[IPA_QSB_MASTER_DDR] = {
> +		.max_writes		= 0,
> +		.max_reads		= 0,	/* no limit (hardware max) */
> +		.max_reads_beats	= 0,
> +	},
> +	[IPA_QSB_MASTER_PCIE] = {
> +		.max_writes		= 0,
> +		.max_reads		= 0,	/* no limit (hardware max) */
> +		.max_reads_beats	= 0,
> +	},
> +};

I think the DDR values might be wrong, but it's difficult to be
sure.  In some cases, in arrays like this in the downstream code,
if there is no entry found in an array, the *earlier* version
values should be used.  (Unless someone better informed states
that this is wrong, I think it's fine as-is.)

This information is found in the ipa3_qmb_outstanding[IPA_5_1][]
array in the downstream code.  However there is no entry for that
version.  Given that, all zeroes (as you have it) makes sense.
But it's possible this applies instead:

         [IPA_5_0][IPA_QMB_INSTANCE_DDR]         = {12, 12, 0},
         [IPA_5_0][IPA_QMB_INSTANCE_PCIE]        = {0, 0, 0},

I have no way of knowing; perhaps someone from Qualcomm can
get confirmation that all zeroes is correct.

(Note the order of values presented in the downstream code
differs from upstream.)



Most of the information in the structure below comes from the
ipa3_ep_mapping[IPA_V5_1][] array in the downstream code.
Many of the entries in that array are unused in the upstream
code, because we only use a small subset of the available
endpoints.

> +/* Endpoint configuration data for an SoC having IPA v5.1 */
> +static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
> +	[IPA_ENDPOINT_AP_COMMAND_TX] = {

IPA_ENDPOINT_AP_COMMAND_TX corresponds to IPA_CLIENT_APPS_CMD_PROD
in the downstream code.  The downstream code doesn't label the
assignments within the ipa3_ep_mapping[][] array, so I think it's
a little harder to understand.  Anyway I'll show how they map
between downstream and upstream below.

The downstream structure is named ipa_ep_configuration.  The
upstream structure is named ipa_gsi_endpoint_data.

struct ipa_ep_configuration {
         bool valid;
         int group_num;
         bool support_flt;
         int sequencer_type;
         u8 qmb_master_sel;
         struct ipa_gsi_ep_config ipa_gsi_ep_info;
         u8 tx_instance;
};

And although ipa_gsi_ep_config is not defined in this code
base, here is what it looks like:

struct ipa_gsi_ep_config {
         int ipa_ep_num;
         int ipa_gsi_chan_num;
         int ipa_if_tlv;
         int ipa_if_aos;
         int ee;
         enum gsi_prefetch_mode prefetch_mode;
         uint8_t prefetch_threshold;
};

This might not be current; I'm using code found here:
   https://git.codelinaro.org/clo/la/kernel/msm-5.15.git


Here is the upstream structure, and I indicate where the
information comes from in the downstream code:

struct ipa_gsi_endpoint_data {
         u8 ee_id;	/* ipa_ep_configuration->ee */
         u8 channel_id;  /* ipa_ep_configuration->ipa_gsi_chan_num */
         u8 endpoint_id;	/* ipa_ep_configuration->ipa_ep_num */
         bool toward_ipa;

         struct gsi_channel_data channel;
         struct ipa_endpoint_data endpoint;
};

And here is the first sub-structure:

struct gsi_channel_data {
         u16 tre_count;	/* Computed based on other code (see below) */
         u16 event_count;
         u8 tlv_count;	/* ipa_ep_configuration->ipa_if_tlv */
};

> +		.ee_id		= GSI_EE_AP,

This is the "execution environment" that the endpoint is
associated with.  For upstream, that's either the AP or
the modem.  The "_AP_" sitting where it does in the
IPA_ENDPOINT_AP_COMMAND_TX endpoint ID also indicates
this is an AP endpoint.  It also matches what's seen
in the downstream ipa_gsi_ep_config->ee field.

> +		.channel_id	= 12,
> +		.endpoint_id	= 14,
> +		.toward_ipa	= true,
> +		.channel = {
> +			.tre_count	= 256,
> +			.event_count	= 256,
> +			.tlv_count	= 20,

The tre_count number was derived from code in ipa3_setup_apps_pipes()
in downstream "ipa/ipa_v3/ipa.c".  There a ipa_sys_connect_params
structure contains a field desc_fifo_size, which is the size in bytes
of the transfer ring buffer.  The tre_count in upsteram code is in
units of a TRE (transfer ring element), i.e. it's the number of such
entries (that fit in that number of bytes).

The downstream IPA_CLIENT_APPS_CMD_PROD corresponds to upstream
IPA_ENDPOINT_AP_COMMAND_TX (the array entry we're in the middle
of here), and the downstream size is IPA_SYS_DESC_FIFO_SZ, or
0x800=2048 bytes.  Each TRE (struct gsi_tre) is 16 bytes.

In the downstream code--confusingly--ipa_gsi_setup_channel()
doubles the desc_fifo_sz value (for GSI, versus the older BAM
interface).  So the ring size becomes 4096 bytes, and that
works out to 256 16-byte GSI TRE entries.  I'm not sure why
512 is used for IPA v3.5.1, but it probably just means it's
bigger than it needs to be.

The event_count should be the same as the tre_count.  Again
I no longer know why that's not the case for IPA v3.5.1.


> +		},

Below is the second sub-structure in the upstream structure
ipa_gsi_endpoint_data, and the other structures it
incorporates.

struct ipa_endpoint_data {
         bool filter_support;
         struct ipa_endpoint_config config;
};

struct ipa_endpoint_config {
         u32 resource_group;
         bool checksum;
         bool qmap;
         bool aggregation;
         bool status_enable;
         bool dma_mode;
         enum ipa_endpoint_name dma_endpoint;
         union {
                 struct ipa_endpoint_tx tx;
                 struct ipa_endpoint_rx rx;
         };
};

struct ipa_endpoint_tx {
         enum ipa_seq_type seq_type;
         enum ipa_seq_rep_type seq_rep_type;
         enum ipa_endpoint_name status_endpoint;
};

struct ipa_endpoint_rx {
         u32 buffer_size;
         u32 pad_align;
         u32 aggr_time_limit;
         bool aggr_hard_limit;
         bool aggr_close_eof;
         bool holb_drop;
};

> +		.endpoint = {
> +			.config = {
> +				.resource_group	= IPA_RSRC_GROUP_SRC_UL,

This resource group corresponds to IPA_v5_0_GROUP_UL in
the downstream code.

> +				.dma_mode	= true,

The dma_mode is always true for the AP->IPA command TX
endpoint, false for others.

> +				.dma_endpoint	= IPA_ENDPOINT_AP_LAN_RX,

This is always the DMA endpoint id for the command
endpoint. I think it's where the status messages
related to transmitted commands get sent.  The AP<-LAN
(RX) endpoint is the "default" endpoint.

> +				.tx = {
> +					.seq_type = IPA_SEQ_DMA,

This is the sequencer type, always DMA for the command
endpoint.  The sequencer types are set based on what the
downstream code does.

> +				},
> +			},
> +		},
> +	},
> +	[IPA_ENDPOINT_AP_LAN_RX] = {

This is the default RX endpoint on the AP.  If a LAN
interface were supported it would also be the RX
endpoint for the LAN.  This corresponds to
IPA_CLIENT_APPS_LAN_CONS

> +		.ee_id		= GSI_EE_AP,
> +		.channel_id	= 13,
> +		.endpoint_id	= 16,
> +		.toward_ipa	= false,
> +		.channel = {
> +			.tre_count	= 256,
> +			.event_count	= 256,
> +			.tlv_count	= 9,
> +		},
> +		.endpoint = {
> +			.config = {
> +				.resource_group	= IPA_RSRC_GROUP_DST_UL,
> +				.aggregation	= true,

Aggregation enabled means multiple received messages will
be placed by the IPA hardware into a single receive buffer
before forwarding the buffer to the host for processing.

> +				.status_enable	= true,

This setting means every transfer causes a status header to be
generated for each received message.  ipa_endpoint_status_parse()
splits them apart using information in the status header and
hands each de-aggregated message to the network stack.

> +				.rx = {
> +					.buffer_size	= 8192,

Each receive buffer is this big (in bytes).

> +					.pad_align	= ilog2(sizeof(u32)),

Before a received message is placed in the receive buffer,
IPA updates current buffer pointer to be aligned to this
boundary (in this case, 2^2 bytes).

> +					.aggr_time_limit = 500,

If aggregation hasn't exhausted the receive buffer in this many
microseconds, it forwards the buffer to the host anyway.

The time limit comes from IPA_GENERIC_AGGR_TIME_LIMIT in the
downstream code.

> +				},
> +			},
> +		},
> +	},
> +	[IPA_ENDPOINT_AP_MODEM_TX] = {

The AP_MODEM_TX here says that this is an AP endpoint,
whose destination is the modem (WAN in the downstream
code), and it is a TX endpoint (from the AP to the modem).
This corresponds to IPA_CLIENT_APPS_WAN_PROD.

> +		.ee_id		= GSI_EE_AP,
> +		.channel_id	= 11,
> +		.endpoint_id	= 2,
> +		.toward_ipa	= true,
> +		.channel = {
> +			.tre_count	= 512,
> +			.event_count	= 512,
> +			.tlv_count	= 25,
> +		},
> +		.endpoint = {
> +			.filter_support	= true,
> +			.config = {
> +				.resource_group	= IPA_RSRC_GROUP_SRC_UL,
> +				.checksum       = true,

The checksum true flag means IPA performs checksumming
on messages being sent (so the host doesn't have to).

> +				.qmap		= true,

The qmap true flag says that this channel uses QMAP
protocol (ETH_P_MAP).  A single message contains one
or more QMAP messages, which multiplexes multiple
logical channels over a single connection.

> +				.status_enable	= true,
> +				.tx = {
> +					.seq_type = IPA_SEQ_2_PASS_SKIP_LAST_UC,
> +					.status_endpoint =
> +						IPA_ENDPOINT_MODEM_AP_RX,

This says that status messages generated as a result
of messages received on this channel (i.e., using
this endpoint) are delivered to the *modem* endpoint
that recieves data from the AP.

> +				},
> +			},
> +		},
> +	},
> +	[IPA_ENDPOINT_AP_MODEM_RX] = {

AP endpoint, *from* the modem.  This corresponds to
IPA_CLIENT_APPS_WAN_CONS.

> +		.ee_id		= GSI_EE_AP,
> +		.channel_id	= 1,
> +		.endpoint_id	= 23,
> +		.toward_ipa	= false,
> +		.channel = {
> +			.tre_count	= 256,
> +			.event_count	= 256,
> +			.tlv_count	= 9,
> +		},
> +		.endpoint = {
> +			.config = {
> +				.resource_group	= IPA_RSRC_GROUP_DST_UL,
> +				.checksum       = true,
> +				.qmap		= true,
> +				.aggregation	= true,
> +				.rx = {
> +					.buffer_size	= 8192,
> +					.aggr_time_limit = 500,
> +					.aggr_close_eof	= true,

The aggr_close_eof flag determines which of two ways
aggregation in a receive buffer "closes".  (Closing
means th receive buffer is delivered to the host for
processing, and a new receive buffer begins to be
used.)

One policy closes aggregation when there is not enough
space left to hold an entire incoming message in the
buffer.  The other policy closes aggregation when the
data from a received message crosses a certain mark
(byte count) in the receive buffer.  (I no longer
recall which is which.)

> +				},
> +			},
> +		},
> +	},
> +	[IPA_ENDPOINT_MODEM_AP_TX] = {

Modem endpoint, transmitting (from the modem) *to* the AP.
Downstream calls the modem "Q6".  Configuring these endpoints
is the modem's responsibility, but the AP IPA driver needs
to be aware of these, so they're included in this data.
(I don't remember why; maybe it's to ensure endpoints and
channels are accounted for, and/or not reused?)

This endpoint id corresponds to IPA_CLIENT_Q6_WAN_CONS.

> +		.ee_id		= GSI_EE_MODEM,
> +		.channel_id	= 0,
> +		.endpoint_id	= 12,
> +		.toward_ipa	= true,
> +		.endpoint = {
> +			.filter_support	= true,
> +		},
> +	},
> +	[IPA_ENDPOINT_MODEM_AP_RX] = {

This corresponds to IPA_CLIENT_Q6_WAN_CONS.

> +		.ee_id		= GSI_EE_MODEM,
> +		.channel_id	= 7,
> +		.endpoint_id	= 21,
> +		.toward_ipa	= false,
> +	},
> +	[IPA_ENDPOINT_MODEM_DL_NLO_TX] = {

This has to do with a feature we don't use, but we still
need to configure it (I think so we take into account that
it implements filtering).  This endpoint corresponds to
IPA_CLIENT_Q6_DL_NLO_DATA_PROD.

> +		.ee_id		= GSI_EE_MODEM,
> +		.channel_id	= 2,
> +		.endpoint_id	= 15,
> +		.toward_ipa	= true,
> +		.endpoint = {
> +			.filter_support	= true,
> +		},
> +	},
> +};
"Resources" are data structures managed by the IPA/GSI
firmware.  We must configure these at initialization
time, and once configured, that firmware operates
using these resources.  I don't know much more than
that, and basically we just configure things the way
the downstream code does.

> +
> +/* Source resource configuration data for an SoC having IPA v5.1 */
> +static const struct ipa_resource ipa_resource_src[] = {

Again, this array is filled with information that comes from the
ipa3_rsrc_src_grp_config[IPA_5_1][][] array in the downstream
code, in "ipa_utils.c".  Everything you have here looks correct.

> +	[IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS] = {
> +		.limits[IPA_RSRC_GROUP_SRC_UL] = {
> +			.min = 7,	.max = 12,
> +		},
> +		.limits[IPA_RSRC_GROUP_SRC_URLLC] = {
> +			.min = 1,	.max = 63,
> +		},
> +		.limits[IPA_RSRC_GROUP_SRC_U_RX_QC] = {
> +			.min = 0,	.max = 63,
> +		},
> +	},
> +	[IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS] = {
> +		.limits[IPA_RSRC_GROUP_SRC_UL] = {
> +			.min = 21,	.max = 21,
> +		},
> +		.limits[IPA_RSRC_GROUP_SRC_URLLC] = {
> +			.min = 10,	.max = 10,
> +		},
> +	},
> +	[IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF] = {
> +		.limits[IPA_RSRC_GROUP_SRC_UL] = {
> +			.min = 33,	.max = 33,
> +		},
> +		.limits[IPA_RSRC_GROUP_SRC_URLLC] = {
> +			.min = 20,	.max = 20,
> +		},
> +	},
> +	[IPA_RESOURCE_TYPE_SRC_HPS_DMARS] = {
> +		.limits[IPA_RSRC_GROUP_SRC_UL] = {
> +			.min = 0,	.max = 63,
> +		},
> +		.limits[IPA_RSRC_GROUP_SRC_URLLC] = {
> +			.min = 1,	.max = 63,
> +		},
> +		.limits[IPA_RSRC_GROUP_SRC_U_RX_QC] = {
> +			.min = 0,	.max = 63,
> +		},
> +	},
> +	[IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES] = {
> +		.limits[IPA_RSRC_GROUP_SRC_UL] = {
> +			.min = 38,	.max = 38,
> +		},
> +		.limits[IPA_RSRC_GROUP_SRC_URLLC] = {
> +			.min = 16,	.max = 16,
> +		},
> +	},
> +};
> +
> +/* Destination resource configuration data for an SoC having IPA v5.1 */
> +static const struct ipa_resource ipa_resource_dst[] = {

And the content of this array comes from ipa3_rsrc_dst_grp_config[][].
Everything you have here looks correct as well.

> +	[IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = {
> +		.limits[IPA_RSRC_GROUP_DST_UL] = {
> +			.min = 6,	.max = 6,
> +		},
> +		.limits[IPA_RSRC_GROUP_DST_DL] = {
> +			.min = 5,	.max = 5,
> +		},
> +		.limits[IPA_RSRC_GROUP_DST_DRB_IP] = {
> +			.min = 39,	.max = 39,
> +		},
> +	},
> +	[IPA_RESOURCE_TYPE_DST_DPS_DMARS] = {
> +		.limits[IPA_RSRC_GROUP_DST_UL] = {
> +			.min = 0,	.max = 3,
> +		},
> +		.limits[IPA_RSRC_GROUP_DST_DL] = {
> +			.min = 0,	.max = 3,
> +		},
> +	},
> +	[IPA_RESOURCE_TYPE_DST_ULSO_SEGMENTS] = {
> +		.limits[IPA_RSRC_GROUP_DST_UL] = {
> +			.min = 0,	.max = 63,
> +		},
> +		.limits[IPA_RSRC_GROUP_DST_DL] = {
> +			.min = 0,	.max = 63,
> +		},
> +	},
> +};
> +
> +/* Resource configuration data for an SoC having IPA v5.1 */
> +static const struct ipa_resource_data ipa_resource_data = {
> +	.rsrc_group_dst_count	= IPA_RSRC_GROUP_DST_COUNT,
> +	.rsrc_group_src_count	= IPA_RSRC_GROUP_SRC_COUNT,
> +	.resource_src_count	= ARRAY_SIZE(ipa_resource_src),
> +	.resource_src		= ipa_resource_src,
> +	.resource_dst_count	= ARRAY_SIZE(ipa_resource_dst),
> +	.resource_dst		= ipa_resource_dst,
> +};
> +
> +/* IPA-resident memory region data for an SoC having IPA v5.1 */

Memory regions are sort of similar to resources, in that
there are ranges of available (IPA-local) memory that are
used by IPA for various purposes.  We need to configure
these, and this configuration (base and size of various
memory regions) is shared with the modem via a QMI message
exchange during initialization.

> +static const struct ipa_mem ipa_mem_local_data[] = {

IPA has local memory that is partitioned as defined by this
array.  The regions are used by IPA/GSI firmware and/or
hardware.  The configuration defined here is sent to
the modem in an ipa_init_modem_driver_req QMI message
so both the modem and AP have a consistent view of
how the memory is used.

Many memory regions are preceded by 0-2 "canaries", which
are 32-byte values initialized to IPA_MEM_CANARY_VAL.

In the downstream code there is structure ipa3_mem_partition
that defines these things, and structures of this type are
defined in "ipa_utils.c".  For IPA v5.1, ipa_5_1_mem_part
defines them all.  The mapping between downstream and
upstream is not trivial and direct, but it should be
obvious how they get translated.


With two exceptions, what I see here looks like you
correctly transferred everything.  (The two exceptions
are entries that from what I can tell, should not be
present.)

> +	{
> +		.id		= IPA_MEM_UC_EVENT_RING,
> +		.offset		= 0x0000,
> +		.size		= 0x1000,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_UC_SHARED,
> +		.offset		= 0x1000,
> +		.size		= 0x0080,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_UC_INFO,
> +		.offset		= 0x1080,
> +		.size		= 0x0200,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_V4_FILTER_HASHED,
> +		.offset		= 0x1288,
> +		.size		= 0x0078,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_V4_FILTER,
> +		.offset		= 0x1308,
> +		.size		= 0x0078,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_V6_FILTER_HASHED,
> +		.offset		= 0x1388,
> +		.size		= 0x0078,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_V6_FILTER,
> +		.offset		= 0x1408,
> +		.size		= 0x0078,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_V4_ROUTE_HASHED,
> +		.offset		= 0x1488,
> +		.size		= 0x0098,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_V4_ROUTE,
> +		.offset		= 0x1528,
> +		.size		= 0x0098,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_V6_ROUTE_HASHED,
> +		.offset		= 0x15c8,
> +		.size		= 0x0098,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_V6_ROUTE,
> +		.offset		= 0x1668,
> +		.size		= 0x0098,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_MODEM_HEADER,
> +		.offset		= 0x1708,
> +		.size		= 0x0240,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_AP_HEADER,
> +		.offset		= 0x1948,
> +		.size		= 0x01e0,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_MODEM_PROC_CTX,
> +		.offset		= 0x1b40,
> +		.size		= 0x0b20,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_AP_PROC_CTX,
> +		.offset		= 0x2660,
> +		.size		= 0x0200,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_STATS_QUOTA_MODEM,
> +		.offset		= 0x2868,
> +		.size		= 0x0060,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_STATS_QUOTA_AP,
> +		.offset		= 0x28c8,
> +		.size		= 0x0048,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_STATS_TETHERING,
> +		.offset		= 0x2910,
> +		.size		= 0x03c0,
> +		.canary_count	= 0,
> +	},

The next two entries look wrong to me.  Can you explain where
you got these offsets and sizes?  Is it from "ipa_data-v5.0.c"?

Here are the relevant entries I see in ipa_5_1_mem_part
in the downstream code:
         .stats_flt_v4_ofst = 0,
         .stats_flt_v4_size = 0,
         .stats_flt_v6_ofst = 0,
         .stats_flt_v6_size = 0,
         .stats_rt_v4_ofst = 0,
         .stats_rt_v4_size = 0,
         .stats_rt_v6_ofst = 0,
         .stats_rt_v6_size = 0,
(Since their size is zero, their entries can be omitted.)

> +	{
> +		.id		= IPA_MEM_AP_V4_FILTER,
> +		.offset		= 0x29b8,
> +		.size		= 0x0188,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_AP_V6_FILTER,
> +		.offset		= 0x2b40,
> +		.size		= 0x0228,
> +		.canary_count	= 0,
> +	},

The remaining entries (below) look good.

> +	{
> +		.id		= IPA_MEM_STATS_FILTER_ROUTE,
> +		.offset		= 0x2cd0,
> +		.size		= 0x0ba0,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_STATS_DROP,
> +		.offset		= 0x3870,
> +		.size		= 0x0020,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_MODEM,
> +		.offset		= 0x3898,
> +		.size		= 0x0d48,
> +		.canary_count	= 2,
> +	},
> +	{
> +		.id		= IPA_MEM_NAT_TABLE,
> +		.offset		= 0x45e0,
> +		.size		= 0x0900,
> +		.canary_count	= 0,
> +	},
> +	{
> +		.id		= IPA_MEM_PDN_CONFIG,
> +		.offset		= 0x4ee8,
> +		.size		= 0x0100,
> +		.canary_count	= 2,
> +	},
> +};
> +
> +/* Memory configuration data for an SoC having IPA v5.1 */
> +static const struct ipa_mem_data ipa_mem_data = {
> +	.local_count	= ARRAY_SIZE(ipa_mem_local_data),
> +	.local		= ipa_mem_local_data,
> +	.imem_addr	= 0x146a8000,

I think I needed to look up the imem offset value
in Qualcomm documentation I no longer have access
to.  Perhaps someone from there could confirm you
are using the right values here.

> +	.imem_size	= 0x00002000,
> +	/*
> +	 * While this value is 0xb000 on SM8450 and 0x9000 on SM8475,
> +	 * it has been left set to 0x9000 for compatibility with SM8475
> +	 */

As I said earlier, I'm not completely sure this will still
work on the SM8450.  Someone should confirm this, and it
really ought to be tested somehow.

> +	.smem_size	= 0x00009000,
> +};
> +
> +/* Interconnect rates are in 1000 byte/second units */
> +static const struct ipa_interconnect_data ipa_interconnect_data[] = {
> +	{
> +		.name			= "memory",
> +		.peak_bandwidth		= 1900000,	/* 1.9 GBps */
> +		.average_bandwidth	= 590000,	/* 590 MBps */

I no longer recall where to get these bandwidth values
for the interconnects.  Perhaps someone from Qualcomm
can find this out/confirm what you have.

Really nice work figuring out all this stuff...

					-Alex

> +	},
> +	/* Average rate is unused for the next interconnect */
> +	{
> +		.name			= "config",
> +		.peak_bandwidth		= 76800,	/* 76.8 MBps */
> +		.average_bandwidth	= 0,		/* unused */
> +	},
> +};
> +
> +/* Clock and interconnect configuration data for an SoC having IPA v5.1 */
> +static const struct ipa_power_data ipa_power_data = {
> +	.core_clock_rate	= 120 * 1000 * 1000,	/* Hz */
> +	.interconnect_count	= ARRAY_SIZE(ipa_interconnect_data),
> +	.interconnect_data	= ipa_interconnect_data,
> +};
> +
> +/* Configuration data for an SoC having IPA v5.1. */
> +const struct ipa_data ipa_data_v5_1 = {
> +	.version		= IPA_VERSION_5_1,
> +	.qsb_count		= ARRAY_SIZE(ipa_qsb_data),
> +	.qsb_data		= ipa_qsb_data,
> +	.modem_route_count	= 11,
> +	.endpoint_count		= ARRAY_SIZE(ipa_gsi_endpoint_data),
> +	.endpoint_data		= ipa_gsi_endpoint_data,
> +	.resource_data		= &ipa_resource_data,
> +	.mem_data		= &ipa_mem_data,
> +	.power_data		= &ipa_power_data,
> +};
> diff --git a/drivers/net/ipa/gsi_reg.c b/drivers/net/ipa/gsi_reg.c
> index e13cf835a013..a57072ba4bef 100644
> --- a/drivers/net/ipa/gsi_reg.c
> +++ b/drivers/net/ipa/gsi_reg.c
> @@ -110,6 +110,7 @@ static const struct regs *gsi_regs(struct gsi *gsi)
>   		return &gsi_regs_v4_11;
>   
>   	case IPA_VERSION_5_0:
> +	case IPA_VERSION_5_1:
>   	case IPA_VERSION_5_2:
>   	case IPA_VERSION_5_5:
>   		return &gsi_regs_v5_0;
> diff --git a/drivers/net/ipa/ipa_data.h b/drivers/net/ipa/ipa_data.h
> index 3eb9dc2ce339..fe6f7d5bfe88 100644
> --- a/drivers/net/ipa/ipa_data.h
> +++ b/drivers/net/ipa/ipa_data.h
> @@ -253,6 +253,7 @@ extern const struct ipa_data ipa_data_v4_7;
>   extern const struct ipa_data ipa_data_v4_9;
>   extern const struct ipa_data ipa_data_v4_11;
>   extern const struct ipa_data ipa_data_v5_0;
> +extern const struct ipa_data ipa_data_v5_1;
>   extern const struct ipa_data ipa_data_v5_2;
>   extern const struct ipa_data ipa_data_v5_5;
>   
> diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
> index 788dd99af2a4..6c449032ae45 100644
> --- a/drivers/net/ipa/ipa_main.c
> +++ b/drivers/net/ipa/ipa_main.c
> @@ -669,6 +669,10 @@ static const struct of_device_id ipa_match[] = {
>   		.compatible	= "qcom,sdx65-ipa",
>   		.data		= &ipa_data_v5_0,
>   	},
> +	{
> +		.compatible	= "qcom,sm8450-ipa",
> +		.data		= &ipa_data_v5_1,
> +	},
>   	{
>   		.compatible	= "qcom,milos-ipa",
>   		.data		= &ipa_data_v5_2,
> diff --git a/drivers/net/ipa/ipa_reg.c b/drivers/net/ipa/ipa_reg.c
> index 30bd69f4c147..5f22ca6295b1 100644
> --- a/drivers/net/ipa/ipa_reg.c
> +++ b/drivers/net/ipa/ipa_reg.c
> @@ -125,6 +125,7 @@ static const struct regs *ipa_regs(enum ipa_version version)
>   	case IPA_VERSION_4_11:
>   		return &ipa_regs_v4_11;
>   	case IPA_VERSION_5_0:
> +	case IPA_VERSION_5_1:
>   	case IPA_VERSION_5_2:
>   		return &ipa_regs_v5_0;
>   	case IPA_VERSION_5_5:
> 


^ permalink raw reply

* Re: [PATCH net v3 1/2] net/stmmac: Check for STMMAC_DOWN flag in all XDP paths
From: Jakub Raczynski @ 2026-07-08 20:12 UTC (permalink / raw)
  To: netdev
  Cc: k.tegowski, k.domagalski, andrew+netdev, davem, edumazet, kuba,
	pabeni, mcoquelin.stm32, alexandre.torgue, linux-stm32,
	linux-arm-kernel, linux-kernel
In-Reply-To: <20260707174551.1264558-2-j.raczynski@samsung.com>

[-- Attachment #1: Type: text/plain, Size: 836 bytes --]

On Tue, Jul 07, 2026 at 07:45:50PM +0200, Jakub Raczynski wrote:
> Currently STMMAC_DOWN flag is only set/cleared by stmmac_reset_subtask(),
> to notify driver to stop processing of TX/RX frames. One of these processing
> paths is for XDP, but it is only ever checked in stmmac_xdp_xmit(), which
> leaves all other XDP paths vulnerable to processing data while interface is
> restarting.
> 
> Make verification of STMMAC_DOWN flag consistent by applying check to
> all XDP paths.
> 
> Fixes: 8b278a5b69a22 ("net: stmmac: Add support for XDP_REDIRECT action")
> Co-developed-by: Chang-Sub Lee <cs0617.lee@samsung.com>
> Signed-off-by: Chang-Sub Lee <cs0617.lee@samsung.com>
> Signed-off-by: Jakub Raczynski <j.raczynski@samsung.com>
> ---

Sashiko AI gave review that has valid points, patch needs changes.
Please drop it

--
pw-bot: cr

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: [PATCH net 2/2] net/stmmac: Prevent dma queue NULL free on allocation failure
From: Jakub Raczynski @ 2026-07-08 20:16 UTC (permalink / raw)
  To: netdev
  Cc: k.tegowski, k.domagalski, andrew+netdev, davem, edumazet, kuba,
	pabeni, mcoquelin.stm32, alexandre.torgue, linux-stm32,
	linux-arm-kernel, linux-kernel, Sashiko AI
In-Reply-To: <20260707174115.1264466-3-j.raczynski@samsung.com>

[-- Attachment #1: Type: text/plain, Size: 1037 bytes --]

On Tue, Jul 07, 2026 at 07:41:15PM +0200, Jakub Raczynski wrote:
> During allocation of RX/TX descriptor resources and its DMA,
> there is verification of failed dma_alloc_coherent() due to lack of memory.
> In case of that failure, all allocated resources are freed instantly after,
> but there are no checks for dma_free_coherent() whether previous step has
> failed.
> This will generally result in panic due to freeing NULL address.
> 
> Fix it by adding NULL verification of memory that is to be freed.
> 
> Theoretically code should also set address of pointed memory to zero when
> freeing, but currently the only path of invalid address is non intialized zero,
> and there is no case possible of double-free of same memory.
> 
> Fixes: e73b19baa3b1c ("net: stmmac: simplify DMA descriptor allocation/init/freeing")
> Reported-by: Sashiko AI <sashiko-bot@kernel.org>
> Signed-off-by: Jakub Raczynski <j.raczynski@samsung.com>
> ---

Sashiko AI gave review that has valid point, patch needs changes.
Please drop it.

--
pw-bot: cr

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply

* Re: [PATCH v4 1/3] drm/drm_ras: Add drm_ras netlink error event
From: Rodrigo Vivi @ 2026-07-08 20:21 UTC (permalink / raw)
  To: Tauro, Riana
  Cc: intel-xe, aravind.iddamsetty, kuba, anshuman.gupta,
	joonas.lahtinen, simona.vetter, airlied, pratik.bari,
	joshua.santosh.ranjan, ashwin.kumar.kulkarni, shubham.kumar,
	ravi.kishore.koppuravuri, raag.jadav, maarten.lankhorst,
	mallesh.koujalagi, soham.purkait, Zack McKevitt, Lijo Lazar,
	Hawking Zhang, David S. Miller, Paolo Abeni, Eric Dumazet,
	dri-devel, netdev
In-Reply-To: <202f6d3a-c29b-491b-979f-1d8223f59108@intel.com>

On Tue, Jul 07, 2026 at 12:02:11PM +0530, Tauro, Riana wrote:
> Hi Rodrigo/Jakub/Aravind
> 
> Please let me know if you have any feedback for this patch or can you please
> ack this if it looks good to you.

I looks good to me, but could you please double check the sashiko's comments?

Patch 3 still needs review I believe, then we get Jakub and drm maintainers acks
to get this through drm-xe-next.

Thanks,
Rodrigo.

> 
> Thanks
> Riana
> 
> On 01-07-2026 15:14, Riana Tauro wrote:
> > Define a new netlink event 'error-event' and a new multicast group
> > 'error-report' in drm_ras. Each event contains device name, node and
> > error information to identify the error triggering the event.
> > 
> > Add drm_ras_nl_error_event() to trigger an event from the driver.
> > Userspace must subscribe to 'error-report' to receive 'error-event'
> > notifications.
> > 
> > Usage:
> > 
> > $ sudo ynl --family drm_ras --subscribe error-report
> > 
> > Cc: Jakub Kicinski <kuba@kernel.org>
> > Cc: Zack McKevitt <zachary.mckevitt@oss.qualcomm.com>
> > Cc: Lijo Lazar <lijo.lazar@amd.com>
> > Cc: Hawking Zhang <Hawking.Zhang@amd.com>
> > Cc: David S. Miller <davem@davemloft.net>
> > Cc: Paolo Abeni <pabeni@redhat.com>
> > Cc: Eric Dumazet <edumazet@google.com>
> > Signed-off-by: Riana Tauro <riana.tauro@intel.com>
> > Reviewed-by: Raag Jadav <raag.jadav@intel.com>
> > ---
> > v2: remove redundant initialization
> >      remove unnecessary space
> >      use ynl in commit message and doc (Raag)
> >      simplify doc for error-event attrs
> > 
> > v3: rename error-notify to error-report
> >      Replace notify with report across the file (Raag)
> > ---
> >   Documentation/gpu/drm-ras.rst            | 21 ++++++
> >   Documentation/netlink/specs/drm_ras.yaml | 48 +++++++++++++
> >   drivers/gpu/drm/drm_ras.c                | 87 ++++++++++++++++++++++++
> >   drivers/gpu/drm/drm_ras_nl.c             |  6 ++
> >   drivers/gpu/drm/drm_ras_nl.h             |  4 ++
> >   include/drm/drm_ras.h                    |  5 ++
> >   include/uapi/drm/drm_ras.h               | 15 ++++
> >   7 files changed, 186 insertions(+)
> > 
> > diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
> > index 83c21853b74b..406e4c49bac1 100644
> > --- a/Documentation/gpu/drm-ras.rst
> > +++ b/Documentation/gpu/drm-ras.rst
> > @@ -56,6 +56,7 @@ User space tools can:
> >     ``node-id`` and ``error-id`` as parameters.
> >   * Clear specific error counters with the ``clear-error-counter`` command, using both
> >     ``node-id`` and ``error-id`` as parameters.
> > +* Subscribe to the ``error-report`` multicast group to receive ``error-event``.
> >   YAML-based Interface
> >   --------------------
> > @@ -111,3 +112,23 @@ Example: Clear an error counter for a given node
> >       sudo ynl --family drm_ras --do clear-error-counter --json '{"node-id":0, "error-id":1}'
> >       None
> > +
> > +Example: Subscribe to ``error-report`` multicast group
> > +
> > +.. code-block:: bash
> > +
> > +    sudo ynl --family drm_ras --output-json --subscribe error-report
> > +
> > +.. code-block:: json
> > +
> > +    {
> > +        "name": "error-event",
> > +        "msg": {
> > +            "device-name": "0000:03:00.0",
> > +            "node-id": 1,
> > +            "node-name": "uncorrectable-errors",
> > +            "error-id": 1,
> > +            "error-name": "error_name1",
> > +            "error-value": 1
> > +        }
> > +    }
> > diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
> > index e113056f8c01..8aed3d4515e5 100644
> > --- a/Documentation/netlink/specs/drm_ras.yaml
> > +++ b/Documentation/netlink/specs/drm_ras.yaml
> > @@ -69,6 +69,33 @@ attribute-sets:
> >           name: error-value
> >           type: u32
> >           doc: Current value of the requested error counter.
> > +  -
> > +    name: error-event-attrs
> > +    attributes:
> > +      -
> > +        name: device-name
> > +        type: string
> > +        doc: Device (PCI BDF, UUID) that reported the error.
> > +      -
> > +        name: node-id
> > +        type: u32
> > +        doc: ID of the node that reported the error.
> > +      -
> > +        name: node-name
> > +        type: string
> > +        doc: Name of the node that reported the error.
> > +      -
> > +        name: error-id
> > +        type: u32
> > +        doc: ID of the error counter.
> > +      -
> > +        name: error-name
> > +        type: string
> > +        doc: Name of the error.
> > +      -
> > +        name: error-value
> > +        type: u32
> > +        doc: Current value of the error counter.
> >   operations:
> >     list:
> > @@ -124,3 +151,24 @@ operations:
> >         do:
> >           request:
> >             attributes: *id-attrs
> > +    -
> > +      name: error-event
> > +      doc: >-
> > +           Report an error event to userspace.
> > +           The event includes the device, node and error information
> > +           of the error that triggered the event.
> > +      attribute-set: error-event-attrs
> > +      mcgrp: error-report
> > +      event:
> > +        attributes:
> > +          - device-name
> > +          - node-id
> > +          - node-name
> > +          - error-id
> > +          - error-name
> > +          - error-value
> > +
> > +mcast-groups:
> > +  list:
> > +    -
> > +      name: error-report
> > diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
> > index d6eab29a1394..77f912a4d101 100644
> > --- a/drivers/gpu/drm/drm_ras.c
> > +++ b/drivers/gpu/drm/drm_ras.c
> > @@ -41,6 +41,11 @@
> >    *    Userspace must provide Node ID, Error ID.
> >    *    Clears specific error counter of a node if supported.
> >    *
> > + * 4. ERROR_REPORT: Subscribe to this multicast group to receive error events
> > + *
> > + * 5. ERROR_EVENT: Report an error event to userspace. The event contains device, node
> > + *    and error information that triggered the event.
> > + *
> >    * Node registration:
> >    *
> >    * - drm_ras_node_register(): Registers a new node and assigns
> > @@ -186,6 +191,34 @@ static int msg_reply_value(struct sk_buff *msg, u32 error_id,
> >   			   value);
> >   }
> > +static int msg_put_error_event_attrs(struct sk_buff *msg, struct drm_ras_node *node,
> > +				     u32 error_id, const char *error_name, u32 value)
> > +{
> > +	int ret;
> > +
> > +	ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_DEVICE_NAME, node->device_name);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_ID, node->id);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_NAME, node->node_name);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_ID, error_id);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_NAME, error_name);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_VALUE, value);
> > +}
> > +
> >   static int doit_reply_value(struct genl_info *info, u32 node_id,
> >   			    u32 error_id)
> >   {
> > @@ -222,6 +255,60 @@ static int doit_reply_value(struct genl_info *info, u32 node_id,
> >   	return genlmsg_reply(msg, info);
> >   }
> > +/**
> > + * drm_ras_nl_error_event() - Report an error event
> > + * @node: Node structure
> > + * @error_id: ID of the error
> > + * @error_name: Name of the error
> > + * @value: Value associated with the error
> > + * @flags: GFP flags for memory allocation
> > + *
> > + * Report an error-event to userspace using the error-report multicast group.
> > + *
> > + * Return: 0 on success, or negative errno on failure.
> > + */
> > +int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id, const char *error_name,
> > +			   u32 value, gfp_t flags)
> > +{
> > +	struct genl_info info;
> > +	struct sk_buff *msg;
> > +	struct nlattr *hdr;
> > +	int ret;
> > +
> > +	if (!error_name)
> > +		return -EINVAL;
> > +
> > +	if (!genl_has_listeners(&drm_ras_nl_family, &init_net, DRM_RAS_NLGRP_ERROR_REPORT))
> > +		return 0;
> > +
> > +	genl_info_init_ntf(&info, &drm_ras_nl_family, DRM_RAS_CMD_ERROR_EVENT);
> > +
> > +	msg = genlmsg_new(NLMSG_GOODSIZE, flags);
> > +	if (!msg)
> > +		return -ENOMEM;
> > +
> > +	hdr = genlmsg_iput(msg, &info);
> > +	if (!hdr) {
> > +		ret = -EMSGSIZE;
> > +		goto free_msg;
> > +	}
> > +
> > +	ret = msg_put_error_event_attrs(msg, node, error_id, error_name, value);
> > +	if (ret)
> > +		goto cancel_msg;
> > +
> > +	genlmsg_end(msg, hdr);
> > +	genlmsg_multicast(&drm_ras_nl_family, msg, 0, DRM_RAS_NLGRP_ERROR_REPORT, flags);
> > +	return 0;
> > +
> > +cancel_msg:
> > +	genlmsg_cancel(msg, hdr);
> > +free_msg:
> > +	nlmsg_free(msg);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL(drm_ras_nl_error_event);
> > +
> >   /**
> >    * drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters
> >    * @skb: Netlink message buffer
> > diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
> > index dea1c1b2494e..9d3123cc9f9c 100644
> > --- a/drivers/gpu/drm/drm_ras_nl.c
> > +++ b/drivers/gpu/drm/drm_ras_nl.c
> > @@ -58,6 +58,10 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
> >   	},
> >   };
> > +static const struct genl_multicast_group drm_ras_nl_mcgrps[] = {
> > +	[DRM_RAS_NLGRP_ERROR_REPORT] = { "error-report", },
> > +};
> > +
> >   struct genl_family drm_ras_nl_family __ro_after_init = {
> >   	.name		= DRM_RAS_FAMILY_NAME,
> >   	.version	= DRM_RAS_FAMILY_VERSION,
> > @@ -66,4 +70,6 @@ struct genl_family drm_ras_nl_family __ro_after_init = {
> >   	.module		= THIS_MODULE,
> >   	.split_ops	= drm_ras_nl_ops,
> >   	.n_split_ops	= ARRAY_SIZE(drm_ras_nl_ops),
> > +	.mcgrps		= drm_ras_nl_mcgrps,
> > +	.n_mcgrps	= ARRAY_SIZE(drm_ras_nl_mcgrps),
> >   };
> > diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
> > index a398643572a5..03ec275aca92 100644
> > --- a/drivers/gpu/drm/drm_ras_nl.h
> > +++ b/drivers/gpu/drm/drm_ras_nl.h
> > @@ -21,6 +21,10 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
> >   int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb,
> >   					struct genl_info *info);
> > +enum {
> > +	DRM_RAS_NLGRP_ERROR_REPORT,
> > +};
> > +
> >   extern struct genl_family drm_ras_nl_family;
> >   #endif /* _LINUX_DRM_RAS_GEN_H */
> > diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
> > index 0beede3ddc4e..8abfb7d2077b 100644
> > --- a/include/drm/drm_ras.h
> > +++ b/include/drm/drm_ras.h
> > @@ -80,9 +80,14 @@ struct drm_device;
> >   #if IS_ENABLED(CONFIG_DRM_RAS)
> >   int drm_ras_node_register(struct drm_ras_node *node);
> >   void drm_ras_node_unregister(struct drm_ras_node *node);
> > +int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id, const char *error_name,
> > +			   u32 value, gfp_t flags);
> >   #else
> >   static inline int drm_ras_node_register(struct drm_ras_node *node) { return 0; }
> >   static inline void drm_ras_node_unregister(struct drm_ras_node *node) { }
> > +static inline int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id,
> > +					 const char *error_name, u32 value, gfp_t flags)
> > +{ return 0; }
> >   #endif
> >   #endif
> > diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
> > index 218a3ee86805..eab8231aa87c 100644
> > --- a/include/uapi/drm/drm_ras.h
> > +++ b/include/uapi/drm/drm_ras.h
> > @@ -38,13 +38,28 @@ enum {
> >   	DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1)
> >   };
> > +enum {
> > +	DRM_RAS_A_ERROR_EVENT_ATTRS_DEVICE_NAME = 1,
> > +	DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_ID,
> > +	DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_NAME,
> > +	DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_ID,
> > +	DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_NAME,
> > +	DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_VALUE,
> > +
> > +	__DRM_RAS_A_ERROR_EVENT_ATTRS_MAX,
> > +	DRM_RAS_A_ERROR_EVENT_ATTRS_MAX = (__DRM_RAS_A_ERROR_EVENT_ATTRS_MAX - 1)
> > +};
> > +
> >   enum {
> >   	DRM_RAS_CMD_LIST_NODES = 1,
> >   	DRM_RAS_CMD_GET_ERROR_COUNTER,
> >   	DRM_RAS_CMD_CLEAR_ERROR_COUNTER,
> > +	DRM_RAS_CMD_ERROR_EVENT,
> >   	__DRM_RAS_CMD_MAX,
> >   	DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
> >   };
> > +#define DRM_RAS_MCGRP_ERROR_REPORT	"error-report"
> > +
> >   #endif /* _UAPI_LINUX_DRM_RAS_H */

^ permalink raw reply

* Re: [PATCH net-next v11 7/7] selftests: netconsole: validate target resume
From: Andre Carvalho @ 2026-07-08 20:24 UTC (permalink / raw)
  To: Matthieu Baerts
  Cc: Breno Leitao, netdev, linux-kernel, linux-kselftest, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Shuah Khan, Simon Horman
In-Reply-To: <f398373e-2cb4-4649-a491-9763df94d98b@kernel.org>

Hello Matthieu,

On Wed, Jul 08, 2026 at 05:50:53PM +0200, Matthieu Baerts wrote:
> 
> > +function trigger_reactivation() {
> > +	# Add back low level module
> > +	modprobe netdevsim
> > +	# Recreate namespace and two interfaces
> > +	set_network
> > +	# Restore MACs
> > +	ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" \
> > +		address "${SAVED_DSTMAC}"
> > +	if [ "${BINDMODE}" == "mac" ]; then
> > +		ip link set dev "${SRCIF}" down
> > +		ip link set dev "${SRCIF}" address "${SAVED_SRCMAC}"
> > +		# Rename device in order to trigger target resume, as initial
> > +		# when device was recreated it didn't have correct mac address.
> > +		ip link set dev "${SRCIF}" name "${TARGET}"
> 
> When I execute the test, the "ifname" bind mode works without issues,
> but the "mac" one not. From what I see, the socat process doesn't get
> any UDP packet when expected. I wonder if the problem might not come
> from here: the interface is disabled before changing the MAC address and
> renaming the interface, but not re-enabled at the end. Is it normal?

Yes, the expectation is that the target would be automatically re-enabled by
netconsole. That is why we don't 'up' the interface here explicitly.

The problem is that the test has an implict dependency on interface mac address
changing when we recreate them, which is why we have to do this whole down/update/rename
flow to trigger the reactivation in this case.

> If I add 'up' at the end of this last line here, or if I remove the
> whole if-statement block, the test passes.

For cases where the mac is persistent (e.g with systemd MACAddressPolicy=persistent),
the actual re-enablement should "just work", which I suspect is why it works when
you remove the whole if-statement block.

I think to make the test more robust to such scenarios, we should skip the
if-statement block when we detect that the interface came back with the same mac
as previously. Something like this:

if [ "${BINDMODE}" == "mac" ]; then
	CURR_SRCMAC=$(mac_get "${SRCIF}")
	if [ "${CURR_SRCMAC}" == "${SAVED_SRCMAC}" ]; then
		# Interface came back with same mac, no need to restore
		return
	fi
	ip link set dev "${SRCIF}" down
	ip link set dev "${SRCIF}" address "${SAVED_SRCMAC}"
	# Rename device in order to trigger target resume, as initial
	# when device was recreated it didn't have correct mac address.
	ip link set dev "${SRCIF}" name "${TARGET}"
fi

Could you confirm if this fixes the selftest in your environment?

> The "network logging resumed on interface" seems to suggest that the
> previous patch of this series here, commit 220dbe3c76ed ("netconsole:
> resume previously deactivated target"), managed to resume the previously
> activated target, but not in my case.

Thanks for including the logs, this helps quite a bit and I think confirms that
the interface comes back with the same mac address as previously, and is indeed
resumed, I believe the down/update/rename portion of the test then drops the target
and causes the failure.

> What I don't understand is why is it working on the Netdev CI, and not
> on my side. The main difference is that I might be missing some
> userspace packages -- but I don't see what can be missing here, all
> other netconsole tests pass -- a specific kernel config, or not applied
> patch. Or something different on the host -- in a container on my side
> -- but there shouldn't be any interactions with the host here,
> everything is happening in the VM. Any ideas? :)

Netdev CI executes with MACAddressPolicy=none (which is why I added the if-statement
block [1]) and I think it might explain the behaviour difference.

> 
> > +	echo "Running with bind mode: ${BINDMODE}" >&2
> > +	# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5)
> > +	echo "6 5" > /proc/sys/kernel/printk
> 
> Can we remove this? Without that, it is hard to understand what went
> wrong in case of issues.

Can you elaborate? This is typical for netconsole tests and I think required to
ensure the write will show up on netconsole. I'm not opposed to changing it if
there is a reason, but we probably want to make it consistent with other tests too.

> > +	# Send the message
> > +	echo "${MSG}: ${TARGET}" > /dev/kmsg
> > +	# Wait until socat saves the file to disk
> > +	busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}"
> 
> In my case, the script was stopping here, without any message. I can
> send a patch adding "|| true" to go to the next instruction, and display
> "FAIL: File was not generated.".
> 

This seems reasonable to me.

> > +	# Make sure the message was received in the dst part
> > +	# and exit
> > +	validate_msg "${OUTPUT_FILE}"
> > +
> > +	# kill socat in case it is still running
> > +	pkill_socat
> > +	# Cleanup & unload the module
> > +	cleanup
> > +
> > +	echo "${BINDMODE} : Test passed" >&2
> > +done
> > +
> > +trap - EXIT
> > +exit "${EXIT_STATUS}"
> > 
> 
> Cheers,
> Matt

[1] https://lore.kernel.org/all/20260117092227.741cba3b@kernel.org/

-- 
Andre Carvalho

^ permalink raw reply

* [PATCH bpf-next v4 0/6] Add the capability to load HW RX checksum in eBPF programs
From: Vladimir Vdovin @ 2026-07-08 20:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Donald Hunter, Jakub Kicinski, David S . Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Andrew Lunn, Tony Nguyen, Przemek Kitszel,
	Alexander Lobakin, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh, Hao Luo,
	Jiri Olsa, Shuah Khan, Maciej Fijalkowski
  Cc: Jakub Sitnicki, Aleksandr Loktionov, netdev, bpf, intel-wired-lan,
	linux-kselftest, Vladimir Vdovin

Introduce bpf_xdp_metadata_rx_checksum() kfunc in order to load the HW
RX checksum results in the eBPF program bound to the NIC.
Implement xmo_rx_checksum callback for veth and ice drivers.

If the hardware detects a wrong/failed checksum, it will report
CHECKSUM_NONE in the packet metadata. Moreover, CHECKSUM_NONE will be
returned even if the NIC can't parse the packet (e.g. if it does not
support a specific protocol). A possible use case for
bpf_xdp_metadata_rx_checksum() would be to implement a XDP DDoS
application [1] combining the info from bpf_xdp_metadata_rx_checksum()
and bpf_xdp_metadata_rx_hash() kfuncs in order to filter packets with a
wrong/failed checksum.

This is a repost of Lorenzo's series, rebased on top of net-next, with
a new drv-net selftest for the RX checksum metadata added on top of it,
as Lorenzo suggested [2].

A note on the new selftest semantics: for traffic with a correct
checksum the test requires a usable verdict (CHECKSUM_UNNECESSARY
and/or CHECKSUM_COMPLETE) but reports SKIP on CHECKSUM_NONE, since the
API allows devices that do not verify the packets (e.g. veth reports
NONE for locally generated CHECKSUM_PARTIAL traffic). For corrupted
packets it only asserts that CHECKSUM_UNNECESSARY is not set, as
CHECKSUM_COMPLETE legitimately carries the raw checksum of bad packets
too.

[1] https://blog.cloudflare.com/unimog-cloudflares-edge-load-balancer/
[2] https://lore.kernel.org/r/ak5ox296M46FAcWX@lore-desk

---
Changes in v4:
- Report ip_summed as a bitmask of XDP_CHECKSUM_* values and return the
  hw checksum and the checksum level via dedicated
  bpf_xdp_metadata_rx_checksum() arguments
- Rebase on top of net-next
- Add a drv-net selftest for the XDP RX checksum metadata
- Link to v3: https://lore.kernel.org/r/20260217-bpf-xdp-meta-rxcksum-v3-0-30024c50ba71@kernel.org

Changes in v3:
- Remove leftover assignment from v2 in veth_xdp_rx_checksum()
- Fix typos
- Fix commit logs
- Link to v2: https://lore.kernel.org/r/20260213-bpf-xdp-meta-rxcksum-v2-0-a82c4802afbe@kernel.org

Changes in v2:
- Remove XDP_CHECKSUM_PARTIAL definition
- Improve veth_xdp_rx_checksum() callback
- Fix uninitialized case for cksum_meta in ice_get_rx_csum()
- Fix sparse warnings in ice driver
- Fix typos
- Link to v1: https://lore.kernel.org/r/20260210-bpf-xdp-meta-rxcksum-v1-0-e5d55caa0541@kernel.org

Changes in v1:
- Rebase on top of bpf-next
- Test ice driver using xdp_hw_metadata tool available in the bpf
  kernel selftest
- Improve cover letter with an use-case for
  bpf_xdp_metadata_rx_checksum()
- Link to RFC v2: https://lore.kernel.org/r/20250925-bpf-xdp-meta-rxcksum-v2-0-6b3fe987ce91@kernel.org

change-id: 20250925-bpf-xdp-meta-rxcksum-900685e2909d

Lorenzo Bianconi (5):
  netlink: specs: Add XDP RX checksum capability to XDP metadata specs
  net: veth: Add xmo_rx_checksum callback to veth driver
  net: ice: Add xmo_rx_checksum callback
  selftests/bpf: Add selftest support for bpf_xdp_metadata_rx_checksum
  selftests/bpf: Add bpf_xdp_metadata_rx_checksum support to
    xdp_hw_metadat prog

Vladimir Vdovin (1):
  selftests: drv-net: add XDP RX checksum metadata tests

 Documentation/netlink/specs/netdev.yaml       |   5 +
 drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 123 ++++++++++++------
 drivers/net/veth.c                            |  32 +++++
 include/net/xdp.h                             |  18 +++
 include/uapi/linux/netdev.h                   |   3 +
 net/core/xdp.c                                |  32 +++++
 tools/include/uapi/linux/netdev.h             |   3 +
 .../selftests/bpf/prog_tests/xdp_metadata.c   |   9 ++
 .../selftests/bpf/progs/xdp_hw_metadata.c     |   7 +
 .../selftests/bpf/progs/xdp_metadata.c        |   2 +
 tools/testing/selftests/bpf/xdp_hw_metadata.c |  31 +++++
 tools/testing/selftests/bpf/xdp_metadata.h    |  13 ++
 .../selftests/drivers/net/hw/xdp_metadata.py  | 110 ++++++++++++++++
 .../selftests/net/lib/xdp_metadata.bpf.c      | 112 ++++++++++++++--
 14 files changed, 445 insertions(+), 55 deletions(-)


base-commit: 08030ddb87b4c6c6a2c03c82731b5e188f02f5b9
-- 
2.47.0


^ permalink raw reply

* [PATCH bpf-next v4 1/6] netlink: specs: Add XDP RX checksum capability to XDP metadata specs
From: Vladimir Vdovin @ 2026-07-08 20:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Donald Hunter, Jakub Kicinski, David S . Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Andrew Lunn, Tony Nguyen, Przemek Kitszel,
	Alexander Lobakin, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh, Hao Luo,
	Jiri Olsa, Shuah Khan, Maciej Fijalkowski
  Cc: Jakub Sitnicki, Aleksandr Loktionov, netdev, bpf, intel-wired-lan,
	linux-kselftest, Vladimir Vdovin
In-Reply-To: <20260708203410.45121-1-deliran@verdict.gg>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Introduce XDP RX checksum capability to XDP metadata specs. XDP RX
checksum will be use by devices capable of exposing receive checksum
result via bpf_xdp_metadata_rx_checksum().
Moreover, introduce xmo_rx_checksum netdev callback in order to allow
the eBPF program bound to the device to retrieve the RX checksum result
computed by the hw NIC and reported via DMA descriptors.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
 Documentation/netlink/specs/netdev.yaml |  5 ++++
 include/net/xdp.h                       | 18 ++++++++++++++
 include/uapi/linux/netdev.h             |  3 +++
 net/core/xdp.c                          | 32 +++++++++++++++++++++++++
 tools/include/uapi/linux/netdev.h       |  3 +++
 5 files changed, 61 insertions(+)

diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
index 5f143da7458c..6d0d90d3a614 100644
--- a/Documentation/netlink/specs/netdev.yaml
+++ b/Documentation/netlink/specs/netdev.yaml
@@ -61,6 +61,11 @@ definitions:
         doc: |
           Device is capable of exposing receive packet VLAN tag via
           bpf_xdp_metadata_rx_vlan_tag().
+      -
+        name: checksum
+        doc: |
+          Device is capable of exposing receive checksum result via
+          bpf_xdp_metadata_rx_checksum().
   -
     type: flags
     name: xsk-flags
diff --git a/include/net/xdp.h b/include/net/xdp.h
index aa742f413c35..e255ff786131 100644
--- a/include/net/xdp.h
+++ b/include/net/xdp.h
@@ -586,6 +586,10 @@ void xdp_attachment_setup(struct xdp_attachment_info *info,
 			   NETDEV_XDP_RX_METADATA_VLAN_TAG, \
 			   bpf_xdp_metadata_rx_vlan_tag, \
 			   xmo_rx_vlan_tag) \
+	XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_CHECKSUM, \
+			   NETDEV_XDP_RX_METADATA_CHECKSUM, \
+			   bpf_xdp_metadata_rx_checksum, \
+			   xmo_rx_checksum)
 
 enum xdp_rx_metadata {
 #define XDP_METADATA_KFUNC(name, _, __, ___) name,
@@ -643,12 +647,26 @@ enum xdp_rss_hash_type {
 	XDP_RSS_TYPE_L4_IPV6_SCTP_EX = XDP_RSS_TYPE_L4_IPV6_SCTP | XDP_RSS_L3_DYNHDR,
 };
 
+/* Please note the driver is required to invalidate the checksum if the NIC
+ * reports CHECKSUM_UNNECESSARY or CHECKSUM_COMPLETE and the eBPF program
+ * modifies the packet since it can change some fields validated by the
+ * checksum.
+ */
+enum xdp_checksum {
+	XDP_CHECKSUM_NONE		= BIT(CHECKSUM_NONE),
+	XDP_CHECKSUM_UNNECESSARY	= BIT(CHECKSUM_UNNECESSARY),
+	XDP_CHECKSUM_COMPLETE		= BIT(CHECKSUM_COMPLETE),
+};
+
 struct xdp_metadata_ops {
 	int	(*xmo_rx_timestamp)(const struct xdp_md *ctx, u64 *timestamp);
 	int	(*xmo_rx_hash)(const struct xdp_md *ctx, u32 *hash,
 			       enum xdp_rss_hash_type *rss_type);
 	int	(*xmo_rx_vlan_tag)(const struct xdp_md *ctx, __be16 *vlan_proto,
 				   u16 *vlan_tci);
+	int	(*xmo_rx_checksum)(const struct xdp_md *ctx,
+				   enum xdp_checksum *ip_summed,
+				   u32 *cksum, u8 *cksum_level);
 };
 
 #ifdef CONFIG_NET
diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
index 2f3ab75e8cc0..f8caade93c8c 100644
--- a/include/uapi/linux/netdev.h
+++ b/include/uapi/linux/netdev.h
@@ -47,11 +47,14 @@ enum netdev_xdp_act {
  *   hash via bpf_xdp_metadata_rx_hash().
  * @NETDEV_XDP_RX_METADATA_VLAN_TAG: Device is capable of exposing receive
  *   packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag().
+ * @NETDEV_XDP_RX_METADATA_CHECKSUM: Device is capable of exposing receive
+ *   checksum result via bpf_xdp_metadata_rx_checksum().
  */
 enum netdev_xdp_rx_metadata {
 	NETDEV_XDP_RX_METADATA_TIMESTAMP = 1,
 	NETDEV_XDP_RX_METADATA_HASH = 2,
 	NETDEV_XDP_RX_METADATA_VLAN_TAG = 4,
+	NETDEV_XDP_RX_METADATA_CHECKSUM = 8,
 };
 
 /**
diff --git a/net/core/xdp.c b/net/core/xdp.c
index 9890a30584ba..9bcaa423ad17 100644
--- a/net/core/xdp.c
+++ b/net/core/xdp.c
@@ -961,6 +961,38 @@ __bpf_kfunc int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx,
 	return -EOPNOTSUPP;
 }
 
+/**
+ * bpf_xdp_metadata_rx_checksum - Read XDP frame RX checksum.
+ * @ctx: XDP context pointer.
+ * @ip_summed: Return value pointer to a bitmask indicating available checksums.
+ * @cksum: Return value pointer indicating the hw checksum value.
+ * @cksum_level: Return value pointer indicating the checksum level result.
+ *
+ * In case of success, ``ip_summed`` is set to the RX checksum result. Possible
+ * values are:
+ * ``XDP_CHECKSUM_NONE``
+ * ``XDP_CHECKSUM_UNNECESSARY``
+ * ``XDP_CHECKSUM_COMPLETE``
+ * ``XDP_CHECKSUM_COMPLETE`` | ``XDP_CHECKSUM_UNNECESSARY``
+ *
+ * In case of success, ``cksum`` contains the checksum value calculated by the
+ * NIC. ``cksum`` is valid only if ``XDP_CHECKSUM_COMPLETE`` is set in
+ * ``ip_summed``. ``cksum_level`` contains the checksum level reported by the
+ * hw. ``cksum_level`` can be considered valid only if
+ * ``XDP_CHECKSUM_UNNECESSARY`` is set in ``ip_summed``.
+ *
+ * Return:
+ * * Returns 0 on success or ``-errno`` on error.
+ * * ``-EOPNOTSUPP`` : means device driver does not implement kfunc
+ * * ``-ENODATA``    : means no RX-checksum available for this frame
+ */
+__bpf_kfunc int bpf_xdp_metadata_rx_checksum(const struct xdp_md *ctx,
+					     enum xdp_checksum *ip_summed,
+					     u32 *cksum, u8 *cksum_level)
+{
+	return -EOPNOTSUPP;
+}
+
 __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(xdp_metadata_kfunc_ids)
diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h
index 2f3ab75e8cc0..f8caade93c8c 100644
--- a/tools/include/uapi/linux/netdev.h
+++ b/tools/include/uapi/linux/netdev.h
@@ -47,11 +47,14 @@ enum netdev_xdp_act {
  *   hash via bpf_xdp_metadata_rx_hash().
  * @NETDEV_XDP_RX_METADATA_VLAN_TAG: Device is capable of exposing receive
  *   packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag().
+ * @NETDEV_XDP_RX_METADATA_CHECKSUM: Device is capable of exposing receive
+ *   checksum result via bpf_xdp_metadata_rx_checksum().
  */
 enum netdev_xdp_rx_metadata {
 	NETDEV_XDP_RX_METADATA_TIMESTAMP = 1,
 	NETDEV_XDP_RX_METADATA_HASH = 2,
 	NETDEV_XDP_RX_METADATA_VLAN_TAG = 4,
+	NETDEV_XDP_RX_METADATA_CHECKSUM = 8,
 };
 
 /**
-- 
2.47.0


^ permalink raw reply related

* [PATCH bpf-next v4 2/6] net: veth: Add xmo_rx_checksum callback to veth driver
From: Vladimir Vdovin @ 2026-07-08 20:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Donald Hunter, Jakub Kicinski, David S . Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Andrew Lunn, Tony Nguyen, Przemek Kitszel,
	Alexander Lobakin, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh, Hao Luo,
	Jiri Olsa, Shuah Khan, Maciej Fijalkowski
  Cc: Jakub Sitnicki, Aleksandr Loktionov, netdev, bpf, intel-wired-lan,
	linux-kselftest, Vladimir Vdovin
In-Reply-To: <20260708203410.45121-1-deliran@verdict.gg>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Implement xmo_rx_checksum callback in veth driver to report RX checksum
result to the eBPF program bounded to the veth device.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
 drivers/net/veth.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 1c5142149175..498d894d043d 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1700,6 +1700,37 @@ static int veth_xdp_rx_vlan_tag(const struct xdp_md *ctx, __be16 *vlan_proto,
 	return err;
 }
 
+static int veth_xdp_rx_checksum(const struct xdp_md *ctx,
+				enum xdp_checksum *ip_summed,
+				u32 *cksum, u8 *cksum_level)
+{
+	const struct veth_xdp_buff *_ctx = (void *)ctx;
+	const struct sk_buff *skb = _ctx->skb;
+
+	if (!skb)
+		return -ENODATA;
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_COMPLETE:
+		*ip_summed = XDP_CHECKSUM_COMPLETE;
+		*cksum = skb->csum;
+		*cksum_level = 0;
+		break;
+	case CHECKSUM_UNNECESSARY:
+		*ip_summed = XDP_CHECKSUM_UNNECESSARY;
+		*cksum_level = skb->csum_level;
+		*cksum = 0;
+		break;
+	default:
+		*ip_summed = XDP_CHECKSUM_NONE;
+		*cksum_level = 0;
+		*cksum = 0;
+		break;
+	}
+
+	return 0;
+}
+
 static const struct net_device_ops veth_netdev_ops = {
 	.ndo_init            = veth_dev_init,
 	.ndo_open            = veth_open,
@@ -1725,6 +1756,7 @@ static const struct xdp_metadata_ops veth_xdp_metadata_ops = {
 	.xmo_rx_timestamp		= veth_xdp_rx_timestamp,
 	.xmo_rx_hash			= veth_xdp_rx_hash,
 	.xmo_rx_vlan_tag		= veth_xdp_rx_vlan_tag,
+	.xmo_rx_checksum		= veth_xdp_rx_checksum,
 };
 
 #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | \
-- 
2.47.0


^ permalink raw reply related

* [PATCH bpf-next v4 3/6] net: ice: Add xmo_rx_checksum callback
From: Vladimir Vdovin @ 2026-07-08 20:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Donald Hunter, Jakub Kicinski, David S . Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Andrew Lunn, Tony Nguyen, Przemek Kitszel,
	Alexander Lobakin, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh, Hao Luo,
	Jiri Olsa, Shuah Khan, Maciej Fijalkowski
  Cc: Jakub Sitnicki, Aleksandr Loktionov, netdev, bpf, intel-wired-lan,
	linux-kselftest, Vladimir Vdovin
In-Reply-To: <20260708203410.45121-1-deliran@verdict.gg>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Implement xmo_rx_checksum callback in ice driver to report RX checksum
result to the eBPF program bounded to the NIC.
Introduce ice_get_rx_csum utility routine in order to make the rx checksum
code reusable from ice_rx_csum()

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
 drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 123 ++++++++++++------
 1 file changed, 81 insertions(+), 42 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
index e695a664e53d..3aa82ff03d9e 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
@@ -78,69 +78,48 @@ ice_rx_hash_to_skb(const struct ice_rx_ring *rx_ring,
 		libeth_rx_pt_set_hash(skb, hash, decoded);
 }
 
-/**
- * ice_rx_gcs - Set generic checksum in skb
- * @skb: skb currently being received and modified
- * @rx_desc: receive descriptor
- */
-static void ice_rx_gcs(struct sk_buff *skb,
-		       const union ice_32b_rx_flex_desc *rx_desc)
-{
-	const struct ice_32b_rx_flex_desc_nic *desc;
-	u16 csum;
-
-	desc = (struct ice_32b_rx_flex_desc_nic *)rx_desc;
-	skb->ip_summed = CHECKSUM_COMPLETE;
-	csum = (__force u16)desc->raw_csum;
-	skb->csum = csum_unfold((__force __sum16)swab16(csum));
-}
-
-/**
- * ice_rx_csum - Indicate in skb if checksum is good
- * @ring: the ring we care about
- * @skb: skb currently being received and modified
- * @rx_desc: the receive descriptor
- * @ptype: the packet type decoded by hardware
- *
- * skb->protocol must be set before this function is called
- */
 static void
-ice_rx_csum(struct ice_rx_ring *ring, struct sk_buff *skb,
-	    union ice_32b_rx_flex_desc *rx_desc, u16 ptype)
+ice_get_rx_csum(const union ice_32b_rx_flex_desc *rx_desc, u16 ptype,
+		struct ice_rx_ring *ring, enum xdp_checksum *ip_summed,
+		u32 *cksum, u8 *cksum_level)
 {
-	struct libeth_rx_pt decoded;
+	struct libeth_rx_pt decoded = libie_rx_pt_parse(ptype);
 	u16 rx_status0, rx_status1;
 	bool ipv4, ipv6;
 
-	/* Start with CHECKSUM_NONE and by default csum_level = 0 */
-	skb->ip_summed = CHECKSUM_NONE;
-
-	decoded = libie_rx_pt_parse(ptype);
 	if (!libeth_rx_pt_has_checksum(ring->netdev, decoded))
-		return;
+		goto checksum_none;
 
 	rx_status0 = le16_to_cpu(rx_desc->wb.status_error0);
 	rx_status1 = le16_to_cpu(rx_desc->wb.status_error1);
-
 	if ((ring->flags & ICE_RX_FLAGS_RING_GCS) &&
 	    rx_desc->wb.rxdid == ICE_RXDID_FLEX_NIC &&
 	    (decoded.inner_prot == LIBETH_RX_PT_INNER_TCP ||
 	     decoded.inner_prot == LIBETH_RX_PT_INNER_UDP ||
 	     decoded.inner_prot == LIBETH_RX_PT_INNER_ICMP)) {
-		ice_rx_gcs(skb, rx_desc);
+		const struct ice_32b_rx_flex_desc_nic *desc;
+		__wsum wcsum;
+		u16 csum;
+
+		desc = (struct ice_32b_rx_flex_desc_nic *)rx_desc;
+		*ip_summed = XDP_CHECKSUM_COMPLETE;
+		csum = (__force u16)desc->raw_csum;
+		wcsum = csum_unfold((__force __sum16)swab16(csum));
+		*cksum = (__force u32)wcsum;
+		*cksum_level = 0;
 		return;
 	}
 
 	/* check if HW has decoded the packet and checksum */
 	if (!(rx_status0 & BIT(ICE_RX_FLEX_DESC_STATUS0_L3L4P_S)))
-		return;
+		goto checksum_none;
 
 	ipv4 = libeth_rx_pt_get_ip_ver(decoded) == LIBETH_RX_PT_OUTER_IPV4;
 	ipv6 = libeth_rx_pt_get_ip_ver(decoded) == LIBETH_RX_PT_OUTER_IPV6;
 
 	if (ipv4 && (rx_status0 & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S)))) {
 		ring->vsi->back->hw_rx_eipe_error++;
-		return;
+		goto checksum_none;
 	}
 
 	if (ipv4 && (rx_status0 & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S))))
@@ -164,14 +143,51 @@ ice_rx_csum(struct ice_rx_ring *ring, struct sk_buff *skb,
 	 * we need to bump the checksum level by 1 to reflect the fact that
 	 * we are indicating we validated the inner checksum.
 	 */
-	if (decoded.tunnel_type >= LIBETH_RX_PT_TUNNEL_IP_GRENAT)
-		skb->csum_level = 1;
-
-	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	*cksum_level = decoded.tunnel_type >= LIBETH_RX_PT_TUNNEL_IP_GRENAT;
+	*ip_summed = XDP_CHECKSUM_UNNECESSARY;
+	*cksum = 0;
 	return;
 
 checksum_fail:
 	ring->vsi->back->hw_csum_rx_error++;
+checksum_none:
+	*ip_summed = XDP_CHECKSUM_NONE;
+	*cksum_level = 0;
+	*cksum = 0;
+}
+
+/**
+ * ice_rx_csum - Indicate in skb if checksum is good
+ * @ring: the ring we care about
+ * @skb: skb currently being received and modified
+ * @rx_desc: the receive descriptor
+ * @ptype: the packet type decoded by hardware
+ *
+ * skb->protocol must be set before this function is called
+ */
+static void
+ice_rx_csum(struct ice_rx_ring *ring, struct sk_buff *skb,
+	    union ice_32b_rx_flex_desc *rx_desc, u16 ptype)
+{
+	enum xdp_checksum ip_summed;
+	u8 cksum_level;
+	u32 cksum;
+
+	ice_get_rx_csum(rx_desc, ptype, ring, &ip_summed, &cksum,
+			&cksum_level);
+	switch (ip_summed) {
+	case XDP_CHECKSUM_UNNECESSARY:
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		skb->csum_level = cksum_level;
+		break;
+	case XDP_CHECKSUM_COMPLETE:
+		skb->ip_summed = CHECKSUM_COMPLETE;
+		skb->csum = (__force __wsum)cksum;
+		break;
+	default:
+		skb->ip_summed = CHECKSUM_NONE;
+		break;
+	}
 }
 
 /**
@@ -566,6 +582,28 @@ static int ice_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash,
 	return 0;
 }
 
+/**
+ * ice_xdp_rx_checksum - RX checksum XDP hint handler
+ * @ctx: XDP buff pointer
+ * @ip_summed: RX checksum result destination address
+ * @cksum: RX checksum value destination address
+ * @cksum_level: RX checksum level value destination address
+ */
+static int ice_xdp_rx_checksum(const struct xdp_md *ctx,
+			       enum xdp_checksum *ip_summed,
+			       u32 *cksum, u8 *cksum_level)
+{
+	const struct libeth_xdp_buff *xdp_ext = (void *)ctx;
+	const union ice_32b_rx_flex_desc *rx_desc = xdp_ext->desc;
+	struct ice_rx_ring *ring;
+
+	ring = libeth_xdp_buff_to_rq(xdp_ext, typeof(*ring), xdp_rxq);
+	ice_get_rx_csum(rx_desc, ice_get_ptype(rx_desc), ring, ip_summed,
+			cksum, cksum_level);
+
+	return 0;
+}
+
 /**
  * ice_xdp_rx_vlan_tag - VLAN tag XDP hint handler
  * @ctx: XDP buff pointer
@@ -598,4 +636,5 @@ const struct xdp_metadata_ops ice_xdp_md_ops = {
 	.xmo_rx_timestamp		= ice_xdp_rx_hw_ts,
 	.xmo_rx_hash			= ice_xdp_rx_hash,
 	.xmo_rx_vlan_tag		= ice_xdp_rx_vlan_tag,
+	.xmo_rx_checksum		= ice_xdp_rx_checksum,
 };
-- 
2.47.0


^ permalink raw reply related

* [PATCH bpf-next v4 4/6] selftests/bpf: Add selftest support for bpf_xdp_metadata_rx_checksum
From: Vladimir Vdovin @ 2026-07-08 20:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Donald Hunter, Jakub Kicinski, David S . Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Andrew Lunn, Tony Nguyen, Przemek Kitszel,
	Alexander Lobakin, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh, Hao Luo,
	Jiri Olsa, Shuah Khan, Maciej Fijalkowski
  Cc: Jakub Sitnicki, Aleksandr Loktionov, netdev, bpf, intel-wired-lan,
	linux-kselftest, Vladimir Vdovin
In-Reply-To: <20260708203410.45121-1-deliran@verdict.gg>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Introduce dedicated selftest for bpf_xdp_metadata_rx_checksum kfunc to
bpf selftest framework.

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
 tools/testing/selftests/bpf/prog_tests/xdp_metadata.c | 9 +++++++++
 tools/testing/selftests/bpf/progs/xdp_metadata.c      | 2 ++
 tools/testing/selftests/bpf/xdp_metadata.h            | 9 +++++++++
 3 files changed, 20 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
index 5c31054ad4a4..91de61c822f5 100644
--- a/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_metadata.c
@@ -310,6 +310,15 @@ static int verify_xsk_metadata(struct xsk *xsk, bool sent_from_af_xdp)
 	if (!ASSERT_NEQ(meta->rx_hash, 0, "rx_hash"))
 		return -1;
 
+	if (!ASSERT_EQ(meta->ip_summed, XDP_CHECKSUM_NONE, "rx_ip_summed"))
+		return -1;
+
+	if (!ASSERT_EQ(meta->cksum, 0, "rx_cksum"))
+		return -1;
+
+	if (!ASSERT_EQ(meta->cksum_level, 0, "rx_cksum_level"))
+		return -1;
+
 	if (!sent_from_af_xdp) {
 		if (!ASSERT_NEQ(meta->rx_hash_type & XDP_RSS_TYPE_L4, 0, "rx_hash_type"))
 			return -1;
diff --git a/tools/testing/selftests/bpf/progs/xdp_metadata.c b/tools/testing/selftests/bpf/progs/xdp_metadata.c
index 09bb8a038d52..af1e19d48d67 100644
--- a/tools/testing/selftests/bpf/progs/xdp_metadata.c
+++ b/tools/testing/selftests/bpf/progs/xdp_metadata.c
@@ -98,6 +98,8 @@ int rx(struct xdp_md *ctx)
 	bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type);
 	bpf_xdp_metadata_rx_vlan_tag(ctx, &meta->rx_vlan_proto,
 				     &meta->rx_vlan_tci);
+	bpf_xdp_metadata_rx_checksum(ctx, &meta->ip_summed, &meta->cksum,
+				     &meta->cksum_level);
 
 	return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS);
 }
diff --git a/tools/testing/selftests/bpf/xdp_metadata.h b/tools/testing/selftests/bpf/xdp_metadata.h
index 87318ad1117a..bca09b94af26 100644
--- a/tools/testing/selftests/bpf/xdp_metadata.h
+++ b/tools/testing/selftests/bpf/xdp_metadata.h
@@ -30,6 +30,10 @@ enum xdp_meta_field {
 	XDP_META_FIELD_VLAN_TAG	= BIT(2),
 };
 
+#define XDP_CHECKSUM_NONE		BIT(0)
+#define XDP_CHECKSUM_UNNECESSARY	BIT(1)
+#define XDP_CHECKSUM_COMPLETE		BIT(2)
+
 struct xdp_meta {
 	union {
 		__u64 rx_timestamp;
@@ -48,5 +52,10 @@ struct xdp_meta {
 		};
 		__s32 rx_vlan_tag_err;
 	};
+	struct {
+		__u32 ip_summed;
+		__u32 cksum;
+		__u8 cksum_level;
+	};
 	enum xdp_meta_field hint_valid;
 };
-- 
2.47.0


^ permalink raw reply related

* [PATCH bpf-next v4 5/6] selftests/bpf: Add bpf_xdp_metadata_rx_checksum support to xdp_hw_metadat prog
From: Vladimir Vdovin @ 2026-07-08 20:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Donald Hunter, Jakub Kicinski, David S . Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Andrew Lunn, Tony Nguyen, Przemek Kitszel,
	Alexander Lobakin, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh, Hao Luo,
	Jiri Olsa, Shuah Khan, Maciej Fijalkowski
  Cc: Jakub Sitnicki, Aleksandr Loktionov, netdev, bpf, intel-wired-lan,
	linux-kselftest, Vladimir Vdovin
In-Reply-To: <20260708203410.45121-1-deliran@verdict.gg>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Introduce the capability to dump HW rx checksum in xdp_hw_metadata
program via bpf_xdp_metadata_rx_checksum() kfunc.

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
 .../selftests/bpf/progs/xdp_hw_metadata.c     |  7 +++++
 tools/testing/selftests/bpf/xdp_hw_metadata.c | 31 +++++++++++++++++++
 tools/testing/selftests/bpf/xdp_metadata.h    | 12 ++++---
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c
index 330ece2eabdb..5eeadb7e27cf 100644
--- a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c
+++ b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c
@@ -110,6 +110,13 @@ int rx(struct xdp_md *ctx)
 	else
 		meta->hint_valid |= XDP_META_FIELD_VLAN_TAG;
 
+	err = bpf_xdp_metadata_rx_checksum(ctx, &meta->ip_summed,
+					   &meta->cksum, &meta->cksum_level);
+	if (err)
+		meta->rx_cksum_err = err;
+	else
+		meta->hint_valid |= XDP_META_FIELD_CHECKSUM;
+
 	__sync_add_and_fetch(&pkts_redir, 1);
 	return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS);
 }
diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c
index 6db3b5555a22..c63a70a54075 100644
--- a/tools/testing/selftests/bpf/xdp_hw_metadata.c
+++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c
@@ -8,6 +8,7 @@
  * - Metadata verified:
  *   - rx_timestamp
  *   - rx_hash
+ *   - rx_checksum
  *
  * TX:
  * - UDP 9091 packets trigger TX reply
@@ -219,6 +220,30 @@ static void print_vlan_tci(__u16 tag)
 	printf("PCP=%u, DEI=%d, VID=0x%X\n", pcp, dei, vlan_id);
 }
 
+static void print_rx_cksum(__u8 ip_summed, __u32 cksum, __u8 cksum_level)
+{
+	const char *cksum_str;
+
+	switch (ip_summed) {
+	case XDP_CHECKSUM_COMPLETE | XDP_CHECKSUM_UNNECESSARY:
+		cksum_str = "CHECKSUM_COMPLETE,CHECKSUM_UNNECESSARY";
+		break;
+	case XDP_CHECKSUM_UNNECESSARY:
+		cksum_str = "CHECKSUM_UNNECESSARY";
+		break;
+	case XDP_CHECKSUM_COMPLETE:
+		cksum_str = "CHECKSUM_COMPLETE";
+		break;
+	case XDP_CHECKSUM_NONE:
+	default:
+		cksum_str = "CHECKSUM_NONE";
+		break;
+	}
+
+	printf("rx-cksum: %s, csum=0x%x, cksum_level=0x%x\n",
+	       cksum_str, cksum, cksum_level);
+}
+
 static void verify_xdp_metadata(void *data, clockid_t clock_id)
 {
 	struct xdp_meta *meta;
@@ -254,6 +279,12 @@ static void verify_xdp_metadata(void *data, clockid_t clock_id)
 		printf("No rx_vlan_tci or rx_vlan_proto, err=%d\n",
 		       meta->rx_vlan_tag_err);
 	}
+
+	if (meta->hint_valid & XDP_META_FIELD_CHECKSUM)
+		print_rx_cksum(meta->ip_summed, meta->cksum,
+			       meta->cksum_level);
+	else
+		printf("No rx_cksum, err=%d\n", meta->rx_cksum_err);
 }
 
 static void verify_skb_metadata(int fd)
diff --git a/tools/testing/selftests/bpf/xdp_metadata.h b/tools/testing/selftests/bpf/xdp_metadata.h
index bca09b94af26..f864d4a8bd8c 100644
--- a/tools/testing/selftests/bpf/xdp_metadata.h
+++ b/tools/testing/selftests/bpf/xdp_metadata.h
@@ -28,6 +28,7 @@ enum xdp_meta_field {
 	XDP_META_FIELD_TS	= BIT(0),
 	XDP_META_FIELD_RSS	= BIT(1),
 	XDP_META_FIELD_VLAN_TAG	= BIT(2),
+	XDP_META_FIELD_CHECKSUM = BIT(3),
 };
 
 #define XDP_CHECKSUM_NONE		BIT(0)
@@ -52,10 +53,13 @@ struct xdp_meta {
 		};
 		__s32 rx_vlan_tag_err;
 	};
-	struct {
-		__u32 ip_summed;
-		__u32 cksum;
-		__u8 cksum_level;
+	union {
+		struct {
+			__u32 ip_summed;
+			__u32 cksum;
+			__u8 cksum_level;
+		};
+		__s32 rx_cksum_err;
 	};
 	enum xdp_meta_field hint_valid;
 };
-- 
2.47.0


^ permalink raw reply related

* [PATCH bpf-next v4 6/6] selftests: drv-net: add XDP RX checksum metadata tests
From: Vladimir Vdovin @ 2026-07-08 20:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Donald Hunter, Jakub Kicinski, David S . Miller,
	Eric Dumazet, Paolo Abeni, Simon Horman, Alexei Starovoitov,
	Daniel Borkmann, Jesper Dangaard Brouer, John Fastabend,
	Stanislav Fomichev, Andrew Lunn, Tony Nguyen, Przemek Kitszel,
	Alexander Lobakin, Andrii Nakryiko, Martin KaFai Lau,
	Eduard Zingerman, Song Liu, Yonghong Song, KP Singh, Hao Luo,
	Jiri Olsa, Shuah Khan, Maciej Fijalkowski
  Cc: Jakub Sitnicki, Aleksandr Loktionov, netdev, bpf, intel-wired-lan,
	linux-kselftest, Vladimir Vdovin
In-Reply-To: <20260708203410.45121-1-deliran@verdict.gg>

Extend the xdp_metadata.py driver test with coverage for
bpf_xdp_metadata_rx_checksum().

Add an xdp_rx_csum program to xdp_metadata.bpf.o that reads the RX
checksum verdict and stores the ip_summed bitmask, the hw checksum
value and the checksum level into a map.  The L4 port/protocol filter
is the same as in the existing xdp_rss_hash program, so move it into a
common helper.

The new cases only run on devices whose driver implements the
xmo_rx_checksum callback, detected through the "checksum" bit of the
xdp-rx-metadata-features netlink attribute; on other devices they
report SKIP:

 - xdp_rx_csum_valid (tcp/udp variants): traffic with a correct
   checksum sent from the remote endpoint must be reported with a
   usable verdict, i.e. CHECKSUM_UNNECESSARY and/or CHECKSUM_COMPLETE.
   CHECKSUM_NONE is a legitimate verdict for a device that does not
   verify the packets (e.g. veth reports it for locally generated
   CHECKSUM_PARTIAL traffic), so it results in SKIP rather than in a
   failure;

 - xdp_rx_csum_invalid: UDP packets with a corrupted L4 checksum
   (sent with the net/lib csum tool) must not be reported as
   CHECKSUM_UNNECESSARY.

Signed-off-by: Vladimir Vdovin <deliran@verdict.gg>
---
 .../selftests/drivers/net/hw/xdp_metadata.py  | 110 +++++++++++++++++
 .../selftests/net/lib/xdp_metadata.bpf.c      | 112 ++++++++++++++++--
 2 files changed, 209 insertions(+), 13 deletions(-)

diff --git a/tools/testing/selftests/drivers/net/hw/xdp_metadata.py b/tools/testing/selftests/drivers/net/hw/xdp_metadata.py
index 33a1985356d9..1a623771477b 100644
--- a/tools/testing/selftests/drivers/net/hw/xdp_metadata.py
+++ b/tools/testing/selftests/drivers/net/hw/xdp_metadata.py
@@ -8,6 +8,8 @@ These tests load device-bound XDP programs from xdp_metadata.bpf.o
 that call metadata kfuncs, send traffic, and verify the extracted
 metadata via BPF maps.
 """
+import time
+
 from lib.py import ksft_run, ksft_eq, ksft_exit, ksft_ge, ksft_ne, ksft_pr
 from lib.py import KsftNamedVariant, ksft_variants
 from lib.py import CmdExitFailure, KsftSkipEx, NetDrvEpEnv
@@ -81,8 +83,22 @@ _RSS_KEY_TYPE = 1
 _RSS_KEY_PKT_CNT = 2
 _RSS_KEY_ERR_CNT = 3
 
+_CSUM_KEY_IP_SUMMED = 0
+_CSUM_KEY_CKSUM = 1
+_CSUM_KEY_LEVEL = 2
+_CSUM_KEY_PKT_CNT = 3
+_CSUM_KEY_ERR_CNT = 4
+
 XDP_RSS_L4 = 0x8  # BIT(3) from enum xdp_rss_hash_type
 
+# Mirror of enum xdp_checksum from include/net/xdp.h
+XDP_CHECKSUM_NONE = 0x1
+XDP_CHECKSUM_UNNECESSARY = 0x2
+XDP_CHECKSUM_COMPLETE = 0x4
+
+# Fixed destination port of the net/lib csum tool
+_CSUM_TOOL_PORT = 34000
+
 
 @ksft_variants([
     KsftNamedVariant("tcp", "tcp"),
@@ -130,6 +146,98 @@ def test_xdp_rss_hash(cfg, proto):
             f"RSS hash type should include L4 for {proto.upper()} traffic")
 
 
+def _require_rx_csum_meta(cfg):
+    """Skip unless the device exposes XDP RX checksum metadata."""
+    dev_info = cfg.netnl.dev_get({"ifindex": cfg.ifindex})
+    rx_meta = dev_info.get("xdp-rx-metadata-features", [])
+    if "checksum" not in rx_meta:
+        raise KsftSkipEx("device does not support XDP rx checksum metadata")
+
+
+@ksft_variants([
+    KsftNamedVariant("tcp", "tcp"),
+    KsftNamedVariant("udp", "udp"),
+])
+def test_xdp_rx_csum_valid(cfg, proto):
+    """Test RX checksum metadata for packets with a correct checksum.
+
+    Loads the xdp_rx_csum program, sends traffic with a valid L4 checksum
+    from the remote endpoint, and verifies that the checksum verdict
+    reported via bpf_xdp_metadata_rx_checksum() is usable
+    (CHECKSUM_UNNECESSARY and/or a CHECKSUM_COMPLETE value).
+
+    CHECKSUM_NONE is a valid verdict for a device that did not verify
+    the packets (e.g. veth reports it for locally generated traffic,
+    which is CHECKSUM_PARTIAL on the skb), so it results in SKIP, not
+    in a failure.
+    """
+    _require_rx_csum_meta(cfg)
+
+    prog_info = _load_xdp_metadata_prog(cfg, "xdp_rx_csum")
+
+    port = rand_port()
+    bpf_map_set("map_xdp_setup", _SETUP_KEY_PORT, port)
+
+    csum_map_id = prog_info["maps"]["map_csum"]
+
+    _send_probe(cfg, port, proto=proto)
+
+    csum = bpf_map_dump(csum_map_id)
+
+    pkt_cnt = csum.get(_CSUM_KEY_PKT_CNT, 0)
+    err_cnt = csum.get(_CSUM_KEY_ERR_CNT, 0)
+    ip_summed = csum.get(_CSUM_KEY_IP_SUMMED, 0)
+
+    ksft_ge(pkt_cnt, 1, comment="should have received at least one packet")
+    ksft_eq(err_cnt, 0, comment=f"RX checksum error count: {err_cnt}")
+
+    ksft_pr(f"  ip_summed: {ip_summed:#x} cksum: "
+            f"{csum.get(_CSUM_KEY_CKSUM, 0):#010x} "
+            f"level: {csum.get(_CSUM_KEY_LEVEL, 0)}")
+    ksft_ne(ip_summed, 0, "the program should have stored a checksum verdict")
+    if not ip_summed & (XDP_CHECKSUM_UNNECESSARY | XDP_CHECKSUM_COMPLETE):
+        raise KsftSkipEx("device did not verify the packet checksum "
+                         "(CHECKSUM_NONE)")
+
+
+def test_xdp_rx_csum_invalid(cfg):
+    """Test RX checksum metadata for packets with a corrupted checksum.
+
+    Sends UDP packets with an intentionally bad L4 checksum using the
+    net/lib csum tool and verifies the device does not claim it validated
+    them: the CHECKSUM_UNNECESSARY bit must not be set.
+    """
+    _require_rx_csum_meta(cfg)
+
+    ipver = cfg.addr_ipver
+    bin_remote = cfg.remote.deploy(cfg.net_lib_dir / "csum")
+
+    prog_info = _load_xdp_metadata_prog(cfg, "xdp_rx_csum")
+
+    bpf_map_set("map_xdp_setup", _SETUP_KEY_PORT, _CSUM_TOOL_PORT)
+
+    csum_map_id = prog_info["maps"]["map_csum"]
+
+    cmd(f"{bin_remote} -i {cfg.remote_ifname} -n 20 -{ipver} "
+        f"-S {cfg.remote_addr} -D {cfg.addr} -r 1 -T -E",
+        host=cfg.remote)
+
+    # no receiver to synchronize against; let NAPI drain the last packets
+    time.sleep(1)
+
+    csum = bpf_map_dump(csum_map_id)
+
+    pkt_cnt = csum.get(_CSUM_KEY_PKT_CNT, 0)
+    ip_summed = csum.get(_CSUM_KEY_IP_SUMMED, 0)
+
+    ksft_ge(pkt_cnt, 1, comment="should have received at least one packet")
+
+    ksft_pr(f"  ip_summed: {ip_summed:#x}")
+    ksft_eq(ip_summed & XDP_CHECKSUM_UNNECESSARY, 0,
+            "device must not report CHECKSUM_UNNECESSARY for a corrupted "
+            "checksum")
+
+
 def main():
     """Run XDP metadata kfunc tests against a real device."""
     with NetDrvEpEnv(__file__) as cfg:
@@ -137,6 +245,8 @@ def main():
         ksft_run(
             [
                 test_xdp_rss_hash,
+                test_xdp_rx_csum_valid,
+                test_xdp_rx_csum_invalid,
             ],
             args=(cfg,))
     ksft_exit()
diff --git a/tools/testing/selftests/net/lib/xdp_metadata.bpf.c b/tools/testing/selftests/net/lib/xdp_metadata.bpf.c
index f71f59215239..70decae0a663 100644
--- a/tools/testing/selftests/net/lib/xdp_metadata.bpf.c
+++ b/tools/testing/selftests/net/lib/xdp_metadata.bpf.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include <stddef.h>
+#include <stdbool.h>
 #include <linux/bpf.h>
 #include <linux/in.h>
 #include <linux/if_ether.h>
@@ -40,6 +41,24 @@ struct {
 	__uint(max_entries, 4);
 } map_rss SEC(".maps");
 
+/* RX checksum results: key 0 = ip_summed bitmask, key 1 = hw cksum value,
+ * key 2 = cksum level, key 3 = packet count, key 4 = error count.
+ */
+enum {
+	CSUM_KEY_IP_SUMMED = 0,
+	CSUM_KEY_CKSUM = 1,
+	CSUM_KEY_LEVEL = 2,
+	CSUM_KEY_PKT_CNT = 3,
+	CSUM_KEY_ERR_CNT = 4,
+};
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__type(key, __u32);
+	__type(value, __u32);
+	__uint(max_entries, 5);
+} map_csum SEC(".maps");
+
 /* Mirror of enum xdp_rss_hash_type from include/net/xdp.h.
  * Needed because the enum is not part of UAPI headers.
  */
@@ -55,8 +74,20 @@ enum xdp_rss_hash_type {
 	XDP_RSS_L4_ICMP = 1U << 8,
 };
 
+/* Mirror of enum xdp_checksum from include/net/xdp.h.
+ * Needed because the enum is not part of UAPI headers.
+ */
+enum xdp_checksum {
+	XDP_CHECKSUM_NONE = 1U << 0,
+	XDP_CHECKSUM_UNNECESSARY = 1U << 1,
+	XDP_CHECKSUM_COMPLETE = 1U << 2,
+};
+
 extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash,
 				    enum xdp_rss_hash_type *rss_type) __ksym;
+extern int bpf_xdp_metadata_rx_checksum(const struct xdp_md *ctx,
+					enum xdp_checksum *ip_summed,
+					__u32 *cksum, __u8 *cksum_level) __ksym;
 
 static __always_inline __u16 get_dest_port(void *l4, void *data_end,
 					   __u8 protocol)
@@ -78,41 +109,39 @@ static __always_inline __u16 get_dest_port(void *l4, void *data_end,
 	return 0;
 }
 
-SEC("xdp")
-int xdp_rss_hash(struct xdp_md *ctx)
+/* Return true when the packet matches the L4 protocol and destination
+ * port configured in map_xdp_setup (zero/unset filters match anything).
+ */
+static __always_inline bool xdp_match_setup(struct xdp_md *ctx)
 {
 	void *data_end = (void *)(long)ctx->data_end;
 	void *data = (void *)(long)ctx->data;
-	enum xdp_rss_hash_type rss_type = 0;
 	struct ethhdr *eth = data;
 	__u8 l4_proto = 0;
-	__u32 hash = 0;
-	__u32 key, val;
 	void *l4 = NULL;
-	__u32 *cnt;
-	int ret;
+	__u32 key;
 
 	if ((void *)(eth + 1) > data_end)
-		return XDP_PASS;
+		return false;
 
 	if (eth->h_proto == bpf_htons(ETH_P_IP)) {
 		struct iphdr *iph = (void *)(eth + 1);
 
 		if ((void *)(iph + 1) > data_end)
-			return XDP_PASS;
+			return false;
 		l4_proto = iph->protocol;
 		l4 = (void *)(iph + 1);
 	} else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) {
 		struct ipv6hdr *ip6h = (void *)(eth + 1);
 
 		if ((void *)(ip6h + 1) > data_end)
-			return XDP_PASS;
+			return false;
 		l4_proto = ip6h->nexthdr;
 		l4 = (void *)(ip6h + 1);
 	}
 
 	if (!l4)
-		return XDP_PASS;
+		return false;
 
 	/* Filter on the configured protocol (map_xdp_setup key XDP_PROTO).
 	 * When set, only process packets matching the requested L4 protocol.
@@ -121,7 +150,7 @@ int xdp_rss_hash(struct xdp_md *ctx)
 	__s32 *proto_cfg = bpf_map_lookup_elem(&map_xdp_setup, &key);
 
 	if (proto_cfg && *proto_cfg != 0 && l4_proto != (__u8)*proto_cfg)
-		return XDP_PASS;
+		return false;
 
 	/* Filter on the configured port (map_xdp_setup key XDP_PORT).
 	 * Only applies to protocols with ports (UDP, TCP).
@@ -133,9 +162,24 @@ int xdp_rss_hash(struct xdp_md *ctx)
 		__u16 dest = get_dest_port(l4, data_end, l4_proto);
 
 		if (!dest || bpf_ntohs(dest) != (__u16)*port_cfg)
-			return XDP_PASS;
+			return false;
 	}
 
+	return true;
+}
+
+SEC("xdp")
+int xdp_rss_hash(struct xdp_md *ctx)
+{
+	enum xdp_rss_hash_type rss_type = 0;
+	__u32 hash = 0;
+	__u32 key, val;
+	__u32 *cnt;
+	int ret;
+
+	if (!xdp_match_setup(ctx))
+		return XDP_PASS;
+
 	ret = bpf_xdp_metadata_rx_hash(ctx, &hash, &rss_type);
 	if (ret < 0) {
 		key = RSS_KEY_ERR_CNT;
@@ -160,4 +204,46 @@ int xdp_rss_hash(struct xdp_md *ctx)
 	return XDP_PASS;
 }
 
+SEC("xdp")
+int xdp_rx_csum(struct xdp_md *ctx)
+{
+	enum xdp_checksum ip_summed = 0;
+	__u8 cksum_level = 0;
+	__u32 cksum = 0;
+	__u32 key, val;
+	__u32 *cnt;
+	int ret;
+
+	if (!xdp_match_setup(ctx))
+		return XDP_PASS;
+
+	ret = bpf_xdp_metadata_rx_checksum(ctx, &ip_summed, &cksum,
+					   &cksum_level);
+	if (ret < 0) {
+		key = CSUM_KEY_ERR_CNT;
+		cnt = bpf_map_lookup_elem(&map_csum, &key);
+		if (cnt)
+			__sync_fetch_and_add(cnt, 1);
+		return XDP_PASS;
+	}
+
+	key = CSUM_KEY_IP_SUMMED;
+	val = (__u32)ip_summed;
+	bpf_map_update_elem(&map_csum, &key, &val, BPF_ANY);
+
+	key = CSUM_KEY_CKSUM;
+	bpf_map_update_elem(&map_csum, &key, &cksum, BPF_ANY);
+
+	key = CSUM_KEY_LEVEL;
+	val = cksum_level;
+	bpf_map_update_elem(&map_csum, &key, &val, BPF_ANY);
+
+	key = CSUM_KEY_PKT_CNT;
+	cnt = bpf_map_lookup_elem(&map_csum, &key);
+	if (cnt)
+		__sync_fetch_and_add(cnt, 1);
+
+	return XDP_PASS;
+}
+
 char _license[] SEC("license") = "GPL";
-- 
2.47.0


^ permalink raw reply related

* Re: [PATCH net-next v4 1/3] net: devmem: allow rx-buf-size > PAGE_SIZE per dmabuf binding
From: Bobby Eshleman @ 2026-07-08 20:35 UTC (permalink / raw)
  To: Paolo Abeni
  Cc: Mina Almasry, Donald Hunter, Jakub Kicinski, David S. Miller,
	Eric Dumazet, Simon Horman, Andrew Lunn, Gerd Hoffmann,
	Vivek Kasireddy, Sumit Semwal, Christian König, Shuah Khan,
	netdev, linux-kernel, dri-devel, linux-media, linaro-mm-sig,
	linux-kselftest, sdf, razor, daniel, matttbe, skhawaja, dw,
	Joe Damato, Bobby Eshleman
In-Reply-To: <15e72c82-ca99-481b-bd53-744fabd503b0@redhat.com>

On Wed, Jul 08, 2026 at 12:50:07PM +0200, Paolo Abeni wrote:
> On 7/7/26 10:36 PM, Mina Almasry wrote:
> > On Wed, Jul 1, 2026 at 12:22 PM Bobby Eshleman <bobbyeshleman@gmail.com> wrote:
> >>
> >> From: Bobby Eshleman <bobbyeshleman@meta.com>
> >>
> >> Every devmem dmabuf binding today hands the page_pool PAGE_SIZE niovs.
> >> This caps a single RX descriptor at PAGE_SIZE, burning CPU on buffer
> >> churn for large flows.
> >>
> >> Add a bind-time netlink attribute, NETDEV_A_DMABUF_RX_BUF_SIZE, that
> >> lets userspace request a larger niov size. The value must be a power of
> >> two >= PAGE_SIZE.
> >>
> >> Measurements
> >> ------------
> 
> Checkpatch complains about this separator usage:
> 
> ERROR: Invalid commit separator - some tools may have problems applying this
> #15:
> ------------
> 
> Please replace or remove it in the next revision
> 
> >> @@ -90,16 +90,17 @@ net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding)
> >>         struct dmabuf_genpool_chunk_owner *owner;
> >>         unsigned long dma_addr;
> >>         struct net_iov *niov;
> >> -       ssize_t offset;
> >> -       ssize_t index;
> >> +       size_t offset;
> >> +       size_t index;
> >>
> > 
> > nit: I would keep this signed. Some of the most frustrating issues I
> > ran into is some of the underflowing and then passing a > check or
> > something. Although if the LLM is not complaining about this
> > particular case, there is probably no issue with it. I also notice a
> > lot of existing code that deals with indexes and offsets goes for
> > signed.
> 
> At very least the above change should go in a separate patch, as is
> quite unrelated from the rest.
> 
> /P
> 

Sounds good, I'll drop the type change.

Thanks,
Bobby

^ permalink raw reply

* Re: [PATCH 0/3] SM8450 IPA support
From: Esteban Urrutia @ 2026-07-08 20:45 UTC (permalink / raw)
  To: Alex Elder, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Alex Elder
  Cc: linux-arm-msm, devicetree, linux-kernel, netdev
In-Reply-To: <8309e9c7-a110-478b-8cd4-c002070d2b4c@riscstar.com>

On 7/8/26 3:49 PM, Alex Elder wrote:
> This was interesting to see.  It's something I should probably
> document better.  Most everything maps to the downstream code,
> but it's not always completely obvious how, because the upstream
> driver has evolved substantially.

On a personal note, I'm surprised to see someone not from Qualcomm
maintaining this driver. It must be hard, so kudos.

> This means that the SRAM size (ipa_mem_data->smem_size) should
> possibly be defined in devicetree (as the IMEM address and size
> now are).
> 
> The SMEM region is used for "IPA filter tables", and access to
> it is shared between the AP and the modem.  Unlike the other
> (host) memory regions, the size used is *not* included in the
> ipa_init_modem_driver_req message that communicates from the
> AP to the modem where the regions are, and their sizes.
> 
> So it's possible that the size used must actually match what
> is expected by both the AP and modem.  If that is the case,
> using the smaller size might have problems on whichever
> platform (SM8450?) expects the larger one.
> 
> So I'm not sure whether using the smaller size for both
> platforms is OK; someone from Qualcomm might be able to
> answer that question.

I actually went ahead and reviewed downstream device trees I found on
GitHub (1) which contain both SM8450 and SM8475 device trees looking for
the qcom,ipa-q6-smem-size property, which would correspond to the SRAM
size, and to my surprise, this was set to 0x9000 for both SoCs.
Most likely the commit I got the SRAM information from (2) never made it
to production devices.

With this clarified, I think it should be okay to keep things defined as
they currently are.

> I'll try to explain those things separately.
Regarding this, I have a question: where would this be published?

Thanks for taking the time to properly review my changes.
I'll address the review when I can.

(1) https://github.com/sm8450-mainline/fdt
(2) https://github.com/LineageOS/android_kernel_qcom_sm8450-devicetrees/commit/477aab9e7479ff553c7a162ae74029170a2e8291.patch

Regards,
Esteban


^ permalink raw reply

* RE: [EXTERNAL] Re: [PATCH net-next v2] net: mana: Add handler for sriov configure
From: Haiyang Zhang @ 2026-07-08 20:52 UTC (permalink / raw)
  To: Paolo Abeni, haiyangz@linux.microsoft.com
  Cc: linux-hyperv@vger.kernel.org, netdev@vger.kernel.org,
	KY Srinivasan, wei.liu@kernel.org, Dexuan Cui, Long Li,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, horms@kernel.org, ernis@linux.microsoft.com,
	dipayanroy@linux.microsoft.com, gargaditya@linux.microsoft.com,
	shradhagupta@linux.microsoft.com, linux-kernel@vger.kernel.org,
	Paul Rosswurm
In-Reply-To: <20260708080854.64655-1-pabeni@redhat.com>



> -----Original Message-----
> From: Paolo Abeni <pabeni@redhat.com>
> Sent: Wednesday, July 8, 2026 4:09 AM
> To: haiyangz@linux.microsoft.com
> Cc: linux-hyperv@vger.kernel.org; netdev@vger.kernel.org; KY Srinivasan
> <kys@microsoft.com>; Haiyang Zhang <haiyangz@microsoft.com>;
> wei.liu@kernel.org; Dexuan Cui <DECUI@microsoft.com>; Long Li
> <longli@microsoft.com>; andrew+netdev@lunn.ch; davem@davemloft.net;
> edumazet@google.com; kuba@kernel.org; pabeni@redhat.com; horms@kernel.org;
> ernis@linux.microsoft.com; dipayanroy@linux.microsoft.com;
> gargaditya@linux.microsoft.com; shradhagupta@linux.microsoft.com; linux-
> kernel@vger.kernel.org; Paul Rosswurm <paulros@microsoft.com>
> Subject: [EXTERNAL] Re: [PATCH net-next v2] net: mana: Add handler for
> sriov configure
> 
> From: AI Reviewer <ai@example.com>
> 
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at:
> https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsashiko.
> dev%2F&data=05%7C02%7Chaiyangz%40microsoft.com%7C27add93a1c4b4c0c7b4808ded
> cc833d4%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C639190949593984694%7C
> Unknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJX
> aW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=qLm%2BrL1nEF6%
> 2FlF2%2Fmed2mnc%2BVR4Vp9P6G6i5Im1PquU%3D&reserved=0
> ---
> net: mana: Add handler for sriov configure
> 
> Add callback function for the pci_driver / sriov_configure.
> 
> It asks the NIC to provide certain number of VFs, or disable
> VFs if the request is zero.
> 
> > diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> > index e8b7ffb47eb98..f7a79874fd0eb 100644
> > --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> > +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> > @@ -2496,6 +2496,20 @@ static void mana_gd_shutdown(struct pci_dev
> *pdev)
> >  	pci_disable_device(pdev);
> >  }
> 
> [Severity: High]
> With the addition of SR-IOV support in this patch, do mana_gd_shutdown()
> and
> mana_gd_remove() need to call pci_disable_sriov()?
> 
> If a user enables VFs via sysfs and then unbinds the driver or shuts down
> the
> system, could this omission introduce a regression where orphaned, dead VF
> PCI
> devices are left in the kernel?
> 
> Accessing these orphaned VFs might trigger use-after-free crashes or
> hardware
> faults, as the underlying PF hardware and driver context have been
> destroyed.
Will fix.

> 
> > +static int mana_sriov_configure(struct pci_dev *pdev, int numvfs)
> > +{
> > +	int err = 0;
> > +
> > +	dev_info(&pdev->dev, "Requested num VFs: %d\n", numvfs);
> > +
> > +	if (numvfs > 0)
> > +		err = pci_enable_sriov(pdev, numvfs);
> > +	else
> > +		pci_disable_sriov(pdev);
> 
> [Severity: High]
> Should this path check if the VFs are currently assigned to a guest VM
> before
> disabling SR-IOV?
> 
> If a privileged user writes 0 to sriov_numvfs while VFs are actively
> assigned
> to a VM (e.g., via vfio-pci), could forcefully removing the PCI devices
> cause
> a regression resulting in host IOMMU faults and guest kernel panics?
> 
> Would it be better to check pci_vfs_assigned(pdev) here, or use the
> pci_sriov_configure_simple() helper to safely enforce this?

Will update.
I will send out an updated patch soon.

Thanks,
- Haiyang

^ permalink raw reply

* [PATCH nf] netfilter: flowtable: tear down HW offloaded flows on FIB route changes
From: Ahmed Zaki @ 2026-07-08 20:54 UTC (permalink / raw)
  To: netfilter-devel; +Cc: pablo, fw, kuba, edumazet, davem, pabeni, horms, netdev

Hardware-offloaded flows bypass the CPU and, unlike the software
datapath, dst_check() does not invalidate them when a route changes.
For ephemeral flows, this is usually not a problem as the flow expire on
its own and the driver clears the entry in the HW. However, for persistent
flows forwarded through the device, the HW is never informed that the
route has expired.

For tables marked with NF_FLOWTABLE_HW_OFFLOAD, listen to the per-net FIB
notifier chain and tear down the affected flows so they are re-evaluated by
the SW forwarding path.

A lockless list is used to reduce the work items overhead in case of a
route change storm allowing many FIB events to be processed by one work
item.

Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support")
Assisted-by: Claude:claude-opus-4.8
Signed-off-by: Ahmed Zaki <anzaki@gmail.com>
---
 include/net/netfilter/nf_flow_table.h |   3 +
 net/netfilter/nf_flow_table_core.c    | 202 ++++++++++++++++++++++++++
 2 files changed, 205 insertions(+)

diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 7b23b245a5a8..7c36255f5a4f 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -84,6 +84,9 @@ struct nf_flowtable {
 	struct flow_block		flow_block;
 	struct rw_semaphore		flow_block_lock; /* Guards flow_block */
 	possible_net_t			net;
+	struct notifier_block		fib_nb;
+	struct work_struct		fib_work;
+	struct llist_head		fib_events;
 };
 
 static inline bool nf_flowtable_hw_offload(struct nf_flowtable *flowtable)
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 99c5b9d671a0..2c912056921a 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -5,8 +5,12 @@
 #include <linux/netfilter.h>
 #include <linux/rhashtable.h>
 #include <linux/netdevice.h>
+#include <linux/llist.h>
 #include <net/ip.h>
 #include <net/ip6_route.h>
+#include <net/fib_notifier.h>
+#include <net/ip_fib.h>
+#include <net/ip6_fib.h>
 #include <net/netfilter/nf_tables.h>
 #include <net/netfilter/nf_flow_table.h>
 #include <net/netfilter/nf_conntrack.h>
@@ -695,11 +699,179 @@ void nf_flow_dnat_port(const struct flow_offload *flow, struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(nf_flow_dnat_port);
 
+struct nf_flow_fib_match {
+	struct llist_node	*events;
+};
+
+struct nf_flow_fib_event {
+	struct llist_node	node;
+	u8			family;
+	u8			prefix_len;
+	union {
+		__be32		ip4;
+		struct in6_addr	ip6;
+	} addr;
+};
+
+static bool nf_flow_fib_tuple_match(const struct flow_offload_tuple *tuple,
+				    const struct nf_flow_fib_event *ev)
+{
+	if (tuple->l3proto != ev->family)
+		return false;
+
+	switch (ev->family) {
+	case NFPROTO_IPV4: {
+		__be32 mask = ev->prefix_len ?
+			htonl(~0u << (32 - ev->prefix_len)) : 0;
+		return (tuple->dst_v4.s_addr & mask) == (ev->addr.ip4 & mask);
+	}
+#if IS_ENABLED(CONFIG_IPV6)
+	case NFPROTO_IPV6:
+		return ipv6_prefix_equal(&tuple->dst_v6, &ev->addr.ip6,
+					 ev->prefix_len);
+#endif
+	default:
+		return false;
+	}
+}
+
+static bool nf_flow_fib_flow_match(const struct flow_offload *flow,
+				   const struct nf_flow_fib_match *m)
+{
+	const struct flow_offload_tuple *orig, *reply;
+	const struct nf_flow_fib_event *ev;
+	struct llist_node *node;
+
+	orig  = &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple;
+	reply = &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple;
+
+	for (node = m->events; node; node = node->next) {
+		ev = llist_entry(node, struct nf_flow_fib_event, node);
+		if (nf_flow_fib_tuple_match(orig, ev) ||
+		    nf_flow_fib_tuple_match(reply, ev))
+			return true;
+	}
+
+	return false;
+}
+
+static void nf_flow_offload_fib_cb(struct nf_flowtable *flow_table,
+				   struct flow_offload *flow, void *data)
+{
+	const struct nf_flow_fib_match *m = data;
+
+	if (test_bit(NF_FLOW_TEARDOWN, &flow->flags))
+		return;
+
+	if (nf_flow_fib_flow_match(flow, m))
+		flow_offload_teardown(flow);
+}
+
+static void nf_flow_table_fib_work(struct work_struct *work)
+{
+	struct nf_flowtable *flow_table =
+		container_of(work, struct nf_flowtable, fib_work);
+	struct nf_flow_fib_event *ev, *next;
+	struct nf_flow_fib_match m = {};
+	struct llist_node *events;
+
+	events = llist_del_all(&flow_table->fib_events);
+	if (!events)
+		return;
+
+	m.events = events;
+	nf_flow_table_iterate(flow_table, nf_flow_offload_fib_cb, &m);
+
+	llist_for_each_entry_safe(ev, next, events, node)
+		kfree(ev);
+}
+
+static bool nf_flowtable_fib_family_match(const struct nf_flowtable *flowtable,
+					  u8 event_family)
+{
+	switch (flowtable->type->family) {
+	case NFPROTO_IPV4:
+		return event_family == NFPROTO_IPV4;
+	case NFPROTO_IPV6:
+		return event_family == NFPROTO_IPV6;
+	case NFPROTO_INET:
+		return event_family == NFPROTO_IPV4 ||
+		       event_family == NFPROTO_IPV6;
+	default:
+		return false;
+	}
+}
+
+/* Called with rcu_read_lock() */
+static int nf_flow_table_fib_event(struct notifier_block *nb,
+				   unsigned long event, void *ptr)
+{
+	struct nf_flowtable *flow_table =
+		container_of(nb, struct nf_flowtable, fib_nb);
+	struct fib_notifier_info *info = ptr;
+	struct nf_flow_fib_event *ev;
+
+	switch (event) {
+	case FIB_EVENT_ENTRY_REPLACE:
+	case FIB_EVENT_ENTRY_APPEND:
+	case FIB_EVENT_ENTRY_DEL:
+		break;
+	default:
+		return NOTIFY_DONE;
+	}
+
+	/* Skip events for an address family this table cannot hold. */
+	if (!nf_flowtable_fib_family_match(flow_table, info->family))
+		return NOTIFY_DONE;
+
+	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev)
+		return NOTIFY_DONE;
+
+	switch (info->family) {
+	case NFPROTO_IPV4:
+		struct fib_entry_notifier_info *fen;
+
+		fen = container_of(info, struct fib_entry_notifier_info, info);
+		ev->family     = NFPROTO_IPV4;
+		ev->addr.ip4   = htonl(fen->dst);
+		ev->prefix_len = fen->dst_len;
+		break;
+
+#if IS_ENABLED(CONFIG_IPV6)
+	case NFPROTO_IPV6:
+		struct fib6_entry_notifier_info *fen6;
+
+		fen6 = container_of(info, struct fib6_entry_notifier_info, info);
+		if (!fen6->rt)
+			goto err;
+
+		ev->family     = NFPROTO_IPV6;
+		ev->addr.ip6   = fen6->rt->fib6_dst.addr;
+		ev->prefix_len = fen6->rt->fib6_dst.plen;
+		break;
+#endif
+	default:
+		goto err;
+	}
+
+	llist_add(&ev->node, &flow_table->fib_events);
+	queue_work(system_power_efficient_wq, &flow_table->fib_work);
+	return NOTIFY_DONE;
+
+err:
+	kfree(ev);
+	return NOTIFY_DONE;
+}
+
 int nf_flow_table_init(struct nf_flowtable *flowtable)
 {
+	struct net *net = read_pnet(&flowtable->net);
 	int err;
 
 	INIT_DELAYED_WORK(&flowtable->gc_work, nf_flow_offload_work_gc);
+	INIT_WORK(&flowtable->fib_work, nf_flow_table_fib_work);
+	init_llist_head(&flowtable->fib_events);
 	flow_block_init(&flowtable->flow_block);
 	init_rwsem(&flowtable->flow_block_lock);
 
@@ -711,11 +883,24 @@ int nf_flow_table_init(struct nf_flowtable *flowtable)
 	queue_delayed_work(system_power_efficient_wq,
 			   &flowtable->gc_work, HZ);
 
+	if (nf_flowtable_hw_offload(flowtable)) {
+		flowtable->fib_nb.notifier_call = nf_flow_table_fib_event;
+		err = register_fib_notifier(net, &flowtable->fib_nb,
+					    NULL, NULL);
+		if (err < 0)
+			goto err_fib;
+	}
+
 	mutex_lock(&flowtable_lock);
 	list_add(&flowtable->list, &flowtables);
 	mutex_unlock(&flowtable_lock);
 
 	return 0;
+
+err_fib:
+	cancel_delayed_work_sync(&flowtable->gc_work);
+	rhashtable_destroy(&flowtable->rhashtable);
+	return err;
 }
 EXPORT_SYMBOL_GPL(nf_flow_table_init);
 
@@ -754,8 +939,25 @@ void nf_flow_table_cleanup(struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(nf_flow_table_cleanup);
 
+static void nf_flow_table_fib_drain(struct nf_flowtable *flow_table)
+{
+	struct nf_flow_fib_event *ev, *next;
+	struct llist_node *events;
+
+	events = llist_del_all(&flow_table->fib_events);
+	llist_for_each_entry_safe(ev, next, events, node)
+		kfree(ev);
+}
+
 void nf_flow_table_free(struct nf_flowtable *flow_table)
 {
+	if (nf_flowtable_hw_offload(flow_table)) {
+		unregister_fib_notifier(read_pnet(&flow_table->net),
+					&flow_table->fib_nb);
+		cancel_work_sync(&flow_table->fib_work);
+		nf_flow_table_fib_drain(flow_table);
+	}
+
 	mutex_lock(&flowtable_lock);
 	list_del(&flow_table->list);
 	mutex_unlock(&flowtable_lock);
-- 
2.43.0


^ permalink raw reply related

* [PATCH net-next v3] net: mana: Add handler for sriov configure
From: Haiyang Zhang @ 2026-07-08 20:59 UTC (permalink / raw)
  To: linux-hyperv, netdev, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Long Li, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Erni Sri Satya Vennela,
	Dipayaan Roy, Aditya Garg, Shradha Gupta, linux-kernel
  Cc: paulros

From: Haiyang Zhang <haiyangz@microsoft.com>

Add callback function for the pci_driver / sriov_configure.

It asks the NIC to provide certain number of VFs, or disable
VFs if the request is zero.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
v3:
  Updated sriov disabling paths suggested by Paolo Abeni

v2:
  No longer change VF autoprobe as discussed with Leon Romanovsky and Bjorn Helgaas.

---
 .../net/ethernet/microsoft/mana/gdma_main.c   | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index aef3b77229c1..80a9118a90bc 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -2456,6 +2456,8 @@ static void mana_gd_remove(struct pci_dev *pdev)
 {
 	struct gdma_context *gc = pci_get_drvdata(pdev);
 
+	pci_disable_sriov(pdev);
+
 	mana_rdma_remove(&gc->mana_ib);
 	mana_remove(&gc->mana, false);
 
@@ -2517,6 +2519,8 @@ static void mana_gd_shutdown(struct pci_dev *pdev)
 
 	dev_info(&pdev->dev, "Shutdown was called\n");
 
+	pci_disable_sriov(pdev);
+
 	mana_rdma_remove(&gc->mana_ib);
 	mana_remove(&gc->mana, true);
 
@@ -2525,6 +2529,27 @@ static void mana_gd_shutdown(struct pci_dev *pdev)
 	pci_disable_device(pdev);
 }
 
+static int mana_sriov_configure(struct pci_dev *pdev, int numvfs)
+{
+	int err = 0;
+
+	dev_info(&pdev->dev, "Requested num VFs: %d\n", numvfs);
+
+	if (numvfs > 0) {
+		err = pci_enable_sriov(pdev, numvfs);
+	} else {
+		if (pci_vfs_assigned(pdev)) {
+			dev_warn(&pdev->dev,
+				 "Cannot disable SR-IOV while VFs are assigned\n");
+			return -EPERM;
+		}
+
+		pci_disable_sriov(pdev);
+	}
+
+	return err ? err : numvfs;
+}
+
 static const struct pci_device_id mana_id_table[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_PF_DEVICE_ID) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_PF2_DEVICE_ID) },
@@ -2540,6 +2565,7 @@ static struct pci_driver mana_driver = {
 	.suspend	= mana_gd_suspend,
 	.resume		= mana_gd_resume,
 	.shutdown	= mana_gd_shutdown,
+	.sriov_configure = mana_sriov_configure,
 };
 
 static int __init mana_driver_init(void)
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH net] sctp: validate stream count in sctp_process_strreset_inreq()
From: Xin Long @ 2026-07-08 21:20 UTC (permalink / raw)
  To: Cen Zhang (Microsoft)
  Cc: marcelo.leitner, davem, edumazet, kuba, pabeni, horms, linux-sctp,
	netdev, linux-kernel, AutonomousCodeSecurity, tgopinath, kys
In-Reply-To: <20260707203215.2752-1-blbllhy@gmail.com>

On Tue, Jul 7, 2026 at 4:32 PM Cen Zhang (Microsoft) <blbllhy@gmail.com> wrote:
>
> When processing a RESET_IN_REQUEST from a peer,
> sctp_process_strreset_inreq() derives the stream count from the
> parameter length but does not check whether the resulting
> RESET_OUT_REQUEST response would exceed SCTP_MAX_CHUNK_LEN.
>
> The OUT request header (sctp_strreset_outreq, 16 bytes) is 8 bytes larger
> than the IN request header (sctp_strreset_inreq, 8 bytes). Generally, the
> IP payload is bounded to 65535 bytes, so the stream list cannot be
> large enough to trigger the overflow. However, on interfaces with MTU >
> 65535 (e.g., loopback with IPv6 jumbograms), a stream list that fits
> within the incoming IN parameter can cause a __u16 overflow in
> sctp_make_strreset_req() when computing the OUT response size, leading to
> an undersized skb allocation, raising a kernel BUG:
>
>   net/core/skbuff.c:207        skb_panic
>   net/core/skbuff.c:2625       skb_put
>   net/sctp/sm_make_chunk.c:1535 sctp_addto_chunk
>   net/sctp/sm_make_chunk.c:3695 sctp_make_strreset_req
>   net/sctp/stream.c:655        sctp_process_strreset_inreq
>
> The local setsockopt path (sctp_send_reset_streams) already performs length
> validation, but the network packet path does not. Fix by adding similar
> length check before calling sctp_make_strreset_req().
>
> Fixes: 7f9d68ac944e ("sctp: implement sender-side procedures for SSN Reset
> Request Parameter")
> Reported-by: AutonomousCodeSecurity@microsoft.com
> Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
> ---
>  net/sctp/stream.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/net/sctp/stream.c b/net/sctp/stream.c
> index 5c2fdedea..ea3805712 100644
> --- a/net/sctp/stream.c
> +++ b/net/sctp/stream.c
> @@ -639,6 +639,10 @@ struct sctp_chunk *sctp_process_strreset_inreq(
>
>         nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
>         str_p = inreq->list_of_streams;
> +       if (nums * sizeof(__u16) + sizeof(struct sctp_strreset_outreq)
> +                       > SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_reconf_chunk)) {
> +               goto out;
> +       }
>         for (i = 0; i < nums; i++) {
>                 if (ntohs(str_p[i]) >= stream->outcnt) {
>                         result = SCTP_STRRESET_ERR_WRONG_SSN;
> --
> 2.53.0
>
I think we should also prevent sending such an 'inreq', since it will
always be rejected by the peer. We can add improve the check in
'sctp_send_reset_streams()' like:

diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index ea3805712b76..51a14d1f2391 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -308,7 +308,8 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
                                        goto out;

                        param_len += str_nums * sizeof(__u16) +
-                                    sizeof(struct sctp_strreset_inreq);
+                                    (out ? sizeof(struct sctp_strreset_inreq)
+                                         : sizeof(struct
sctp_strreset_outreq));
                }

Nits: Please keep the '>' on the same line as the left-hand operand and
indent the continuation line using the usual kernel style. Also No braces
are needed for a single statement.

if (nums * sizeof(__u16) + sizeof(struct sctp_strreset_outreq) >
    SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_reconf_chunk))
        goto out;

Thanks.

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox