* [PATCH net 1/6] batman-adv: retrieve ethhdr after potential skb realloc on RX
From: Simon Wunderlich @ 2026-06-30 13:44 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable, Sashiko,
Simon Wunderlich
In-Reply-To: <20260630134430.85786-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
pskb_may_pull() in batadv_interface_rx() could reallocate the buffer behind
the skb. Variables which were pointing to the old buffer need to be
reassigned to avoid an use-after-free.
This was done correctly for the VLAN header but missed for the ethernet
header which is later used for the TT and AP isolation handling.
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: c6c8fea29769 ("net: Add batman-adv meshing protocol")
Fixes: c78296665c3d ("batman-adv: Check skb size before using encapsulated ETH+VLAN header")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/mesh-interface.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 44026810b99ce..511f70e0706a7 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -434,6 +434,7 @@ void batadv_interface_rx(struct net_device *mesh_iface,
if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
goto dropped;
+ ethhdr = eth_hdr(skb);
vhdr = skb_vlan_eth_hdr(skb);
/* drop batman-in-batman packets to prevent loops */
--
2.47.3
^ permalink raw reply related
* [PATCH net 0/6] pull request: batman-adv 2026-06-30
From: Simon Wunderlich @ 2026-06-30 13:44 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Simon Wunderlich
Dear net maintainers,
here are a couple of bugfixes for batman-adv which we would like to have integrated into net.
Please pull or let me know of any problem!
Thank you,
Simon
The following changes since commit 805185b7c7a1069e407b6f7b3bc98e44d415f484:
Merge tag 'net-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2026-06-25 12:25:36 -0700)
are available in the Git repository at:
https://git.open-mesh.org/batadv.git tags/batadv-net-pullrequest-20260630
for you to fetch changes up to 26560c4a03dc4d607331600c187f59ab2df5f341:
batman-adv: dat: ensure accessible eth_hdr proto field (2026-06-28 11:49:04 +0200)
----------------------------------------------------------------
Here are some batman-adv bugfix, all by Sven Eckelmann:
- fix pointers after potential skb reallocs (5 patches)
- dat: ensure accessible eth_hdr proto field
----------------------------------------------------------------
Sven Eckelmann (6):
batman-adv: retrieve ethhdr after potential skb realloc on RX
batman-adv: access unicast_ttvn skb->data only after skb realloc
batman-adv: gw: acquire ethernet header only after skb realloc
batman-adv: dat: acquire ARP hw source only after skb realloc
batman-adv: bla: reacquire gw address after skb realloc
batman-adv: dat: ensure accessible eth_hdr proto field
net/batman-adv/distributed-arp-table.c | 28 +++++++++++++++++++++++++++-
net/batman-adv/gateway_client.c | 3 ++-
net/batman-adv/main.c | 3 +++
net/batman-adv/mesh-interface.c | 1 +
net/batman-adv/routing.c | 3 ++-
5 files changed, 35 insertions(+), 3 deletions(-)
^ permalink raw reply
* [PATCH net 3/6] batman-adv: gw: acquire ethernet header only after skb realloc
From: Simon Wunderlich @ 2026-06-30 13:44 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
In-Reply-To: <20260630134430.85786-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer
behind the skb. Variables which were pointing to the old buffer need to be
reassigned to avoid an use-after-free.
Cc: stable@vger.kernel.org
Fixes: 6c413b1c22a2 ("batman-adv: send every DHCP packet as bat-unicast")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/gateway_client.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 305488a74a256..a5ac82eabd250 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -684,12 +684,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct batadv_gw_node *gw_node = NULL;
struct batadv_gw_node *curr_gw = NULL;
struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
- struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+ struct ethhdr *ethhdr;
bool out_of_range = false;
u8 curr_tq_avg;
unsigned short vid;
vid = batadv_get_vid(skb, 0);
+ ethhdr = (struct ethhdr *)skb->data;
if (is_multicast_ether_addr(ethhdr->h_dest))
goto out;
--
2.47.3
^ permalink raw reply related
* [PATCH net 2/6] batman-adv: access unicast_ttvn skb->data only after skb realloc
From: Simon Wunderlich @ 2026-06-30 13:44 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable, Sashiko,
Simon Wunderlich
In-Reply-To: <20260630134430.85786-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer
behind the skb. Variables which were pointing to the old buffer need to be
reassigned to avoid an use-after-free.
This was done correctly for the ethernet header but missed for the
unicast_packet pointer.
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: c018ad3de61a ("batman-adv: add the VLAN ID attribute to the TT entry")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/routing.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index c05fcc9241add..2cc2307a41702 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -855,8 +855,8 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
if (skb_cow(skb, sizeof(*unicast_packet)) < 0)
return false;
- unicast_packet = (struct batadv_unicast_packet *)skb->data;
vid = batadv_get_vid(skb, hdr_len);
+ unicast_packet = (struct batadv_unicast_packet *)skb->data;
ethhdr = (struct ethhdr *)(skb->data + hdr_len);
/* do not reroute multicast frames in a unicast header */
--
2.47.3
^ permalink raw reply related
* [PATCH net 4/6] batman-adv: dat: acquire ARP hw source only after skb realloc
From: Simon Wunderlich @ 2026-06-30 13:44 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
In-Reply-To: <20260630134430.85786-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer
behind the skb. Variables which were pointing to the old buffer need to be
reassigned to avoid an use-after-free.
Cc: stable@vger.kernel.org
Fixes: b61ec31c8575 ("batman-adv: Snoop DHCPACKs for DAT")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/distributed-arp-table.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index ae39ceaa2e29a..ead02c9e08484 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -1747,6 +1747,7 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
struct ethhdr *ethhdr;
__be32 ip_src, yiaddr;
unsigned short vid;
+ int hdr_size_tmp;
__be16 proto;
u8 *hw_src;
@@ -1763,8 +1764,10 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr))
return;
+ hdr_size_tmp = hdr_size;
+ vid = batadv_dat_get_vid(skb, &hdr_size_tmp);
+ ethhdr = (struct ethhdr *)(skb->data + hdr_size);
hw_src = ethhdr->h_source;
- vid = batadv_dat_get_vid(skb, &hdr_size);
batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);
batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
--
2.47.3
^ permalink raw reply related
* Re: [PATCH net-next v4 06/13] dpaa2-switch: add dpaa2_switch_port_to_bridge_port() helper
From: Ioana Ciornei @ 2026-06-30 13:51 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, netdev; +Cc: linux-kernel
In-Reply-To: <20260629112309.154328-7-ioana.ciornei@nxp.com>
On Mon, Jun 29, 2026 at 02:23:02PM +0300, Ioana Ciornei wrote:
> In preparation for adding offloading support for upper bond devices we
> have to let the switchdev framework know if a specific bridge port is
> offloaded or not, even if that brport is an upper device.
>
> For this to happen, create the dpaa2_switch_port_to_bridge_port function
> which will determine the bridge port corresponding to a particular DPAA2
> switch interface and use it in the switchdev_bridge_port_offload call.
>
> Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
> ---
> Changes in v4:
> - Split the patch so that the first part only adds the base function and
> its call sites and the logic aroung lag is added later in the patch
> which actually adds the support for LAG.
> - Moved the patch so that it's a preparatory patch
>
> Changes in v3:
> - Access lag field through rtnl_dereference() so that we adapt to the
> __rcu change.
> - Check that the brport is non-NULL before calling
> switchdev_bridge_port_unoffload() on it.
>
> Changes in v2:
> - none
> ---
> .../ethernet/freescale/dpaa2/dpaa2-switch.c | 23 ++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
> index d4975d08fa44..88d199befbd9 100644
> --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
> +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
> @@ -2017,6 +2017,15 @@ static int dpaa2_switch_port_attr_set_event(struct net_device *netdev,
> return notifier_from_errno(err);
> }
>
> +static struct net_device *
> +dpaa2_switch_port_to_bridge_port(struct ethsw_port_priv *port_priv)
> +{
> + if (!port_priv->fdb->bridge_dev)
> + return NULL;
> +
> + return port_priv->netdev;
> +}
> +
> static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
> struct net_device *upper_dev,
> struct netlink_ext_ack *extack)
> @@ -2024,6 +2033,7 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
> struct ethsw_port_priv *port_priv = netdev_priv(netdev);
> struct dpaa2_switch_fdb *old_fdb = port_priv->fdb;
> struct ethsw_core *ethsw = port_priv->ethsw_data;
> + struct net_device *brport_dev;
> bool learn_ena;
> int err;
>
> @@ -2035,7 +2045,8 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
> dpaa2_switch_port_set_fdb(port_priv, upper_dev, true);
sashiko.dev notes:
Does the removal of rtnl_lock() earlier in this patch series
expose port_priv->fdb to a concurrent data race here?
dpaa2_switch_event_work() reads port_priv->fdb without taking
rtnl_lock or using READ_ONCE(), which can race with bridge
join/leave operations that modify it via
dpaa2_switch_port_set_fdb().
No, that is not correct and how was this avoided is explained in the
commit message from patch 2/13:
To avoid this kind of concurency without a rtnl_lock, flush the
event workqueue as the last step from the pre_bridge_leave so
that any in-flight operations targeting the current FDB are
finalized before the bridge layout (and the per port FDB
assignment) changes.
Ioana
^ permalink raw reply
* Re: [PATCH 0/3] arm64: dts/net: stmmac: Add Agilex5 SoCDK TSN Config2 board support
From: Maxime Chevallier @ 2026-06-30 13:53 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade, dinguyen
Cc: rmk+kernel, krzk+dt, conor+dt, robh, davem, edumazet, kuba,
pabeni, andrew+netdev, devicetree, linux-arm-kernel, netdev,
linux-kernel
In-Reply-To: <20260630133108.27244-1-muhammad.nazim.amirul.nazle.asmade@altera.com>
Hi,
On 6/30/26 15:31, muhammad.nazim.amirul.nazle.asmade@altera.com wrote:
> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>
> The Intel SoCFPGA Agilex5 SoCDK TSN Config2 board uses a dual-port
> Ethernet setup where gmac1 (TSN port) operates with different MAC-side
> and PHY-side interface modes: GMII internally in the MAC, and RGMII
> towards the PHY.
There's the same behaviour on Gen5, e.g. CycloneV where we have the
"EMAC splitter". Based on wether or not we have that splitter in DT,
we override the INTF_SEL bits to set GMII as the MAC output, the splitter
converting that to RGMII/SGMII.
Is there something similar on this AgileX5 version by any chance, for
which we could reuse the logic ?
I know that on CycloneV you also need to adjust that GMII -> RGMII/SGMII
splitter whenever the speed changes, is that different on agileX5 ? have
you tested 10/100Mbps ?
Thanks,
Maxime
^ permalink raw reply
* [PATCH RESEND net-next] net: hns3: add support to query/set TX pfc_prevention_tout for ethtool with RX prevention disabled
From: Jijie Shao @ 2026-06-30 13:40 UTC (permalink / raw)
To: davem, edumazet, kuba, pabeni, andrew+netdev, horms
Cc: shenjian15, liuyonglong, chenhao418, yangshuaisong, netdev,
linux-kernel, shaojijie
From: Hao Chen <chenhao418@huawei.com>
Add ethtool support to query and configure the PFC (Priority Flow Control)
storm prevention timeout. When TX continuously sends PFC frames, the peer
end is suppressed from sending packets. If this persists, a PFC frame storm
may occur.
This feature allows configuring a timeout to prevent such storms.
Signed-off-by: Hao Chen <chenhao418@huawei.com>
Signed-off-by: Jijie Shao <shaojijie@huawei.com>
---
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 14 ++
.../hns3/hns3_common/hclge_comm_cmd.h | 3 +
.../ethernet/hisilicon/hns3/hns3_ethtool.c | 12 ++
.../hisilicon/hns3/hns3pf/hclge_cmd.h | 9 +
.../hisilicon/hns3/hns3pf/hclge_main.c | 172 ++++++++++++++++++
.../hisilicon/hns3/hns3pf/hclge_main.h | 7 +
6 files changed, 217 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
index a8798eecd9fb..4286af9239b0 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
@@ -602,6 +602,10 @@ typedef int (*read_func)(struct seq_file *s, void *data);
* Config wake on lan
* dbg_get_read_func
* Return the read func for debugfs seq file
+ * set_pfc_prevention_tout
+ * Set PFC storm prevention timeout
+ * get_pfc_prevention_tout
+ * Get PFC storm prevention timeout
*/
struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
@@ -810,6 +814,8 @@ struct hnae3_ae_ops {
int (*hwtstamp_set)(struct hnae3_handle *handle,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack);
+ int (*set_pfc_prevention_tout)(struct hnae3_handle *handle, u16 times);
+ int (*get_pfc_prevention_tout)(struct hnae3_handle *handle, u16 *times);
};
struct hnae3_dcb_ops {
@@ -891,6 +897,14 @@ struct hnae3_roce_private_info {
unsigned long state;
};
+struct hnae3_pfc_storm_para {
+ u32 dir;
+ u32 enable;
+ u32 period_ms;
+ u32 times;
+ u32 recovery_period_ms;
+};
+
#define HNAE3_SUPPORT_APP_LOOPBACK BIT(0)
#define HNAE3_SUPPORT_PHY_LOOPBACK BIT(1)
#define HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK BIT(2)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h
index 2c2a2f1e0d7a..6dde07dde1e8 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_cmd.h
@@ -314,6 +314,9 @@ enum hclge_opcode_type {
/* Query link diagnosis info command */
HCLGE_OPC_QUERY_LINK_DIAGNOSIS = 0x702A,
+
+ /* Config pause storm param command */
+ HCLGE_OPC_CFG_PAUSE_STORM_PARA = 0x7019,
};
enum hclge_comm_cmd_return_status {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index 442f15476af3..e7318f236315 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -1895,6 +1895,12 @@ static int hns3_get_tunable(struct net_device *netdev,
case ETHTOOL_TX_COPYBREAK_BUF_SIZE:
*(u32 *)data = h->kinfo.tx_spare_buf_size;
break;
+ case ETHTOOL_PFC_PREVENTION_TOUT:
+ if (!h->ae_algo->ops->get_pfc_prevention_tout)
+ return -EOPNOTSUPP;
+
+ ret = h->ae_algo->ops->get_pfc_prevention_tout(h, (u16 *)data);
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -2020,6 +2026,12 @@ static int hns3_set_tunable(struct net_device *netdev,
netdev_info(netdev, "the active tx spare buf size is %u, due to page order\n",
priv->ring->tx_spare->len);
+ break;
+ case ETHTOOL_PFC_PREVENTION_TOUT:
+ if (!h->ae_algo->ops->set_pfc_prevention_tout)
+ return -EOPNOTSUPP;
+
+ ret = h->ae_algo->ops->set_pfc_prevention_tout(h, *(u16 *)data);
break;
default:
ret = -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
index 4ce92ddefcde..1c029dc32ab8 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h
@@ -890,6 +890,15 @@ struct hclge_query_wol_supported_cmd {
u8 rsv[20];
};
+struct hclge_pfc_storm_para_cmd {
+ __le32 dir;
+ __le32 enable;
+ __le32 period_ms;
+ __le32 times;
+ __le32 recovery_period_ms;
+ __le32 rsv;
+};
+
struct hclge_hw;
int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num);
#endif
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index fc8587c80813..a08d8a35aef9 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -3524,6 +3524,122 @@ static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf,
return ret;
}
+static int hclge_set_pfc_storm_para(struct hclge_dev *hdev,
+ struct hnae3_pfc_storm_para *para)
+{
+ struct hclge_pfc_storm_para_cmd *para_cmd;
+ struct hclge_desc desc;
+ int ret;
+
+ if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3)
+ return -EOPNOTSUPP;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA,
+ false);
+ para_cmd = (struct hclge_pfc_storm_para_cmd *)desc.data;
+ para_cmd->dir = cpu_to_le32(para->dir);
+ para_cmd->enable = cpu_to_le32(para->enable);
+ para_cmd->period_ms = cpu_to_le32(para->period_ms);
+ para_cmd->times = cpu_to_le32(para->times);
+ para_cmd->recovery_period_ms = cpu_to_le32(para->recovery_period_ms);
+
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret)
+ dev_err(&hdev->pdev->dev,
+ "failed to set pfc storm para, ret = %d\n", ret);
+ return ret;
+}
+
+static int hclge_get_pfc_storm_para(struct hclge_dev *hdev,
+ struct hnae3_pfc_storm_para *para)
+{
+ struct hclge_pfc_storm_para_cmd *para_cmd;
+ struct hclge_desc desc;
+ int ret;
+
+ if (hdev->ae_dev->dev_version < HNAE3_DEVICE_VERSION_V3)
+ return -EOPNOTSUPP;
+
+ hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA, true);
+ para_cmd = (struct hclge_pfc_storm_para_cmd *)desc.data;
+ para_cmd->dir = cpu_to_le32(para->dir);
+ ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+ if (ret) {
+ dev_err(&hdev->pdev->dev,
+ "failed to get pfc storm para, ret = %d\n", ret);
+ return ret;
+ }
+
+ para->enable = le32_to_cpu(para_cmd->enable);
+ para->period_ms = le32_to_cpu(para_cmd->period_ms);
+ para->times = le32_to_cpu(para_cmd->times);
+ para->recovery_period_ms = le32_to_cpu(para_cmd->recovery_period_ms);
+
+ return 0;
+}
+
+static int hclge_enable_pfc_storm_prevent(struct hclge_dev *hdev,
+ int dir, bool enable)
+{
+ struct hnae3_pfc_storm_para para = {0};
+ int ret;
+
+ para.dir = dir;
+ ret = hclge_get_pfc_storm_para(hdev, ¶);
+ if (ret)
+ return ret;
+
+ para.enable = enable;
+ return hclge_set_pfc_storm_para(hdev, ¶);
+}
+
+static int hclge_set_pfc_prevention_tout(struct hnae3_handle *h, u16 times)
+{
+ struct hclge_vport *vport = hclge_get_vport(h);
+ struct hclge_dev *hdev = vport->back;
+ struct hnae3_pfc_storm_para para;
+ int ret;
+
+ if (times > HCLGE_MAX_PFC_PREVENTION_TOUT) {
+ dev_err(&hdev->pdev->dev,
+ "times %u should be no more than %u!\n",
+ times, HCLGE_MAX_PFC_PREVENTION_TOUT);
+ return -EINVAL;
+ }
+
+ para.dir = HCLGE_DIR_TX;
+ ret = hclge_get_pfc_storm_para(hdev, ¶);
+ if (ret)
+ return ret;
+
+ para.enable = times ? 1 : 0;
+ para.times = (u32)times;
+ ret = hclge_set_pfc_storm_para(hdev, ¶);
+ if (ret)
+ return ret;
+
+ hdev->pfc_prevention_tout = times;
+
+ return 0;
+}
+
+static int hclge_get_pfc_prevention_tout(struct hnae3_handle *h, u16 *times)
+{
+ struct hclge_vport *vport = hclge_get_vport(h);
+ struct hclge_dev *hdev = vport->back;
+ struct hnae3_pfc_storm_para para;
+ int ret;
+
+ para.dir = HCLGE_DIR_TX;
+ ret = hclge_get_pfc_storm_para(hdev, ¶);
+ if (ret)
+ return ret;
+
+ *times = para.enable ? (u16)para.times : 0;
+
+ return 0;
+}
+
static void hclge_set_reset_pending(struct hclge_dev *hdev,
enum hnae3_reset_type reset_type)
{
@@ -4317,6 +4433,26 @@ static int hclge_reset_prepare(struct hclge_dev *hdev)
return hclge_reset_prepare_wait(hdev);
}
+static void hclge_restore_pfc_storm_prevention_tout(struct hclge_dev *hdev)
+{
+ struct hnae3_handle *handle = &hdev->vport[0].nic;
+ int ret;
+
+ ret = hclge_enable_pfc_storm_prevent(hdev, HCLGE_DIR_RX, false);
+ if (ret == -EOPNOTSUPP)
+ return;
+ else if (ret)
+ dev_warn(&hdev->pdev->dev,
+ "failed to disable rx pfc storm prevent, ret = %d\n",
+ ret);
+
+ ret = hclge_set_pfc_prevention_tout(handle, hdev->pfc_prevention_tout);
+ if (ret)
+ dev_warn(&hdev->pdev->dev,
+ "failed to set tx pfc storm prevent, ret = %d\n",
+ ret);
+}
+
static int hclge_reset_rebuild(struct hclge_dev *hdev)
{
int ret;
@@ -9278,6 +9414,32 @@ static int hclge_init_wol(struct hclge_dev *hdev)
return hclge_update_wol(hdev);
}
+static void hclge_init_pfc_prevention_tout(struct hclge_dev *hdev)
+{
+ struct hnae3_handle *handle = &hdev->vport[0].nic;
+ u16 times;
+ int ret;
+
+ ret = hclge_enable_pfc_storm_prevent(hdev, HCLGE_DIR_RX, false);
+ if (ret == -EOPNOTSUPP)
+ return;
+ else if (ret)
+ dev_warn(&hdev->pdev->dev,
+ "failed to disable rx pfc storm prevent, ret = %d\n",
+ ret);
+
+ ret = hclge_get_pfc_prevention_tout(handle, ×);
+ if (ret) {
+ dev_warn(&hdev->pdev->dev,
+ "failed to get tx pfc prevention timeout, ret = %d\n",
+ ret);
+ times = HCLGE_DEFAULT_PFC_PREVENTION_TOUT;
+ }
+
+ hdev->pfc_prevention_tout = times;
+ hdev->pfc_prevention_tout_default = times;
+}
+
static void hclge_get_wol(struct hnae3_handle *handle,
struct ethtool_wolinfo *wol)
{
@@ -9547,6 +9709,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
dev_warn(&pdev->dev,
"failed to wake on lan init, ret = %d\n", ret);
+ hclge_init_pfc_prevention_tout(hdev);
+
ret = hclge_devlink_init(hdev);
if (ret)
goto err_ptp_uninit;
@@ -9946,6 +10110,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
dev_warn(&pdev->dev,
"failed to update wol config, ret = %d\n", ret);
+ hclge_restore_pfc_storm_prevention_tout(hdev);
+
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
HCLGE_DRIVER_NAME);
@@ -9977,6 +10143,10 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
hclge_config_nic_hw_error(hdev, false);
hclge_config_rocee_ras_interrupt(hdev, false);
+ /* Restore hw default values for the next initialization */
+ hclge_set_pfc_prevention_tout(&hdev->vport->nic,
+ hdev->pfc_prevention_tout_default);
+
hclge_comm_cmd_uninit(hdev->ae_dev, &hdev->hw.hw);
hclge_misc_irq_uninit(hdev);
hclge_devlink_uninit(hdev);
@@ -10539,6 +10709,8 @@ static const struct hnae3_ae_ops hclge_ops = {
.set_wol = hclge_set_wol,
.hwtstamp_get = hclge_ptp_get_cfg,
.hwtstamp_set = hclge_ptp_set_cfg,
+ .set_pfc_prevention_tout = hclge_set_pfc_prevention_tout,
+ .get_pfc_prevention_tout = hclge_get_pfc_prevention_tout,
};
static struct hnae3_ae_algo ae_algo = {
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
index 7419481422c3..0cee8947f6b4 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
@@ -346,6 +346,11 @@ enum hclge_link_fail_code {
#define HCLGE_LINK_STATUS_DOWN 0
#define HCLGE_LINK_STATUS_UP 1
+#define HCLGE_DIR_RX 0
+#define HCLGE_DIR_TX 1
+#define HCLGE_MAX_PFC_PREVENTION_TOUT 2000
+#define HCLGE_DEFAULT_PFC_PREVENTION_TOUT 1000
+
#define HCLGE_PG_NUM 4
#define HCLGE_SCH_MODE_SP 0
#define HCLGE_SCH_MODE_DWRR 1
@@ -898,6 +903,8 @@ struct hclge_dev {
u16 vf_rss_size_max; /* HW defined VF max RSS task queue */
u16 pf_rss_size_max; /* HW defined PF max RSS task queue */
u32 tx_spare_buf_size; /* HW defined TX spare buffer size */
+ u16 pfc_prevention_tout; /* User config, restored after reset */
+ u16 pfc_prevention_tout_default; /* HW default, to avoid stale state */
u16 fdir_pf_filter_count; /* Num of guaranteed filters for this PF */
u16 num_alloc_vport; /* Num vports this driver supports */
base-commit: cef9d6804030793cf8b8796fd6936197d065dd3e
--
2.33.0
^ permalink raw reply related
* Re: [PATCH 2/3] arm64: dts: socfpga: agilex5: Add SoCDK TSN Config2 board
From: Andrew Lunn @ 2026-06-30 13:58 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade
Cc: dinguyen, maxime.chevallier, rmk+kernel, krzk+dt, conor+dt, robh,
davem, edumazet, kuba, pabeni, andrew+netdev, devicetree,
linux-arm-kernel, netdev, linux-kernel
In-Reply-To: <20260630133108.27244-3-muhammad.nazim.amirul.nazle.asmade@altera.com>
> + * gmac1 is the TSN port. The MAC operates in GMII mode internally
> + * while the PHY-side interface is RGMII, so mac-mode and phy-mode differ.
> + */
> +&gmac1 {
> + status = "okay";
> + phy-mode = "rgmii"; /* TX/RX clock delays provided by Agilex5 I/O hardware */
Could you provide more details about this. I want to understand the
big picture.
Normally we talk about the PCB providing the delays. This sounds like
it is the FPGA? So i need convincing this is correct.
https://elixir.bootlin.com/linux/v6.15/source/Documentation/devicetree/bindings/net/ethernet-controller.yaml#L287
Andrew
^ permalink raw reply
* [PATCH net-next v2 0/4] net: convert UDP getsockopt to sockopt_t
From: Breno Leitao @ 2026-06-30 14:01 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Willem de Bruijn, Shuah Khan, sdf.kernel
Cc: netdev, linux-kernel, linux-kselftest, Breno Leitao, kernel-team
The leaf proto_ops getsockopt callbacks have been moving to the new
getsockopt_iter()/sockopt_t interface.
I was trying to get SMC into getsockop and retire .getsockopt, but,
I found the best approach is to keep converting other protocols.
This series starts the same conversion one layer down, at the struct proto
getsockopt path, beginning with UDP.
Example of the current code.
static int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
if (level == SOL_UDP)
return udp_lib_getsockopt(sk, level, optname, optval, optlen);
return ip_getsockopt(sk, level, optname, optval, optlen);
}
We want udp_getsockopt to go to .getsockopt_iter, and there are two
approaches in this case:
1) Create a patchset that moves both of them to getsockopt_iter, which
is will be a huge change (ip_getsockopt() is used in many places)
2) Break this down, and transform from bottoms up. First
udp_lib_getsockopt() up to the point we can easily convert
others, such as ip_getsockopt().
I am taking the approach 2), so, the intermediate code will be something
like:
static int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
sockopt_t opt;
int err;
if (level != SOL_UDP)
return ip_getsockopt(sk, level, optname, optval, optlen);
// Convert optlen/optval in sockopt // (first patch)
err = udp_lib_getsockopt(sk, level, optname, &opt);
}
The work is bottom-up and mergeable in small steps: a protocol's inner
getsockopt helper is switched to sockopt_t behind its existing thin
__user wrapper, one patch at a time.
Once every inner helper speaks sockopt_t, a later series flips the shared
struct proto.getsockopt and inet_connection_sock_af_ops.getsockopt signatures
and drops the transitional wrappers.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Changes in v2:
- Check for invalid `len` at call site (Stanlislav)
- Do not rewrite `optlen` on error path (Sashiko)
- Converted ipv4 raw
- Expanded the selftest to test this new helper.
- Link to v1: https://lore.kernel.org/r/20260612-getsockopt_phase2-v1-0-7b01f1f5d106@debian.org
---
Breno Leitao (4):
net: add sockopt_init_user() for getsockopt conversion
udp: convert udp_lib_getsockopt to sockopt_t
ipv4: raw: convert do_raw_getsockopt to sockopt_t
selftests: net: getsockopt_iter: add raw ICMP_FILTER coverage
include/linux/net.h | 23 +++++++
include/net/udp.h | 2 +-
net/ipv4/raw.c | 41 ++++++-----
net/ipv4/udp.c | 39 ++++++++---
net/ipv6/udp.c | 19 +++++-
tools/testing/selftests/net/getsockopt_iter.c | 97 +++++++++++++++++++++++++++
6 files changed, 191 insertions(+), 30 deletions(-)
---
base-commit: c8459ee2fef502d6ef6c063751c33d9ac7943eab
change-id: 20260611-getsockopt_phase2-cd495a0115ca
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply
* [PATCH net-next v2 1/4] net: add sockopt_init_user() for getsockopt conversion
From: Breno Leitao @ 2026-06-30 14:01 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Willem de Bruijn, Shuah Khan, sdf.kernel
Cc: netdev, linux-kernel, linux-kselftest, Breno Leitao, kernel-team
In-Reply-To: <20260630-getsockopt_phase2-v2-0-193335f3d4d1@debian.org>
Add a helper that initializes a user-backed sockopt_t from the (optval,
optlen) __user pair passed to a getsockopt() callback.
It is used by transitional __user getsockopt wrappers while the
proto-layer getsockopt callbacks are converted to take a sockopt_t, and
is removed once the conversion is complete.
The goal is to help to convert leafs. Example:
sock_common_getsockopt(... char __user *optval, int __user *optlen)
→ udp_getsockopt(sk, level, optname, optval__user, optlen__user)
→ udp_lib_getsockopt(sk, level, optname, &opt) /* needs a sockopt_t */
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/linux/net.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/include/linux/net.h b/include/linux/net.h
index f268f395ce473..277188a40c72e 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -47,6 +47,29 @@ typedef struct sockopt {
int optlen;
} sockopt_t;
+/*
+ * Initialize a user-backed sockopt_t from the (optval, optlen) __user pair of
+ * a getsockopt() callback. Used by transitional __user getsockopt wrappers
+ * while the proto-layer callbacks are converted to take a sockopt_t; the
+ * caller writes opt->optlen back to the user optlen after the callback.
+ */
+static inline int sockopt_init_user(sockopt_t *opt, char __user *optval,
+ int __user *optlen)
+{
+ int len;
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+ if (len < 0)
+ return -EINVAL;
+
+ iov_iter_ubuf(&opt->iter_out, ITER_DEST, optval, len);
+ iov_iter_ubuf(&opt->iter_in, ITER_SOURCE, optval, len);
+ opt->optlen = len;
+
+ return 0;
+}
+
struct poll_table_struct;
struct pipe_inode_info;
struct inode;
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 2/4] udp: convert udp_lib_getsockopt to sockopt_t
From: Breno Leitao @ 2026-06-30 14:01 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Willem de Bruijn, Shuah Khan, sdf.kernel
Cc: netdev, linux-kernel, linux-kselftest, Breno Leitao, kernel-team
In-Reply-To: <20260630-getsockopt_phase2-v2-0-193335f3d4d1@debian.org>
In preparation for converting the proto-layer getsockopt callbacks to the
sockopt_t interface, switch udp_lib_getsockopt() to take a sockopt_t.
The thin udp_getsockopt()/udpv6_getsockopt() wrappers keep their __user
signature for now: they build a user-backed sockopt_t with
sockopt_init_user(), call the helper, and write the returned length back
to optlen. The helper uses copy_to_iter() instead of copy_to_user().
No functional change.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
include/net/udp.h | 2 +-
net/ipv4/udp.c | 39 +++++++++++++++++++++++++++++----------
net/ipv6/udp.c | 19 ++++++++++++++++---
3 files changed, 46 insertions(+), 14 deletions(-)
diff --git a/include/net/udp.h b/include/net/udp.h
index 8262e2b215b4e..1fee17274745f 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -430,7 +430,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
netdev_features_t features,
bool is_ipv6);
int udp_lib_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen);
+ sockopt_t *opt);
int udp_lib_setsockopt(struct sock *sk, int level, int optname,
sockptr_t optval, unsigned int optlen,
int (*push_pending_frames)(struct sock *));
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 70f6cbd4ef73b..59248a59358ca 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -76,6 +76,7 @@
#include <linux/bpf-cgroup.h>
#include <linux/uaccess.h>
+#include <linux/uio.h>
#include <asm/ioctls.h>
#include <linux/memblock.h>
#include <linux/highmem.h>
@@ -2995,14 +2996,13 @@ static int udp_setsockopt(struct sock *sk, int level, int optname, sockptr_t opt
}
int udp_lib_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+ sockopt_t *opt)
{
struct udp_sock *up = udp_sk(sk);
int val, len;
- if (get_user(len, optlen))
- return -EFAULT;
-
+ len = opt->optlen;
+ /* keep the check so direct sockopt_t callers stay covered. */
if (len < 0)
return -EINVAL;
@@ -3037,9 +3037,8 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
return -ENOPROTOOPT;
}
- if (put_user(len, optlen))
- return -EFAULT;
- if (copy_to_user(optval, &val, len))
+ opt->optlen = len;
+ if (copy_to_iter(&val, len, &opt->iter_out) != len)
return -EFAULT;
return 0;
}
@@ -3047,9 +3046,29 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname,
static int udp_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
- if (level == SOL_UDP)
- return udp_lib_getsockopt(sk, level, optname, optval, optlen);
- return ip_getsockopt(sk, level, optname, optval, optlen);
+ sockopt_t opt;
+ int err;
+
+ /*
+ * keep the old __user pointers, until ip_getsockopt() moves
+ * to sockopt_t
+ */
+ if (level != SOL_UDP)
+ return ip_getsockopt(sk, level, optname, optval, optlen);
+
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = udp_lib_getsockopt(sk, level, optname, &opt);
+ if (err)
+ return err;
+
+ /* optval was written by copy_to_iter() in udp_lib_getsockopt() */
+ if (put_user(opt.optlen, optlen))
+ return -EFAULT;
+
+ return 0;
}
/**
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 15e032194eccc..392e18b970454 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1826,9 +1826,22 @@ static int udpv6_setsockopt(struct sock *sk, int level, int optname,
static int udpv6_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
- if (level == SOL_UDP)
- return udp_lib_getsockopt(sk, level, optname, optval, optlen);
- return ipv6_getsockopt(sk, level, optname, optval, optlen);
+ sockopt_t opt;
+ int err;
+
+ if (level != SOL_UDP)
+ return ipv6_getsockopt(sk, level, optname, optval, optlen);
+
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = udp_lib_getsockopt(sk, level, optname, &opt);
+ if (err)
+ return err;
+ if (put_user(opt.optlen, optlen))
+ return -EFAULT;
+ return 0;
}
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 3/4] ipv4: raw: convert do_raw_getsockopt to sockopt_t
From: Breno Leitao @ 2026-06-30 14:01 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Willem de Bruijn, Shuah Khan, sdf.kernel
Cc: netdev, linux-kernel, linux-kselftest, Breno Leitao, kernel-team
In-Reply-To: <20260630-getsockopt_phase2-v2-0-193335f3d4d1@debian.org>
Continue converting the proto-layer getsockopt callbacks to the sockopt_t
interface, switching do_raw_getsockopt() and its raw_geticmpfilter()
helper to take a sockopt_t.
The thin raw_getsockopt() wrapper keeps its __user signature for now: it
builds a user-backed sockopt_t with sockopt_init_user(), calls the helper,
and writes the returned length back to optlen. The helper uses
copy_to_iter() instead of copy_to_user(). No functional change.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
net/ipv4/raw.c | 41 +++++++++++++++++++++++++----------------
1 file changed, 25 insertions(+), 16 deletions(-)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index e9fbab6ad9146..2aebaf8297e04 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -809,23 +809,18 @@ static int raw_seticmpfilter(struct sock *sk, sockptr_t optval, int optlen)
return 0;
}
-static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *optlen)
+static int raw_geticmpfilter(struct sock *sk, sockopt_t *opt)
{
- int len, ret = -EFAULT;
+ int len = opt->optlen;
- if (get_user(len, optlen))
- goto out;
- ret = -EINVAL;
if (len < 0)
- goto out;
+ return -EINVAL;
if (len > sizeof(struct icmp_filter))
len = sizeof(struct icmp_filter);
- ret = -EFAULT;
- if (put_user(len, optlen) ||
- copy_to_user(optval, &raw_sk(sk)->filter, len))
- goto out;
- ret = 0;
-out: return ret;
+ opt->optlen = len;
+ if (copy_to_iter(&raw_sk(sk)->filter, len, &opt->iter_out) != len)
+ return -EFAULT;
+ return 0;
}
static int do_raw_setsockopt(struct sock *sk, int optname,
@@ -848,14 +843,13 @@ static int raw_setsockopt(struct sock *sk, int level, int optname,
return do_raw_setsockopt(sk, optname, optval, optlen);
}
-static int do_raw_getsockopt(struct sock *sk, int optname,
- char __user *optval, int __user *optlen)
+static int do_raw_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
{
if (optname == ICMP_FILTER) {
if (inet_sk(sk)->inet_num != IPPROTO_ICMP)
return -EOPNOTSUPP;
else
- return raw_geticmpfilter(sk, optval, optlen);
+ return raw_geticmpfilter(sk, opt);
}
return -ENOPROTOOPT;
}
@@ -863,9 +857,24 @@ static int do_raw_getsockopt(struct sock *sk, int optname,
static int raw_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
+ sockopt_t opt;
+ int err;
+
if (level != SOL_RAW)
return ip_getsockopt(sk, level, optname, optval, optlen);
- return do_raw_getsockopt(sk, optname, optval, optlen);
+
+ err = sockopt_init_user(&opt, optval, optlen);
+ if (err)
+ return err;
+
+ err = do_raw_getsockopt(sk, optname, &opt);
+ if (err)
+ return err;
+
+ if (put_user(opt.optlen, optlen))
+ return -EFAULT;
+
+ return 0;
}
static int raw_ioctl(struct sock *sk, int cmd, int *karg)
--
2.53.0-Meta
^ permalink raw reply related
* [PATCH net-next v2 4/4] selftests: net: getsockopt_iter: add raw ICMP_FILTER coverage
From: Breno Leitao @ 2026-06-30 14:01 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Willem de Bruijn, Shuah Khan, sdf.kernel
Cc: netdev, linux-kernel, linux-kselftest, Breno Leitao, kernel-team
In-Reply-To: <20260630-getsockopt_phase2-v2-0-193335f3d4d1@debian.org>
Exercise the raw getsockopt path now backed by sockopt_t. ICMP_FILTER
returns a fixed-size struct and, unlike the int/u64 options already
covered, clamps the length down to the user buffer on a short read
instead of failing, so check that semantic explicitly along with the
exact and oversized cases, the -EOPNOTSUPP path on a non-ICMP raw
socket, and an unknown optname.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
tools/testing/selftests/net/getsockopt_iter.c | 97 +++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/tools/testing/selftests/net/getsockopt_iter.c b/tools/testing/selftests/net/getsockopt_iter.c
index 209569354d0e3..fe5a5268bc34e 100644
--- a/tools/testing/selftests/net/getsockopt_iter.c
+++ b/tools/testing/selftests/net/getsockopt_iter.c
@@ -11,6 +11,8 @@
* that always reports the required buffer length back via optlen,
* even when the user buffer is too small to receive any group bits.
* - vsock: SO_VM_SOCKETS_BUFFER_SIZE covers the u64 path.
+ * - raw: ICMP_FILTER covers a fixed-size struct payload that clamps
+ * the length down on a short buffer instead of failing.
*
* Author: Breno Leitao <leitao@debian.org>
*/
@@ -24,12 +26,20 @@
#include <linux/rtnetlink.h>
#include <linux/time_types.h>
#include <linux/vm_sockets.h>
+#include <linux/icmp.h>
+#include <netinet/in.h>
#include <sys/socket.h>
#include "kselftest_harness.h"
#ifndef AF_VSOCK
#define AF_VSOCK 40
#endif
+#ifndef SOL_RAW
+#define SOL_RAW 255
+#endif
+#ifndef ICMP_FILTER
+#define ICMP_FILTER 1
+#endif
/* ---------- netlink ---------- */
@@ -297,4 +307,91 @@ TEST_F(vsock, connect_timeout_old_exact)
ASSERT_EQ(sizeof(tv), optlen);
}
+/* ---------- raw (ipv4) ---------- */
+
+FIXTURE(raw)
+{
+ int fd;
+};
+
+FIXTURE_SETUP(raw)
+{
+ struct icmp_filter filt = { .data = 0xdeadbeef };
+
+ self->fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (self->fd < 0)
+ SKIP(return, "SOCK_RAW/ICMP socket: %s", strerror(errno));
+
+ if (setsockopt(self->fd, SOL_RAW, ICMP_FILTER, &filt, sizeof(filt)) < 0)
+ SKIP(return, "set ICMP_FILTER: %s", strerror(errno));
+}
+
+FIXTURE_TEARDOWN(raw)
+{
+ if (self->fd >= 0)
+ close(self->fd);
+}
+
+TEST_F(raw, icmpfilter_exact)
+{
+ struct icmp_filter filt = {};
+ socklen_t optlen = sizeof(filt);
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_RAW, ICMP_FILTER,
+ &filt, &optlen));
+ ASSERT_EQ(sizeof(filt), optlen);
+ ASSERT_EQ(0xdeadbeef, filt.data);
+}
+
+TEST_F(raw, icmpfilter_oversize_clamped)
+{
+ char buf[16] = {};
+ socklen_t optlen = sizeof(buf);
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_RAW, ICMP_FILTER,
+ buf, &optlen));
+ ASSERT_EQ(sizeof(struct icmp_filter), optlen);
+}
+
+/* Unlike the int/u64 options above, ICMP_FILTER clamps the length down
+ * to the user buffer instead of returning EINVAL: a short buffer
+ * succeeds and reports the truncated length back via optlen.
+ */
+TEST_F(raw, icmpfilter_undersize_clamped)
+{
+ char buf[2] = {};
+ socklen_t optlen = sizeof(buf);
+
+ ASSERT_EQ(0, getsockopt(self->fd, SOL_RAW, ICMP_FILTER,
+ buf, &optlen));
+ ASSERT_EQ(sizeof(buf), optlen);
+}
+
+TEST_F(raw, icmpfilter_wrong_proto)
+{
+ struct icmp_filter filt;
+ socklen_t optlen = sizeof(filt);
+ int fd;
+
+ fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
+ if (fd < 0)
+ SKIP(return, "SOCK_RAW/UDP socket: %s", strerror(errno));
+
+ ASSERT_EQ(-1, getsockopt(fd, SOL_RAW, ICMP_FILTER, &filt, &optlen));
+ ASSERT_EQ(EOPNOTSUPP, errno);
+ close(fd);
+}
+
+TEST_F(raw, bad_optname)
+{
+ socklen_t optlen;
+ int val;
+
+ optlen = sizeof(val);
+
+ ASSERT_EQ(-1, getsockopt(self->fd, SOL_RAW, 0x7fff, &val, &optlen));
+ ASSERT_EQ(ENOPROTOOPT, errno);
+ ASSERT_EQ(sizeof(val), optlen);
+}
+
TEST_HARNESS_MAIN
--
2.53.0-Meta
^ permalink raw reply related
* Re: [PATCH net] selftests: net: bump default cmd() timeout to 20 seconds
From: Breno Leitao @ 2026-06-30 14:02 UTC (permalink / raw)
To: Jakub Kicinski
Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms, shuah,
petrm, dw, noren, gal, linux-kselftest
In-Reply-To: <20260629233348.2145841-1-kuba@kernel.org>
On Mon, Jun 29, 2026 at 04:33:48PM -0700, Jakub Kicinski wrote:
> We always used 5 sec as the default command timeout. But soon after
> it was introduced, David effectively made us ignore the timeout
> (it was passed to process.communicate() as the wrong argument).
> Gal recently fixed that, but turns out the 5 sec is not enough
> for a lot of tests and setups. The fix regressed regressions.
>
> In particular running reconfig commands (e.g. XDP attach) on mlx5
> with 32 rings and 9k MTU, on a heavily-debug-enabled kernel takes
> more than 5 sec. The XDP installation command will time out after
> 5 sec but since the sleeps in the kernel are non interruptible
> the command finishes anyway, leaving the XDP program attached,
> but with non-zero exit code. defer()ed cleanups are not installed,
> breaking the environment for subsequent tests.
>
> Since "install XDP" is a pretty normal command a "point fix"
> does not seem appropriate. 32 rings is a fairly reasonable
> config, too, so we should just increase the timeout to 20 sec.
>
> There's no real reason behind the value of 20.
>
> Fixes: 1cf270424218 ("net: selftest: add test for netdev netlink queue-get API")
> Fixes: f0bd19316663 ("selftests: net: fix timeout passed as positional argument to communicate()")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Acked-by: Breno Leitao <leitao@debian.org>
^ permalink raw reply
* Re: [PATCH 3/3] net: stmmac: dwmac-socfpga: Add mac-mode DT property support
From: Andrew Lunn @ 2026-06-30 14:02 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade
Cc: dinguyen, maxime.chevallier, rmk+kernel, krzk+dt, conor+dt, robh,
davem, edumazet, kuba, pabeni, andrew+netdev, devicetree,
linux-arm-kernel, netdev, linux-kernel
In-Reply-To: <20260630133108.27244-4-muhammad.nazim.amirul.nazle.asmade@altera.com>
On Tue, Jun 30, 2026 at 06:31:08AM -0700, muhammad.nazim.amirul.nazle.asmade@altera.com wrote:
> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>
> Russell King's commit de696c63c1dc ("net: stmmac: socfpga: convert to
> use phy_interface") replaced mac_interface with phy_interface in
> socfpga_get_plat_phymode(), noting that no upstream DTS files set the
> "mac-mode" property, making the two values identical.
>
> The Agilex5 SoCDK TSN Config2 board is an exception: its gmac1 TSN
> port uses GMII internally in the MAC while the PHY-side interface is
> RGMII, so mac-mode and phy-mode differ.
Maybe you need to represent the hardware block which magically
converts GMII to RGMII in DT?
Andrew
^ permalink raw reply
* Re: [PATCH net-next v7 5/5] veth: time-based BQL completion coalescing via ethtool tx-usecs
From: Jonas Köppeler @ 2026-06-30 14:00 UTC (permalink / raw)
To: Simon Schippers, hawk, netdev
Cc: kernel-team, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Alexei Starovoitov, Daniel Borkmann,
John Fastabend, Stanislav Fomichev, linux-kernel, bpf
In-Reply-To: <f120fd22-1ee5-4d5b-9cdd-71804353e6a7@tu-dortmund.de>
On 6/13/26 4:14 PM, Simon Schippers wrote:
> On 6/12/26 10:35, hawk@kernel.org wrote:
>> From: Simon Schippers <simon.schippers@tu-dortmund.de>
>>
>> Per-packet BQL completion forces DQL to converge on limit=2, causing
>> excessive NAPI scheduling overhead and qdisc requeues.
>>
>> Accumulate BQL completions and flush them when a configurable time
>> threshold (tx-usecs) is exceeded, letting DQL discover a limit that
>> bounds actual queuing delay to the configured interval. Coalescing
>> state persists across NAPI polls in struct veth_rq so completions can
>> accumulate beyond a single budget=64 cycle.
>>
>> The flush condition is:
>>
>> state->time + bql_flush_ns <= current_time || state->n_bql > dql.limit
>>
>> Flushing when n_bql exceeds dql.limit handles BQL starvation.
>>
>> The comparison is strictly greater-than because netdev_tx_sent_queue()
>> always lets the producer exceed the limit by one before it stops, so
>> n_bql == dql.limit is a normal in-flight state. dql.limit lives in
>> the same cacheline as the completion path, so the check is cheap.
>>
>> Add ethtool tx-usecs support for runtime tuning. Default is 100 us;
>> setting tx-usecs to 0 disables coalescing and falls back to per-packet
>> completion.
>>
>> ethtool -C <veth-dev> tx-usecs 500 # 500us coalescing
>> ethtool -C <veth-dev> tx-usecs 0 # per-packet (no coalescing)
>>
>> Co-developed-by: Jesper Dangaard Brouer <hawk@kernel.org>
>> Signed-off-by: Jesper Dangaard Brouer <hawk@kernel.org>
>> Co-developed-by: Jonas Köppeler <j.koeppeler@tu-berlin.de>
>> Signed-off-by: Jonas Köppeler <j.koeppeler@tu-berlin.de>
>> Signed-off-by: Simon Schippers <simon.schippers@tu-dortmund.de>
>> ---
>> drivers/net/veth.c | 123 ++++++++++++++++++++++++++++++++++++++++++---
>> 1 file changed, 117 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/net/veth.c b/drivers/net/veth.c
>> index 2473f730734b..c62d87a8402c 100644
>> --- a/drivers/net/veth.c
>> +++ b/drivers/net/veth.c
>> @@ -28,6 +28,7 @@
>> #include <linux/bpf_trace.h>
>> #include <linux/net_tstamp.h>
>> #include <linux/skbuff_ref.h>
>> +#include <linux/sched/clock.h>
>> #include <net/page_pool/helpers.h>
>>
>> #define DRV_NAME "veth"
>> @@ -50,6 +51,7 @@
>> * delay => 64 * 250 ms = 16 s.
>> */
>> #define VETH_WATCHDOG_TIMEOUT_MS (64 * 250)
>> +#define VETH_BQL_COAL_TX_USECS 100 /* default tx-usecs for BQL batching*/
>>
>> struct veth_stats {
>> u64 rx_drops;
>> @@ -69,6 +71,11 @@ struct veth_rq_stats {
>> struct u64_stats_sync syncp;
>> };
>>
>> +struct veth_bql_state {
>> + u64 time; /* sched_clock() when current coalescing window started */
>> + uint n_bql; /* BQL completions batched in the current window */
>> +};
>> +
>> struct veth_rq {
>> struct napi_struct xdp_napi;
>> struct napi_struct __rcu *napi; /* points to xdp_napi when the latteris initialized */
>> @@ -76,6 +83,7 @@ struct veth_rq {
>> struct bpf_prog __rcu *xdp_prog;
>> struct xdp_mem_info xdp_mem;
>> struct veth_rq_stats stats;
>> + struct veth_bql_state bql_state;
>> bool rx_notify_masked;
>> struct ptr_ring xdp_ring;
>> struct xdp_rxq_info xdp_rxq;
>> @@ -88,6 +96,7 @@ struct veth_priv {
>> struct bpf_prog *_xdp_prog;
>> struct veth_rq *rq;
>> unsigned int requested_headroom;
>> + unsigned int tx_coal_usecs; /* BQL completion coalescing */
>> };
>>
>> struct veth_xdp_tx_bq {
>> @@ -272,7 +281,56 @@ static void veth_get_channels(struct net_device *dev,
>> static int veth_set_channels(struct net_device *dev,
>> struct ethtool_channels *ch);
>>
>> +static int veth_get_coalesce(struct net_device *dev,
>> + struct ethtool_coalesce *ec,
>> + struct kernel_ethtool_coalesce *kernel_coal,
>> + struct netlink_ext_ack *extack)
>> +{
>> + struct veth_priv *priv = netdev_priv(dev);
>> +
>> + ec->tx_coalesce_usecs = priv->tx_coal_usecs;
>> + return 0;
>> +}
>> +
>> +static int veth_set_coalesce(struct net_device *dev,
>> + struct ethtool_coalesce *ec,
>> + struct kernel_ethtool_coalesce *kernel_coal,
>> + struct netlink_ext_ack *extack)
>> +{
>> + struct veth_priv *priv = netdev_priv(dev);
>> + struct net_device *peer;
>> +
>> + /* The coalescing window delays BQL completions, so keep tx-usecs well
>> + * below the tx_timeout watchdog; otherwise a large value could stall a
>> + * stopped queue long enough to trip a false watchdog timeout. Cap at
>> + * half the watchdog to leave a generous safety margin. tx-usecs is
>> + * microseconds, the watchdog is milliseconds.
>> + */
>> + if (ec->tx_coalesce_usecs > VETH_WATCHDOG_TIMEOUT_MS / 2 * USEC_PER_MSEC) {
>> + NL_SET_ERR_MSG_MOD(extack,
>> + "tx-usecs must stay below half the tx_timeout watchdog");
>> + return -ERANGE;
>> + }
>> +
>> + /* Paired with READ_ONCE in veth_xdp_rcv(). */
>> + WRITE_ONCE(priv->tx_coal_usecs, ec->tx_coalesce_usecs);
>> +
>> + /* veth_xdp_rcv() reads each device's own value, so mirror it onto
>> + * the peer to keep the pair symmetric: both directions coalesce
>> + * with the same tx-usecs. Called under RTNL, rtnl_dereference() is safe.
>> + */
>> + peer = rtnl_dereference(priv->peer);
>> + if (peer) {
>> + struct veth_priv *peer_priv = netdev_priv(peer);
>> +
>> + WRITE_ONCE(peer_priv->tx_coal_usecs, ec->tx_coalesce_usecs);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static const struct ethtool_ops veth_ethtool_ops = {
>> + .supported_coalesce_params = ETHTOOL_COALESCE_TX_USECS,
>> .get_drvinfo = veth_get_drvinfo,
>> .get_link = ethtool_op_get_link,
>> .get_strings = veth_get_strings,
>> @@ -282,6 +340,8 @@ static const struct ethtool_ops veth_ethtool_ops ={
>> .get_ts_info = ethtool_op_get_ts_info,
>> .get_channels = veth_get_channels,
>> .set_channels = veth_set_channels,
>> + .get_coalesce = veth_get_coalesce,
>> + .set_coalesce = veth_set_coalesce,
>> };
>>
>> /* general routines */
>> @@ -969,13 +1029,54 @@ static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq,
>> return NULL;
>> }
>>
>> +static void veth_bql_maybe_complete(struct veth_bql_state *state,
>> + struct netdev_queue *peer_txq,
>> + u64 bql_flush_ns)
>> +{
>> + u64 current_time;
>> +
>> + /* There is no reason to complete with 0 and
>> + * peer_txq could go away.
>> + */
>> + if (!state->n_bql || !peer_txq)
>> + return;
>> +
>> + current_time = sched_clock();
>> +
>> + /* We complete if:
>> + * 1. We reach bql_flush_ns.
>> + * 2. We potentially have BQL starvation.
>> + */
>> + if (state->time + bql_flush_ns <= current_time ||
>> + state->n_bql > peer_txq->dql.limit) {
>
Indeed, this does not compile when CONFIG_BQL is not set. I think we
should just bring back the 'queue is empty + queue is stopped' check
from v6 back at the end of the poll and remove the n_bql > dql.limit
check. It also feels not obvious why this is handling the starvation
case. This only works, because the producer has went overlimit
previously and was stopped. So more than 'limit' packets have been
enqueued to the ring, and they are eventually drained when this check is
true. By removing this we can also avoid accessing dql internal members,
but if you don't think that's a problem we can leave as is.
Further, this is only works if VETH_BQL_UNIT stays 1, otherwise it will
never fire. Anyway, still its necessary to check for CONFIG_BQL. But we
could solve this by adding VETH_BQL_UNIT to n_bql instead of 1. This is
also safe from any overflows, since limit is bound to limit_max,
inflight is always less than limit + 1*VETH_BQL_UNIT and n_bql <= inflight.
In a version of bringing back the 'queue-empty' check and keeping most
of the current logic (so a mixture of v6 and v7) resulted in the same
performance on an x86_64 architecture.
> Both Sashiko-Nipa and Sashiko-Gemini are right, this is missing a
> #ifdef CONFIG_BQL. Not sure what is the best way to add them.
> And for the struct we could maybe do:
>
> #ifdef CONFIG_BQL
> struct veth_bql_state {
> u64 time; /* sched_clock() when current coalescing window started */
> uint n_bql; /* BQL completions batched in the current window */
> };
> #else
> struct veth_bql_state {};
> #endif
Regarding the configs: we can just do something along those lines.
struct veth_rq {
...
#ifdef CONFIG_BQL
struct veth_bql_state dql;
#endif
...
}
and we put the rest of the code that accesses or performs an action
regarding bql in some functions and do it like in netdev_* functions with
Function-Signature()
{
#ifdef CONFIG_BQL
// Code
#endif
}
Wdyt?
- Jonas
>
>> + netdev_tx_completed_queue(peer_txq, state->n_bql,
>> + state->n_bql * VETH_BQL_UNIT);
>> + state->time = current_time;
>> + state->n_bql = 0;
>> + }
>> +}
>> +
>> static int veth_xdp_rcv(struct veth_rq *rq, int budget,
>> struct veth_xdp_tx_bq *bq,
>> struct veth_stats *stats,
>> struct netdev_queue *peer_txq)
>> {
>> + struct veth_priv *priv = netdev_priv(rq->dev);
>> + struct veth_bql_state *state = &rq->bql_state;
>> int i, done = 0, n_xdpf = 0;
>> void *xdpf[VETH_XDP_BATCH];
>> + u64 bql_flush_ns;
>> +
>> + /* Mirrored to both peers; paired with WRITE_ONCE() in veth_set_coalesce */
>> + bql_flush_ns = (u64)READ_ONCE(priv->tx_coal_usecs) * 1000;
>> +
>> + /* Clamp stored timestamp in case we migrated to a CPU with a behind
>> + * sched_clock(); tries to reduce late BQL flushes.
>> + */
>> + state->time = min(state->time, sched_clock());
>> +
>> + /* Flush completions that timed out since the previous NAPI poll. */
>> + veth_bql_maybe_complete(state, peer_txq, bql_flush_ns);>>
>> for (i = 0; i < budget; i++) {
>> void *ptr = __ptr_ring_consume(&rq->xdp_ring);
>> @@ -1000,12 +1101,11 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget,
>> }
>> } else {
>> /* ndo_start_xmit */
>> - bool bql_charged = veth_ptr_is_bql(ptr);
>> struct sk_buff *skb = veth_ptr_to_skb(ptr);
>>
>> + if (veth_ptr_is_bql(ptr))
>> + state->n_bql++;
>> stats->xdp_bytes += skb->len;
>> - if (peer_txq && bql_charged)
>> - netdev_tx_completed_queue(peer_txq, 1, VETH_BQL_UNIT);
>>
>> skb = veth_xdp_rcv_skb(rq, skb, bq, stats);
>> if (skb) {
>> @@ -1015,6 +1115,7 @@ static int veth_xdp_rcv(struct veth_rq *rq, int budget,
>> napi_gro_receive(&rq->xdp_napi, skb);
>> }
>> }
>> + veth_bql_maybe_complete(state, peer_txq, bql_flush_ns);
>> done++;
>
> Sashiko-Nipa reports:
>
> "If veth_xdp_rcv() finishes and returns a done count less than the budget,
> NAPI will go to sleep in veth_poll(). Do we need to unconditionally flush
> any stranded BQL completions in veth_poll() before sleeping?
> If completions are left in rq->bql_state indefinitely across NAPI idle
> periods, it might present an artificially massive delay to DQL. This could
> cause DQL to mistakenly conclude the hardware is extremely slow and
> aggressively shrink dql.limit to its minimum, crippling throughput on
> subsequent bursts."
>
> Again the issue that I found to be non-problematic in [1] and can be
> seen by an BQL inflight > 0 when for example pktgen suddenly stops.
>
> If we would "unconditionally flush any stranded BQL completions in
> veth_poll() before sleeping" we would *not* accumulate BQL completions
> across NAPI polls but we want to do that.
>
> Do you agree?
>
> [1] https://lore.kernel.org/netdev/c8650d3a-e488-4279-b28f-549d766c23a1@tu-dortmund.de/
^ permalink raw reply
* Re: [PATCH v2 1/1] xfrm: nat_keepalive: avoid double free on send error
From: Steffen Klassert @ 2026-06-30 14:03 UTC (permalink / raw)
To: Eyal Birger; +Cc: Ren Wei, netdev, herbert, davem, yuantan098, bird, qianyuluo3
In-Reply-To: <CAHsH6Gupn_PVjZjOWPRLWL6LCL=-p8Gde6_BruGdetn+eP3NMQ@mail.gmail.com>
On Sun, Jun 28, 2026 at 06:42:44AM -0700, Eyal Birger wrote:
> On Wed, Jun 24, 2026 at 10:55 PM Ren Wei <n05ec@lzu.edu.cn> wrote:
> >
> > From: Qianyu Luo <qianyuluo3@gmail.com>
> >
> > nat_keepalive_send() frees the keepalive skb whenever the IPv4 or IPv6
> > send helper reports an error.
> >
> > That cleanup is only correct before the skb is handed to the output
> > path. Once ip_build_and_send_pkt() or ip6_xmit() takes ownership, the
> > networking stack may already have consumed the skb before returning an
> > error, so freeing it again is unsafe.
> >
> > Handle the pre-handoff failure cases inside nat_keepalive_send_ipv4()
> > and nat_keepalive_send_ipv6(), where the caller still owns the skb, and
> > keep nat_keepalive_send() responsible only for family dispatch and the
> > unsupported-family cleanup path.
> >
> > Fixes: f531d13bdfe3 ("xfrm: support sending NAT keepalives in ESP in UDP states")
>
> Thanks for the fix!
>
> Reviewed-by: Eyal Birger <eyal.birger@gmail.com>
Applied, thanks everyone!
^ permalink raw reply
* Re: [PATCH 3/3] net: stmmac: dwmac-socfpga: Add mac-mode DT property support
From: Maxime Chevallier @ 2026-06-30 14:04 UTC (permalink / raw)
To: Andrew Lunn, muhammad.nazim.amirul.nazle.asmade
Cc: dinguyen, rmk+kernel, krzk+dt, conor+dt, robh, davem, edumazet,
kuba, pabeni, andrew+netdev, devicetree, linux-arm-kernel, netdev,
linux-kernel
In-Reply-To: <4c285993-978c-4d9e-a8c5-c3b36baa6840@lunn.ch>
On 6/30/26 16:02, Andrew Lunn wrote:
> On Tue, Jun 30, 2026 at 06:31:08AM -0700, muhammad.nazim.amirul.nazle.asmade@altera.com wrote:
>> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>>
>> Russell King's commit de696c63c1dc ("net: stmmac: socfpga: convert to
>> use phy_interface") replaced mac_interface with phy_interface in
>> socfpga_get_plat_phymode(), noting that no upstream DTS files set the
>> "mac-mode" property, making the two values identical.
>>
>> The Agilex5 SoCDK TSN Config2 board is an exception: its gmac1 TSN
>> port uses GMII internally in the MAC while the PHY-side interface is
>> RGMII, so mac-mode and phy-mode differ.
>
> Maybe you need to represent the hardware block which magically
> converts GMII to RGMII in DT?
Yeah that's what we have on CycloneV, and we force the INTF_SEL to GMII if that
HW block is present. I wonder if there's the same on agileX5 ?
>
> Andrew
^ permalink raw reply
* [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-30
From: Simon Wunderlich @ 2026-06-30 14:06 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Simon Wunderlich
Dear net maintainers,
here is cleanup pull request of batman-adv to go into net-next.
Please pull or let me know of any problem!
Thank you,
Simon
The following changes since commit 805185b7c7a1069e407b6f7b3bc98e44d415f484:
Merge tag 'net-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2026-06-25 12:25:36 -0700)
are available in the Git repository at:
https://git.open-mesh.org/batadv.git tags/batadv-next-pullrequest-20260630
for you to fetch changes up to 247691642fd4de7a029de253e47dba936542ce9f:
batman-adv: tp_meter: delay allocation of unacked entry (2026-06-28 22:09:04 +0200)
----------------------------------------------------------------
This cleanup patchset includes the following patches:
- drop hardif global list, by Nora Schiffer (2 patches)
- make hard_iface->mesh_iface immutable, by Sven Eckelmann
- further post-hardif global list cleanups,
by Nora Schiffer (3 patches)
- cleanups and simplifications depending on the hardif->mesh_iface
immutability guarantee, by Sven Eckelmann (3 patches)
- tvlv: extract tvlv header iterator, by Sven Eckelmann
- tp_meter: improve unacked list handling,
by Sven Eckelmann (5 patches)
----------------------------------------------------------------
Nora Schiffer (5):
batman-adv: create hardif only for netdevs that are part of a mesh
batman-adv: remove global hardif list
batman-adv: remove BATADV_IF_NOT_IN_USE hardif state
batman-adv: move hardif generation counter into batadv_priv
batman-adv: drop unneeded goto and initialization from batadv_hardif_disable_interface()
Sven Eckelmann (10):
batman-adv: make hard_iface->mesh_iface immutable
batman-adv: drop NULL check for immutable hardif->mesh_iface
Revert "batman-adv: v: stop OGMv2 on disabled interface"
batman-adv: iv: drop migration check for batadv_hard_iface
batman-adv: tvlv: extract tvlv header iterator
batman-adv: tp_meter: simplify unordered ack calculation
batman-adv: tp_meter: combine adjacent/overlapping unacked entries
batman-adv: tp_meter: keep unacked list for receivers
batman-adv: tp_meter: adjust name of receiver lock
batman-adv: tp_meter: delay allocation of unacked entry
net/batman-adv/bat_iv_ogm.c | 12 +-
net/batman-adv/bat_v_elp.c | 9 +-
net/batman-adv/bat_v_ogm.c | 33 ++---
net/batman-adv/bridge_loop_avoidance.c | 9 +-
net/batman-adv/hard-interface.c | 165 ++++++++-----------------
net/batman-adv/hard-interface.h | 10 +-
net/batman-adv/main.c | 9 --
net/batman-adv/main.h | 3 -
net/batman-adv/mesh-interface.c | 13 +-
net/batman-adv/netlink.c | 4 +-
net/batman-adv/originator.c | 4 -
net/batman-adv/tp_meter.c | 217 ++++++++++++++++++++-------------
net/batman-adv/tvlv.c | 86 +++++++------
net/batman-adv/types.h | 28 ++---
14 files changed, 273 insertions(+), 329 deletions(-)
^ permalink raw reply
* [PATCH net-next 01/15] batman-adv: create hardif only for netdevs that are part of a mesh
From: Simon Wunderlich @ 2026-06-30 14:06 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Nora Schiffer, Sven Eckelmann,
Simon Wunderlich
In-Reply-To: <20260630140623.88431-1-sw@simonwunderlich.de>
From: Nora Schiffer <neocturne@universe-factory.net>
batman-adv is using netdev notifiers to create a hard_iface struct for
every Ethernet-like netdev in the system. These hardifs are tracked in a
global linked list, which results in a few performance issues:
Lookups in this list are O(n) in the total number of netdevs. As a
hardif is looked up when a netdev is removed, this also takes O(n) in
the number of netdevs, and removing n netdevs may take O(n^2). This
slowdown will always happen when the batman-adv module is loaded, no
mesh needs to be active.
With the hardif being referenced as iflink private data, the global list
is only needed for hardifs that are *not* part of a mesh (that is, the
hardif is unused). To prepare for removing the global list, only create
a hardif struct when an interface is added to a mesh and destroy it on
removal.
As adding/removing and enabling/disabling a hardif become one and the
same, batadv_hardif_add_interface() is merged into
batadv_hardif_enable_interface(), and batadv_hardif_remove_interface()
can be dropped altogether.
Signed-off-by: Nora Schiffer <neocturne@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/hard-interface.c | 120 +++++++++++---------------------
net/batman-adv/hard-interface.h | 2 +-
net/batman-adv/mesh-interface.c | 13 +---
3 files changed, 44 insertions(+), 91 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 03d01c20a9548..9c9a892d22c6b 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -723,33 +723,58 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
}
/**
- * batadv_hardif_enable_interface() - Enslave hard interface to mesh interface
- * @hard_iface: hard interface to add to mesh interface
+ * batadv_hardif_enable_interface() - Enslave interface to mesh interface
+ * @net_dev: netdev struct of the interface to add to mesh interface
* @mesh_iface: netdev struct of the mesh interface
*
* Return: 0 on success or negative error number in case of failure
*/
-int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
+int batadv_hardif_enable_interface(struct net_device *net_dev,
struct net_device *mesh_iface)
{
struct batadv_priv *bat_priv;
__be16 ethertype = htons(ETH_P_BATMAN);
int max_header_len = batadv_max_header_len();
+ struct batadv_hard_iface *hard_iface;
unsigned int required_mtu;
unsigned int hardif_mtu;
bool fragmentation;
int ret;
- hardif_mtu = READ_ONCE(hard_iface->net_dev->mtu);
+ ASSERT_RTNL();
+
+ if (!batadv_is_valid_iface(net_dev))
+ return -EINVAL;
+
+ hardif_mtu = READ_ONCE(net_dev->mtu);
required_mtu = READ_ONCE(mesh_iface->mtu) + max_header_len;
if (hardif_mtu < ETH_MIN_MTU + max_header_len)
return -EINVAL;
- if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- goto out;
+ hard_iface = kzalloc_obj(*hard_iface, GFP_ATOMIC);
+ if (!hard_iface)
+ return -ENOMEM;
+
+ netdev_hold(net_dev, &hard_iface->dev_tracker, GFP_ATOMIC);
+ hard_iface->net_dev = net_dev;
+
+ hard_iface->if_status = BATADV_IF_INACTIVE;
+
+ INIT_LIST_HEAD(&hard_iface->list);
+ INIT_HLIST_HEAD(&hard_iface->neigh_list);
- kref_get(&hard_iface->refcount);
+ mutex_init(&hard_iface->bat_iv.ogm_buff_mutex);
+ spin_lock_init(&hard_iface->neigh_list_lock);
+ kref_init(&hard_iface->refcount);
+
+ hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
+ if (batadv_is_wifi_hardif(hard_iface))
+ hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
+
+ WRITE_ONCE(hard_iface->hop_penalty, 0);
+
+ batadv_v_hardif_init(hard_iface);
netdev_hold(mesh_iface, &hard_iface->meshif_dev_tracker, GFP_ATOMIC);
hard_iface->mesh_iface = mesh_iface;
@@ -764,9 +789,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (ret < 0)
goto err_upper;
- hard_iface->if_status = BATADV_IF_INACTIVE;
-
- kref_get(&hard_iface->refcount);
hard_iface->batman_adv_ptype.type = ethertype;
hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
@@ -802,7 +824,9 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (bat_priv->algo_ops->iface.enabled)
bat_priv->algo_ops->iface.enabled(hard_iface);
-out:
+ list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
+ batadv_hardif_generation++;
+
return 0;
err_upper:
@@ -823,15 +847,19 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
struct batadv_hard_iface *primary_if = NULL;
+ ASSERT_RTNL();
+
batadv_hardif_deactivate_interface(hard_iface);
if (hard_iface->if_status != BATADV_IF_INACTIVE)
goto out;
+ list_del_rcu(&hard_iface->list);
+ batadv_hardif_generation++;
+
batadv_info(hard_iface->mesh_iface, "Removing interface: %s\n",
hard_iface->net_dev->name);
dev_remove_pack(&hard_iface->batman_adv_ptype);
- batadv_hardif_put(hard_iface);
primary_if = batadv_primary_if_get_selected(bat_priv);
if (hard_iface == primary_if) {
@@ -844,7 +872,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
}
bat_priv->algo_ops->iface.disable(hard_iface);
- hard_iface->if_status = BATADV_IF_NOT_IN_USE;
+ hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
/* delete all references to this hard_iface */
batadv_purge_orig_ref(bat_priv);
@@ -865,63 +893,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
batadv_hardif_put(primary_if);
}
-static struct batadv_hard_iface *
-batadv_hardif_add_interface(struct net_device *net_dev)
-{
- struct batadv_hard_iface *hard_iface;
-
- ASSERT_RTNL();
-
- if (!batadv_is_valid_iface(net_dev))
- return NULL;
-
- hard_iface = kzalloc_obj(*hard_iface, GFP_ATOMIC);
- if (!hard_iface)
- return NULL;
-
- netdev_hold(net_dev, &hard_iface->dev_tracker, GFP_ATOMIC);
- hard_iface->net_dev = net_dev;
-
- hard_iface->mesh_iface = NULL;
- hard_iface->if_status = BATADV_IF_NOT_IN_USE;
-
- INIT_LIST_HEAD(&hard_iface->list);
- INIT_HLIST_HEAD(&hard_iface->neigh_list);
-
- mutex_init(&hard_iface->bat_iv.ogm_buff_mutex);
- spin_lock_init(&hard_iface->neigh_list_lock);
- kref_init(&hard_iface->refcount);
-
- hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
- if (batadv_is_wifi_hardif(hard_iface))
- hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
-
- WRITE_ONCE(hard_iface->hop_penalty, 0);
-
- batadv_v_hardif_init(hard_iface);
-
- kref_get(&hard_iface->refcount);
- list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
- batadv_hardif_generation++;
-
- return hard_iface;
-}
-
-static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
-{
- ASSERT_RTNL();
-
- /* first deactivate interface */
- if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- batadv_hardif_disable_interface(hard_iface);
-
- if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- return;
-
- hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
- batadv_hardif_put(hard_iface);
-}
-
/**
* batadv_hard_if_event_meshif() - Handle events for mesh interfaces
* @event: NETDEV_* event to handle
@@ -1082,10 +1053,6 @@ static int batadv_hard_if_event(struct notifier_block *this,
batadv_wifi_net_device_event(event, net_dev);
hard_iface = batadv_hardif_get_by_netdev(net_dev);
- if (!hard_iface && (event == NETDEV_REGISTER ||
- event == NETDEV_POST_TYPE_CHANGE))
- hard_iface = batadv_hardif_add_interface(net_dev);
-
if (!hard_iface)
goto out;
@@ -1099,10 +1066,7 @@ static int batadv_hard_if_event(struct notifier_block *this,
break;
case NETDEV_UNREGISTER:
case NETDEV_PRE_TYPE_CHANGE:
- list_del_rcu(&hard_iface->list);
- batadv_hardif_generation++;
-
- batadv_hardif_remove_interface(hard_iface);
+ batadv_hardif_disable_interface(hard_iface);
break;
case NETDEV_CHANGEMTU:
if (hard_iface->mesh_iface)
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index af31696c39780..6d72dbdd5c203 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -75,7 +75,7 @@ u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface);
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface);
struct batadv_hard_iface*
batadv_hardif_get_by_netdev(const struct net_device *net_dev);
-int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
+int batadv_hardif_enable_interface(struct net_device *net_dev,
struct net_device *mesh_iface);
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface);
int batadv_hardif_min_mtu(struct net_device *mesh_iface);
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 44026810b99ce..a37368c1f5b55 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -836,18 +836,7 @@ static int batadv_meshif_slave_add(struct net_device *dev,
struct net_device *slave_dev,
struct netlink_ext_ack *extack)
{
- struct batadv_hard_iface *hard_iface;
- int ret = -EINVAL;
-
- hard_iface = batadv_hardif_get_by_netdev(slave_dev);
- if (!hard_iface || hard_iface->mesh_iface)
- goto out;
-
- ret = batadv_hardif_enable_interface(hard_iface, dev);
-
-out:
- batadv_hardif_put(hard_iface);
- return ret;
+ return batadv_hardif_enable_interface(slave_dev, dev);
}
/**
--
2.47.3
^ permalink raw reply related
* [PATCH net-next 02/15] batman-adv: remove global hardif list
From: Simon Wunderlich @ 2026-06-30 14:06 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Nora Schiffer, Sven Eckelmann,
Simon Wunderlich
In-Reply-To: <20260630140623.88431-1-sw@simonwunderlich.de>
From: Nora Schiffer <neocturne@universe-factory.net>
With interfaces being kept track of as iflink private data, there is no
need for the global list anymore. batadv_hardif_get_by_netdev() can now
use netdev_master_upper_dev_get()+netdev_lower_dev_get_private() to find
the hardif corresponding to a netdev.
Signed-off-by: Nora Schiffer <neocturne@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/hard-interface.c | 29 ++++++++++++-----------------
net/batman-adv/hard-interface.h | 2 +-
net/batman-adv/main.c | 5 -----
net/batman-adv/main.h | 1 -
net/batman-adv/netlink.c | 2 ++
net/batman-adv/types.h | 3 ---
6 files changed, 15 insertions(+), 27 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 9c9a892d22c6b..ace81348ddef7 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -75,21 +75,21 @@ void batadv_hardif_release(struct kref *ref)
* Return: batadv_hard_iface of net_dev (with increased refcnt), NULL on errors
*/
struct batadv_hard_iface *
-batadv_hardif_get_by_netdev(const struct net_device *net_dev)
+batadv_hardif_get_by_netdev(struct net_device *net_dev)
{
struct batadv_hard_iface *hard_iface;
+ struct net_device *mesh_iface;
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
- if (hard_iface->net_dev == net_dev &&
- kref_get_unless_zero(&hard_iface->refcount))
- goto out;
- }
+ ASSERT_RTNL();
- hard_iface = NULL;
+ mesh_iface = netdev_master_upper_dev_get(net_dev);
+ if (!mesh_iface || !batadv_meshif_is_valid(mesh_iface))
+ return NULL;
+
+ hard_iface = netdev_lower_dev_get_private(mesh_iface, net_dev);
+ if (!kref_get_unless_zero(&hard_iface->refcount))
+ return NULL;
-out:
- rcu_read_unlock();
return hard_iface;
}
@@ -761,7 +761,6 @@ int batadv_hardif_enable_interface(struct net_device *net_dev,
hard_iface->if_status = BATADV_IF_INACTIVE;
- INIT_LIST_HEAD(&hard_iface->list);
INIT_HLIST_HEAD(&hard_iface->neigh_list);
mutex_init(&hard_iface->bat_iv.ogm_buff_mutex);
@@ -780,6 +779,7 @@ int batadv_hardif_enable_interface(struct net_device *net_dev,
hard_iface->mesh_iface = mesh_iface;
bat_priv = netdev_priv(hard_iface->mesh_iface);
+ batadv_hardif_generation++;
ret = netdev_master_upper_dev_link(hard_iface->net_dev,
mesh_iface, hard_iface, NULL, NULL);
if (ret)
@@ -824,9 +824,6 @@ int batadv_hardif_enable_interface(struct net_device *net_dev,
if (bat_priv->algo_ops->iface.enabled)
bat_priv->algo_ops->iface.enabled(hard_iface);
- list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
- batadv_hardif_generation++;
-
return 0;
err_upper:
@@ -854,9 +851,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
if (hard_iface->if_status != BATADV_IF_INACTIVE)
goto out;
- list_del_rcu(&hard_iface->list);
- batadv_hardif_generation++;
-
batadv_info(hard_iface->mesh_iface, "Removing interface: %s\n",
hard_iface->net_dev->name);
dev_remove_pack(&hard_iface->batman_adv_ptype);
@@ -879,6 +873,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
batadv_purge_outstanding_packets(bat_priv, hard_iface);
netdev_put(hard_iface->mesh_iface, &hard_iface->meshif_dev_tracker);
+ batadv_hardif_generation++;
netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->mesh_iface);
batadv_hardif_recalc_extra_skbroom(hard_iface->mesh_iface);
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 6d72dbdd5c203..aa9275dec0976 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -74,7 +74,7 @@ u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev);
u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface);
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface);
struct batadv_hard_iface*
-batadv_hardif_get_by_netdev(const struct net_device *net_dev);
+batadv_hardif_get_by_netdev(struct net_device *net_dev);
int batadv_hardif_enable_interface(struct net_device *net_dev,
struct net_device *mesh_iface);
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface);
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 3c4572284b532..1d82f3a841a1b 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -59,10 +59,6 @@
#include "tp_meter.h"
#include "translation-table.h"
-/* List manipulations on hardif_list have to be rtnl_lock()'ed,
- * list traversals just rcu-locked
- */
-struct list_head batadv_hardif_list;
unsigned int batadv_hardif_generation;
static int (*batadv_rx_handler[256])(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
@@ -95,7 +91,6 @@ static int __init batadv_init(void)
if (ret < 0)
return ret;
- INIT_LIST_HEAD(&batadv_hardif_list);
batadv_algo_init();
batadv_recv_handler_init();
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index f68fc8b7239cd..e34145047a341 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -226,7 +226,6 @@ static inline int batadv_print_vid(unsigned short vid)
return -1;
}
-extern struct list_head batadv_hardif_list;
extern unsigned int batadv_hardif_generation;
extern struct workqueue_struct *batadv_event_workqueue;
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 4cf9e3c54ad3b..62ea91aa3ead6 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1211,7 +1211,9 @@ batadv_netlink_get_hardif_from_ifindex(struct batadv_priv *bat_priv,
if (!hard_dev)
return ERR_PTR(-ENODEV);
+ rtnl_lock();
hard_iface = batadv_hardif_get_by_netdev(hard_dev);
+ rtnl_unlock();
if (!hard_iface)
goto err_put_harddev;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index b1f9f8964c3fd..1671380b37929 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -214,9 +214,6 @@ struct batadv_wifi_net_device_state {
* struct batadv_hard_iface - network device known to batman-adv
*/
struct batadv_hard_iface {
- /** @list: list node for batadv_hardif_list */
- struct list_head list;
-
/** @if_status: status of the interface for batman-adv */
char if_status;
--
2.47.3
^ permalink raw reply related
* [PATCH net-next 03/15] batman-adv: make hard_iface->mesh_iface immutable
From: Simon Wunderlich @ 2026-06-30 14:06 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, Nora Schiffer,
Simon Wunderlich
In-Reply-To: <20260630140623.88431-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
With the hard_iface now being created for a specific mesh_iface, it is
beneficial not to set mesh_iface to NULL when the interface is disabled,
but instead keeping it immutable after the initial setup of the
hard_iface. By also holding the reference to the mesh_iface until the
hard_iface is released, hard_ifaces iterated over under RCU will always
point to a valid mesh_iface.
Co-developed-by: Nora Schiffer <neocturne@universe-factory.net>
Signed-off-by: Nora Schiffer <neocturne@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/hard-interface.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index ace81348ddef7..a0b8b06f9a644 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -63,6 +63,7 @@ void batadv_hardif_release(struct kref *ref)
struct batadv_hard_iface *hard_iface;
hard_iface = container_of(ref, struct batadv_hard_iface, refcount);
+ netdev_put(hard_iface->mesh_iface, &hard_iface->meshif_dev_tracker);
netdev_put(hard_iface->net_dev, &hard_iface->dev_tracker);
kfree_rcu(hard_iface, rcu);
@@ -829,8 +830,6 @@ int batadv_hardif_enable_interface(struct net_device *net_dev,
err_upper:
netdev_upper_dev_unlink(hard_iface->net_dev, mesh_iface);
err_dev:
- hard_iface->mesh_iface = NULL;
- netdev_put(mesh_iface, &hard_iface->meshif_dev_tracker);
batadv_hardif_put(hard_iface);
return ret;
}
@@ -871,7 +870,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
/* delete all references to this hard_iface */
batadv_purge_orig_ref(bat_priv);
batadv_purge_outstanding_packets(bat_priv, hard_iface);
- netdev_put(hard_iface->mesh_iface, &hard_iface->meshif_dev_tracker);
batadv_hardif_generation++;
netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->mesh_iface);
@@ -881,7 +879,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
if (list_empty(&hard_iface->mesh_iface->adj_list.lower))
batadv_gw_check_client_stop(bat_priv);
- hard_iface->mesh_iface = NULL;
batadv_hardif_put(hard_iface);
out:
--
2.47.3
^ permalink raw reply related
* [PATCH net-next 04/15] batman-adv: remove BATADV_IF_NOT_IN_USE hardif state
From: Simon Wunderlich @ 2026-06-30 14:06 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Nora Schiffer, Sven Eckelmann,
Simon Wunderlich
In-Reply-To: <20260630140623.88431-1-sw@simonwunderlich.de>
From: Nora Schiffer <neocturne@universe-factory.net>
With hardifs only existing while an interface is part of a mesh, the
BATADV_IF_NOT_IN_USE state has become redundant.
Signed-off-by: Nora Schiffer <neocturne@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/bat_iv_ogm.c | 3 +--
net/batman-adv/bat_v_elp.c | 3 +--
net/batman-adv/hard-interface.c | 9 ---------
net/batman-adv/hard-interface.h | 6 ------
net/batman-adv/originator.c | 4 ----
5 files changed, 2 insertions(+), 23 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index bb2f012b454ea..4514c51bba777 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -910,8 +910,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
{
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
- hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
+ if (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
return;
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
index 4841f0f1a9b13..bc3e4f264afa1 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -311,8 +311,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work)
goto out;
/* we are in the process of shutting this interface down */
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
- hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
+ if (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
goto out;
/* the interface was enabled but may not be ready yet */
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index a0b8b06f9a644..86010bc32818e 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -547,9 +547,6 @@ static void batadv_check_known_mac_addr(const struct batadv_hard_iface *hard_ifa
if (tmp_hard_iface == hard_iface)
continue;
- if (tmp_hard_iface->if_status == BATADV_IF_NOT_IN_USE)
- continue;
-
if (!batadv_compare_eth(tmp_hard_iface->net_dev->dev_addr,
hard_iface->net_dev->dev_addr))
continue;
@@ -575,9 +572,6 @@ static void batadv_hardif_recalc_extra_skbroom(struct net_device *mesh_iface)
rcu_read_lock();
netdev_for_each_lower_private_rcu(mesh_iface, hard_iface, iter) {
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
- continue;
-
lower_header_len = max_t(unsigned short, lower_header_len,
hard_iface->net_dev->hard_header_len);
@@ -1065,9 +1059,6 @@ static int batadv_hard_if_event(struct notifier_block *this,
batadv_update_min_mtu(hard_iface->mesh_iface);
break;
case NETDEV_CHANGEADDR:
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
- goto hardif_put;
-
batadv_check_known_mac_addr(hard_iface);
bat_priv = netdev_priv(hard_iface->mesh_iface);
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index aa9275dec0976..935f47ca9a48f 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -21,12 +21,6 @@
* enum batadv_hard_if_state - State of a hard interface
*/
enum batadv_hard_if_state {
- /**
- * @BATADV_IF_NOT_IN_USE: interface is not used as slave interface of a
- * batman-adv mesh interface
- */
- BATADV_IF_NOT_IN_USE,
-
/**
* @BATADV_IF_TO_BE_REMOVED: interface will be removed from mesh
* interface
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 9b38bd9e8da7e..48f837cf665a2 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -1033,7 +1033,6 @@ batadv_purge_neigh_ifinfo(struct batadv_priv *bat_priv,
/* don't purge if the interface is not (going) down */
if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
- if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
continue;
@@ -1077,7 +1076,6 @@ batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
/* don't purge if the interface is not (going) down */
if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
- if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
continue;
@@ -1127,10 +1125,8 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
if (batadv_has_timed_out(last_seen, BATADV_PURGE_TIMEOUT) ||
if_incoming->if_status == BATADV_IF_INACTIVE ||
- if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
if_incoming->if_status == BATADV_IF_TO_BE_REMOVED) {
if (if_incoming->if_status == BATADV_IF_INACTIVE ||
- if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
if_incoming->if_status == BATADV_IF_TO_BE_REMOVED)
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
--
2.47.3
^ permalink raw reply related
* [PATCH net-next 05/15] batman-adv: move hardif generation counter into batadv_priv
From: Simon Wunderlich @ 2026-06-30 14:06 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Nora Schiffer, Sven Eckelmann,
Simon Wunderlich
In-Reply-To: <20260630140623.88431-1-sw@simonwunderlich.de>
From: Nora Schiffer <neocturne@universe-factory.net>
The counter doesn't need to be global.
Signed-off-by: Nora Schiffer <neocturne@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/hard-interface.c | 4 ++--
net/batman-adv/main.c | 1 -
net/batman-adv/main.h | 2 --
net/batman-adv/netlink.c | 2 +-
net/batman-adv/types.h | 3 +++
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 86010bc32818e..9b8108d464dbc 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -774,7 +774,7 @@ int batadv_hardif_enable_interface(struct net_device *net_dev,
hard_iface->mesh_iface = mesh_iface;
bat_priv = netdev_priv(hard_iface->mesh_iface);
- batadv_hardif_generation++;
+ bat_priv->hardif_generation++;
ret = netdev_master_upper_dev_link(hard_iface->net_dev,
mesh_iface, hard_iface, NULL, NULL);
if (ret)
@@ -865,7 +865,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
batadv_purge_orig_ref(bat_priv);
batadv_purge_outstanding_packets(bat_priv, hard_iface);
- batadv_hardif_generation++;
+ bat_priv->hardif_generation++;
netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->mesh_iface);
batadv_hardif_recalc_extra_skbroom(hard_iface->mesh_iface);
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 1d82f3a841a1b..badc1df0af1d5 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -59,7 +59,6 @@
#include "tp_meter.h"
#include "translation-table.h"
-unsigned int batadv_hardif_generation;
static int (*batadv_rx_handler[256])(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index e34145047a341..e738758ee4a7a 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -226,8 +226,6 @@ static inline int batadv_print_vid(unsigned short vid)
return -1;
}
-extern unsigned int batadv_hardif_generation;
-
extern struct workqueue_struct *batadv_event_workqueue;
int batadv_mesh_init(struct net_device *mesh_iface);
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 62ea91aa3ead6..d2bc48c707143 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -968,7 +968,7 @@ batadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb)
bat_priv = netdev_priv(mesh_iface);
rtnl_lock();
- cb->seq = batadv_hardif_generation << 1 | 1;
+ cb->seq = bat_priv->hardif_generation << 1 | 1;
netdev_for_each_lower_private(mesh_iface, hard_iface, iter) {
if (i++ < skip)
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 1671380b37929..e1463a029e835 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1676,6 +1676,9 @@ struct batadv_priv {
/** @tp_num: number of currently active tp sessions */
atomic_t tp_num;
+ /** @hardif_generation: generation counter added to netlink hardif dumps */
+ unsigned int hardif_generation;
+
/** @orig_work: work queue callback item for orig node purging */
struct delayed_work orig_work;
--
2.47.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox