* [PATCH RFC 4/4] net: ipa: add Eliza configuration data
From: Alexander Koskovich @ 2026-04-16 22:41 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alex Elder
Cc: linux-arm-msm, netdev, devicetree, linux-kernel,
Alexander Koskovich
In-Reply-To: <20260416-eliza-ipa-v1-0-f4109a8e43c4@pm.me>
Add the configuration data required for Eliza, which uses IPA v5.5. The
difference over other platforms that use IPA 5.5 is the Q6 FnR counters
have been increased on the firmware version it uses, which results in a
different memory layout.
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
drivers/net/ipa/data/ipa_data-v5.5.c | 163 +++++++++++++++++++++++++++++++++++
drivers/net/ipa/ipa_data.h | 1 +
drivers/net/ipa/ipa_main.c | 4 +
3 files changed, 168 insertions(+)
diff --git a/drivers/net/ipa/data/ipa_data-v5.5.c b/drivers/net/ipa/data/ipa_data-v5.5.c
index 44a9df7346b7..e1454454bde9 100644
--- a/drivers/net/ipa/data/ipa_data-v5.5.c
+++ b/drivers/net/ipa/data/ipa_data-v5.5.c
@@ -288,6 +288,148 @@ static const struct ipa_resource_data ipa_resource_data = {
.resource_dst = ipa_resource_dst,
};
+/* IPA-resident memory region data for the Eliza SoC */
+static const struct ipa_mem ipa_mem_local_data_eliza[] = {
+ {
+ .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,
+ },
+ {
+ .id = IPA_MEM_STATS_FILTER_ROUTE,
+ .offset = 0x2cd0,
+ .size = 0x0c40,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_STATS_DROP,
+ .offset = 0x3910,
+ .size = 0x0020,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_MODEM,
+ .offset = 0x3938,
+ .size = 0x0d48,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_NAT_TABLE,
+ .offset = 0x4680,
+ .size = 0x0900,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_PDN_CONFIG,
+ .offset = 0x4f88,
+ .size = 0x0050,
+ .canary_count = 2,
+ },
+};
+
/* IPA-resident memory region data for an SoC having IPA v5.5 */
static const struct ipa_mem ipa_mem_local_data[] = {
{
@@ -442,6 +584,14 @@ static const struct ipa_mem ipa_mem_local_data[] = {
},
};
+/* Memory configuration data for the Eliza SoC */
+static const struct ipa_mem_data ipa_mem_data_eliza = {
+ .local_count = ARRAY_SIZE(ipa_mem_local_data_eliza),
+ .local = ipa_mem_local_data_eliza,
+ .smem_size = 0x0000b000,
+ .fnr_idx_cnt = 68,
+};
+
/* Memory configuration data for an SoC having IPA v5.5 */
static const struct ipa_mem_data ipa_mem_data = {
.local_count = ARRAY_SIZE(ipa_mem_local_data),
@@ -486,3 +636,16 @@ const struct ipa_data ipa_data_v5_5 = {
.mem_data = &ipa_mem_data,
.power_data = &ipa_power_data,
};
+
+/* Configuration data for the Eliza SoC (IPA v5.5). */
+const struct ipa_data ipa_data_v5_5_eliza = {
+ .version = IPA_VERSION_5_5,
+ .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_eliza,
+ .power_data = &ipa_power_data,
+};
diff --git a/drivers/net/ipa/ipa_data.h b/drivers/net/ipa/ipa_data.h
index f7566c8edabd..da01fc84edac 100644
--- a/drivers/net/ipa/ipa_data.h
+++ b/drivers/net/ipa/ipa_data.h
@@ -258,5 +258,6 @@ 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_2;
extern const struct ipa_data ipa_data_v5_5;
+extern const struct ipa_data ipa_data_v5_5_eliza;
#endif /* _IPA_DATA_H_ */
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 788dd99af2a4..981be8b538d0 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -637,6 +637,10 @@ static int ipa_firmware_load(struct device *dev)
}
static const struct of_device_id ipa_match[] = {
+ {
+ .compatible = "qcom,eliza-ipa",
+ .data = &ipa_data_v5_5_eliza,
+ },
{
.compatible = "qcom,msm8998-ipa",
.data = &ipa_data_v3_1,
--
2.53.0
^ permalink raw reply related
* [PATCH RFC 3/4] net: ipa: add new QMI request for HW filter stats info
From: Alexander Koskovich @ 2026-04-16 22:41 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alex Elder
Cc: linux-arm-msm, netdev, devicetree, linux-kernel,
Alexander Koskovich
In-Reply-To: <20260416-eliza-ipa-v1-0-f4109a8e43c4@pm.me>
Some IPA firmware versions on IPA 5.5 require ipa_filter_stats_info in
the init_modem_driver QMI request. For example on Eliza, if this is not
passed then shortly after IPA init the system will halt and reboot
shortly after.
Downstream this is marked as optional but does not seem to be the case
on newer IPA firmware versions.
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
drivers/net/ipa/data/ipa_data-v4.5.c | 1 +
drivers/net/ipa/data/ipa_data-v4.7.c | 1 +
drivers/net/ipa/data/ipa_data-v4.9.c | 1 +
drivers/net/ipa/data/ipa_data-v5.0.c | 1 +
drivers/net/ipa/data/ipa_data-v5.5.c | 1 +
drivers/net/ipa/ipa.h | 3 ++
drivers/net/ipa/ipa_data.h | 3 ++
drivers/net/ipa/ipa_mem.c | 2 ++
drivers/net/ipa/ipa_qmi.c | 18 +++++++++++
drivers/net/ipa/ipa_qmi_msg.c | 58 ++++++++++++++++++++++++++++++++++++
drivers/net/ipa/ipa_qmi_msg.h | 15 +++++++++-
11 files changed, 103 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ipa/data/ipa_data-v4.5.c b/drivers/net/ipa/data/ipa_data-v4.5.c
index 730d8c43a45c..25eceffdd9f7 100644
--- a/drivers/net/ipa/data/ipa_data-v4.5.c
+++ b/drivers/net/ipa/data/ipa_data-v4.5.c
@@ -419,6 +419,7 @@ static const struct ipa_mem_data ipa_mem_data = {
.imem_addr = 0x14688000,
.imem_size = 0x00003000,
.smem_size = 0x00009000,
+ .fnr_idx_cnt = 52,
};
/* Interconnect rates are in 1000 byte/second units */
diff --git a/drivers/net/ipa/data/ipa_data-v4.7.c b/drivers/net/ipa/data/ipa_data-v4.7.c
index 5e1d9049c62b..ef4695ee1b2d 100644
--- a/drivers/net/ipa/data/ipa_data-v4.7.c
+++ b/drivers/net/ipa/data/ipa_data-v4.7.c
@@ -361,6 +361,7 @@ static const struct ipa_mem_data ipa_mem_data = {
.imem_addr = 0x146a8000,
.imem_size = 0x00002000,
.smem_size = 0x00009000,
+ .fnr_idx_cnt = 52,
};
/* Interconnect rates are in 1000 byte/second units */
diff --git a/drivers/net/ipa/data/ipa_data-v4.9.c b/drivers/net/ipa/data/ipa_data-v4.9.c
index da472a2a2e29..0e2e521d98bb 100644
--- a/drivers/net/ipa/data/ipa_data-v4.9.c
+++ b/drivers/net/ipa/data/ipa_data-v4.9.c
@@ -417,6 +417,7 @@ static const struct ipa_mem_data ipa_mem_data = {
.imem_addr = 0x146bd000,
.imem_size = 0x00002000,
.smem_size = 0x00009000,
+ .fnr_idx_cnt = 52,
};
/* Interconnect rates are in 1000 byte/second units */
diff --git a/drivers/net/ipa/data/ipa_data-v5.0.c b/drivers/net/ipa/data/ipa_data-v5.0.c
index bc5722e4b053..9f7aaf37b8fd 100644
--- a/drivers/net/ipa/data/ipa_data-v5.0.c
+++ b/drivers/net/ipa/data/ipa_data-v5.0.c
@@ -443,6 +443,7 @@ static const struct ipa_mem_data ipa_mem_data = {
.imem_addr = 0x14688000,
.imem_size = 0x00003000,
.smem_size = 0x00009000,
+ .fnr_idx_cnt = 52,
};
/* Interconnect rates are in 1000 byte/second units */
diff --git a/drivers/net/ipa/data/ipa_data-v5.5.c b/drivers/net/ipa/data/ipa_data-v5.5.c
index f6ba3b944700..44a9df7346b7 100644
--- a/drivers/net/ipa/data/ipa_data-v5.5.c
+++ b/drivers/net/ipa/data/ipa_data-v5.5.c
@@ -449,6 +449,7 @@ static const struct ipa_mem_data ipa_mem_data = {
.imem_addr = 0x14688000,
.imem_size = 0x00002000,
.smem_size = 0x0000b000,
+ .fnr_idx_cnt = 52,
};
/* Interconnect rates are in 1000 byte/second units */
diff --git a/drivers/net/ipa/ipa.h b/drivers/net/ipa/ipa.h
index 7ef10a4ff35e..d2ceaea31635 100644
--- a/drivers/net/ipa/ipa.h
+++ b/drivers/net/ipa/ipa.h
@@ -69,6 +69,7 @@ struct ipa_smp2p;
* @modem_state: State of modem (stopped, running)
* @modem_netdev: Network device structure used for modem
* @qmi: QMI information
+ * @fnr_idx_cnt: Number of FnR counters
*/
struct ipa {
struct gsi gsi;
@@ -129,6 +130,8 @@ struct ipa {
atomic_t modem_state; /* enum ipa_modem_state */
struct net_device *modem_netdev;
struct ipa_qmi qmi;
+
+ u8 fnr_idx_cnt;
};
/**
diff --git a/drivers/net/ipa/ipa_data.h b/drivers/net/ipa/ipa_data.h
index 3eb9dc2ce339..f7566c8edabd 100644
--- a/drivers/net/ipa/ipa_data.h
+++ b/drivers/net/ipa/ipa_data.h
@@ -181,6 +181,7 @@ struct ipa_resource_data {
* @imem_addr: physical address of IPA region within IMEM
* @imem_size: size in bytes of IPA IMEM region
* @smem_size: size in bytes of the IPA SMEM region
+ * @fnr_idx_cnt: Number of FnR counters
*/
struct ipa_mem_data {
u32 local_count;
@@ -193,6 +194,8 @@ struct ipa_mem_data {
u32 imem_size; /* DEPRECATED */
u32 smem_size;
+
+ u8 fnr_idx_cnt;
};
/**
diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c
index 078d32a18dbf..fb04f953bf7a 100644
--- a/drivers/net/ipa/ipa_mem.c
+++ b/drivers/net/ipa/ipa_mem.c
@@ -631,6 +631,8 @@ int ipa_mem_init(struct ipa *ipa, struct platform_device *pdev,
ipa->mem_count = mem_data->local_count;
ipa->mem = mem_data->local;
+ ipa->fnr_idx_cnt = mem_data->fnr_idx_cnt;
+
/* Check the route and filter table memory regions */
if (!ipa_table_mem_valid(ipa, false))
return -EINVAL;
diff --git a/drivers/net/ipa/ipa_qmi.c b/drivers/net/ipa/ipa_qmi.c
index d771f3a71f94..a5a5572c9ccd 100644
--- a/drivers/net/ipa/ipa_qmi.c
+++ b/drivers/net/ipa/ipa_qmi.c
@@ -74,6 +74,8 @@
#define IPA_MODEM_SERVICE_INS_ID 2
#define IPA_MODEM_SVC_VERS 1
+#define IPA_MODEM_FNR_IDX_START 128
+
#define QMI_INIT_DRIVER_TIMEOUT 60000 /* A minute in milliseconds */
/* Send an INIT_COMPLETE indication message to the modem */
@@ -394,6 +396,22 @@ init_modem_driver_req(struct ipa_qmi *ipa_qmi)
}
}
+ if (ipa->version >= IPA_VERSION_4_5 && ipa->fnr_idx_cnt) {
+ mem = ipa_mem_find(ipa, IPA_MEM_STATS_FILTER_ROUTE);
+ if (mem && mem->size) {
+ req.hw_stats_filter_info_valid = 1;
+ req.hw_stats_filter_info.start_addr =
+ ipa->mem_offset + mem->offset;
+ req.hw_stats_filter_info.size =
+ ipa->fnr_idx_cnt * 16;
+ req.hw_stats_filter_info.start_index =
+ IPA_MODEM_FNR_IDX_START;
+ req.hw_stats_filter_info.end_index =
+ IPA_MODEM_FNR_IDX_START +
+ ipa->fnr_idx_cnt - 1;
+ }
+ }
+
return &req;
}
diff --git a/drivers/net/ipa/ipa_qmi_msg.c b/drivers/net/ipa/ipa_qmi_msg.c
index 51dc13a577a5..160c0d207691 100644
--- a/drivers/net/ipa/ipa_qmi_msg.c
+++ b/drivers/net/ipa/ipa_qmi_msg.c
@@ -250,6 +250,43 @@ const struct qmi_elem_info ipa_mem_range_ei[] = {
},
};
+/* QMI message structure definition for struct ipa_stats_filter */
+const struct qmi_elem_info ipa_stats_filter_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size =
+ sizeof_field(struct ipa_stats_filter, start_addr),
+ .offset = offsetof(struct ipa_stats_filter,
+ start_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size =
+ sizeof_field(struct ipa_stats_filter, size),
+ .offset = offsetof(struct ipa_stats_filter, size),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size =
+ sizeof_field(struct ipa_stats_filter, start_index),
+ .offset = offsetof(struct ipa_stats_filter,
+ start_index),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size =
+ sizeof_field(struct ipa_stats_filter, end_index),
+ .offset = offsetof(struct ipa_stats_filter, end_index),
+ },
+ {
+ .data_type = QMI_EOTI,
+ },
+};
+
/* QMI message structure definition for struct ipa_init_modem_driver_req */
const struct qmi_elem_info ipa_init_modem_driver_req_ei[] = {
{
@@ -640,6 +677,27 @@ const struct qmi_elem_info ipa_init_modem_driver_req_ei[] = {
.offset = offsetof(struct ipa_init_modem_driver_req,
hw_stats_drop_size),
},
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size =
+ sizeof_field(struct ipa_init_modem_driver_req,
+ hw_stats_filter_info_valid),
+ .tlv_type = 0x23,
+ .offset = offsetof(struct ipa_init_modem_driver_req,
+ hw_stats_filter_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size =
+ sizeof_field(struct ipa_init_modem_driver_req,
+ hw_stats_filter_info),
+ .tlv_type = 0x23,
+ .offset = offsetof(struct ipa_init_modem_driver_req,
+ hw_stats_filter_info),
+ .ei_array = ipa_stats_filter_ei,
+ },
{
.data_type = QMI_EOTI,
},
diff --git a/drivers/net/ipa/ipa_qmi_msg.h b/drivers/net/ipa/ipa_qmi_msg.h
index 644b8c27108b..3a2205c213d1 100644
--- a/drivers/net/ipa/ipa_qmi_msg.h
+++ b/drivers/net/ipa/ipa_qmi_msg.h
@@ -27,7 +27,7 @@
*/
#define IPA_QMI_INDICATION_REGISTER_REQ_SZ 20 /* -> server handle */
#define IPA_QMI_INDICATION_REGISTER_RSP_SZ 7 /* <- server handle */
-#define IPA_QMI_INIT_DRIVER_REQ_SZ 162 /* client handle -> */
+#define IPA_QMI_INIT_DRIVER_REQ_SZ 186 /* client handle -> */
#define IPA_QMI_INIT_DRIVER_RSP_SZ 25 /* client handle <- */
#define IPA_QMI_INIT_COMPLETE_IND_SZ 7 /* <- server handle */
#define IPA_QMI_DRIVER_INIT_COMPLETE_REQ_SZ 4 /* -> server handle */
@@ -119,6 +119,13 @@ struct ipa_mem_range {
u32 size;
};
+struct ipa_stats_filter {
+ u32 start_addr;
+ u32 size;
+ u8 start_index;
+ u8 end_index;
+};
+
/* The message for the IPA_QMI_INIT_DRIVER request contains information
* from the AP that affects modem initialization.
*/
@@ -216,6 +223,11 @@ struct ipa_init_modem_driver_req {
u32 hw_stats_drop_base_addr;
u8 hw_stats_drop_size_valid;
u32 hw_stats_drop_size;
+
+ /* Hardware filter statistics information. (IPA v4.5 and above)
+ */
+ u8 hw_stats_filter_info_valid;
+ struct ipa_stats_filter hw_stats_filter_info;
};
/* The response to a IPA_QMI_INIT_DRIVER request begins with a standard
@@ -256,6 +268,7 @@ extern const struct qmi_elem_info ipa_init_complete_ind_ei[];
extern const struct qmi_elem_info ipa_mem_bounds_ei[];
extern const struct qmi_elem_info ipa_mem_array_ei[];
extern const struct qmi_elem_info ipa_mem_range_ei[];
+extern const struct qmi_elem_info ipa_stats_filter_ei[];
extern const struct qmi_elem_info ipa_init_modem_driver_req_ei[];
extern const struct qmi_elem_info ipa_init_modem_driver_rsp_ei[];
--
2.53.0
^ permalink raw reply related
* [PATCH RFC 2/4] net: ipa: fix IPA v5.5 configuration data
From: Alexander Koskovich @ 2026-04-16 22:40 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alex Elder
Cc: linux-arm-msm, netdev, devicetree, linux-kernel,
Alexander Koskovich
In-Reply-To: <20260416-eliza-ipa-v1-0-f4109a8e43c4@pm.me>
struct ipa_qmb_outstanding {
u16 ot_reads;
u16 ot_writes;
u16 ot_read_beats;
};
[IPA_5_5][IPA_QMB_INSTANCE_DDR] = {16, 12, 0},
[IPA_5_5][IPA_QMB_INSTANCE_PCIE] = {16, 8, 0},
IPA_ENDPOINT_AP_LAN_RX:
[IPA_5_5][IPA_CLIENT_APPS_LAN_CONS] = {
true, IPA_v5_5_GROUP_UL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 17, 14, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 },
IPA_TX_INSTANCE_UL },
IPA_ENDPOINT_AP_MODEM_RX:
[IPA_5_5][IPA_CLIENT_APPS_WAN_CONS] = {
true, IPA_v5_5_GROUP_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 24, 1, 9, 9, IPA_EE_AP, GSI_SMART_PRE_FETCH, 3 },
IPA_TX_INSTANCE_DL },
IPA_ENDPOINT_MODEM_AP_RX:
[IPA_5_5][IPA_CLIENT_Q6_WAN_CONS] = {
true, IPA_v5_5_GROUP_UL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
{ 22, 7, 9, 9, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY, 0 },
IPA_TX_INSTANCE_UL },
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
drivers/net/ipa/data/ipa_data-v5.5.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ipa/data/ipa_data-v5.5.c b/drivers/net/ipa/data/ipa_data-v5.5.c
index 741ae21d9d78..f6ba3b944700 100644
--- a/drivers/net/ipa/data/ipa_data-v5.5.c
+++ b/drivers/net/ipa/data/ipa_data-v5.5.c
@@ -50,13 +50,13 @@ enum ipa_rsrc_group_id {
/* QSB configuration data for an SoC having IPA v5.5 */
static const struct ipa_qsb_data ipa_qsb_data[] = {
[IPA_QSB_MASTER_DDR] = {
- .max_writes = 0, /* Unlimited */
- .max_reads = 12,
+ .max_writes = 12,
+ .max_reads = 0, /* Unlimited */
.max_reads_beats = 0,
},
[IPA_QSB_MASTER_PCIE] = {
- .max_writes = 0, /* Unlimited */
- .max_reads = 8,
+ .max_writes = 8,
+ .max_reads = 0, /* Unlimited */
.max_reads_beats = 0,
},
};
@@ -86,8 +86,8 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
},
[IPA_ENDPOINT_AP_LAN_RX] = {
.ee_id = GSI_EE_AP,
- .channel_id = 13,
- .endpoint_id = 16,
+ .channel_id = 14,
+ .endpoint_id = 17,
.toward_ipa = false,
.channel = {
.tre_count = 256,
@@ -135,7 +135,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
[IPA_ENDPOINT_AP_MODEM_RX] = {
.ee_id = GSI_EE_AP,
.channel_id = 1,
- .endpoint_id = 23,
+ .endpoint_id = 24,
.toward_ipa = false,
.channel = {
.tre_count = 256,
@@ -168,7 +168,7 @@ static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
[IPA_ENDPOINT_MODEM_AP_RX] = {
.ee_id = GSI_EE_MODEM,
.channel_id = 7,
- .endpoint_id = 21,
+ .endpoint_id = 22,
.toward_ipa = false,
},
[IPA_ENDPOINT_MODEM_DL_NLO_TX] = {
--
2.53.0
^ permalink raw reply related
* [PATCH RFC 1/4] dt-bindings: net: qcom,ipa: document Eliza compatible
From: Alexander Koskovich @ 2026-04-16 22:40 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alex Elder
Cc: linux-arm-msm, netdev, devicetree, linux-kernel,
Alexander Koskovich
In-Reply-To: <20260416-eliza-ipa-v1-0-f4109a8e43c4@pm.me>
Document the IPA on the Eliza Platform which uses version 5.5.1,
which is a minor revision of v5.5 found on SM8550, thus we can
use the SM8550 bindings as fallback since it shares the same
register mappings.
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
Documentation/devicetree/bindings/net/qcom,ipa.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml
index fdeaa81b9645..38a5a337c34f 100644
--- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml
+++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml
@@ -60,6 +60,7 @@ properties:
- const: qcom,sc7180-ipa
- items:
- enum:
+ - qcom,eliza-ipa
- qcom,sm8650-ipa
- const: qcom,sm8550-ipa
--
2.53.0
^ permalink raw reply related
* [PATCH RFC 0/4] net: ipa: add support for Eliza SoC (IPA 5.5)
From: Alexander Koskovich @ 2026-04-16 22:40 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Alex Elder
Cc: linux-arm-msm, netdev, devicetree, linux-kernel,
Alexander Koskovich
This series adds support to the IPA driver for the Eliza SoC (IPA 5.5).
Wanted some feedback on how best to handle the difference in the Q6 FNR
counters between Eliza & SM8550/SM8650, since it also changes the memory
layout [1].
I was thinking about something like checking firmware version after
loading IPA firmware and if above X version, use increased FnR counters
but I am not sure what firmware version this was introduced in.
For now I am just doing it with a seperate Eliza compatible but this
feels kind of meh. I'm also not sure if it's possible there's some Eliza
variant out there that actually has firmware that is too old, and then
68 for FnR counters is too much.
I also wanted some clarification on the general need to pass hw filter
stats info, downstream this is marked as "optional", but seems very
much needed for Eliza.
Is this actually optional and there is just some other misconfiguration
or is firmware broken? Hard to debug what modem wants since system does
a complete halt shortly after starting IPA if I don't pass this.
[1]: https://git.codelinaro.org/clo/la/platform/vendor/opensource/dataipa/-/commit/0a3c432e4fd294eba6def56378acb6fa39feb400
Signed-off-by: Alexander Koskovich <akoskovich@pm.me>
---
Alexander Koskovich (4):
dt-bindings: net: qcom,ipa: document Eliza compatible
net: ipa: fix IPA v5.5 configuration data
net: ipa: add new QMI request for HW filter stats info
net: ipa: add Eliza configuration data
.../devicetree/bindings/net/qcom,ipa.yaml | 1 +
drivers/net/ipa/data/ipa_data-v4.5.c | 1 +
drivers/net/ipa/data/ipa_data-v4.7.c | 1 +
drivers/net/ipa/data/ipa_data-v4.9.c | 1 +
drivers/net/ipa/data/ipa_data-v5.0.c | 1 +
drivers/net/ipa/data/ipa_data-v5.5.c | 180 ++++++++++++++++++++-
drivers/net/ipa/ipa.h | 3 +
drivers/net/ipa/ipa_data.h | 4 +
drivers/net/ipa/ipa_main.c | 4 +
drivers/net/ipa/ipa_mem.c | 2 +
drivers/net/ipa/ipa_qmi.c | 18 +++
drivers/net/ipa/ipa_qmi_msg.c | 58 +++++++
drivers/net/ipa/ipa_qmi_msg.h | 15 +-
13 files changed, 280 insertions(+), 9 deletions(-)
---
base-commit: 936c21068d7ade00325e40d82bfd2f3f29d9f659
change-id: 20260416-eliza-ipa-c26a88213ff3
Best regards,
--
Alexander Koskovich <akoskovich@pm.me>
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH iwl-net] i40e: set supported_extts_flags for rising edge
From: Jacob Keller @ 2026-04-16 22:27 UTC (permalink / raw)
To: Przemyslaw Korba, intel-wired-lan
Cc: netdev, anthony.l.nguyen, przemyslaw.kitszel,
Arkadiusz Kubalewski, Aleksandr Loktionov
In-Reply-To: <20260415102511.1560665-1-przemyslaw.korba@intel.com>
On 4/15/2026 3:25 AM, Przemyslaw Korba wrote:
> The i40e driver always supported only rising edge detection, so
> advertise PTP_RISING_EDGE, and PTP_STRICT_FLAGS to ensure the
> PTP core properly validates user requests.
>
> Fixes: 7c571ac57d9d ("net: ptp: introduce .supported_extts_flags to ptp_clock_info")
> Signed-off-by: Przemyslaw Korba <przemyslaw.korba@intel.com>
> Reviewed-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> ---
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Thanks! This is the correct fix for net, then we can update i40e to
support all modes in the future as a next feature implementation.
Thanks,
Jake
^ permalink raw reply
* Re: [PATCH net v2] RDS: Fix memory leak in rds_rdma_extra_size()
From: Allison Henderson @ 2026-04-16 22:18 UTC (permalink / raw)
To: Xiaobo Liu, Paolo Abeni
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Simon Horman,
netdev, linux-rdma, rds-devel, linux-kernel
In-Reply-To: <CAJeqHv+kCScdMLYgOPG0TaRwTH5-Vo-=HEPs+oX24OprbmtbwA@mail.gmail.com>
On Thu, 2026-04-16 at 18:00 +0800, Xiaobo Liu wrote:
> The internal addition of kfree and setting the pointer to NULL in
> rds_rdma_extra_size makes the function more self‑consistent and secure.
> After applying this patch, kfree(NULL) in rds_sendmsg is also safe and will
> not cause a double‑free.
Hi Xiaobo,
Paolo makes a good point that I had missed in that rds_sendmsg owns the
cleanup. So even though iov->iov isn't freed here, it isn't leaked
either. Self-consistency is fair as a style point, but it's not
strong enough to justify the change on its own since it isn't a bug
fix. That said, thank you for taking the time to look at this area;
we appreciate the effort to help track down and fix bugs.
Thanks,
Allison
>
> On 4/16/2616:20 Paolo Abeni <pabeni@redhat.com> wrote:
> >
> > On 4/13/26 9:00 AM, Xiaobo Liu wrote:
> > > @@ -595,11 +600,20 @@ int rds_rdma_extra_size(struct rds_rdma_args
> *args,
> > > * nr_pages for one entry is limited to
> (UINT_MAX>>PAGE_SHIFT)+1,
> > > * so tot_pages cannot overflow without first going
> negative.
> > > */
> > > - if (tot_pages < 0)
> > > - return -EINVAL;
> > > + if (tot_pages < 0) {
> > > + ret = -EINVAL;
> > > + goto out;
> > > + }
> > > }
> > >
> > > - return tot_pages * sizeof(struct scatterlist);
> > > + ret = tot_pages * sizeof(struct scatterlist);
> > > +
> > > +out:
> > > + if (ret < 0) {
> > > + kfree(iov->iov);
> > > + iov->iov = NULL;
> >
> > Is this really needed?!? AFAICS rds_rdma_extra_size() is invoked only
> > via: rds_sendmsg() -> rds_rm_size() -> rds_rdma_extra_size(), and the
> > rds_sendmsg() error path already frees any non NULL iov.
> >
> > /P
^ permalink raw reply
* [PATCH] Document TCP_DEFER_ACCEPT rounding
From: Josh Triplett @ 2026-04-16 21:57 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: linux-man, netdev
In-Reply-To: <aeAAXdBe1f2THR2N@devuan>
[-- Attachment #1: Type: text/plain, Size: 15 bytes --]
Patch attached.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Document-TCP_DEFER_ACCEPT-rounding.patch --]
[-- Type: text/x-patch; name="0001-Document-TCP_DEFER_ACCEPT-rounding.patch", Size: 885 bytes --]
From ad2b798376326d40944f6998270a755f61c57815 Mon Sep 17 00:00:00 2001
Message-ID: <ad2b798376326d40944f6998270a755f61c57815.1776374539.git.josh@joshtriplett.org>
From: Josh Triplett <josh@joshtriplett.org>
Date: Thu, 16 Apr 2026 14:21:34 -0700
Subject: [PATCH] Document `TCP_DEFER_ACCEPT` rounding
Signed-off-by: Josh Triplett <josh@joshtriplett.org>
---
man/man7/tcp.7 | 2 ++
1 file changed, 2 insertions(+)
diff --git a/man/man7/tcp.7 b/man/man7/tcp.7
index ff46ea7bc..26a99b879 100644
--- a/man/man7/tcp.7
+++ b/man/man7/tcp.7
@@ -1091,6 +1091,8 @@ Allow a listener to be awakened only when data arrives on the socket.
Takes an integer value (seconds), this can
bound the maximum number of attempts TCP will make to
complete the connection.
+The kernel will round this value up to the next larger TCP retransmit
+duration.
.IP
On a client socket,
if nonzero,
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net] eth: fbnic: fix double-free of PCS on phylink creation failure
From: Bobby Eshleman @ 2026-04-16 21:54 UTC (permalink / raw)
To: Andrew Lunn
Cc: Alexander Duyck, Jakub Kicinski, kernel-team, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Russell King, netdev,
linux-kernel, Bobby Eshleman
In-Reply-To: <1873b5ba-419f-4247-ab92-1b5e899458e8@lunn.ch>
On Thu, Apr 16, 2026 at 11:00:01PM +0200, Andrew Lunn wrote:
> On Thu, Apr 16, 2026 at 12:31:39PM -0700, Bobby Eshleman wrote:
> > From: Bobby Eshleman <bobbyeshleman@meta.com>
> >
> > fbnic_phylink_create() stores the newly allocated PCS in fbn->pcs before
> > calling phylink_create(). When phylink_create() fails the error path
> > calls xpcs_destroy_pcs(pcs) to release the PCS, but neglects to clear
> > fbn->pcs.
> >
> > The caller, fbnic_netdev_alloc(), responds to the failure by calling
> > fbnic_netdev_free() which in turn calls fbnic_phylink_destroy().
>
> Isn't the real problem here? fbnic_phylink_create() failed, and it
> correctly did its cleanup. Because it failed, you should not be
> calling fbnic_phylink_destroy(). You only call the _destroy() if the
> previous _create() was successful.
>
> Andrew
>
> ---
> pw-bot: cr
True, the real issue is the _create/_destroy call asymmetry.
How about something like this (untested)?:
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index e3ca5fcfabef..2a6a73393732 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -818,7 +818,8 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
netif_tx_stop_all_queues(netdev);
if (fbnic_phylink_create(netdev)) {
- fbnic_netdev_free(fbd);
+ free_netdev(netdev);
+ fbd->netdev = NULL;
return NULL;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
index 09c5225111be..50240e6c2ee9 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_phylink.c
@@ -237,6 +237,7 @@ int fbnic_phylink_create(struct net_device *netdev)
dev_err(netdev->dev.parent,
"Failed to create Phylink interface, err: %d\n", err);
xpcs_destroy_pcs(pcs);
+ fbn->pcs = NULL;
return err;
}
I think we still probably want to be NULL-ing the pcs, even if it won't
necessarily matter anymore.
Best,
Bobby
^ permalink raw reply related
* Re: [PATCH v3 1/4] rust: netlink: add raw netlink abstraction
From: Matthew Maurer @ 2026-04-16 21:54 UTC (permalink / raw)
To: Andrew Lunn
Cc: Alice Ryhl, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Donald Hunter, Jakub Kicinski,
David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
Greg Kroah-Hartman, Arve Hjønnevåg, Todd Kjos,
Christian Brauner, Carlos Llamas, linux-kernel, rust-for-linux,
netdev
In-Reply-To: <845b36ba-7b3a-41f2-acb2-b284f253e2ca@lunn.ch>
>
> So i would agree with you, freeing it on error somewhere within
> genlmsg_multicast() would make sense.
>
> Andrew
If this should be fixed separately, then for the rust part:
Reviewed-by: Matthew Maurer <mmaurer@google.com>
with the caveat that documentation is added to the two `const_new`
functions to indicate that they are expected to panic on error, and
should only be used at const time.
^ permalink raw reply
* [PATCH net] virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET
From: Brett Creeley @ 2026-04-16 21:21 UTC (permalink / raw)
To: mst, jasowang, andrew+netdev, davem, edumazet, kuba, pabeni,
netdev
Cc: brett.creeley
When netif_is_rxfh_configured() is true (i.e., the user has explicitly
configured the RSS indirection table), virtnet_set_queues() skips the
RSS update path and falls through to the VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET
command to change the number of queue pairs. However, it does not update
vi->rss_trailer.max_tx_vq to reflect the new queue_pairs value.
This causes a mismatch between vi->curr_queue_pairs and
vi->rss_trailer.max_tx_vq. Any subsequent RSS reconfiguration (e.g.,
via ethtool -X) calls virtnet_commit_rss_command(), which sends the
stale max_tx_vq to the device, silently reverting the queue count.
Reproduction:
1. User configured RSS
ethtool -X eth0 equal 8
2. VQ_PAIRS_SET path; max_tx_vq stays 16
ethtool -L eth0 combined 12
3. RSS commit uses max_tx_vq=16 instead of 12
ethtool -X eth0 equal 4
Fix this by updating vi->rss_trailer.max_tx_vq after a successful
VQ_PAIRS_SET command when RSS is enabled, keeping it in sync with
curr_queue_pairs.
Fixes: 50bfcaedd78e ("virtio_net: Update rss when set queue")
Assisted-by: Claude: claude-opus-4.6
Signed-off-by: Brett Creeley <brett.creeley@amd.com>
---
drivers/net/virtio_net.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index bfb566fecb92..f4adcfee7a80 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3759,6 +3759,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
queue_pairs);
return -EINVAL;
}
+
+ /* Keep max_tx_vq in sync so that a later RSS command does not
+ * revert queue_pairs to a stale value.
+ */
+ if (vi->has_rss)
+ vi->rss_trailer.max_tx_vq = cpu_to_le16(queue_pairs);
succ:
vi->curr_queue_pairs = queue_pairs;
if (dev->flags & IFF_UP) {
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v3 1/4] rust: netlink: add raw netlink abstraction
From: Andrew Lunn @ 2026-04-16 21:19 UTC (permalink / raw)
To: Matthew Maurer
Cc: Alice Ryhl, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Danilo Krummrich, Donald Hunter, Jakub Kicinski,
David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
Greg Kroah-Hartman, Arve Hjønnevåg, Todd Kjos,
Christian Brauner, Carlos Llamas, linux-kernel, rust-for-linux,
netdev
In-Reply-To: <CAGSQo03b4tTQW=bXiRrmjvF8NympD_dcJX=2jwPdMmguXLfifQ@mail.gmail.com>
On Thu, Apr 16, 2026 at 01:06:42PM -0700, Matthew Maurer wrote:
> > + /// Sends the generic netlink message as a multicast message.
> > + #[inline]
> > + pub fn multicast(
> > + self,
> > + family: &'static Family,
> > + portid: u32,
> > + group: u32,
> > + flags: alloc::Flags,
> > + ) -> Result {
> > + let me = ManuallyDrop::new(self);
> > + // SAFETY: The `skb` and `family` pointers are valid. We pass ownership of the `skb` to
> > + // `genlmsg_multicast` by not dropping `self`.
Hi Matthew
Please trim when replying, to just the needed context.
> I think if genlmsg_multicast returns an error code we may need to drop
> to avoid leaking. Specifically, there is at least this path:
> 1. Set group to a large number (that's an unconstrained public parameter)
> 2. We suppress drop
> 3. We call genlmsg_multicast
> 4. We call genlmsg_multicast_netns
> 4. We call genlmsg_multicast_netns_filtered, which does an inbounds
> check for the `group`. If it is too large, it returns EINVAL without
> consuming the SKB - include/net/genetlink.h:493
> 5. We leak the skb
>
> However, at the same time, if we pass that check and descend into
> `netlink_broadcast_filtered`, it will unconditionally consume the SKB,
> and possibly return an error code in other situations.
A quick grep of the code suggests very few callers of
genlmsg_multicast look at the return code.
drivers/scsi/pmcraid.c prints an error message, but does nothing with
the skb.
drivers/regulator/event.c returns the error code to its caller, which
discards is, and the skb is leaked.
net/ieee802154/netlink.c returns the error code up the call stack but
leaks the skb.
net/nfc/netlink.c returns the error code up the call stack but leaks
the skb.
So i would agree with you, freeing it on error somewhere within
genlmsg_multicast() would make sense.
Andrew
^ permalink raw reply
* Re: [PATCH net 1/1] mptcp: hold subflow request owners when cloning reqsk
From: Matthieu Baerts @ 2026-04-16 21:18 UTC (permalink / raw)
To: Kuniyuki Iwashima
Cc: Ren Wei, netdev, mptcp, davem, edumazet, kuba, pabeni, horms,
ncardwell, dsahern, martineau, geliang, daniel, kafai, yuantan098,
yifanwucs, tomapufckgml, bird, caoruide123, enjou1224z
In-Reply-To: <CAAVpQUDzh-dGsQpBCZjN3rUsoDc2QjzWh-o5yVWoBWDQNXbjmQ@mail.gmail.com>
Hi Kuniyuki,
Thank you for your reply!
16 Apr 2026 20:48:58 Kuniyuki Iwashima <kuniyu@google.com>:
> On Thu, Apr 16, 2026 at 10:45 AM Matthieu Baerts <matttbe@kernel.org> wrote:
>>
>> Hi Ren,
>>
>> On 15/04/2026 11:31, Ren Wei wrote:
>>> From: Ruide Cao <caoruide123@gmail.com>
>>>
>>> TCP request migration clones pending request sockets with
>>> inet_reqsk_clone(). For MPTCP MP_JOIN requests this raw-copies
>>> subflow_req->msk, but the cloned request does not take a new reference.
>>>
>>> Both the original and the cloned request can later drop the same msk in
>>> subflow_req_destructor(), and a migrated request may keep a dangling msk
>>> pointer after the original owner has already been released.
>>>
>>> Add a request_sock clone callback and let MPTCP grab a reference for cloned
>>> subflow requests that carry an msk. This keeps ownership balanced across
>>> both successful migrations and failed clone/insert paths without changing
>>> other protocols.
(...)
>>> diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
>>> index e961936b6be7..140a9e96ad58 100644
>>> --- a/net/ipv4/inet_connection_sock.c
>>> +++ b/net/ipv4/inet_connection_sock.c
>>> @@ -954,6 +954,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
>>> if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(nreq)->tfo_listener)
>>> rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
>>
>> (Maybe TCP with fastopen could be this other user to call
>> rcu_assign_pointer()? (net-next material))
>>
>>> + if (req->rsk_ops->init_clone)
>>> + req->rsk_ops->init_clone(req, nreq);
>
> I think a simple direct call is better.
>
> #ifdef CONFIG_MPTCP
> if (tcp_rsk(req)->is_mptcp)
> mptcp_reqsk_clone(nreq);
> #endif
Fine by me!
I guess it is needed to check the protocol, similar to what is fine with
TFO above:
if (sk->sk_protocol == IPPROTO_TCP) {
if TFO
...
if MPTCP (+ifdef)
...
}
Cheers,
Matt
^ permalink raw reply
* Re: [PATCH net,v2 00/11] Netfilter/IPVS fixes for net
From: Florian Westphal @ 2026-04-16 21:16 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: netfilter-devel, davem, netdev, kuba, pabeni, edumazet, horms
In-Reply-To: <20260416131453.308611-1-pablo@netfilter.org>
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> v2: Keep back patches that have lengthy feedback by AI, they might
> need more work.
sashiko findings response:
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 01/11] netfilter: arp_tables: fix IEEE1394 ARP payload parsing in arp_packet_match()
yes, arpt_mangle.c has same bug pattern, will follow up.
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 02/11] netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 03/11] netfilter: nft_osf: restrict it to ipv4
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 04/11] netfilter: nfnetlink_osf: fix null-ptr-deref in nf_osf_ttl
yes, osf has more issues, I asked Fernando to investigate. Brief glance
the reports are accurate but these are NOT new issues added by these 3
fixes.
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 07/11] netfilter: nat: use kfree_rcu to release ops
shashiko wants /kfree/kfree_rcu/ in error unwind path and I think we
should just do it. Its an error path so it makes no practical
difference. Also, with upcoming -next patch to dump the nat
hooks too it would be required.
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 11/11] netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase
report is accurate BUT this issue is already known and not a regression
added here.
The fix for this bug was in v1 PR but it needs more work and will come
in a followup batch.
If you don't want to take this v2 because of above issues, please
consider at least applying
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 08/11] ipvs: fix MTU check for GSO packets in tunnel mode
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 09/11] netfilter: nf_tables: use list_del_rcu for netlink hooks
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 10/11] rculist: add list_splice_rcu() for private lists
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 05/11] netfilter: conntrack: remove sprintf usage
↳ [2026-04-16] Pablo Neira Ayuso <pablo@netfilter.org>: [PATCH net 06/11] netfilter: xtables: restrict several matches to inet family
manually. nf:main always tracks net:main, applying them manually
doesn't cause issues.
I hope we get shashiko to also digest netfilter-devel;
otherwise this situation will persist forever or can
dissolve nf-devel and spam netdev@ directly :-|
^ permalink raw reply
* Re: [PATCH net] eth: fbnic: fix double-free of PCS on phylink creation failure
From: Andrew Lunn @ 2026-04-16 21:00 UTC (permalink / raw)
To: Bobby Eshleman
Cc: Alexander Duyck, Jakub Kicinski, kernel-team, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Russell King, netdev,
linux-kernel, Bobby Eshleman
In-Reply-To: <20260416-fbnic-pcs-fix-v1-1-ac4b6badeac0@meta.com>
On Thu, Apr 16, 2026 at 12:31:39PM -0700, Bobby Eshleman wrote:
> From: Bobby Eshleman <bobbyeshleman@meta.com>
>
> fbnic_phylink_create() stores the newly allocated PCS in fbn->pcs before
> calling phylink_create(). When phylink_create() fails the error path
> calls xpcs_destroy_pcs(pcs) to release the PCS, but neglects to clear
> fbn->pcs.
>
> The caller, fbnic_netdev_alloc(), responds to the failure by calling
> fbnic_netdev_free() which in turn calls fbnic_phylink_destroy().
Isn't the real problem here? fbnic_phylink_create() failed, and it
correctly did its cleanup. Because it failed, you should not be
calling fbnic_phylink_destroy(). You only call the _destroy() if the
previous _create() was successful.
Andrew
---
pw-bot: cr
^ permalink raw reply
* Re: [PATCH v2 iwl-net] i40e: keep q_vectors array in sync with channel count changes
From: Jacob Keller @ 2026-04-16 20:51 UTC (permalink / raw)
To: Maciej Fijalkowski, intel-wired-lan
Cc: netdev, magnus.karlsson, kuba, pabeni, horms, przemyslaw.kitszel
In-Reply-To: <20260416114046.642171-1-maciej.fijalkowski@intel.com>
On 4/16/2026 4:40 AM, Maciej Fijalkowski wrote:
> For the main VSI, i40e_set_num_rings_in_vsi() always derives
> num_q_vectors from pf->num_lan_msix. At the same time, ethtool -L stores
> the user requested channel count in vsi->req_queue_pairs and the queue
> setup path uses that value for the effective number of queue pairs.
>
> This leaves queue and vector counts out of sync after shrinking channel
> count via ethtool -L. The active queue configuration is reduced, but the
> VSI still keeps the full PF-sized q_vector topology.
>
> That mismatch breaks reconfiguration flows which rely on vector/NAPI
> state matching the effective channel configuration. In particular,
> toggling /sys/class/net/<dev>/threaded after reducing the channel count
> can hang, and later channel-count changes can fail because VSI reinit
> does not rebuild q_vectors to match the new vector count.
>
> Fix this by making the main VSI num_q_vectors follow the effective
> requested channel count, capped by the available MSI-X vectors. Update
> i40e_vsi_reinit_setup() to rebuild q_vectors during VSI reinit so the
> vector topology is refreshed together with the ring arrays when channel
> count changes.
>
> Keep alloc_queue_pairs unchanged and based on pf->num_lan_qps so the VSI
> retains its full queue capacity.
>
> Selftest napi_threaded.py was originally used when Jakub reported hang
> on /sys/class/net/<dev>/threaded toggle. In order to make it pass on
> i40e, use persistent NAPI configuration for q_vector NAPIs so NAPI
> identity and threaded settings survive q_vector reallocation across
> channel-count changes. This is achieved by using netif_napi_add_config()
> when configuring q_vectors.
>
> $ export NETIF=ens259f1np1
> $ sudo -E env PATH="$PATH" ./tools/testing/selftests/drivers/net/napi_threaded.py
> TAP version 13
> 1..3
> ok 1 napi_threaded.napi_init
> ok 2 napi_threaded.change_num_queues
> ok 3 napi_threaded.enable_dev_threaded_disable_napi_threaded
> Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0
>
> Reported-by: Jakub Kicinski <kuba@kernel.org>
> Closes: https://lore.kernel.org/intel-wired-lan/20260316133100.6054a11f@kernel.org/
> Fixes: d2a69fefd756 ("i40e: Fix changing previously set num_queue_pairs for PFs")
> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> ---
> v2:
> - NULL vsi->tx_rings in i40e_vsi_alloc_arrays() (Sashiko)
> ---
Thanks Maciej,
I'll go ahead and replace the older version of the fix on dev-queue
today. Apologies for missing the exchange related to this and the
previous fix :(
Thanks,
Jake
^ permalink raw reply
* Re: [PATCH net 10/13] i40e: fix napi_enable/disable skipping ringless q_vectors
From: Jacob Keller @ 2026-04-16 20:50 UTC (permalink / raw)
To: Przemek Kitszel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, Aleksandr Loktionov, stable, Sunitha Mekala,
Maciej Fijalkowski
In-Reply-To: <70776680-1b60-4898-b9cd-bcc48abaac76@intel.com>
On 4/16/2026 1:46 PM, Jacob Keller wrote:
> On 4/15/2026 9:20 PM, Przemek Kitszel wrote:
>> On 4/15/26 07:48, Jacob Keller wrote:
>>> From: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>>>
>>> After ethtool -L reduces the queue count, i40e_napi_disable_all() sets
>>> NAPI_STATE_SCHED on all q_vectors, then i40e_vsi_map_rings_to_vectors()
>>> clears ring pointers on the excess ones. i40e_napi_enable_all() skips
>>> those with:
>>>
>>> if (q_vector->rx.ring || q_vector->tx.ring)
>>> napi_enable(&q_vector->napi);
>>>
>>> leaving them on dev->napi_list with NAPI_STATE_SCHED permanently set.
>>>
>>> Writing to /sys/class/net/<iface>/threaded calls napi_stop_kthread()
>>> on every entry in dev->napi_list. The function loops on msleep(20)
>>> waiting for NAPI_STATE_SCHED to clear -- which never happens for the
>>> stale q_vectors. The task hangs in D state forever; a concurrent write
>>> deadlocks on dev->lock held by the first.
>>>
>>> Commit 13a8cd191a2b ("i40e: Do not enable NAPI on q_vectors that have no
>>> rings") added the guard to prevent a divide-by-zero in i40e_napi_poll()
>>> when epoll busy-poll iterated all device NAPIs (4.x era). Since
>>> 7adc3d57fe2b ("net: Introduce preferred busy-polling"), from v5.11,
>>> napi_busy_loop() polls by napi_id keyed to the socket, so ringless
>>> q_vectors are never selected. i40e_msix_clean_rings() also independently
>>> avoids scheduling NAPI for them. The guard is safe to remove.
>>>
>>> Add an early return in i40e_napi_poll() for num_ringpairs == 0 so the
>>> function is self-defending against a NULL tx.ring dereference at the
>>> WB_ON_ITR check, should the NAPI ever fire through an unexpected path.
>>>
>>> Reported-by: Jakub Kicinski <kuba@kernel.org>
>>> Closes: https://lore.kernel.org/intel-wired-
>>> lan/20260316133100.6054a11f@kernel.org/
>>
>> Maciej developed a better fix for the problem, and he explicitly asked
>> to not include this patch. Please drop it from this series.
>>
>> Maciej's fix:
>> https://lore.kernel.org/intel-wired-lan/20260414121405.631092-1-
>> maciej.fijalkowski@intel.com/T/#u
>>
>> ask for reject:
>> https://lore.kernel.org/intel-wired-lan/
>> PH0PR11MB75223C8A00C3183C5082A096A0252@PH0PR11MB7522.namprd11.prod.outlook.com/T/#mbac55f7219d7855a2e5d1527904b2da43ad080cb
>>
>
> Ugh, sorry for failing to notice this when batching this series up :(
>
> Thanks,
> Jake
>
Jakub,
Can you discard this patch out of the series when applying? Or should I
go ahead and send a v2?
Thanks,
Jake
^ permalink raw reply
* Re: [PATCH net 10/13] i40e: fix napi_enable/disable skipping ringless q_vectors
From: Jacob Keller @ 2026-04-16 20:46 UTC (permalink / raw)
To: Przemek Kitszel, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, Aleksandr Loktionov, stable, Sunitha Mekala,
Maciej Fijalkowski
In-Reply-To: <6cc3c5b2-fb71-42a4-8d5b-57cd85de2f02@intel.com>
On 4/15/2026 9:20 PM, Przemek Kitszel wrote:
> On 4/15/26 07:48, Jacob Keller wrote:
>> From: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
>>
>> After ethtool -L reduces the queue count, i40e_napi_disable_all() sets
>> NAPI_STATE_SCHED on all q_vectors, then i40e_vsi_map_rings_to_vectors()
>> clears ring pointers on the excess ones. i40e_napi_enable_all() skips
>> those with:
>>
>> if (q_vector->rx.ring || q_vector->tx.ring)
>> napi_enable(&q_vector->napi);
>>
>> leaving them on dev->napi_list with NAPI_STATE_SCHED permanently set.
>>
>> Writing to /sys/class/net/<iface>/threaded calls napi_stop_kthread()
>> on every entry in dev->napi_list. The function loops on msleep(20)
>> waiting for NAPI_STATE_SCHED to clear -- which never happens for the
>> stale q_vectors. The task hangs in D state forever; a concurrent write
>> deadlocks on dev->lock held by the first.
>>
>> Commit 13a8cd191a2b ("i40e: Do not enable NAPI on q_vectors that have no
>> rings") added the guard to prevent a divide-by-zero in i40e_napi_poll()
>> when epoll busy-poll iterated all device NAPIs (4.x era). Since
>> 7adc3d57fe2b ("net: Introduce preferred busy-polling"), from v5.11,
>> napi_busy_loop() polls by napi_id keyed to the socket, so ringless
>> q_vectors are never selected. i40e_msix_clean_rings() also independently
>> avoids scheduling NAPI for them. The guard is safe to remove.
>>
>> Add an early return in i40e_napi_poll() for num_ringpairs == 0 so the
>> function is self-defending against a NULL tx.ring dereference at the
>> WB_ON_ITR check, should the NAPI ever fire through an unexpected path.
>>
>> Reported-by: Jakub Kicinski <kuba@kernel.org>
>> Closes: https://lore.kernel.org/intel-wired-
>> lan/20260316133100.6054a11f@kernel.org/
>
> Maciej developed a better fix for the problem, and he explicitly asked
> to not include this patch. Please drop it from this series.
>
> Maciej's fix:
> https://lore.kernel.org/intel-wired-lan/20260414121405.631092-1-
> maciej.fijalkowski@intel.com/T/#u
>
> ask for reject:
> https://lore.kernel.org/intel-wired-lan/
> PH0PR11MB75223C8A00C3183C5082A096A0252@PH0PR11MB7522.namprd11.prod.outlook.com/T/#mbac55f7219d7855a2e5d1527904b2da43ad080cb
>
Ugh, sorry for failing to notice this when batching this series up :(
Thanks,
Jake
^ permalink raw reply
* Re: [PATCH net-next 5/6] net: stmmac: move PHY handling out of __stmmac_open()/release()
From: Jakub Kicinski @ 2026-04-16 20:16 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Alexander Stein, Andrew Lunn, Heiner Kallweit, Alexandre Torgue,
Andrew Lunn, David S. Miller, Eric Dumazet, linux-arm-kernel,
linux-stm32, Maxime Coquelin, netdev, Paolo Abeni
In-Reply-To: <aeE8mpXy9FRHvN9q@shell.armlinux.org.uk>
On Thu, 16 Apr 2026 20:46:34 +0100 Russell King (Oracle) wrote:
> On Thu, Apr 16, 2026 at 09:08:26AM -0700, Jakub Kicinski wrote:
> > On Thu, 16 Apr 2026 14:47:57 +0100 Russell King (Oracle) wrote:
> > > The next problem will be netdev's policy over reviews vs patches
> > > balance which I'm already in deficit, and I have *NO* *TIME*
> > > what so ever to review patches - let alone propose patches to
> > > fix people's problems.
> > >
> > > So I'm going to say this plainly: if netdev wants to enforce that
> > > rule, then I won't be fixing people's problems.
> >
> > Do you have a better proposal?
> > I'm under the same pressure of million stupid projects from my employer
> > as you are. Do y'all think that upstream maintainers have time given by
> > their employers to do the reviews? SMH.
>
> Are you really under the same pressure? I have one of my parents in
> hospital right now, and was in A&E yesterday afternoon through into
> the evening. I've been down at the hospital since 2pm today, only
> just come back to feed the other parent and head back down for what
> could be a long night. Then there's supposed to be an appointment
> that will take up to 3 hours tomorrow morning...
>
> Yea, I'm sure you have the same pressures and worry from your
> employer - except my pressures are medical, looking after my parents.
>
> Thank you for your lack of understanding.
Not my point. Sorry to hear about the issues you're facing.
I don't think making vague complaints about the development process
is going to make anything better.
^ permalink raw reply
* Re: [PATCH v2] Documentation: sysctl: document net core sysctls
From: Jay Vosburgh @ 2026-04-16 20:11 UTC (permalink / raw)
To: Simon Horman
Cc: Shubham Chakraborty, netdev, davem, edumazet, kuba, pabeni,
kuniyu, corbet, skhan, linux-doc, linux-kernel
In-Reply-To: <20260413164707.GT469338@kernel.org>
Simon Horman <horms@kernel.org> wrote:
>On Thu, Apr 09, 2026 at 11:18:59PM +0530, Shubham Chakraborty wrote:
[...]
>> netdev_budget_usecs
>> ---------------------
>>
>
>The lines above the following hunk are:
>
>netdev_budget_usecs
>---------------------
>
>Maximum number of microseconds in one NAPI polling cycle. Polling
>
>> @@ -297,12 +332,16 @@ Maximum number of microseconds in one NAPI polling cycle. Polling
>> will exit when either netdev_budget_usecs have elapsed during the
>> poll cycle or the number of packets processed reaches netdev_budget.
>>
>> +Default: ``2 * USEC_PER_SEC / HZ`` (2000 when ``HZ`` is 1000)
>> +
>
>Well, that is awkward.
>
>Looking at git history, it seems that this sysctl was added by 7acf8a1e8a28
>("Replace 2 jiffies with sysctl netdev_budget_usecs to enable softirq
>tuning") in 2017. And at that time the unic was us, and the default was 2000 us.
>
>But that was changed by a fix for that commit, a4837980fd9f ("net: revert
>default NAPI poll timeout to 2 jiffies"), in 2020. As a side-effect of
>that commit, the default was changed to what you have documented above,
>and the unit changed to jiffies.
>
>So while what you have is correct it seems nonsensical to me for the unit
>to be jiffies. Because that's not a meaningful unit for users. And because
>the name of the sysctl ends in usecs.
I don't think the units for netdev_budget_usecs are actually
jiffies, even after a4837980fd9f. The default value, for example, is
2000 if HZ is 1000. However, the granularity of the measurement is in
jiffies, via:
static __latent_entropy void net_rx_action(void)
{
struct softnet_data *sd = this_cpu_ptr(&softnet_data);
unsigned long time_limit = jiffies +
usecs_to_jiffies(READ_ONCE(net_hotdata.netdev_budget_usecs));
I'm not sure offhand if usecs_to_jiffies rounds up or down, but
the netdev_budget_usecs looks to be interpreted as usecs.
-J
>But I'm unsure what to do about it. Since changing the unit this would
>represent (another) KABI break.
>
>* Add another knob that shadows this one (But what to call it?)
>* Simply remove this one (KAPI break)
>* Change the unit of this knob (KAPI break)
>
>If the code is left as is, then I think it should be documented that the
>unit is jiffies.
>
>...
>
---
-Jay Vosburgh, jv@jvosburgh.net
^ permalink raw reply
* Re: [PATCH v3 1/4] rust: netlink: add raw netlink abstraction
From: Matthew Maurer @ 2026-04-16 20:06 UTC (permalink / raw)
To: Alice Ryhl
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, linux-kernel, rust-for-linux, netdev
In-Reply-To: <20260415-binder-netlink-v3-1-84be9ba63ee2@google.com>
On Wed, Apr 15, 2026 at 2:44 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> This implements a safe and relatively simple API over the netlink API,
> that allows you to add different attributes to a netlink message and
> broadcast it. As the first user of this API only makes use of broadcast,
> only broadcast messages are supported here.
>
> This API is intended to be safe and to be easy to use in *generated*
> code. This is because netlink is generally used with yaml files that
> describe the underlying API, and the python generator outputs C code
> (or, soon, Rust code) that lets you use the API more easily. So for
> example, if there is a string field, the code generator will output a
> method that internall calls `put_string()` with the right attr type.
>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> rust/bindings/bindings_helper.h | 3 +
> rust/helpers/genetlink.c | 46 ++++++
> rust/helpers/helpers.c | 1 +
> rust/kernel/lib.rs | 1 +
> rust/kernel/netlink.rs | 329 ++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 380 insertions(+)
>
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 083cc44aa952..8abb626fce6c 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -88,6 +88,8 @@
> #include <linux/wait.h>
> #include <linux/workqueue.h>
> #include <linux/xarray.h>
> +#include <net/genetlink.h>
> +#include <net/netlink.h>
> #include <trace/events/rust_sample.h>
>
> /*
> @@ -105,6 +107,7 @@
> const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
> const size_t RUST_CONST_HELPER_ARCH_KMALLOC_MINALIGN = ARCH_KMALLOC_MINALIGN;
> const size_t RUST_CONST_HELPER_PAGE_SIZE = PAGE_SIZE;
> +const size_t RUST_CONST_HELPER_GENLMSG_DEFAULT_SIZE = GENLMSG_DEFAULT_SIZE;
> const gfp_t RUST_CONST_HELPER_GFP_ATOMIC = GFP_ATOMIC;
> const gfp_t RUST_CONST_HELPER_GFP_KERNEL = GFP_KERNEL;
> const gfp_t RUST_CONST_HELPER_GFP_KERNEL_ACCOUNT = GFP_KERNEL_ACCOUNT;
> diff --git a/rust/helpers/genetlink.c b/rust/helpers/genetlink.c
> new file mode 100644
> index 000000000000..3530b69f6cf7
> --- /dev/null
> +++ b/rust/helpers/genetlink.c
> @@ -0,0 +1,46 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (C) 2026 Google LLC.
> + */
> +
> +#include <net/genetlink.h>
> +
> +#ifdef CONFIG_NET
> +
> +__rust_helper struct sk_buff *rust_helper_genlmsg_new(size_t payload, gfp_t flags)
> +{
> + return genlmsg_new(payload, flags);
> +}
> +
> +__rust_helper
> +int rust_helper_genlmsg_multicast(const struct genl_family *family,
> + struct sk_buff *skb, u32 portid,
> + unsigned int group, gfp_t flags)
> +{
> + return genlmsg_multicast(family, skb, portid, group, flags);
> +}
> +
> +__rust_helper void rust_helper_genlmsg_cancel(struct sk_buff *skb, void *hdr)
> +{
> + genlmsg_cancel(skb, hdr);
> +}
> +
> +__rust_helper void rust_helper_genlmsg_end(struct sk_buff *skb, void *hdr)
> +{
> + genlmsg_end(skb, hdr);
> +}
> +
> +__rust_helper void rust_helper_nlmsg_free(struct sk_buff *skb)
> +{
> + nlmsg_free(skb);
> +}
> +
> +__rust_helper
> +int rust_helper_genl_has_listeners(const struct genl_family *family,
> + struct net *net, unsigned int group)
> +{
> + return genl_has_listeners(family, net, group);
> +}
> +
> +#endif
> diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
> index a3c42e51f00a..0813185d8760 100644
> --- a/rust/helpers/helpers.c
> +++ b/rust/helpers/helpers.c
> @@ -32,6 +32,7 @@
> #include "err.c"
> #include "irq.c"
> #include "fs.c"
> +#include "genetlink.c"
> #include "io.c"
> #include "jump_label.c"
> #include "kunit.c"
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index d93292d47420..f5ea0ae0b6b7 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -122,6 +122,7 @@
> pub mod module_param;
> #[cfg(CONFIG_NET)]
> pub mod net;
> +pub mod netlink;
> pub mod num;
> pub mod of;
> #[cfg(CONFIG_PM_OPP)]
> diff --git a/rust/kernel/netlink.rs b/rust/kernel/netlink.rs
> new file mode 100644
> index 000000000000..21f959c95fdc
> --- /dev/null
> +++ b/rust/kernel/netlink.rs
> @@ -0,0 +1,329 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +// Copyright (C) 2026 Google LLC.
> +
> +//! Rust support for generic netlink.
> +//!
> +//! Currently only supports exposing multicast groups.
> +//!
> +//! C header: [`include/net/genetlink.h`](srctree/include/net/genetlink.h)
> +#![cfg(CONFIG_NET)]
> +
> +use kernel::{
> + alloc::{self, AllocError},
> + error::to_result,
> + prelude::*,
> + transmute::AsBytes,
> + types::Opaque,
> + ThisModule,
> +};
> +
> +use core::{
> + mem::ManuallyDrop,
> + ptr::NonNull, //
> +};
> +
> +/// The default netlink message size.
> +pub const GENLMSG_DEFAULT_SIZE: usize = bindings::GENLMSG_DEFAULT_SIZE;
> +
> +/// A wrapper around `struct sk_buff` for generic netlink messages.
> +///
> +/// This type is intended to be specific for buffers used with netlink only, and other usecases for
> +/// `struct sk_buff` are out-of-scope for this abstraction.
> +///
> +/// # Invariants
> +///
> +/// The pointer has ownership over a valid `sk_buff`.
> +pub struct NetlinkSkBuff {
> + skb: NonNull<kernel::bindings::sk_buff>,
> +}
> +
> +impl NetlinkSkBuff {
> + /// Creates a new `NetlinkSkBuff` with the given size.
> + pub fn new(size: usize, flags: alloc::Flags) -> Result<NetlinkSkBuff, AllocError> {
> + // SAFETY: `genlmsg_new` only requires its arguments to be valid integers.
> + let skb = unsafe { bindings::genlmsg_new(size, flags.as_raw()) };
> + let skb = NonNull::new(skb).ok_or(AllocError)?;
> + Ok(NetlinkSkBuff { skb })
> + }
> +
> + /// Puts a generic netlink header into the `NetlinkSkBuff`.
> + pub fn genlmsg_put(
> + self,
> + portid: u32,
> + seq: u32,
> + family: &'static Family,
> + cmd: u8,
> + ) -> Result<GenlMsg, AllocError> {
> + let skb = self.skb.as_ptr();
> + // SAFETY: The skb and family pointers are valid.
> + let hdr = unsafe { bindings::genlmsg_put(skb, portid, seq, family.as_raw(), 0, cmd) };
> + let hdr = NonNull::new(hdr).ok_or(AllocError)?;
> + Ok(GenlMsg { skb: self, hdr })
> + }
> +}
> +
> +impl Drop for NetlinkSkBuff {
> + fn drop(&mut self) {
> + // SAFETY: We have ownership over the `sk_buff`, so we may free it.
> + unsafe { bindings::nlmsg_free(self.skb.as_ptr()) }
> + }
> +}
> +
> +/// A generic netlink message being constructed.
> +///
> +/// # Invariants
> +///
> +/// `hdr` references the header in this netlink message.
> +pub struct GenlMsg {
> + skb: NetlinkSkBuff,
> + hdr: NonNull<c_void>,
> +}
> +
> +impl GenlMsg {
> + /// Puts an attribute into the message.
> + #[inline]
> + fn put<T>(&mut self, attrtype: c_int, value: &T) -> Result
> + where
> + T: ?Sized + AsBytes,
> + {
> + let skb = self.skb.skb.as_ptr();
> + let len = size_of_val(value);
> + let ptr = core::ptr::from_ref(value).cast::<c_void>();
> + // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and the provided value is
> + // readable and initialized for its `size_of` bytes.
> + to_result(unsafe { bindings::nla_put(skb, attrtype, len as c_int, ptr) })
> + }
> +
> + /// Puts a `u32` attribute into the message.
> + #[inline]
> + pub fn put_u32(&mut self, attrtype: c_int, value: u32) -> Result {
> + self.put(attrtype, &value)
> + }
> +
> + /// Puts a string attribute into the message.
> + #[inline]
> + pub fn put_string(&mut self, attrtype: c_int, value: &CStr) -> Result {
> + self.put(attrtype, value.to_bytes_with_nul())
> + }
> +
> + /// Puts a flag attribute into the message.
> + #[inline]
> + pub fn put_flag(&mut self, attrtype: c_int) -> Result {
> + let skb = self.skb.skb.as_ptr();
> + // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and a null pointer is valid
> + // when the length is zero.
> + to_result(unsafe { bindings::nla_put(skb, attrtype, 0, core::ptr::null()) })
> + }
> +
> + /// Sends the generic netlink message as a multicast message.
> + #[inline]
> + pub fn multicast(
> + self,
> + family: &'static Family,
> + portid: u32,
> + group: u32,
> + flags: alloc::Flags,
> + ) -> Result {
> + let me = ManuallyDrop::new(self);
> + // SAFETY: The `skb` and `family` pointers are valid. We pass ownership of the `skb` to
> + // `genlmsg_multicast` by not dropping `self`.
I think if genlmsg_multicast returns an error code we may need to drop
to avoid leaking. Specifically, there is at least this path:
1. Set group to a large number (that's an unconstrained public parameter)
2. We suppress drop
3. We call genlmsg_multicast
4. We call genlmsg_multicast_netns
4. We call genlmsg_multicast_netns_filtered, which does an inbounds
check for the `group`. If it is too large, it returns EINVAL without
consuming the SKB - include/net/genetlink.h:493
5. We leak the skb
However, at the same time, if we pass that check and descend into
`netlink_broadcast_filtered`, it will unconditionally consume the SKB,
and possibly return an error code in other situations.
I think this either means that we need to make the inbounds check for
groups in `genlmsg_multicast_netns_filtered` use `consume_skb(skb)`
before returning EINVAL, or we need to check the error code for EINVAL
and manually drop if we get it. The second one seems kind of janky
because `genlmsg_multicast` doesn't document that its free-behavior
differs for different error codes.
> + unsafe {
> + bindings::genlmsg_end(me.skb.skb.as_ptr(), me.hdr.as_ptr());
> + to_result(bindings::genlmsg_multicast(
> + family.as_raw(),
> + me.skb.skb.as_ptr(),
> + portid,
> + group,
> + flags.as_raw(),
> + ))
> + }
> + }
> +}
> +impl Drop for GenlMsg {
> + fn drop(&mut self) {
> + // SAFETY: The `hdr` pointer references the header of this generic netlink message.
> + unsafe { bindings::genlmsg_cancel(self.skb.skb.as_ptr(), self.hdr.as_ptr()) };
> + }
> +}
> +
> +/// Flags for a generic netlink family.
> +struct FamilyFlags {
> + /// Whether the family supports network namespaces.
> + netnsok: bool,
> + /// Whether the family supports parallel operations.
> + parallel_ops: bool,
> +}
> +
> +impl FamilyFlags {
> + /// Converts the flags to the bitfield representation used by `genl_family`.
> + const fn into_bitfield(self) -> bindings::__BindgenBitfieldUnit<[u8; 1]> {
> + // The below shifts are verified correct by test_family_flags_bitfield() below.
1. My understanding is that bit layout is implementation defined from C11:
"An implementation may allocate any addressable storage unit large
enough to hold a bitfield." (This one gets tested statically via
interaction with bindgen)
"The order of allocation of bit-fields within a unit (high-order to
low-order or low-order to high-order) is implementation-defined."
(this one gets checked by your KUnit test)
so we can't actually know that any manual bitpack/unpack will do what
we want reliably - another C compiler might do something different.
2. While this looks correct to me from an endianness perspective (in
terms of what compilers actually do rather than what the spec says),
have we run it on a big endian arch just to make sure?
> + //
> + // Although bindgen generates helpers to change bitfields based on the C headers, these
> + // helpers unfortunately can't be used in const context. Since `Family` needs to be filled
> + // out at build-time, we use this helper instead.
> + let mut bits = 0;
> + if self.netnsok {
> + bits |= 1 << 0;
> + }
> + if self.parallel_ops {
> + bits |= 1 << 1;
> + }
> + // SAFETY: This bitfield is represented as an u8.
> + unsafe { core::mem::transmute::<u8, bindings::__BindgenBitfieldUnit<[u8; 1]>>(bits) }
> + }
> +}
> +
> +/// A generic netlink family.
> +#[repr(transparent)]
> +pub struct Family {
> + inner: Opaque<bindings::genl_family>,
> +}
> +
> +// SAFETY: The `Family` type is thread safe.
> +unsafe impl Sync for Family {}
> +
> +impl Family {
> + /// Creates a new `Family` instance.
Might be worth calling out that this panics on bad input rather than
returning an error in docs? It might be fine because this isn't going
to be called dynamically, but it doesn't match the usual behavior for
other kernel functions.
> + pub const fn const_new(
> + module: &ThisModule,
If const_new for MulticastGroup can take a &CStr, why can't we take one here?
> + name: &[u8],
> + version: u32,
> + mcgrps: &'static [MulticastGroup],
> + ) -> Family {
> + let n_mcgrps = mcgrps.len() as u8;
> + if n_mcgrps as usize != mcgrps.len() {
> + panic!("too many mcgrps");
> + }
> + let mut genl_family = bindings::genl_family {
> + version,
> + _bitfield_1: FamilyFlags {
> + netnsok: true,
> + parallel_ops: true,
> + }
> + .into_bitfield(),
> + module: module.as_ptr(),
> + mcgrps: mcgrps.as_ptr().cast(),
> + n_mcgrps,
> + ..pin_init::zeroed()
> + };
> + if CStr::from_bytes_with_nul(name).is_err() {
> + panic!("genl_family name not nul-terminated");
> + }
> + if genl_family.name.len() < name.len() {
> + panic!("genl_family name too long");
> + }
> + let mut i = 0;
> + while i < name.len() {
> + genl_family.name[i] = name[i];
> + i += 1;
> + }
> + Family {
> + inner: Opaque::new(genl_family),
> + }
> + }
> +
> + /// Checks if there are any listeners for the given multicast group.
> + pub fn has_listeners(&self, group: u32) -> bool {
> + // SAFETY: The family and init_net pointers are valid.
> + unsafe {
> + bindings::genl_has_listeners(self.as_raw(), &raw mut bindings::init_net, group) != 0
> + }
> + }
> +
> + /// Returns a raw pointer to the underlying `genl_family` structure.
> + pub fn as_raw(&self) -> *mut bindings::genl_family {
> + self.inner.get()
> + }
> +}
> +
> +/// A generic netlink multicast group.
> +#[repr(transparent)]
> +pub struct MulticastGroup {
> + // No Opaque because fully immutable
> + group: bindings::genl_multicast_group,
> +}
> +
> +// SAFETY: Pure data so thread safe.
> +unsafe impl Sync for MulticastGroup {}
> +
> +impl MulticastGroup {
> + /// Creates a new `MulticastGroup` instance.
Same as before - should the panic be documented?
> + pub const fn const_new(name: &CStr) -> MulticastGroup {
> + let mut group: bindings::genl_multicast_group = pin_init::zeroed();
> +
> + let name = name.to_bytes_with_nul();
> + if group.name.len() < name.len() {
> + panic!("genl_multicast_group name too long");
> + }
> + let mut i = 0;
> + while i < name.len() {
> + group.name[i] = name[i];
> + i += 1;
> + }
> +
> + MulticastGroup { group }
> + }
> +}
> +
> +/// A registration of a generic netlink family.
> +///
> +/// This type represents the registration of a [`Family`]. When an instance of this type is
> +/// dropped, its respective generic netlink family will be unregistered from the system.
> +///
> +/// # Invariants
> +///
> +/// `self.family` always holds a valid reference to an initialized and registered [`Family`].
> +pub struct Registration {
> + family: &'static Family,
> +}
> +
> +impl Family {
> + /// Registers the generic netlink family with the kernel.
> + pub fn register(&'static self) -> Result<Registration> {
> + // SAFETY: `self.as_raw()` is a valid pointer to a `genl_family` struct.
> + // The `genl_family` struct is static, so it will outlive the registration.
> + to_result(unsafe { bindings::genl_register_family(self.as_raw()) })?;
> + Ok(Registration { family: self })
> + }
> +}
> +
> +impl Drop for Registration {
> + fn drop(&mut self) {
> + // SAFETY: `self.family.as_raw()` is a valid pointer to a registered `genl_family` struct.
> + // The `Registration` struct ensures that `genl_unregister_family` is called exactly once
> + // for this family when it goes out of scope.
> + unsafe { bindings::genl_unregister_family(self.family.as_raw()) };
> + }
> +}
> +
> +#[macros::kunit_tests(rust_netlink)]
> +mod tests {
> + use super::*;
> +
> + #[test]
> + fn test_family_flags_bitfield() {
> + for netnsok in [false, true] {
> + for parallel_ops in [false, true] {
> + let mut b_fam = bindings::genl_family {
> + ..Default::default()
> + };
> + b_fam.set_netnsok(if netnsok { 1 } else { 0 });
> + b_fam.set_parallel_ops(if parallel_ops { 1 } else { 0 });
> +
> + let c_bitfield = FamilyFlags {
> + netnsok,
> + parallel_ops,
> + }
> + .into_bitfield();
> +
> + // SAFETY: The bit field is stored as u8.
> + let b_val: u8 = unsafe { core::mem::transmute(b_fam._bitfield_1) };
> + // SAFETY: The bit field is stored as u8.
> + let c_val: u8 = unsafe { core::mem::transmute(c_bitfield) };
> + assert_eq!(b_val, c_val);
> + }
> + }
> + }
> +}
>
> --
> 2.54.0.rc0.605.g598a273b03-goog
>
>
^ permalink raw reply
* [PATCH net 14/14] tcp: annotate data-races around tp->plb_rehash
From: Eric Dumazet @ 2026-04-16 20:03 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, Neal Cardwell, Kuniyuki Iwashima, netdev,
eric.dumazet, Eric Dumazet
In-Reply-To: <20260416200319.3608680-1-edumazet@google.com>
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must
add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
Fixes: 29c1c44646ae ("tcp: add u32 counter in tcp_sock and an SNMP counter for PLB")
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp.c | 3 ++-
net/ipv4/tcp_plb.c | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 68894c03f2622d1a08fd747ff4c5e32be8579d2c..7fbf2fca5eb2c63763231d4d55b770b85a7cbdbf 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -4480,7 +4480,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
nla_put_u8(stats, TCP_NLA_TTL,
tcp_skb_ttl_or_hop_limit(ack_skb));
- nla_put_u32(stats, TCP_NLA_REHASH, tp->plb_rehash + tp->timeout_rehash);
+ nla_put_u32(stats, TCP_NLA_REHASH,
+ READ_ONCE(tp->plb_rehash) + READ_ONCE(tp->timeout_rehash));
return stats;
}
diff --git a/net/ipv4/tcp_plb.c b/net/ipv4/tcp_plb.c
index 68ccdb9a54127632b6b764b5cbb18e1589ab1aa7..c11a0cd3f8feb004150a4056f5ca57f90d2cb2b8 100644
--- a/net/ipv4/tcp_plb.c
+++ b/net/ipv4/tcp_plb.c
@@ -80,7 +80,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb)
sk_rethink_txhash(sk);
plb->consec_cong_rounds = 0;
- tcp_sk(sk)->plb_rehash++;
+ WRITE_ONCE(tcp_sk(sk)->plb_rehash, tcp_sk(sk)->plb_rehash + 1);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPLBREHASH);
}
EXPORT_SYMBOL_GPL(tcp_plb_check_rehash);
--
2.54.0.rc1.513.gad8abe7a5a-goog
^ permalink raw reply related
* [PATCH net 13/14] tcp: annotate data-races around (tp->write_seq - tp->snd_nxt)
From: Eric Dumazet @ 2026-04-16 20:03 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, Neal Cardwell, Kuniyuki Iwashima, netdev,
eric.dumazet, Eric Dumazet
In-Reply-To: <20260416200319.3608680-1-edumazet@google.com>
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must
add READ_ONCE() annotations to keep KCSAN happy.
WRITE_ONCE() annotations are already present.
Fixes: e08ab0b377a1 ("tcp: add bytes not sent to SCM_TIMESTAMPING_OPT_STATS")
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 192e95b71ce9868980a809184be83398d8740427..68894c03f2622d1a08fd747ff4c5e32be8579d2c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -4472,7 +4472,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH,
READ_ONCE(tp->timeout_rehash));
nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT,
- max_t(int, 0, tp->write_seq - tp->snd_nxt));
+ max_t(int, 0,
+ READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt)));
nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns,
TCP_NLA_PAD);
if (ack_skb)
--
2.54.0.rc1.513.gad8abe7a5a-goog
^ permalink raw reply related
* [PATCH net 11/14] tcp: annotate data-races around tp->srtt_us
From: Eric Dumazet @ 2026-04-16 20:03 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, Neal Cardwell, Kuniyuki Iwashima, netdev,
eric.dumazet, Eric Dumazet
In-Reply-To: <20260416200319.3608680-1-edumazet@google.com>
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must
add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
Fixes: e8bd8fca6773 ("tcp: add SRTT to SCM_TIMESTAMPING_OPT_STATS")
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp.c | 5 +++--
net/ipv4/tcp_input.c | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 39a4b06e36bbc63b8bc334c8f568c5a2046573b6..541bd0d2d8c4ed24934fd047dd46e532b30021be 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3623,7 +3623,8 @@ static void tcp_enable_tx_delay(struct sock *sk, int val)
if (delta && sk->sk_state == TCP_ESTABLISHED) {
s64 srtt = (s64)tp->srtt_us + delta;
- tp->srtt_us = clamp_t(s64, srtt, 1, ~0U);
+ WRITE_ONCE(tp->srtt_us,
+ clamp_t(s64, srtt, 1, ~0U));
/* Note: does not deal with non zero icsk_backoff */
tcp_set_rto(sk);
@@ -4467,7 +4468,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD);
nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups));
nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen));
- nla_put_u32(stats, TCP_NLA_SRTT, tp->srtt_us >> 3);
+ nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3);
nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash);
nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT,
max_t(int, 0, tp->write_seq - tp->snd_nxt));
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 896a5a5a6b1a9a678e5321dd802554ab343f7835..e04ae105893c2bf234e593b1529748283bb2176c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1132,7 +1132,7 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us)
tcp_bpf_rtt(sk, mrtt_us, srtt);
}
- tp->srtt_us = max(1U, srtt);
+ WRITE_ONCE(tp->srtt_us, max(1U, srtt));
}
void tcp_update_pacing_rate(struct sock *sk)
--
2.54.0.rc1.513.gad8abe7a5a-goog
^ permalink raw reply related
* [PATCH net 12/14] tcp: annotate data-races around tp->timeout_rehash
From: Eric Dumazet @ 2026-04-16 20:03 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, Neal Cardwell, Kuniyuki Iwashima, netdev,
eric.dumazet, Eric Dumazet
In-Reply-To: <20260416200319.3608680-1-edumazet@google.com>
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must
add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
Fixes: 32efcc06d2a1 ("tcp: export count for rehash attempts")
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp.c | 3 ++-
net/ipv4/tcp_timer.c | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 541bd0d2d8c4ed24934fd047dd46e532b30021be..192e95b71ce9868980a809184be83398d8740427 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -4469,7 +4469,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
nla_put_u32(stats, TCP_NLA_DSACK_DUPS, READ_ONCE(tp->dsack_dups));
nla_put_u32(stats, TCP_NLA_REORD_SEEN, READ_ONCE(tp->reord_seen));
nla_put_u32(stats, TCP_NLA_SRTT, READ_ONCE(tp->srtt_us) >> 3);
- nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH, tp->timeout_rehash);
+ nla_put_u16(stats, TCP_NLA_TIMEOUT_REHASH,
+ READ_ONCE(tp->timeout_rehash));
nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT,
max_t(int, 0, tp->write_seq - tp->snd_nxt));
nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns,
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index ea99988795e7e87412eef2768c4471e90c3e873e..8d791a954cd6ced52380226f205c66224b8f8bbd 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -297,7 +297,7 @@ static int tcp_write_timeout(struct sock *sk)
}
if (sk_rethink_txhash(sk)) {
- tp->timeout_rehash++;
+ WRITE_ONCE(tp->timeout_rehash, tp->timeout_rehash + 1);
__NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEOUTREHASH);
}
--
2.54.0.rc1.513.gad8abe7a5a-goog
^ 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