[PATCH] net/mlx5: fix processing of batched RDMA monitor events

Bing Zhao bingz at nvidia.com
Wed Sep 9 07:00:57 CEST 2026


mlx5_nl_read_events() may deliver multiple RDMA attach or detach
messages in one drain. The interrupt handler previously parsed all
messages into one structure and processed only the last one, leaving
earlier port cache updates unhandled.

Parse and process each Netlink message in its callback. Always drain
pending messages, validate the port index before updating the cache,
and log at INFO when multiple messages for the same IB device are
received in one drain.

Fixes: 2a18d0022c05 ("common/mlx5: use RDMA Netlink to update port info")
Cc: stable at dpdk.org

Signed-off-by: Bing Zhao <bingz at nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo at nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_ethdev_os.c | 135 +++++++++++++-----------
 1 file changed, 75 insertions(+), 60 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_ethdev_os.c b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
index 4bbc590e91..f6394ebd19 100644
--- a/drivers/net/mlx5/linux/mlx5_ethdev_os.c
+++ b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
@@ -890,85 +890,53 @@ mlx5_dev_interrupt_handler_devx(void *cb_arg)
 }
 
 static void
-mlx5_dev_interrupt_ib_cb(struct nlmsghdr *hdr, void *cb_arg)
-{
-	mlx5_nl_rdma_monitor_info_get(hdr, (struct mlx5_nl_port_info *)cb_arg);
-}
-
-void
-mlx5_dev_interrupt_handler_ib(void *arg)
+mlx5_dev_interrupt_ib_process(struct mlx5_dev_ctx_shared *sh,
+			      const struct mlx5_nl_port_info *data)
 {
-	struct mlx5_dev_ctx_shared *sh = arg;
-	struct mlx5_nl_port_info data = {
-		.flags = 0,
-		.name = "",
-		.ifindex = 0,
-		.ibindex = 0,
-		.portnum = 0,
-	};
-	int nlsk_fd = rte_intr_fd_get(sh->intr_handle_ib);
-	struct mlx5_dev_info *dev_info;
+	struct mlx5_dev_info *dev_info = &sh->cdev->dev_info;
 	uint32_t i;
 
-	dev_info = &sh->cdev->dev_info;
-	DRV_LOG(DEBUG, "IB device %s received RDMA monitor netlink event", dev_info->ibname);
 	if (dev_info->port_num <= 1 || dev_info->port_info == NULL)
 		return;
-
-	if (nlsk_fd < 0)
-		return;
-
-	if (mlx5_nl_read_events(nlsk_fd, mlx5_dev_interrupt_ib_cb, &data) < 0)
-		DRV_LOG(ERR, "Failed to process Netlink events: %s",
-			rte_strerror(rte_errno));
-
-	if (!(data.flags & MLX5_NL_CMD_GET_EVENT_TYPE) ||
-		!(data.flags & MLX5_NL_CMD_GET_PORT_INDEX) ||
-		!(data.flags & MLX5_NL_CMD_GET_IB_INDEX))
+	if (!(data->flags & MLX5_NL_CMD_GET_EVENT_TYPE) ||
+	    !(data->flags & MLX5_NL_CMD_GET_PORT_INDEX) ||
+	    !(data->flags & MLX5_NL_CMD_GET_IB_INDEX))
 		return;
-
-	if (data.ibindex != dev_info->ibindex)
+	if (data->ibindex != dev_info->ibindex)
 		return;
-
-	if (data.event_type != MLX5_NL_RDMA_NETDEV_ATTACH_EVENT &&
-		data.event_type != MLX5_NL_RDMA_NETDEV_DETACH_EVENT)
+	if (data->event_type != MLX5_NL_RDMA_NETDEV_ATTACH_EVENT &&
+	    data->event_type != MLX5_NL_RDMA_NETDEV_DETACH_EVENT)
 		return;
-
-	if (data.event_type == MLX5_NL_RDMA_NETDEV_ATTACH_EVENT &&
-	    !(data.flags & MLX5_NL_CMD_GET_NET_INDEX)) {
+	/* IB ports are 1-based. */
+	if (data->portnum < 1 || data->portnum > dev_info->port_num) {
+		DRV_LOG(ERR, "Port[%u] is outside valid range [1, %u]",
+			data->portnum, dev_info->port_num);
+		goto flush_all;
+	}
+	if (data->event_type == MLX5_NL_RDMA_NETDEV_ATTACH_EVENT &&
+	    !(data->flags & MLX5_NL_CMD_GET_NET_INDEX)) {
 		DRV_LOG(WARNING, "Incomplete RDMA ATTACH event for ibdev[%d]",
 			dev_info->ibindex);
-		if (data.flags & MLX5_NL_CMD_GET_PORT_INDEX)
-			memset(dev_info->port_info + data.portnum, 0,
-			       sizeof(struct mlx5_port_nl_info));
-		else
-			goto flush_all;
+		memset(dev_info->port_info + data->portnum, 0,
+		       sizeof(struct mlx5_port_nl_info));
 		return;
 	}
-
 	DRV_LOG(INFO, "Event info: type %d, ibindex %d, ifindex %d, portnum %d,",
-		data.event_type, data.ibindex, data.ifindex, data.portnum);
-
-	/* Changes found in number of SF/VF ports. All information is likely unreliable. */
-	if (data.portnum > dev_info->port_num) {
-		DRV_LOG(ERR, "Port[%d] exceeds maximum[%d]", data.portnum, dev_info->port_num);
-		goto flush_all;
-	}
-	if (data.event_type == MLX5_NL_RDMA_NETDEV_ATTACH_EVENT) {
-		if (!dev_info->port_info[data.portnum].ifindex) {
-			dev_info->port_info[data.portnum].ifindex = data.ifindex;
-			dev_info->port_info[data.portnum].valid = 1;
+		data->event_type, data->ibindex, data->ifindex, data->portnum);
+	if (data->event_type == MLX5_NL_RDMA_NETDEV_ATTACH_EVENT) {
+		if (!dev_info->port_info[data->portnum].ifindex) {
+			dev_info->port_info[data->portnum].ifindex = data->ifindex;
+			dev_info->port_info[data->portnum].valid = 1;
 		} else {
 			DRV_LOG(WARNING, "Duplicate RDMA event for port[%d] ifindex[%d]",
-				data.portnum, data.ifindex);
-			if (data.ifindex != dev_info->port_info[data.portnum].ifindex)
+				data->portnum, data->ifindex);
+			if (data->ifindex != dev_info->port_info[data->portnum].ifindex)
 				goto flush_all;
 		}
-	} else if (data.event_type == MLX5_NL_RDMA_NETDEV_DETACH_EVENT) {
-		dev_info->port_info[data.portnum].ifindex = 0;
+	} else if (data->event_type == MLX5_NL_RDMA_NETDEV_DETACH_EVENT) {
+		dev_info->port_info[data->portnum].ifindex = 0;
 	}
 	return;
-
 flush_all:
 	for (i = 1; i <= dev_info->port_num; i++) {
 		dev_info->port_info[i].ifindex = 0;
@@ -976,6 +944,53 @@ mlx5_dev_interrupt_handler_ib(void *arg)
 	}
 }
 
+struct mlx5_dev_interrupt_ib_cb_arg {
+	struct mlx5_dev_ctx_shared *sh;
+	uint32_t message_count;
+};
+
+static void
+mlx5_dev_interrupt_ib_cb(struct nlmsghdr *hdr, void *cb_arg)
+{
+	struct mlx5_dev_interrupt_ib_cb_arg *arg = cb_arg;
+	const uint32_t count_flags = MLX5_NL_CMD_GET_EVENT_TYPE |
+				     MLX5_NL_CMD_GET_IB_INDEX;
+	struct mlx5_nl_port_info data = { 0 };
+
+	mlx5_nl_rdma_monitor_info_get(hdr, &data);
+	if ((data.flags & count_flags) == count_flags &&
+	    data.ibindex == arg->sh->cdev->dev_info.ibindex)
+		arg->message_count++;
+	mlx5_dev_interrupt_ib_process(arg->sh, &data);
+}
+
+void
+mlx5_dev_interrupt_handler_ib(void *arg)
+{
+	struct mlx5_dev_ctx_shared *sh = arg;
+	struct mlx5_dev_info *dev_info = &sh->cdev->dev_info;
+	struct mlx5_dev_interrupt_ib_cb_arg cb_arg = {
+		.sh = sh,
+		.message_count = 0,
+	};
+	int nlsk_fd = rte_intr_fd_get(sh->intr_handle_ib);
+
+	DRV_LOG(DEBUG,
+		"IB device %s received RDMA monitor netlink event",
+		dev_info->ibname);
+	if (nlsk_fd < 0)
+		return;
+	if (mlx5_nl_read_events(nlsk_fd, mlx5_dev_interrupt_ib_cb,
+				&cb_arg) < 0)
+		DRV_LOG(ERR, "Failed to process Netlink events: %s",
+			rte_strerror(rte_errno));
+	if (cb_arg.message_count > 1)
+		DRV_LOG(INFO,
+			"RDMA monitor received %u netlink messages for "
+			"IB device %s in one drain",
+			cb_arg.message_count, dev_info->ibname);
+}
+
 /**
  * DPDK callback to bring the link DOWN.
  *
-- 
2.43.0



More information about the stable mailing list