* [PATCH 01/13] common/mlx5: rework IB port number query
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
@ 2026-10-26 16:26 ` Dariusz Sosnowski
2026-10-26 16:26 ` [PATCH 02/13] common/mlx5: allow ifindex query without cache Dariusz Sosnowski
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:26 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
mlx5_nl_portnum() function currently requires that
IB port to netdev info cache (mlx5_dev_info) is always provided.
Rework this function:
- Allow calling mlx5_nl_portnum() without cache.
- Extract cache fetch/update logic into separate functions.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/mlx5_nl.c | 79 ++++++++++++++++++++---------
1 file changed, 54 insertions(+), 25 deletions(-)
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index 3fabcfaee0..1132e3fa5f 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -1275,15 +1275,60 @@ mlx5_nl_port_state(int nl, const char *name, uint32_t pindex, struct mlx5_dev_in
return (int)data.state;
}
+static unsigned int
+mlx5_dev_info_get_portnum(const char *ibname, struct mlx5_dev_info *dev_info)
+{
+ if (dev_info == NULL ||
+ !dev_info->probe_opt ||
+ dev_info->port_num == 0 ||
+ strcmp(ibname, dev_info->ibname) != 0)
+ return 0;
+
+ return dev_info->port_num;
+}
+
+static unsigned int
+mlx5_dev_info_set_portnum(const char *ibname,
+ struct mlx5_dev_info *dev_info,
+ const struct mlx5_nl_port_info *data)
+{
+ size_t size;
+
+ /* If cache is not available or probe optimization is not enabled, just return portnum. */
+ if (dev_info == NULL || !dev_info->probe_opt)
+ return data->portnum;
+
+ MLX5_ASSERT(data->flags & MLX5_NL_CMD_GET_IB_NAME);
+ MLX5_ASSERT(data->flags & MLX5_NL_CMD_GET_IB_INDEX);
+ MLX5_ASSERT(data->flags & MLX5_NL_CMD_GET_PORT_INDEX);
+ MLX5_ASSERT(strlen(dev_info->ibname) == 0);
+
+ dev_info->port_num = data->portnum;
+ dev_info->ibindex = data->ibindex;
+ snprintf(dev_info->ibname, MLX5_FS_NAME_MAX, "%s", ibname);
+ if (data->portnum > 1) {
+ size = (data->portnum + 1) * sizeof(struct mlx5_port_nl_info);
+ dev_info->port_info = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, size,
+ RTE_CACHE_LINE_SIZE,
+ SOCKET_ID_ANY);
+ if (dev_info->port_info == NULL) {
+ memset(dev_info, 0, sizeof(*dev_info));
+ rte_errno = ENOMEM;
+ return 0;
+ }
+ }
+ return data->portnum;
+}
+
/**
* Get the number of physical ports of given IB device.
*
- * @param nl
+ * @param[in] nl
* Netlink socket of the RDMA kind (NETLINK_RDMA).
* @param[in] name
* IB device name.
- * @param[in] dev_info
- * Cached mlx5 device info.
+ * @param[in,out] dev_info
+ * Cached mlx5 device info. If NULL, netlink query is done and caching is skipped.
*
* @return
* A valid (nonzero) number of ports on success, 0 otherwise
@@ -1306,11 +1351,12 @@ mlx5_nl_portnum(int nl, const char *name, struct mlx5_dev_info *dev_info)
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
};
uint32_t sn = MLX5_NL_SN_GENERATE;
- int ret, size;
+ unsigned int portnum;
+ int ret;
- if (dev_info->probe_opt && dev_info->port_num &&
- !strcmp(name, dev_info->ibname))
- return dev_info->port_num;
+ portnum = mlx5_dev_info_get_portnum(name, dev_info);
+ if (portnum > 0)
+ return portnum;
ret = mlx5_nl_send(nl, &req, sn);
if (ret < 0)
@@ -1328,24 +1374,7 @@ mlx5_nl_portnum(int nl, const char *name, struct mlx5_dev_info *dev_info)
rte_errno = EINVAL;
return 0;
}
- if (!dev_info->probe_opt)
- return data.portnum;
- MLX5_ASSERT(!strlen(dev_info->ibname));
- dev_info->port_num = data.portnum;
- dev_info->ibindex = data.ibindex;
- snprintf(dev_info->ibname, MLX5_FS_NAME_MAX, "%s", name);
- if (data.portnum > 1) {
- size = (data.portnum + 1) * sizeof(struct mlx5_port_nl_info);
- dev_info->port_info = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, size,
- RTE_CACHE_LINE_SIZE,
- SOCKET_ID_ANY);
- if (dev_info->port_info == NULL) {
- memset(dev_info, 0, sizeof(*dev_info));
- rte_errno = ENOMEM;
- return 0;
- }
- }
- return data.portnum;
+ return mlx5_dev_info_set_portnum(name, dev_info, &data);
}
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 02/13] common/mlx5: allow ifindex query without cache
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
2026-10-26 16:26 ` [PATCH 01/13] common/mlx5: rework IB port number query Dariusz Sosnowski
@ 2026-10-26 16:26 ` Dariusz Sosnowski
2026-10-26 16:26 ` [PATCH 03/13] common/mlx5: separate netdev info from switch info Dariusz Sosnowski
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:26 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Translating IB port to netdev ifindex requires that cache
on mlx5 common device is initialized and RDMA monitoring
is set up. Latter happens only when ethdev mlx5 port is spawned.
To enable usage of mlx5_nl_ifindex() inside common driver code,
allow calling it without cache.
If cache is not provided, netlink query will always be executed.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/mlx5_nl.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index 1132e3fa5f..d4b40bec2c 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -1181,14 +1181,14 @@ mlx5_nl_port_info(int nl, uint32_t pindex, struct mlx5_nl_port_info *data)
* when faced with port representors. Unfortunately it requires at least
* Linux 4.17.
*
- * @param nl
+ * @param[in] nl
* Netlink socket of the RDMA kind (NETLINK_RDMA).
* @param[in] name
* IB device name.
* @param[in] pindex
* IB device port index, starting from 1
- * @param[in] dev_info
- * Cached mlx5 device information.
+ * @param[in,out] dev_info
+ * Cached mlx5 device information. If NULL, netlink query is done and caching is skipped.
* @return
* A valid (nonzero) interface index on success, 0 otherwise and rte_errno
* is set.
@@ -1206,6 +1206,9 @@ mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex, struct mlx5_dev_info
.flags = 0,
};
+ if (dev_info == NULL)
+ goto query_port_info;
+
if (dev_info->probe_opt && !strcmp(name, dev_info->ibname)) {
if (dev_info->port_info && pindex <= dev_info->port_num &&
dev_info->port_info[pindex].valid) {
@@ -1222,8 +1225,9 @@ mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex, struct mlx5_dev_info
rte_errno = ENODEV;
return 0;
}
+query_port_info:
ret = mlx5_nl_port_info(nl, pindex, &data);
- if (dev_info->probe_opt && !strcmp(dev_info->ibname, name)) {
+ if (dev_info != NULL && dev_info->probe_opt && !strcmp(dev_info->ibname, name)) {
if ((!ret || ret == -ENODEV) && dev_info->port_info &&
pindex <= dev_info->port_num) {
if (!ret)
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 03/13] common/mlx5: separate netdev info from switch info
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
2026-10-26 16:26 ` [PATCH 01/13] common/mlx5: rework IB port number query Dariusz Sosnowski
2026-10-26 16:26 ` [PATCH 02/13] common/mlx5: allow ifindex query without cache Dariusz Sosnowski
@ 2026-10-26 16:26 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 04/13] common/mlx5: query parent device over Netlink Dariusz Sosnowski
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:26 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
mlx5_nl_switch_info() is used to query information
about the Linux netdev relevant for NICs with embedded switch.
It calls and parses data from netlink directly.
Rework this function to allow more generic netlink calls
about Linux netdevs. Netlink call is moved to dedicated
function, mlx5_nl_netdev_info_get(), parametrized by ifindex.
Switch info is then filled in from returned netdev info.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/mlx5_nl.c | 236 +++++++++++++++-------------
drivers/common/mlx5/linux/mlx5_nl.h | 17 ++
2 files changed, 143 insertions(+), 110 deletions(-)
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index d4b40bec2c..eafae78883 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -32,8 +32,6 @@
#define MLX5_SEND_BUF_SIZE 32768
/* Receive buffer size for the Netlink socket */
#define MLX5_RECV_BUF_SIZE 32768
-/* Maximal physical port name length. */
-#define MLX5_PHYS_PORT_NAME_MAX 128
/** Parameters of VLAN devices created by driver. */
#define MLX5_VMWA_VLAN_DEVICE_PFX "evmlx"
@@ -1381,6 +1379,111 @@ mlx5_nl_portnum(int nl, const char *name, struct mlx5_dev_info *dev_info)
return mlx5_dev_info_set_portnum(name, dev_info, &data);
}
+static int
+mlx5_nl_netdev_info_cb(struct nlmsghdr *nh, void *arg)
+{
+ struct mlx5_netdev_info *out = arg;
+ struct mlx5_netdev_info info;
+ struct rtattr *ra;
+ int payload_len;
+ int off;
+ int len;
+
+ if (nh->nlmsg_type != RTM_NEWLINK)
+ goto error;
+
+ memset(&info, 0, sizeof(info));
+ info.ifindex = out->ifindex;
+
+ off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ len = nh->nlmsg_len - off;
+ for (ra = RTE_PTR_ADD(nh, off);
+ RTA_OK(ra, len);
+ ra = RTA_NEXT(ra, len)) {
+ void *payload = RTA_DATA(ra);
+ unsigned int i;
+
+ switch (ra->rta_type) {
+ case IFLA_NUM_VF:
+ if (RTA_PAYLOAD(ra) < sizeof(uint32_t))
+ goto error;
+ info.num_vf = *(uint32_t *)payload;
+ info.flags |= MLX5_NETDEV_INFO_FLAG_NUM_VF;
+ break;
+ case IFLA_PHYS_PORT_NAME:
+ payload_len = RTA_PAYLOAD(ra);
+ /* Some kernels do not pad attributes with zero. */
+ if (payload_len > 0 && payload_len < MLX5_PHYS_PORT_NAME_MAX) {
+ memcpy(info.phys_port_name, payload, payload_len);
+ info.phys_port_name[payload_len] = '\0';
+ info.flags |= MLX5_NETDEV_INFO_FLAG_PHYS_PORT_NAME;
+ }
+ break;
+ case IFLA_PHYS_SWITCH_ID:
+ info.phys_switch_id = 0;
+ for (i = 0; i < RTA_PAYLOAD(ra); ++i) {
+ info.phys_switch_id <<= 8;
+ info.phys_switch_id |= ((uint8_t *)payload)[i];
+ }
+ info.flags |= MLX5_NETDEV_INFO_FLAG_PHYS_SWITCH_ID;
+ break;
+ }
+ }
+ *out = info;
+ return 0;
+error:
+ rte_errno = EINVAL;
+ return -rte_errno;
+}
+
+/**
+ * Query Linux netdev information through netlink.
+ *
+ * Information is queried only for a single interface, selected by ifindex field
+ * in @p info. flags field in @p info will be a bitmap of MLX5_NETDEV_INFO_FLAG_* flags.
+ * Each flag denotes that related field's value was returned by the kernel and can be used.
+ *
+ * @param[in] nl
+ * Netlink socket file descriptor. Must be opened for NETLINK_ROUTE family.
+ * @param[in,out] info
+ * Pointer to structure with netdev information.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_nl_netdev_info_get(int nl, struct mlx5_netdev_info *info)
+{
+ struct {
+ struct nlmsghdr nh;
+ struct ifinfomsg info;
+ struct rtattr rta;
+ uint32_t extmask;
+ } req = {
+ .nh = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(req.info) + RTA_LENGTH(sizeof(uint32_t))),
+ .nlmsg_type = RTM_GETLINK,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
+ },
+ .info = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = info->ifindex,
+ },
+ .rta = {
+ .rta_type = IFLA_EXT_MASK,
+ .rta_len = RTA_LENGTH(sizeof(int32_t)),
+ },
+ .extmask = RTE_LE32(1),
+ };
+ uint32_t sn = MLX5_NL_SN_GENERATE;
+ int ret;
+
+ ret = mlx5_nl_send(nl, &req.nh, sn);
+ if (ret >= 0)
+ ret = mlx5_nl_recv(nl, sn, mlx5_nl_netdev_info_cb, info);
+ return ret;
+}
+
/**
* Analyze gathered port parameters via Netlink to recognize master
* and representor devices for E-Switch configuration.
@@ -1434,88 +1537,6 @@ mlx5_nl_check_switch_info(bool num_vf_set,
}
}
-/**
- * Process switch information from Netlink message.
- *
- * @param nh
- * Pointer to Netlink message header.
- * @param arg
- * Opaque data pointer for this callback.
- *
- * @return
- * 0 on success, a negative errno value otherwise and rte_errno is set.
- */
-static int
-mlx5_nl_switch_info_cb(struct nlmsghdr *nh, void *arg)
-{
- struct mlx5_switch_info info = {
- .master = 0,
- .representor = 0,
- .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
- .port_name = 0,
- .switch_id = 0,
- };
- size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- bool switch_id_set = false;
- bool num_vf_set = false;
- int len;
-
- if (nh->nlmsg_type != RTM_NEWLINK)
- goto error;
- while (off < nh->nlmsg_len) {
- struct rtattr *ra = (void *)((uintptr_t)nh + off);
- void *payload = RTA_DATA(ra);
- unsigned int i;
-
- if (ra->rta_len > nh->nlmsg_len - off)
- goto error;
- switch (ra->rta_type) {
- case IFLA_NUM_VF:
- num_vf_set = true;
- break;
- case IFLA_PHYS_PORT_NAME:
- len = RTA_PAYLOAD(ra);
- /* Some kernels do not pad attributes with zero. */
- if (len > 0 && len < MLX5_PHYS_PORT_NAME_MAX) {
- char name[MLX5_PHYS_PORT_NAME_MAX];
-
- /*
- * We can't just patch the message with padding
- * zero - it might corrupt the following items
- * in the message, we have to copy the string
- * by attribute length and pad the copied one.
- */
- memcpy(name, payload, len);
- name[len] = 0;
- mlx5_translate_port_name(name, &info);
- } else {
- info.name_type =
- MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN;
- }
- break;
- case IFLA_PHYS_SWITCH_ID:
- info.switch_id = 0;
- for (i = 0; i < RTA_PAYLOAD(ra); ++i) {
- info.switch_id <<= 8;
- info.switch_id |= ((uint8_t *)payload)[i];
- }
- switch_id_set = true;
- break;
- }
- off += RTA_ALIGN(ra->rta_len);
- }
- if (switch_id_set) {
- /* We have some E-Switch configuration. */
- mlx5_nl_check_switch_info(num_vf_set, &info);
- }
- MLX5_ASSERT(!(info.master && info.representor));
- memcpy(arg, &info, sizeof(info));
- return 0;
-error:
- rte_errno = EINVAL;
- return -rte_errno;
-}
-
/**
* Get switch information associated with network interface.
*
@@ -1534,35 +1555,30 @@ int
mlx5_nl_switch_info(int nl, unsigned int ifindex,
struct mlx5_switch_info *info)
{
- struct {
- struct nlmsghdr nh;
- struct ifinfomsg info;
- struct rtattr rta;
- uint32_t extmask;
- } req = {
- .nh = {
- .nlmsg_len = NLMSG_LENGTH
- (sizeof(req.info) +
- RTA_LENGTH(sizeof(uint32_t))),
- .nlmsg_type = RTM_GETLINK,
- .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
- },
- .info = {
- .ifi_family = AF_UNSPEC,
- .ifi_index = ifindex,
- },
- .rta = {
- .rta_type = IFLA_EXT_MASK,
- .rta_len = RTA_LENGTH(sizeof(int32_t)),
- },
- .extmask = RTE_LE32(1),
+ struct mlx5_netdev_info netdev_info = {
+ .ifindex = ifindex,
};
- uint32_t sn = MLX5_NL_SN_GENERATE;
+ bool num_vf_set;
int ret;
- ret = mlx5_nl_send(nl, &req.nh, sn);
- if (ret >= 0)
- ret = mlx5_nl_recv(nl, sn, mlx5_nl_switch_info_cb, info);
+ ret = mlx5_nl_netdev_info_get(nl, &netdev_info);
+ if (ret < 0)
+ return ret;
+
+ memset(info, 0, sizeof(*info));
+
+ if (netdev_info.flags & MLX5_NETDEV_INFO_FLAG_PHYS_PORT_NAME)
+ mlx5_translate_port_name(netdev_info.phys_port_name, info);
+ else
+ info->name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET;
+
+ num_vf_set = !!(netdev_info.flags & MLX5_NETDEV_INFO_FLAG_NUM_VF);
+
+ if (netdev_info.flags & MLX5_NETDEV_INFO_FLAG_PHYS_SWITCH_ID) {
+ info->switch_id = netdev_info.phys_switch_id;
+ mlx5_nl_check_switch_info(num_vf_set, info);
+ }
+
if (info->master && info->representor) {
DRV_LOG(ERR, "ifindex %u device is recognized as master"
" and as representor", ifindex);
diff --git a/drivers/common/mlx5/linux/mlx5_nl.h b/drivers/common/mlx5/linux/mlx5_nl.h
index 07a3b531b5..6446df1812 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.h
+++ b/drivers/common/mlx5/linux/mlx5_nl.h
@@ -53,6 +53,21 @@ struct mlx5_nl_port_info {
#define MLX5_NL_RDMA_NETDEV_ATTACH_EVENT (1)
#define MLX5_NL_RDMA_NETDEV_DETACH_EVENT (2)
+/* Maximal physical port name length. */
+#define MLX5_PHYS_PORT_NAME_MAX 128
+
+#define MLX5_NETDEV_INFO_FLAG_NUM_VF RTE_BIT32(0)
+#define MLX5_NETDEV_INFO_FLAG_PHYS_PORT_NAME RTE_BIT32(1)
+#define MLX5_NETDEV_INFO_FLAG_PHYS_SWITCH_ID RTE_BIT32(2)
+
+struct mlx5_netdev_info {
+ unsigned int ifindex; /* [in] */
+ uint32_t flags; /* [out] */
+ uint32_t num_vf; /* [out] */
+ char phys_port_name[MLX5_PHYS_PORT_NAME_MAX]; /* [out] */
+ uint64_t phys_switch_id; /* [out] */
+};
+
__rte_internal
int mlx5_nl_init(int protocol, int groups);
__rte_internal
@@ -119,4 +134,6 @@ int mlx5_nl_rdma_monitor_cap_get(int nl, uint8_t *cap);
__rte_internal
int mlx5_nl_get_mtu_bounds(int nl, unsigned int ifindex, uint16_t *min_mtu, uint16_t *max_mtu);
+int mlx5_nl_netdev_info_get(int nl, struct mlx5_netdev_info *info);
+
#endif /* RTE_PMD_MLX5_NL_H_ */
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 04/13] common/mlx5: query parent device over Netlink
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (2 preceding siblings ...)
2026-10-26 16:26 ` [PATCH 03/13] common/mlx5: separate netdev info from switch info Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 05/13] common/mlx5: add check for auxiliary device Dariusz Sosnowski
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Extend mlx5_nl_netdev_info_get() to gather Linux netdev's
parent device and bus name. This will be used in follow up patches
to match probed additional rte_device related to
single mlx5 common device.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/meson.build | 4 ++++
drivers/common/mlx5/linux/mlx5_nl.c | 24 ++++++++++++++++++++++++
drivers/common/mlx5/linux/mlx5_nl.h | 10 ++++++++++
3 files changed, 38 insertions(+)
diff --git a/drivers/common/mlx5/linux/meson.build b/drivers/common/mlx5/linux/meson.build
index 3767e7a69b..1b2104b48e 100644
--- a/drivers/common/mlx5/linux/meson.build
+++ b/drivers/common/mlx5/linux/meson.build
@@ -154,6 +154,10 @@ has_sym_args = [
'IFLA_PHYS_SWITCH_ID' ],
[ 'HAVE_IFLA_PHYS_PORT_NAME', 'linux/if_link.h',
'IFLA_PHYS_PORT_NAME' ],
+ [ 'HAVE_IFLA_PARENT_DEV_NAME', 'linux/if_link.h',
+ 'IFLA_PARENT_DEV_NAME' ],
+ [ 'HAVE_IFLA_PARENT_DEV_BUS_NAME', 'linux/if_link.h',
+ 'IFLA_PARENT_DEV_BUS_NAME' ],
[ 'HAVE_RDMA_NL_NLDEV', 'rdma/rdma_netlink.h',
'RDMA_NL_NLDEV' ],
[ 'HAVE_RDMA_NLDEV_CMD_GET', 'rdma/rdma_netlink.h',
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index eafae78883..4eebec5223 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -113,6 +113,12 @@
#ifndef HAVE_IFLA_PHYS_PORT_NAME
#define IFLA_PHYS_PORT_NAME 38
#endif
+#ifndef HAVE_IFLA_PARENT_DEV_NAME
+#define IFLA_PARENT_DEV_NAME 56
+#endif
+#ifndef HAVE_IFLA_PARENT_DEV_BUS_NAME
+#define IFLA_PARENT_DEV_BUS_NAME 57
+#endif
/*
* Some Devlink defines may be missed in old kernel versions,
@@ -1427,6 +1433,24 @@ mlx5_nl_netdev_info_cb(struct nlmsghdr *nh, void *arg)
}
info.flags |= MLX5_NETDEV_INFO_FLAG_PHYS_SWITCH_ID;
break;
+ case IFLA_PARENT_DEV_NAME:
+ payload_len = RTA_PAYLOAD(ra);
+ /* Some kernels do not pad attributes with zero. */
+ if (payload_len > 0 && payload_len < MLX5_PARENT_DEV_NAME_MAX) {
+ memcpy(info.parent_dev_name, payload, payload_len);
+ info.parent_dev_name[payload_len] = '\0';
+ info.flags |= MLX5_NETDEV_INFO_FLAG_PARENT_DEV_NAME;
+ }
+ break;
+ case IFLA_PARENT_DEV_BUS_NAME:
+ payload_len = RTA_PAYLOAD(ra);
+ /* Some kernels do not pad attributes with zero. */
+ if (payload_len > 0 && payload_len < MLX5_PARENT_DEV_BUS_NAME_MAX) {
+ memcpy(info.parent_dev_bus_name, payload, payload_len);
+ info.parent_dev_bus_name[payload_len] = '\0';
+ info.flags |= MLX5_NETDEV_INFO_FLAG_PARENT_DEV_BUS_NAME;
+ }
+ break;
}
}
*out = info;
diff --git a/drivers/common/mlx5/linux/mlx5_nl.h b/drivers/common/mlx5/linux/mlx5_nl.h
index 6446df1812..39691569bc 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.h
+++ b/drivers/common/mlx5/linux/mlx5_nl.h
@@ -56,9 +56,17 @@ struct mlx5_nl_port_info {
/* Maximal physical port name length. */
#define MLX5_PHYS_PORT_NAME_MAX 128
+/* Maximum length of parent device name. */
+#define MLX5_PARENT_DEV_NAME_MAX 128
+
+/* Maximum length of parent device bus name. */
+#define MLX5_PARENT_DEV_BUS_NAME_MAX 128
+
#define MLX5_NETDEV_INFO_FLAG_NUM_VF RTE_BIT32(0)
#define MLX5_NETDEV_INFO_FLAG_PHYS_PORT_NAME RTE_BIT32(1)
#define MLX5_NETDEV_INFO_FLAG_PHYS_SWITCH_ID RTE_BIT32(2)
+#define MLX5_NETDEV_INFO_FLAG_PARENT_DEV_NAME RTE_BIT32(3)
+#define MLX5_NETDEV_INFO_FLAG_PARENT_DEV_BUS_NAME RTE_BIT32(4)
struct mlx5_netdev_info {
unsigned int ifindex; /* [in] */
@@ -66,6 +74,8 @@ struct mlx5_netdev_info {
uint32_t num_vf; /* [out] */
char phys_port_name[MLX5_PHYS_PORT_NAME_MAX]; /* [out] */
uint64_t phys_switch_id; /* [out] */
+ char parent_dev_name[MLX5_PARENT_DEV_NAME_MAX]; /* [out] */
+ char parent_dev_bus_name[MLX5_PARENT_DEV_BUS_NAME_MAX]; /* [out] */
};
__rte_internal
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 05/13] common/mlx5: add check for auxiliary device
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (3 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 04/13] common/mlx5: query parent device over Netlink Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 06/13] common/mlx5: gather associated devices Dariusz Sosnowski
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Add function for checking whether given rte_device is probed
through auxiliary bus.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/mlx5_common.c | 7 +++++++
drivers/common/mlx5/mlx5_common.h | 13 +++++++++++++
2 files changed, 20 insertions(+)
diff --git a/drivers/common/mlx5/mlx5_common.c b/drivers/common/mlx5/mlx5_common.c
index f4b8904366..11a53c8b56 100644
--- a/drivers/common/mlx5/mlx5_common.c
+++ b/drivers/common/mlx5/mlx5_common.c
@@ -138,6 +138,13 @@ driver_get(uint32_t class)
return NULL;
}
+RTE_EXPORT_INTERNAL_SYMBOL(mlx5_dev_is_auxiliary)
+bool
+mlx5_dev_is_auxiliary(const struct rte_device *dev)
+{
+ return strcmp(dev->bus->name, "auxiliary") == 0;
+}
+
RTE_EXPORT_INTERNAL_SYMBOL(mlx5_kvargs_process)
int
mlx5_kvargs_process(struct mlx5_kvargs_ctrl *mkvlist, const char *const keys[],
diff --git a/drivers/common/mlx5/mlx5_common.h b/drivers/common/mlx5/mlx5_common.h
index 8b8f20e2f4..f579ca0904 100644
--- a/drivers/common/mlx5/mlx5_common.h
+++ b/drivers/common/mlx5/mlx5_common.h
@@ -596,6 +596,19 @@ __rte_internal
bool
mlx5_dev_is_pci(const struct rte_device *dev);
+/**
+ * Test device is an auxiliary bus device.
+ *
+ * @param dev
+ * Pointer to EAL device.
+ *
+ * @return
+ * True if device is an auxiliary bus device. False otherwise.
+ */
+__rte_internal
+bool
+mlx5_dev_is_auxiliary(const struct rte_device *dev);
+
/**
* Test PCI device is a VF device.
*
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 06/13] common/mlx5: gather associated devices
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (4 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 05/13] common/mlx5: add check for auxiliary device Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 07/13] common/mlx5: always use EAL device for probing Dariusz Sosnowski
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
There was one-to-one association between rte_device
and mlx5_common_device. Specifically on Linux, this rte_device
is either PCI or auxiliary device where IBV context can be opened.
This association is limiting for cases where embedded switch is shared
between different PFs/VFs/SFs. In such cases:
- There is one IB device where IBV context can be opened.
This IB device is owned by a single PF/VF/SF.
- There are multiple PCI/auxiliary devices within embedded switch
domain.
Goal of this patch is to allow probing ports belonging to the
embedded switch using the real associated device name.
When mlx5_common_device is created on Linux, a list of associated
devices is gathered:
- Number of IB ports (for mlx5 driver IB port is equivalent
to embedded switch port) is queried.
- Using netlink RDMA interface, mlx5 driver translates IB port
to netdev ifindex.
- Using netlink interface, mlx5 queries parent device
of each netdev.
- Each parent device is added to associated devices list:
- Device is added as a pair of bus/name strings.
- Later on probe this are matched to allocated rte_device
and replaced with that info.
As of this patch, all mlx5 driver will support only probing
with the main device (IB device owner).
Future patches will allow networking driver to probe
using multiple rte_device's.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/mlx5_common_os.c | 164 +++++++++++++++++++
drivers/common/mlx5/linux/mlx5_common_os.h | 4 +
drivers/common/mlx5/mlx5_common.c | 52 ++++++
drivers/common/mlx5/mlx5_common.h | 20 +++
drivers/common/mlx5/windows/mlx5_common_os.c | 19 +++
drivers/common/mlx5/windows/mlx5_common_os.h | 1 +
6 files changed, 260 insertions(+)
diff --git a/drivers/common/mlx5/linux/mlx5_common_os.c b/drivers/common/mlx5/linux/mlx5_common_os.c
index 903963670d..bd23c990f0 100644
--- a/drivers/common/mlx5/linux/mlx5_common_os.c
+++ b/drivers/common/mlx5/linux/mlx5_common_os.c
@@ -1251,3 +1251,167 @@ mlx5_os_is_device_bond(const void *dev)
closedir(net_dir);
return result;
}
+
+static bool
+associated_device_matches_dev(const struct mlx5_associated_device *assoc,
+ const char *bus_name,
+ const char *dev_name)
+{
+ return assoc->is_rte_device && mlx5_dev_matches(assoc->dev, bus_name, dev_name);
+}
+
+static bool
+associated_device_matches_info(const struct mlx5_associated_device *assoc,
+ const char *bus_name,
+ const char *dev_name)
+{
+ return !assoc->is_rte_device &&
+ strcmp(assoc->info.bus_name, bus_name) == 0 &&
+ strcmp(assoc->info.dev_name, dev_name) == 0;
+}
+
+static bool
+associated_device_exists(const struct mlx5_common_device *cdev,
+ const char *bus_name,
+ const char *dev_name)
+{
+ struct mlx5_associated_device *assoc;
+
+ TAILQ_FOREACH(assoc, &cdev->associated_devices, next) {
+ if (associated_device_matches_dev(assoc, bus_name, dev_name) ||
+ associated_device_matches_info(assoc, bus_name, dev_name))
+ return true;
+ }
+
+ return false;
+}
+
+static struct mlx5_associated_device *
+associated_device_alloc(const char *bus_name, const char *dev_name)
+{
+ struct mlx5_associated_device *assoc;
+ size_t bus_name_len;
+ size_t dev_name_len;
+ size_t size;
+ char *dst;
+
+ bus_name_len = strlen(bus_name) + 1;
+ dev_name_len = strlen(dev_name) + 1;
+
+ size = sizeof(*assoc);
+ size += bus_name_len;
+ size += dev_name_len;
+
+ assoc = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
+ if (!assoc)
+ return NULL;
+
+ assoc->is_rte_device = false;
+
+ dst = (void *)(assoc + 1);
+ memcpy(dst, bus_name, bus_name_len);
+ assoc->info.bus_name = dst;
+
+ dst = RTE_PTR_ADD(dst, bus_name_len);
+ memcpy(dst, dev_name, dev_name_len);
+ assoc->info.dev_name = dst;
+
+ return assoc;
+}
+
+int
+mlx5_os_fill_associated_devices(struct mlx5_common_device *cdev)
+{
+ struct mlx5_associated_device *assoc;
+ struct ibv_device *ibdev;
+ unsigned int portnum;
+ int nl_route = -1;
+ int nl_rdma;
+ int ret = 0;
+
+ MLX5_ASSERT(cdev != NULL);
+ MLX5_ASSERT(cdev->dev != NULL);
+ MLX5_ASSERT(TAILQ_EMPTY(&cdev->associated_devices));
+
+ assoc = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*assoc), 0, SOCKET_ID_ANY);
+ if (!assoc)
+ return -ENOMEM;
+ assoc->is_rte_device = true;
+ assoc->dev = cdev->dev;
+ TAILQ_INSERT_HEAD(&cdev->associated_devices, assoc, next);
+
+ ibdev = ((struct ibv_context *)cdev->ctx)->device;
+
+ nl_rdma = mlx5_nl_init(NETLINK_RDMA, 0);
+ if (nl_rdma < 0) {
+ ret = -rte_errno;
+ goto release_return;
+ }
+
+ portnum = mlx5_nl_portnum(nl_rdma, ibdev->name, NULL);
+ if (portnum == 0) {
+ ret = -rte_errno;
+ goto release_return;
+ }
+ if (portnum == 1) {
+ ret = 0;
+ goto release_return;
+ }
+
+ nl_route = mlx5_nl_init(NETLINK_ROUTE, 0);
+ if (nl_route < 0) {
+ ret = -rte_errno;
+ goto release_return;
+ }
+
+ for (unsigned int port = 1; port <= portnum; ++port) {
+ struct mlx5_netdev_info netdev_info = { 0 };
+
+ netdev_info.ifindex = mlx5_nl_ifindex(nl_rdma, ibdev->name, port, NULL);
+ if (netdev_info.ifindex == 0)
+ continue;
+
+ ret = mlx5_nl_netdev_info_get(nl_route, &netdev_info);
+ if (ret < 0) {
+ /*
+ * On any failure just skip and don't add the device
+ * to the associated devices list.
+ */
+ DRV_LOG(DEBUG,
+ "ibdev %s port %u ifindex %u failed to get netdev info (%s)",
+ ibdev->name, port, netdev_info.ifindex, rte_strerror(-ret));
+ ret = 0;
+ continue;
+ }
+
+ if (!(netdev_info.flags & MLX5_NETDEV_INFO_FLAG_PARENT_DEV_NAME) ||
+ !(netdev_info.flags & MLX5_NETDEV_INFO_FLAG_PARENT_DEV_BUS_NAME))
+ continue;
+
+ if (associated_device_exists(cdev,
+ netdev_info.parent_dev_bus_name,
+ netdev_info.parent_dev_name))
+ continue;
+
+ assoc = associated_device_alloc(netdev_info.parent_dev_bus_name,
+ netdev_info.parent_dev_name);
+ if (assoc == NULL) {
+ ret = -ENOMEM;
+ goto release_return;
+ }
+
+ TAILQ_INSERT_HEAD(&cdev->associated_devices, assoc, next);
+ }
+
+release_return:
+ while (ret < 0 && !TAILQ_EMPTY(&cdev->associated_devices)) {
+ assoc = TAILQ_FIRST(&cdev->associated_devices);
+ TAILQ_REMOVE(&cdev->associated_devices, assoc, next);
+ mlx5_free(assoc);
+ }
+ if (nl_rdma >= 0)
+ close(nl_rdma);
+ if (nl_route >= 0)
+ close(nl_route);
+ return ret;
+}
diff --git a/drivers/common/mlx5/linux/mlx5_common_os.h b/drivers/common/mlx5/linux/mlx5_common_os.h
index 7d4e3c5fe8..e39afcb9de 100644
--- a/drivers/common/mlx5/linux/mlx5_common_os.h
+++ b/drivers/common/mlx5/linux/mlx5_common_os.h
@@ -22,6 +22,8 @@
#include "mlx5_glue.h"
#include "mlx5_malloc.h"
+struct mlx5_common_device;
+
/* verb enumerations translations to local enums. */
enum {
MLX5_FS_NAME_MAX = IBV_SYSFS_NAME_MAX + 1,
@@ -326,4 +328,6 @@ mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
__rte_internal
bool mlx5_os_is_device_bond(const void *dev);
+int mlx5_os_fill_associated_devices(struct mlx5_common_device *cdev);
+
#endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
diff --git a/drivers/common/mlx5/mlx5_common.c b/drivers/common/mlx5/mlx5_common.c
index 11a53c8b56..67566e01b2 100644
--- a/drivers/common/mlx5/mlx5_common.c
+++ b/drivers/common/mlx5/mlx5_common.c
@@ -755,6 +755,18 @@ mlx5_dev_hw_global_prepare(struct mlx5_common_device *cdev, uint32_t classes)
return ret;
}
+static void
+mlx5_associated_devices_release(struct mlx5_common_device *cdev)
+{
+ struct mlx5_associated_device *assoc;
+
+ while (!TAILQ_EMPTY(&cdev->associated_devices)) {
+ assoc = TAILQ_FIRST(&cdev->associated_devices);
+ TAILQ_REMOVE(&cdev->associated_devices, assoc, next);
+ mlx5_free(assoc);
+ }
+}
+
static void
mlx5_common_dev_release(struct mlx5_common_device *cdev)
{
@@ -762,6 +774,7 @@ mlx5_common_dev_release(struct mlx5_common_device *cdev)
TAILQ_REMOVE(&devices_list, cdev, next);
pthread_mutex_unlock(&devices_list_lock);
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ mlx5_associated_devices_release(cdev);
if (TAILQ_EMPTY(&devices_list))
rte_mem_event_callback_unregister("MLX5_MEM_EVENT_CB",
NULL);
@@ -791,6 +804,7 @@ mlx5_common_dev_create(struct rte_device *eal_dev, uint32_t classes,
return NULL;
}
cdev->dev = eal_dev;
+ TAILQ_INIT(&cdev->associated_devices);
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
goto exit;
/* Parse device parameters. */
@@ -822,6 +836,16 @@ mlx5_common_dev_create(struct rte_device *eal_dev, uint32_t classes,
rte_mem_event_callback_register("MLX5_MEM_EVENT_CB",
mlx5_mr_mem_event_cb, NULL);
cdev->dev_info.probe_opt = cdev->config.probe_opt;
+
+ ret = mlx5_os_fill_associated_devices(cdev);
+ if (ret < 0) {
+ DRV_LOG(DEBUG,
+ "cdev %s Failed to initialize associated devices list. "
+ "Only owner device is allowed",
+ cdev->dev->name);
+ rte_errno = 0;
+ }
+
exit:
pthread_mutex_lock(&devices_list_lock);
TAILQ_INSERT_HEAD(&devices_list, cdev, next);
@@ -1468,4 +1492,32 @@ mlx5_devx_uar_prepare(struct mlx5_common_device *cdev, struct mlx5_uar *uar)
return 0;
}
+RTE_EXPORT_INTERNAL_SYMBOL(mlx5_dev_matches)
+bool
+mlx5_dev_matches(const struct rte_device *dev,
+ const char *bus_name,
+ const char *dev_name)
+{
+ if (strcmp(dev->bus->name, bus_name) != 0)
+ return false;
+
+ if (mlx5_dev_is_pci(dev)) {
+ const struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(dev, *pci_dev);
+ struct rte_pci_addr addr;
+
+ if (rte_pci_addr_parse(dev_name, &addr) < 0)
+ return false;
+
+ return rte_pci_addr_cmp(&addr, &pci_dev->addr) == 0;
+ }
+
+ if (mlx5_dev_is_auxiliary(dev)) {
+ const struct rte_auxiliary_device *aux_dev = RTE_BUS_DEVICE(dev, *aux_dev);
+
+ return strcmp(dev_name, aux_dev->name) == 0;
+ }
+
+ return false;
+}
+
RTE_PMD_EXPORT_NAME(mlx5_common_driver);
diff --git a/drivers/common/mlx5/mlx5_common.h b/drivers/common/mlx5/mlx5_common.h
index f579ca0904..8f8ab01700 100644
--- a/drivers/common/mlx5/mlx5_common.h
+++ b/drivers/common/mlx5/mlx5_common.h
@@ -515,6 +515,22 @@ struct mlx5_common_dev_config {
/* Whether memseg should be extended for MR creation. */
};
+struct mlx5_associated_device_info {
+ const char *bus_name;
+ const char *dev_name;
+};
+
+struct mlx5_associated_device {
+ TAILQ_ENTRY(mlx5_associated_device) next;
+ bool is_rte_device;
+ union {
+ const struct rte_device *dev;
+ struct mlx5_associated_device_info info;
+ };
+};
+
+TAILQ_HEAD(mlx5_associated_device_list, mlx5_associated_device);
+
struct mlx5_common_device {
struct rte_device *dev;
TAILQ_ENTRY(mlx5_common_device) next;
@@ -525,6 +541,7 @@ struct mlx5_common_device {
uint32_t pdn; /* Protection Domain Number. */
struct mlx5_mr_share_cache mr_scache; /* Global shared MR cache. */
struct mlx5_common_dev_config config; /* Device configuration. */
+ struct mlx5_associated_device_list associated_devices;
};
/**
@@ -669,4 +686,7 @@ __rte_internal
void
mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *pmd_mr);
+__rte_internal
+bool mlx5_dev_matches(const struct rte_device *dev, const char *bus_name, const char *dev_name);
+
#endif /* RTE_PMD_MLX5_COMMON_H_ */
diff --git a/drivers/common/mlx5/windows/mlx5_common_os.c b/drivers/common/mlx5/windows/mlx5_common_os.c
index bdafb95df9..e15a97677f 100644
--- a/drivers/common/mlx5/windows/mlx5_common_os.c
+++ b/drivers/common/mlx5/windows/mlx5_common_os.c
@@ -493,3 +493,22 @@ mlx5_os_wrapped_mkey_destroy(struct mlx5_pmd_wrapped_mr *wpmd_mr)
mlx5_os_dereg_mr(&pmd_mr);
memset(wpmd_mr, 0, sizeof(*wpmd_mr));
}
+
+int
+mlx5_os_fill_associated_devices(struct mlx5_common_device *cdev)
+{
+ struct mlx5_associated_device *assoc;
+
+ MLX5_ASSERT(cdev != NULL);
+ MLX5_ASSERT(cdev->dev != NULL);
+ MLX5_ASSERT(TAILQ_EMPTY(&cdev->associated_devices));
+
+ assoc = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*assoc), 0, SOCKET_ID_ANY);
+ if (!assoc)
+ return -ENOMEM;
+ assoc->is_rte_device = true;
+ assoc->dev = cdev->dev;
+ TAILQ_INSERT_HEAD(&cdev->associated_devices, assoc, next);
+
+ return 0;
+}
diff --git a/drivers/common/mlx5/windows/mlx5_common_os.h b/drivers/common/mlx5/windows/mlx5_common_os.h
index 65394035de..a63e29f5f1 100644
--- a/drivers/common/mlx5/windows/mlx5_common_os.h
+++ b/drivers/common/mlx5/windows/mlx5_common_os.h
@@ -282,5 +282,6 @@ mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle,
(void)cb_arg;
}
+int mlx5_os_fill_associated_devices(struct mlx5_common_device *cdev);
#endif /* RTE_PMD_MLX5_COMMON_OS_H_ */
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 07/13] common/mlx5: always use EAL device for probing
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (5 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 06/13] common/mlx5: gather associated devices Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 08/13] common/mlx5: query devlink port for netdevs Dariusz Sosnowski
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Previous patch added gathering a list of all associated devices
for each mlx5 common device.
This patch prepars the mlx5 driver probing to take requested rte_device,
instead of relying on mlx5 common device to rte_device correspondence.
As of this patch, all mlx5 drivers will support only probing
with the main device (IB device owner).
Future patches will allow networking driver to probe
using multiple rte_device's.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/mlx5_common.c | 38 ++++++++++++++++++++++-----
drivers/common/mlx5/mlx5_common.h | 2 ++
drivers/compress/mlx5/mlx5_compress.c | 1 +
drivers/crypto/mlx5/mlx5_crypto.c | 1 +
drivers/net/mlx5/linux/mlx5_os.c | 3 +++
drivers/net/mlx5/mlx5.h | 1 +
drivers/net/mlx5/windows/mlx5_os.c | 1 +
drivers/regex/mlx5/mlx5_regex.c | 1 +
drivers/vdpa/mlx5/mlx5_vdpa.c | 1 +
9 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/drivers/common/mlx5/mlx5_common.c b/drivers/common/mlx5/mlx5_common.c
index 67566e01b2..57f484fcb7 100644
--- a/drivers/common/mlx5/mlx5_common.c
+++ b/drivers/common/mlx5/mlx5_common.c
@@ -470,13 +470,30 @@ mlx5_bus_match(const struct mlx5_class_driver *drv,
return true;
}
+static bool
+mlx5_associated_device_contains(struct mlx5_common_device *cdev,
+ const struct rte_device *rte_dev)
+{
+ struct mlx5_associated_device *assoc;
+
+ TAILQ_FOREACH(assoc, &cdev->associated_devices, next) {
+ if (assoc->is_rte_device && rte_dev == assoc->dev)
+ return true;
+
+ if (mlx5_dev_matches(rte_dev, assoc->info.bus_name, assoc->info.dev_name))
+ return true;
+ }
+
+ return false;
+}
+
static struct mlx5_common_device *
to_mlx5_device(const struct rte_device *rte_dev)
{
struct mlx5_common_device *cdev;
TAILQ_FOREACH(cdev, &devices_list, next) {
- if (rte_dev == cdev->dev)
+ if (mlx5_associated_device_contains(cdev, rte_dev))
return cdev;
}
return NULL;
@@ -981,7 +998,9 @@ drivers_remove(struct mlx5_common_device *cdev, uint32_t enabled_classes)
}
static int
-drivers_probe(struct mlx5_common_device *cdev, uint32_t user_classes,
+drivers_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
+ uint32_t user_classes,
struct mlx5_kvargs_ctrl *mkvlist)
{
struct mlx5_class_driver *driver;
@@ -992,16 +1011,21 @@ drivers_probe(struct mlx5_common_device *cdev, uint32_t user_classes,
TAILQ_FOREACH(driver, &drivers_list, next) {
if ((driver->drv_class & user_classes) == 0)
continue;
- if (!mlx5_bus_match(driver, cdev->dev))
+ if (!mlx5_bus_match(driver, dev))
continue;
+ if (!driver->probe_associated && cdev->dev != dev) {
+ DRV_LOG(ERR, "Invalid device %s used to probe on common device %s",
+ dev->name, cdev->dev->name);
+ ret = -EINVAL;
+ goto probe_err;
+ }
already_loaded = cdev->classes_loaded & driver->drv_class;
if (already_loaded && driver->probe_again == 0) {
- DRV_LOG(ERR, "Device %s is already probed",
- cdev->dev->name);
+ DRV_LOG(ERR, "Device %s is already probed", dev->name);
ret = -EEXIST;
goto probe_err;
}
- ret = driver->probe(cdev, mkvlist);
+ ret = driver->probe(cdev, dev, mkvlist);
if (ret < 0) {
DRV_LOG(ERR, "Failed to load driver %s",
driver->name);
@@ -1091,7 +1115,7 @@ mlx5_common_dev_probe(struct rte_device *eal_dev)
DRV_LOG(ERR, "Unsupported mlx5 classes combination.");
goto class_err;
}
- ret = drivers_probe(cdev, classes, mkvlist_p);
+ ret = drivers_probe(cdev, eal_dev, classes, mkvlist_p);
if (ret)
goto class_err;
/*
diff --git a/drivers/common/mlx5/mlx5_common.h b/drivers/common/mlx5/mlx5_common.h
index 8f8ab01700..0d940b1fdf 100644
--- a/drivers/common/mlx5/mlx5_common.h
+++ b/drivers/common/mlx5/mlx5_common.h
@@ -565,6 +565,7 @@ mlx5_imported_pd_and_ctx(struct mlx5_common_device *cdev)
* Initialization function for the driver called during device probing.
*/
typedef int (mlx5_class_driver_probe_t)(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
struct mlx5_kvargs_ctrl *mkvlist);
/**
@@ -584,6 +585,7 @@ struct mlx5_class_driver {
const struct rte_pci_id *id_table; /**< ID table, NULL terminated. */
uint32_t probe_again:1;
/**< Device already probed can be probed again to check new device. */
+ uint32_t probe_associated:1; /**< Supports probing using associated devices. */
uint32_t intr_lsc:1; /**< Supports link state interrupt. */
uint32_t intr_rmv:1; /**< Supports device remove interrupt. */
};
diff --git a/drivers/compress/mlx5/mlx5_compress.c b/drivers/compress/mlx5/mlx5_compress.c
index 1361dab630..ab503d74e3 100644
--- a/drivers/compress/mlx5/mlx5_compress.c
+++ b/drivers/compress/mlx5/mlx5_compress.c
@@ -820,6 +820,7 @@ mlx5_compress_fill_caps(struct mlx5_compress_priv *priv,
static int
mlx5_compress_dev_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev __rte_unused,
struct mlx5_kvargs_ctrl *mkvlist)
{
struct rte_compressdev *compressdev;
diff --git a/drivers/crypto/mlx5/mlx5_crypto.c b/drivers/crypto/mlx5/mlx5_crypto.c
index 821dd54b31..aba56b300d 100644
--- a/drivers/crypto/mlx5/mlx5_crypto.c
+++ b/drivers/crypto/mlx5/mlx5_crypto.c
@@ -344,6 +344,7 @@ mlx5_crypto_parse_devargs(struct mlx5_kvargs_ctrl *mkvlist,
static int
mlx5_crypto_dev_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev __rte_unused,
struct mlx5_kvargs_ctrl *mkvlist)
{
struct rte_cryptodev *crypto_dev;
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 7c2c35c945..42b23e7f58 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -3163,6 +3163,8 @@ mlx5_os_auxiliary_probe(struct mlx5_common_device *cdev,
*
* @param[in] cdev
* Pointer to the common mlx5 device.
+ * @param[in] dev
+ * Pointer to the probed EAL device.
* @param[in, out] mkvlist
* Pointer to mlx5 kvargs control, can be NULL if there is no devargs.
*
@@ -3171,6 +3173,7 @@ mlx5_os_auxiliary_probe(struct mlx5_common_device *cdev,
*/
int
mlx5_os_net_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev __rte_unused,
struct mlx5_kvargs_ctrl *mkvlist)
{
int ret;
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index e3df458915..b1493745ee 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -2636,6 +2636,7 @@ struct rte_pci_driver;
int mlx5_os_capabilities_prepare(struct mlx5_dev_ctx_shared *sh);
void mlx5_os_free_shared_dr(struct mlx5_priv *priv);
int mlx5_os_net_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
struct mlx5_kvargs_ctrl *mkvlist);
void mlx5_os_dev_shared_handler_install(struct mlx5_dev_ctx_shared *sh);
void mlx5_os_dev_shared_handler_uninstall(struct mlx5_dev_ctx_shared *sh);
diff --git a/drivers/net/mlx5/windows/mlx5_os.c b/drivers/net/mlx5/windows/mlx5_os.c
index cc60f07e17..8e3baa95b4 100644
--- a/drivers/net/mlx5/windows/mlx5_os.c
+++ b/drivers/net/mlx5/windows/mlx5_os.c
@@ -900,6 +900,7 @@ mlx5_os_get_allmulti(struct rte_eth_dev *dev)
*/
int
mlx5_os_net_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev __rte_unused,
struct mlx5_kvargs_ctrl *mkvlist)
{
struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(cdev->dev, *pci_dev);
diff --git a/drivers/regex/mlx5/mlx5_regex.c b/drivers/regex/mlx5/mlx5_regex.c
index 042f585abd..b5f4bfa875 100644
--- a/drivers/regex/mlx5/mlx5_regex.c
+++ b/drivers/regex/mlx5/mlx5_regex.c
@@ -68,6 +68,7 @@ mlx5_regex_get_name(char *name, struct rte_device *dev)
static int
mlx5_regex_dev_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev __rte_unused,
struct mlx5_kvargs_ctrl *mkvlist __rte_unused)
{
struct mlx5_regex_priv *priv = NULL;
diff --git a/drivers/vdpa/mlx5/mlx5_vdpa.c b/drivers/vdpa/mlx5/mlx5_vdpa.c
index 1bb5de51b6..a087b232b6 100644
--- a/drivers/vdpa/mlx5/mlx5_vdpa.c
+++ b/drivers/vdpa/mlx5/mlx5_vdpa.c
@@ -813,6 +813,7 @@ mlx5_vdpa_create_dev_resources(struct mlx5_vdpa_priv *priv)
static int
mlx5_vdpa_dev_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev __rte_unused,
struct mlx5_kvargs_ctrl *mkvlist)
{
struct mlx5_vdpa_priv *priv = NULL;
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 08/13] common/mlx5: query devlink port for netdevs
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (6 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 07/13] common/mlx5: always use EAL device for probing Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 09/13] common/mlx5: get devlink port by port index Dariusz Sosnowski
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Representor matching in mlx5 driver is based on physical port name
(phys_port_name) reported by Linux kernel.
Port type and its location in the topology was derived from this name.
It is available only on representor netdevs.
As a result, when embedded switch is shared by netdevs
based on real VFs/SFs mlx5 driver is unable to deduce port's type.
As a replacement, flavour of a devlink port related to netdev
can be used.
This patch adds parsing of IFLA_DEVLINK_PORT attribute
to mlx5_netdev_info_get(). This info will be used in follow up patches
to query devlink port info.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/meson.build | 2 +
drivers/common/mlx5/linux/mlx5_nl.c | 67 ++++++++++++++++++++++++++-
drivers/common/mlx5/linux/mlx5_nl.h | 17 +++++++
3 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/drivers/common/mlx5/linux/meson.build b/drivers/common/mlx5/linux/meson.build
index 1b2104b48e..a69a8b77a0 100644
--- a/drivers/common/mlx5/linux/meson.build
+++ b/drivers/common/mlx5/linux/meson.build
@@ -158,6 +158,8 @@ has_sym_args = [
'IFLA_PARENT_DEV_NAME' ],
[ 'HAVE_IFLA_PARENT_DEV_BUS_NAME', 'linux/if_link.h',
'IFLA_PARENT_DEV_BUS_NAME' ],
+ [ 'HAVE_IFLA_DEVLINK_PORT', 'linux/if_link.h',
+ 'IFLA_DEVLINK_PORT' ],
[ 'HAVE_RDMA_NL_NLDEV', 'rdma/rdma_netlink.h',
'RDMA_NL_NLDEV' ],
[ 'HAVE_RDMA_NLDEV_CMD_GET', 'rdma/rdma_netlink.h',
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index 4eebec5223..786158fb99 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -119,6 +119,9 @@
#ifndef HAVE_IFLA_PARENT_DEV_BUS_NAME
#define IFLA_PARENT_DEV_BUS_NAME 57
#endif
+#ifndef HAVE_IFLA_DEVLINK_PORT
+#define IFLA_DEVLINK_PORT 62
+#endif
/*
* Some Devlink defines may be missed in old kernel versions,
@@ -1385,6 +1388,64 @@ mlx5_nl_portnum(int nl, const char *name, struct mlx5_dev_info *dev_info)
return mlx5_dev_info_set_portnum(name, dev_info, &data);
}
+static inline bool
+nla_ok(const struct nlattr *nla, const ssize_t len)
+{
+ return len >= NLA_HDRLEN &&
+ nla->nla_len >= NLA_HDRLEN &&
+ nla->nla_len <= len;
+}
+
+static inline struct nlattr *
+nla_next(struct nlattr *nla, ssize_t *len)
+{
+ ptrdiff_t off = NLA_ALIGN(nla->nla_len);
+
+ *len -= off;
+ return RTE_PTR_ADD(nla, off);
+}
+
+static void
+parse_ifla_devlink_port(void *payload, ssize_t len, struct mlx5_netdev_info *info)
+{
+ struct nlattr *nla = payload;
+ uint32_t *val;
+ size_t payload_len;
+ char *src;
+
+ while (nla_ok(nla, len)) {
+ payload_len = nla->nla_len - NLA_HDRLEN;
+
+ switch (nla->nla_type & NLA_TYPE_MASK) {
+ case DEVLINK_ATTR_BUS_NAME:
+ if (payload_len > 0 && payload_len < MLX5_NETDEV_INFO_NAME_MAX) {
+ src = RTE_PTR_ADD(nla, NLA_HDRLEN);
+ memcpy(info->devlink_port_bus_name, src, payload_len);
+ info->devlink_port_bus_name[payload_len] = 0;
+ info->flags |= MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_BUS_NAME;
+ }
+ break;
+ case DEVLINK_ATTR_DEV_NAME:
+ if (payload_len > 0 && payload_len < MLX5_NETDEV_INFO_NAME_MAX) {
+ src = RTE_PTR_ADD(nla, NLA_HDRLEN);
+ memcpy(info->devlink_port_dev_name, src, payload_len);
+ info->devlink_port_dev_name[payload_len] = 0;
+ info->flags |= MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_DEV_NAME;
+ }
+ break;
+ case DEVLINK_ATTR_PORT_INDEX:
+ if (payload_len < sizeof(uint32_t))
+ break;
+ val = RTE_PTR_ADD(nla, NLA_HDRLEN);
+ info->devlink_port_index = *val;
+ info->flags |= MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_INDEX;
+ break;
+ }
+
+ nla = nla_next(nla, &len);
+ }
+}
+
static int
mlx5_nl_netdev_info_cb(struct nlmsghdr *nh, void *arg)
{
@@ -1409,7 +1470,7 @@ mlx5_nl_netdev_info_cb(struct nlmsghdr *nh, void *arg)
void *payload = RTA_DATA(ra);
unsigned int i;
- switch (ra->rta_type) {
+ switch (ra->rta_type & NLA_TYPE_MASK) {
case IFLA_NUM_VF:
if (RTA_PAYLOAD(ra) < sizeof(uint32_t))
goto error;
@@ -1451,6 +1512,10 @@ mlx5_nl_netdev_info_cb(struct nlmsghdr *nh, void *arg)
info.flags |= MLX5_NETDEV_INFO_FLAG_PARENT_DEV_BUS_NAME;
}
break;
+ case IFLA_DEVLINK_PORT:
+ payload_len = RTA_PAYLOAD(ra);
+ parse_ifla_devlink_port(payload, payload_len, &info);
+ break;
}
}
*out = info;
diff --git a/drivers/common/mlx5/linux/mlx5_nl.h b/drivers/common/mlx5/linux/mlx5_nl.h
index 39691569bc..5a9ccfbb7e 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.h
+++ b/drivers/common/mlx5/linux/mlx5_nl.h
@@ -62,11 +62,17 @@ struct mlx5_nl_port_info {
/* Maximum length of parent device bus name. */
#define MLX5_PARENT_DEV_BUS_NAME_MAX 128
+/* Maximum length of a name stored inside netdev info */
+#define MLX5_NETDEV_INFO_NAME_MAX 128
+
#define MLX5_NETDEV_INFO_FLAG_NUM_VF RTE_BIT32(0)
#define MLX5_NETDEV_INFO_FLAG_PHYS_PORT_NAME RTE_BIT32(1)
#define MLX5_NETDEV_INFO_FLAG_PHYS_SWITCH_ID RTE_BIT32(2)
#define MLX5_NETDEV_INFO_FLAG_PARENT_DEV_NAME RTE_BIT32(3)
#define MLX5_NETDEV_INFO_FLAG_PARENT_DEV_BUS_NAME RTE_BIT32(4)
+#define MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_BUS_NAME RTE_BIT32(5)
+#define MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_DEV_NAME RTE_BIT32(6)
+#define MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_INDEX RTE_BIT32(7)
struct mlx5_netdev_info {
unsigned int ifindex; /* [in] */
@@ -76,8 +82,19 @@ struct mlx5_netdev_info {
uint64_t phys_switch_id; /* [out] */
char parent_dev_name[MLX5_PARENT_DEV_NAME_MAX]; /* [out] */
char parent_dev_bus_name[MLX5_PARENT_DEV_BUS_NAME_MAX]; /* [out] */
+ char devlink_port_bus_name[MLX5_NETDEV_INFO_NAME_MAX]; /* [out] */
+ char devlink_port_dev_name[MLX5_NETDEV_INFO_NAME_MAX]; /* [out] */
+ uint32_t devlink_port_index; /* [out] */
};
+static inline bool
+mlx5_netdev_info_has_devlink_port(struct mlx5_netdev_info *info)
+{
+ return (info->flags & MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_BUS_NAME) &&
+ (info->flags & MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_DEV_NAME) &&
+ (info->flags & MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_INDEX);
+}
+
__rte_internal
int mlx5_nl_init(int protocol, int groups);
__rte_internal
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 09/13] common/mlx5: get devlink port by port index
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (7 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 08/13] common/mlx5: query devlink port for netdevs Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 10/13] common/mlx5: add check for managed device Dariusz Sosnowski
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Add mlx5_nl_devlink_port_info_get() which will query specific devlink
port by its:
- bus name
- device name
- port index
As of now, only port's flavour is parsed.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/mlx5_nl.c | 91 +++++++++++++++++++++++++++++
drivers/common/mlx5/linux/mlx5_nl.h | 19 ++++++
2 files changed, 110 insertions(+)
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index 786158fb99..e57007831c 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -190,6 +190,8 @@ static RTE_ATOMIC(uint32_t) atomic_sn;
#define MLX5_NL_SN_GENERATE (rte_atomic_fetch_add_explicit(&atomic_sn, 1, \
rte_memory_order_relaxed) + 1)
+static void nl_attr_put(struct nlmsghdr *nlh, int type, const void *data, int alen);
+
/**
* Opens a Netlink socket.
*
@@ -1573,6 +1575,95 @@ mlx5_nl_netdev_info_get(int nl, struct mlx5_netdev_info *info)
return ret;
}
+static int
+mlx5_nl_devlink_port_info_get_cb(struct nlmsghdr *nh, void *arg)
+{
+ struct mlx5_devlink_port_info *out = arg;
+ struct mlx5_devlink_port_info info;
+ struct genlmsghdr *genlhdr;
+ struct nlattr *nla;
+ ssize_t len;
+
+ memset(&info, 0, sizeof(info));
+ info.bus_name = out->bus_name;
+ info.dev_name = out->dev_name;
+ info.index = out->index;
+
+ if (nh->nlmsg_len < NLMSG_LENGTH(GENL_HDRLEN))
+ goto error;
+
+ genlhdr = NLMSG_DATA(nh);
+ if (genlhdr->cmd != DEVLINK_CMD_PORT_NEW)
+ goto error;
+
+ nla = RTE_PTR_ADD(genlhdr, GENL_HDRLEN);
+ len = nh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
+ while (nla_ok(nla, len)) {
+ void *payload = RTE_PTR_ADD(nla, NLA_HDRLEN);
+ size_t payload_len = nla->nla_len - NLA_HDRLEN;
+
+ switch (nla->nla_type & NLA_TYPE_MASK) {
+ case DEVLINK_ATTR_PORT_FLAVOUR:
+ if (payload_len < sizeof(uint16_t))
+ break;
+ info.flavour = *(uint16_t *)payload;
+ info.flags |= MLX5_DEVLINK_PORT_INFO_FLAG_FLAVOUR;
+ break;
+ }
+
+ nla = nla_next(nla, &len);
+ }
+ *out = info;
+ return 0;
+error:
+ rte_errno = EINVAL;
+ return -rte_errno;
+}
+
+static int __rte_unused
+mlx5_nl_devlink_port_info_get(int nl, int family, struct mlx5_devlink_port_info *info)
+{
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *genl;
+ uint8_t *buf;
+ size_t bus_name_len = strlen(info->bus_name) + 1;
+ size_t dev_name_len = strlen(info->dev_name) + 1;
+ size_t buf_size;
+ uint32_t sn = MLX5_NL_SN_GENERATE;
+ int ret;
+
+ buf_size = NLMSG_ALIGN(sizeof(struct nlmsghdr));
+ buf_size += NLMSG_ALIGN(sizeof(struct genlmsghdr));
+ buf_size += NLMSG_ALIGN(sizeof(struct nlattr) + bus_name_len);
+ buf_size += NLMSG_ALIGN(sizeof(struct nlattr) + dev_name_len);
+ buf_size += NLMSG_ALIGN(sizeof(struct nlattr) + sizeof(info->index));
+ buf = calloc(1, buf_size);
+ if (buf == NULL) {
+ rte_errno = ENOMEM;
+ return -rte_errno;
+ }
+
+ nlh = (struct nlmsghdr *)buf;
+ nlh->nlmsg_len = NLMSG_ALIGN(sizeof(struct nlmsghdr));
+ nlh->nlmsg_type = family;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ genl = RTE_PTR_ADD(nlh, nlh->nlmsg_len);
+ genl->cmd = DEVLINK_CMD_PORT_GET;
+ genl->version = DEVLINK_GENL_VERSION;
+ nlh->nlmsg_len += NLMSG_ALIGN(sizeof(struct genlmsghdr));
+
+ nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, info->bus_name, bus_name_len);
+ nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, info->dev_name, dev_name_len);
+ nl_attr_put(nlh, DEVLINK_ATTR_PORT_INDEX, &info->index, sizeof(info->index));
+
+ ret = mlx5_nl_send(nl, nlh, sn);
+ if (ret >= 0)
+ ret = mlx5_nl_recv(nl, sn, mlx5_nl_devlink_port_info_get_cb, info);
+ free(buf);
+ return ret;
+}
+
/**
* Analyze gathered port parameters via Netlink to recognize master
* and representor devices for E-Switch configuration.
diff --git a/drivers/common/mlx5/linux/mlx5_nl.h b/drivers/common/mlx5/linux/mlx5_nl.h
index 5a9ccfbb7e..0a9aab6610 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.h
+++ b/drivers/common/mlx5/linux/mlx5_nl.h
@@ -95,6 +95,25 @@ mlx5_netdev_info_has_devlink_port(struct mlx5_netdev_info *info)
(info->flags & MLX5_NETDEV_INFO_FLAG_DEVLINK_PORT_INDEX);
}
+#define MLX5_DEVLINK_PORT_INFO_FLAG_FLAVOUR RTE_BIT32(0)
+
+#define MLX5_DEVLINK_PORT_FLAVOUR_PHYSICAL (0)
+#define MLX5_DEVLINK_PORT_FLAVOUR_CPU (1)
+#define MLX5_DEVLINK_PORT_FLAVOUR_DSA (2)
+#define MLX5_DEVLINK_PORT_FLAVOUR_PCI_PF (3)
+#define MLX5_DEVLINK_PORT_FLAVOUR_PCI_VF (4)
+#define MLX5_DEVLINK_PORT_FLAVOUR_VIRTUAL (5)
+#define MLX5_DEVLINK_PORT_FLAVOUR_UNUSED (6)
+#define MLX5_DEVLINK_PORT_FLAVOUR_PCI_SF (7)
+
+struct mlx5_devlink_port_info {
+ const char *bus_name; /* [in] */
+ const char *dev_name; /* [in] */
+ uint32_t index; /* [in] */
+ uint32_t flags; /* [out] */
+ uint16_t flavour; /* [out] */
+};
+
__rte_internal
int mlx5_nl_init(int protocol, int groups);
__rte_internal
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 10/13] common/mlx5: add check for managed device
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (8 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 09/13] common/mlx5: get devlink port by port index Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 11/13] net/mlx5: add sibling device iteration macro Dariusz Sosnowski
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Add a common function for checking whether given
device is managed by any mlx5 driver.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/mlx5_common.c | 11 +++++++++++
drivers/common/mlx5/mlx5_common.h | 14 ++++++++++++++
drivers/net/mlx5/mlx5.c | 8 +-------
3 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/drivers/common/mlx5/mlx5_common.c b/drivers/common/mlx5/mlx5_common.c
index 57f484fcb7..46da81ebd8 100644
--- a/drivers/common/mlx5/mlx5_common.c
+++ b/drivers/common/mlx5/mlx5_common.c
@@ -1516,6 +1516,17 @@ mlx5_devx_uar_prepare(struct mlx5_common_device *cdev, struct mlx5_uar *uar)
return 0;
}
+RTE_EXPORT_INTERNAL_SYMBOL(mlx5_dev_is_managed)
+bool
+mlx5_dev_is_managed(const struct rte_device *dev)
+{
+ if (dev == NULL || dev->driver == NULL || dev->driver->name == NULL)
+ return false;
+
+ return strcmp(dev->driver->name, MLX5_PCI_DRIVER_NAME) == 0 ||
+ strcmp(dev->driver->name, MLX5_AUXILIARY_DRIVER_NAME) == 0;
+}
+
RTE_EXPORT_INTERNAL_SYMBOL(mlx5_dev_matches)
bool
mlx5_dev_matches(const struct rte_device *dev,
diff --git a/drivers/common/mlx5/mlx5_common.h b/drivers/common/mlx5/mlx5_common.h
index 0d940b1fdf..548f0c887b 100644
--- a/drivers/common/mlx5/mlx5_common.h
+++ b/drivers/common/mlx5/mlx5_common.h
@@ -601,6 +601,20 @@ __rte_internal
void
mlx5_class_driver_register(struct mlx5_class_driver *driver);
+/**
+ * Check if given EAL device is managed by any mlx5 driver.
+ *
+ * @param dev
+ * Pointer to device.
+ *
+ * @return
+ * - True if device is managed by mlx5 driver.
+ * - False otherwise.
+ */
+__rte_internal
+bool
+mlx5_dev_is_managed(const struct rte_device *dev);
+
/**
* Test device is a PCI bus device.
*
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 19491b9dc9..7093eefa15 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -3499,13 +3499,7 @@ mlx5_eth_find_next(uint16_t port_id, struct rte_device *odev)
if (dev->state != RTE_ETH_DEV_UNUSED &&
dev->device &&
- (dev->device == odev ||
- (dev->device->driver &&
- dev->device->driver->name &&
- ((strcmp(dev->device->driver->name,
- MLX5_PCI_DRIVER_NAME) == 0) ||
- (strcmp(dev->device->driver->name,
- MLX5_AUXILIARY_DRIVER_NAME) == 0)))))
+ (dev->device == odev || mlx5_dev_is_managed(dev->device)))
break;
port_id++;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 11/13] net/mlx5: add sibling device iteration macro
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (9 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 10/13] common/mlx5: add check for managed device Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 12/13] net/mlx5: allow associated devices Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 13/13] net/mlx5: allow multiport auxiliary device probe Dariusz Sosnowski
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
In some embedded switch topologies, not all DPDK representor ports
will be based on the same rte_device.
One such example is ConnectX socket direct configurations
or nested switches based on VFs/SFs.
mlx5 networking driver in many cases requires to iterate
over all DPDK ethdev ports belonging to the same switch.
In the past it relied on "one rte_device" assumption.
This patch introduces a new macro - MLX5_ETH_FOREACH_SIBLING -
which iterates over all ethdev ports managed by mlx5 driver,
which share the same mlx5 common device.
All relevant usages of previous iteration macros are replaced with
MLX5_ETH_FOREACH_SIBLING, in preparation for allowing usage of multiple
rte_device's in mlx5 networking driver.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/net/mlx5/linux/mlx5_ethdev_os.c | 13 ++---
drivers/net/mlx5/linux/mlx5_os.c | 22 +++-----
drivers/net/mlx5/mlx5.c | 70 ++++++++++++++++++++-----
drivers/net/mlx5/mlx5.h | 6 +++
drivers/net/mlx5/mlx5_ethdev.c | 27 +++-------
drivers/net/mlx5/mlx5_flow.c | 24 ++++-----
drivers/net/mlx5/mlx5_mac.c | 2 +-
drivers/net/mlx5/mlx5_trigger.c | 10 ++--
drivers/net/mlx5/windows/mlx5_os.c | 24 ++++-----
9 files changed, 105 insertions(+), 93 deletions(-)
diff --git a/drivers/net/mlx5/linux/mlx5_ethdev_os.c b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
index f6394ebd19..55cae148f0 100644
--- a/drivers/net/mlx5/linux/mlx5_ethdev_os.c
+++ b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
@@ -300,18 +300,13 @@ mlx5_find_master_dev(struct rte_eth_dev *dev)
{
struct mlx5_priv *priv;
uint16_t port_id;
- uint16_t domain_id;
priv = dev->data->dev_private;
- domain_id = priv->domain_id;
MLX5_ASSERT(priv->representor);
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
- struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
- if (opriv &&
- opriv->master &&
- opriv->domain_id == domain_id &&
- opriv->sh == priv->sh)
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
+
+ if (opriv->master)
return &rte_eth_devices[port_id];
}
return NULL;
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 42b23e7f58..1b1b1bb013 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1585,14 +1585,10 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
* Look for sibling devices in order to reuse their switch domain
* if any, otherwise allocate one.
*/
- MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) {
- const struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
-
- if (!opriv ||
- opriv->sh != priv->sh ||
- opriv->domain_id ==
- RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID)
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ const struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
+
+ if (opriv->domain_id == RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID)
continue;
priv->domain_id = opriv->domain_id;
DRV_LOG(DEBUG, "dev_port-%u inherit domain_id=%u\n",
@@ -1711,13 +1707,9 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
if (priv->representor) {
eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;
eth_dev->data->representor_id = eth_dev->data->port_id;
- MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) {
- struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
- if (opriv &&
- opriv->master &&
- opriv->domain_id == priv->domain_id &&
- opriv->sh == priv->sh) {
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
+ if (opriv->master) {
eth_dev->data->backer_port_id = port_id;
break;
}
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 7093eefa15..615b2ff943 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2565,23 +2565,14 @@ mlx5_dev_close(struct rte_eth_dev *dev)
* since 'mlx5_dev_interrupt_nl_cb' uses priv.
*/
rte_io_wmb();
- /*
- * Free the shared context in last turn, because the cleanup
- * routines above may use some shared fields, like
- * mlx5_os_mac_addr_flush() uses ibdev_path for retrieving
- * ifindex if Netlink fails.
- */
- mlx5_free_shared_dev_ctx(sh);
if (priv->domain_id != RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
unsigned int c = 0;
uint16_t port_id;
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
- struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
- if (!opriv ||
- opriv->domain_id != priv->domain_id ||
+ if (opriv->domain_id != priv->domain_id ||
&rte_eth_devices[port_id] == dev)
continue;
++c;
@@ -2590,6 +2581,13 @@ mlx5_dev_close(struct rte_eth_dev *dev)
if (!c)
claim_zero(rte_eth_switch_domain_free(priv->domain_id));
}
+ /*
+ * Free the shared context in last turn, because the cleanup
+ * routines above may use some shared fields, like
+ * mlx5_os_mac_addr_flush() uses ibdev_path for retrieving
+ * ifindex if Netlink fails.
+ */
+ mlx5_free_shared_dev_ctx(sh);
mlx5_flow_pools_destroy(priv);
memset(priv, 0, sizeof(*priv));
priv->domain_id = RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID;
@@ -3508,6 +3506,54 @@ mlx5_eth_find_next(uint16_t port_id, struct rte_device *odev)
return port_id;
}
+/**
+ * Look for the ethernet device belonging to mlx5 driver, which share the device context.
+ *
+ * If port index is found, then caller can assume that:
+ *
+ * - Port is a valid ethdev port, managed by mlx5 driver.
+ * - Port has private device data set (mlx5_priv).
+ * - Port has shared mlx5 device context set (priv->sh).
+ * - Port is based on the @p cdev common device.
+ *
+ * @param[in] start_port_id
+ * Port index to start looking for device.
+ * @param[in] cdev
+ * Pointer to common device.
+ *
+ * @return
+ * Port index of found device, RTE_MAX_ETHPORTS if not found.
+ */
+uint16_t
+mlx5_eth_find_next_sibling(uint16_t start_port_id, struct mlx5_common_device *cdev)
+{
+ struct mlx5_priv *priv;
+ uint16_t port_id;
+
+ if (cdev == NULL)
+ return RTE_MAX_ETHPORTS;
+
+ for (port_id = start_port_id; port_id < RTE_MAX_ETHPORTS; port_id++) {
+ if (rte_eth_dev_is_valid_port(port_id) == 0)
+ continue;
+
+ if (!mlx5_dev_is_managed(rte_eth_devices[port_id].device))
+ continue;
+
+ priv = rte_eth_devices[port_id].data->dev_private;
+ if (priv == NULL || priv->sh == NULL)
+ continue;
+
+ if (priv->sh->cdev == cdev)
+ break;
+ }
+
+ if (port_id >= RTE_MAX_ETHPORTS)
+ return RTE_MAX_ETHPORTS;
+
+ return port_id;
+}
+
static int
mlx5_hairpin_queue_counter_supported(struct mlx5_priv *priv)
{
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index b1493745ee..e4ebdd4c2f 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -2295,6 +2295,7 @@ void mlx5_proc_priv_uninit(struct rte_eth_dev *dev);
int mlx5_udp_tunnel_port_add(struct rte_eth_dev *dev,
struct rte_eth_udp_tunnel *udp_tunnel);
uint16_t mlx5_eth_find_next(uint16_t port_id, struct rte_device *odev);
+uint16_t mlx5_eth_find_next_sibling(uint16_t port_id, struct mlx5_common_device *cdev);
int mlx5_dev_close(struct rte_eth_dev *dev);
int mlx5_net_remove(struct mlx5_common_device *cdev);
bool mlx5_is_hpf(struct rte_eth_dev *dev);
@@ -2312,6 +2313,11 @@ int mlx5_disable_per_queue_hairpin_counter(struct rte_eth_dev *dev, uint64_t id)
for (port_id = mlx5_eth_find_next(0, dev); \
port_id < RTE_MAX_ETHPORTS; \
port_id = mlx5_eth_find_next(port_id + 1, dev))
+/* Macro to iterate over all valid ports for mlx5 driver spawned on given common device. */
+#define MLX5_ETH_FOREACH_SIBLING(port_id, cdev) \
+ for (port_id = mlx5_eth_find_next_sibling(0, cdev); \
+ port_id < RTE_MAX_ETHPORTS; \
+ port_id = mlx5_eth_find_next_sibling(port_id + 1, cdev))
void mlx5_rt_timestamp_config(struct mlx5_dev_ctx_shared *sh,
struct mlx5_hca_attr *hca_attr);
struct mlx5_dev_ctx_shared *
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index 306c1cd734..f41724725c 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -424,15 +424,12 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
if (priv->representor) {
uint16_t port_id;
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
- struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
-
- if (!opriv ||
- opriv->representor ||
- opriv->sh != priv->sh ||
- opriv->domain_id != priv->domain_id)
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
+
+ if (opriv->representor)
continue;
+
/*
* Override switch name with that of the master
* device.
@@ -523,14 +520,9 @@ mlx5_representor_info_count(struct rte_eth_dev *dev)
uint16_t port_id;
unsigned int count = 0;
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
- if (!opriv ||
- opriv->sh != priv->sh ||
- opriv->domain_id != priv->domain_id)
- continue;
-
count += mlx5_representor_info_count_one(opriv);
}
@@ -629,14 +621,9 @@ mlx5_representor_info_fill(struct rte_eth_dev *dev,
info->controller = priv->port_info.ctrl_num;
info->pf = RTE_BUS_DEVICE(dev->device, struct rte_pci_device)->addr.function;
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
- if (!opriv ||
- opriv->sh != priv->sh ||
- opriv->domain_id != priv->domain_id)
- continue;
-
mlx5_representor_info_fill_one(opriv, info);
}
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index b0eac185b5..cceb6668f9 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1665,15 +1665,12 @@ mlx5_flow_rxq_mark_flag_set(struct rte_eth_dev *dev)
if (priv->sh->shared_mark_enabled)
return;
if (priv->master || priv->representor) {
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
- struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
-
- if (!opriv ||
- opriv->sh != priv->sh ||
- opriv->domain_id != priv->domain_id ||
- opriv->mark_enabled)
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
+
+ if (opriv->mark_enabled)
continue;
+
LIST_FOREACH(rxq_ctrl, &opriv->rxqsctrl, next) {
rxq_ctrl->rxq.mark = 1;
}
@@ -12290,12 +12287,9 @@ mlx5_flow_pick_transfer_proxy(struct rte_eth_dev *dev,
*proxy_port_id = dev->data->port_id;
return 0;
}
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
- const struct rte_eth_dev *port_dev = &rte_eth_devices[port_id];
- const struct mlx5_priv *port_priv = port_dev->data->dev_private;
-
- if (port_priv->master &&
- port_priv->domain_id == priv->domain_id) {
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ const struct mlx5_priv *port_priv = rte_eth_devices[port_id].data->dev_private;
+ if (port_priv->master) {
*proxy_port_id = port_id;
return 0;
}
@@ -12511,7 +12505,7 @@ flow_disable_steering_run_on_related(struct rte_eth_dev *dev,
}
/* Run callback on representors. */
- MLX5_ETH_FOREACH_DEV(other_port_id, dev->device) {
+ MLX5_ETH_FOREACH_SIBLING(other_port_id, priv->sh->cdev) {
struct rte_eth_dev *other_dev = &rte_eth_devices[other_port_id];
if (other_port_id != proxy_port_id)
diff --git a/drivers/net/mlx5/mlx5_mac.c b/drivers/net/mlx5/mlx5_mac.c
index 9e7bf7f2ec..8cbaaf67dd 100644
--- a/drivers/net/mlx5/mlx5_mac.c
+++ b/drivers/net/mlx5/mlx5_mac.c
@@ -191,7 +191,7 @@ mlx5_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
mac_addr,
MLX5_REPRESENTOR_REPR(priv->representor_id));
}
- RTE_ETH_FOREACH_DEV_SIBLING(port_id, dev->data->port_id) {
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
pf_priv = rte_eth_devices[port_id].data->dev_private;
if (pf_priv->master == 1)
return mlx5_os_vf_mac_addr_modify
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index c5f493117b..ae0584f1b4 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -1578,13 +1578,11 @@ mlx5_hw_proxy_port_allowed_stop(struct rte_eth_dev *dev)
/* If transfer proxy port was not configured for HWS, then stopping it is allowed. */
if (!priv->dr_ctx)
return 0;
- MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
- const struct rte_eth_dev *port_dev = &rte_eth_devices[port_id];
- const struct mlx5_priv *port_priv = port_dev->data->dev_private;
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ struct rte_eth_dev *odev = &rte_eth_devices[port_id];
+ struct mlx5_priv *opriv = odev->data->dev_private;
- if (port_id != dev->data->port_id &&
- port_priv->domain_id == priv->domain_id &&
- port_dev->data->dev_started)
+ if (opriv->representor && odev->data->dev_started)
representor_started = true;
}
if (representor_started) {
diff --git a/drivers/net/mlx5/windows/mlx5_os.c b/drivers/net/mlx5/windows/mlx5_os.c
index 8e3baa95b4..2dbcbb1acb 100644
--- a/drivers/net/mlx5/windows/mlx5_os.c
+++ b/drivers/net/mlx5/windows/mlx5_os.c
@@ -437,16 +437,14 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
* Look for sibling devices in order to reuse their switch domain
* if any, otherwise allocate one.
*/
- MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) {
- const struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
-
- if (!opriv ||
- opriv->sh != priv->sh ||
- opriv->domain_id ==
- RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID)
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ const struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
+
+ if (opriv->domain_id == RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID)
continue;
priv->domain_id = opriv->domain_id;
+ DRV_LOG(DEBUG, "dev_port-%u inherit domain_id=%u",
+ priv->dev_port, priv->domain_id);
break;
}
if (priv->domain_id == RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) {
@@ -476,13 +474,9 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
if (priv->representor) {
eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;
eth_dev->data->representor_id = priv->representor_id;
- MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) {
- struct mlx5_priv *opriv =
- rte_eth_devices[port_id].data->dev_private;
- if (opriv &&
- opriv->master &&
- opriv->domain_id == priv->domain_id &&
- opriv->sh == priv->sh) {
+ MLX5_ETH_FOREACH_SIBLING(port_id, priv->sh->cdev) {
+ struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private;
+ if (opriv->master) {
eth_dev->data->backer_port_id = port_id;
break;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 12/13] net/mlx5: allow associated devices
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (10 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 11/13] net/mlx5: add sibling device iteration macro Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
2026-10-26 16:27 ` [PATCH 13/13] net/mlx5: allow multiport auxiliary device probe Dariusz Sosnowski
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Allow probing mlx5 networking devices using multiple rte_device's,
which are associated with single mlx5 common device.
This requires a few changes in probing:
- When going through list of IB devices to check for MPESW
or bond setups, use owner IB device from common device,
not the probed device.
- When preparing data for a list of spawned ports,
keep "probed device" and "owner device" separate.
- Use the name of "probed device" when
ethdev port name is constructed.
- Any device related to VIRTUAL devlink port,
which is not an E-Switch owner should be accepted
as a representor port. Representor devarg is not required.
Patch also extends mlx5_nl_check_switch_info() to query
the flavour of related devlink port if phys_port_name is not available.
As of this patch, probing through associated devices
is only allowed for PCI devices.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/common/mlx5/linux/mlx5_nl.c | 95 +++++++++++++++++++++++-
drivers/common/mlx5/linux/mlx5_nl.h | 4 +-
drivers/common/mlx5/mlx5_common.h | 5 ++
drivers/net/mlx5/linux/mlx5_os.c | 109 +++++++++++++++++++++-------
drivers/net/mlx5/mlx5.c | 3 +-
drivers/net/mlx5/mlx5.h | 1 +
drivers/net/mlx5/mlx5_ethdev.c | 13 +++-
drivers/net/mlx5/mlx5_mac.c | 6 +-
8 files changed, 199 insertions(+), 37 deletions(-)
diff --git a/drivers/common/mlx5/linux/mlx5_nl.c b/drivers/common/mlx5/linux/mlx5_nl.c
index e57007831c..6a22476a15 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.c
+++ b/drivers/common/mlx5/linux/mlx5_nl.c
@@ -1620,7 +1620,7 @@ mlx5_nl_devlink_port_info_get_cb(struct nlmsghdr *nh, void *arg)
return -rte_errno;
}
-static int __rte_unused
+static int
mlx5_nl_devlink_port_info_get(int nl, int family, struct mlx5_devlink_port_info *info)
{
struct nlmsghdr *nlh;
@@ -1668,6 +1668,8 @@ mlx5_nl_devlink_port_info_get(int nl, int family, struct mlx5_devlink_port_info
* Analyze gathered port parameters via Netlink to recognize master
* and representor devices for E-Switch configuration.
*
+ * @param[in] parent_dev_match
+ * True if underlying netdev's parent device is the same as for IB device.
* @param[in] num_vf_set
* flag of presence of number of VFs port attribute.
* @param[inout] switch_info
@@ -1679,7 +1681,8 @@ mlx5_nl_devlink_port_info_get(int nl, int family, struct mlx5_devlink_port_info
* recognized parameters (if any).
*/
static void
-mlx5_nl_check_switch_info(bool num_vf_set,
+mlx5_nl_check_switch_info(bool parent_dev_match,
+ bool num_vf_set,
struct mlx5_switch_info *switch_info)
{
switch (switch_info->name_type) {
@@ -1714,12 +1717,67 @@ mlx5_nl_check_switch_info(bool num_vf_set,
/* New representors naming schema. */
switch_info->representor = 1;
break;
+ case MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL:
+ switch_info->master = parent_dev_match;
+ switch_info->representor = !parent_dev_match;
+ break;
}
}
+static void
+check_virtual_port(struct mlx5_netdev_info *netdev_info,
+ struct mlx5_switch_info *switch_info)
+{
+ struct mlx5_devlink_port_info devlink_port_info = {
+ .bus_name = netdev_info->devlink_port_bus_name,
+ .dev_name = netdev_info->devlink_port_dev_name,
+ .index = netdev_info->devlink_port_index,
+ };
+ int nl;
+ int family;
+ int ret = 0;
+
+ nl = mlx5_nl_init(NETLINK_GENERIC, 0);
+ if (nl < 0) {
+ DRV_LOG(DEBUG, "Unable to open NETLINK_GENERIC socket");
+ return;
+ }
+
+ family = mlx5_nl_devlink_family_id_get(nl);
+ if (family < 0) {
+ DRV_LOG(DEBUG, "Unable to query devlink genetlink family ID");
+ goto exit_end;
+ }
+
+ if (mlx5_netdev_info_has_devlink_port(netdev_info)) {
+ ret = mlx5_nl_devlink_port_info_get(nl, family, &devlink_port_info);
+ } else {
+ /*
+ * TODO: Kernel too old. Devlink port must be found by dumping all ports
+ * and matching by netdev_ifindex. Until this is done, log unsupported.
+ */
+ DRV_LOG(DEBUG, "Kernel does not expose IFLA_DEVLINK_PORT");
+ ret = -ENOTSUP;
+ }
+
+ if (ret < 0) {
+ DRV_LOG(DEBUG, "Unable to query devlink port flavour");
+ goto exit_end;
+ }
+
+ if ((devlink_port_info.flags & MLX5_DEVLINK_PORT_INFO_FLAG_FLAVOUR) &&
+ devlink_port_info.flavour == MLX5_DEVLINK_PORT_FLAVOUR_VIRTUAL)
+ switch_info->name_type = MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL;
+
+exit_end:
+ close(nl);
+}
+
/**
* Get switch information associated with network interface.
*
+ * @param cdev
+ * Pointer to common device.
* @param nl
* Netlink socket of the ROUTE kind (NETLINK_ROUTE).
* @param ifindex
@@ -1732,12 +1790,15 @@ mlx5_nl_check_switch_info(bool num_vf_set,
*/
RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_switch_info)
int
-mlx5_nl_switch_info(int nl, unsigned int ifindex,
+mlx5_nl_switch_info(struct mlx5_common_device *cdev,
+ int nl,
+ unsigned int ifindex,
struct mlx5_switch_info *info)
{
struct mlx5_netdev_info netdev_info = {
.ifindex = ifindex,
};
+ bool parent_dev_match;
bool num_vf_set;
int ret;
@@ -1756,7 +1817,33 @@ mlx5_nl_switch_info(int nl, unsigned int ifindex,
if (netdev_info.flags & MLX5_NETDEV_INFO_FLAG_PHYS_SWITCH_ID) {
info->switch_id = netdev_info.phys_switch_id;
- mlx5_nl_check_switch_info(num_vf_set, info);
+
+ if (info->name_type == MLX5_PHYS_PORT_NAME_TYPE_NOTSET)
+ check_virtual_port(&netdev_info, info);
+
+ /* Port type could be updated to virtual. Recheck. */
+ if (info->name_type == MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL) {
+ if (!(netdev_info.flags & MLX5_NETDEV_INFO_FLAG_PARENT_DEV_NAME) ||
+ !(netdev_info.flags & MLX5_NETDEV_INFO_FLAG_PARENT_DEV_BUS_NAME)) {
+ DRV_LOG(ERR, "ifindex %u cannot get parent dev", ifindex);
+ rte_errno = EINVAL;
+ return -rte_errno;
+ }
+
+ strlcpy(info->parent_dev_bus_name, netdev_info.parent_dev_bus_name,
+ sizeof(info->parent_dev_bus_name));
+ strlcpy(info->parent_dev_name, netdev_info.parent_dev_name,
+ sizeof(info->parent_dev_name));
+
+ parent_dev_match = mlx5_dev_matches(cdev->dev,
+ netdev_info.parent_dev_bus_name,
+ netdev_info.parent_dev_name);
+ } else {
+ /* Irrelevant for other port flavours. */
+ parent_dev_match = false;
+ }
+
+ mlx5_nl_check_switch_info(parent_dev_match, num_vf_set, info);
}
if (info->master && info->representor) {
diff --git a/drivers/common/mlx5/linux/mlx5_nl.h b/drivers/common/mlx5/linux/mlx5_nl.h
index 0a9aab6610..7663864e56 100644
--- a/drivers/common/mlx5/linux/mlx5_nl.h
+++ b/drivers/common/mlx5/linux/mlx5_nl.h
@@ -144,7 +144,9 @@ __rte_internal
int mlx5_nl_vf_mac_addr_modify(int nlsk_fd, unsigned int iface_idx,
struct rte_ether_addr *mac, int vf_index);
__rte_internal
-int mlx5_nl_switch_info(int nl, unsigned int ifindex,
+int mlx5_nl_switch_info(struct mlx5_common_device *cdev,
+ int nl,
+ unsigned int ifindex,
struct mlx5_switch_info *info);
__rte_internal
diff --git a/drivers/common/mlx5/mlx5_common.h b/drivers/common/mlx5/mlx5_common.h
index 548f0c887b..fb73b3a038 100644
--- a/drivers/common/mlx5/mlx5_common.h
+++ b/drivers/common/mlx5/mlx5_common.h
@@ -152,6 +152,7 @@ enum mlx5_nl_phys_port_name_type {
MLX5_PHYS_PORT_NAME_TYPE_PFVF, /* pf0vf0, kernel ver >= 5.0 */
MLX5_PHYS_PORT_NAME_TYPE_PFHPF, /* pf0, kernel ver >= 5.7, HPF rep */
MLX5_PHYS_PORT_NAME_TYPE_PFSF, /* pf0sf0, kernel ver >= 5.0 */
+ MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL, /* Virtual devlink port. */
MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN, /* Unrecognized. */
};
@@ -169,6 +170,8 @@ struct mlx5_dev_info {
struct mlx5_port_nl_info *port_info;
};
+#define MLX5_SWITCH_INFO_PARENT_DEV_NAME_MAX (128)
+
/** Switch information returned by mlx5_nl_switch_info(). */
struct mlx5_switch_info {
uint32_t master:1; /**< Master device. */
@@ -179,6 +182,8 @@ struct mlx5_switch_info {
int32_t port_name; /**< Representor port name. */
int32_t mpesw_owner; /**< MPESW owner port number. */
uint64_t switch_id; /**< Switch identifier. */
+ char parent_dev_bus_name[MLX5_SWITCH_INFO_PARENT_DEV_NAME_MAX];
+ char parent_dev_name[MLX5_SWITCH_INFO_PARENT_DEV_NAME_MAX];
};
/* CQE status. */
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 1b1b1bb013..83c9774443 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1122,6 +1122,9 @@ build_port_name(struct rte_device *dpdk_dev,
written += ret;
if (written >= (int)name_sz)
return written;
+ } else if (spawn->info.name_type == MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL) {
+ /* All relevant information was put in the name. Finish here. */
+ goto end;
} else if (spawn->info.representor) {
/*
* If port is a representor, then switchdev has been enabled.
@@ -1249,6 +1252,13 @@ mlx5_representor_match(struct mlx5_dev_spawn_data *spawn,
bool ignore_ctrl_num = eth_da->nb_mh_controllers == 0 ||
switch_info->name_type == MLX5_PHYS_PORT_NAME_TYPE_UPLINK;
+ /*
+ * Representor on virtual devlink port always match.
+ * Probing logic filters out unwanted ports before mlx5_dev_spawn() is reached.
+ */
+ if (switch_info->name_type == MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL)
+ return true;
+
switch (eth_da->type) {
case RTE_ETH_REPRESENTOR_PF:
if (switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_UPLINK) {
@@ -1299,8 +1309,6 @@ mlx5_representor_match(struct mlx5_dev_spawn_data *spawn,
/**
* Spawn an Ethernet device from Verbs information.
*
- * @param dpdk_dev
- * Backing DPDK device.
* @param spawn
* Verbs device parameters (name, port, switch_info) to spawn.
* @param eth_da
@@ -1316,11 +1324,11 @@ mlx5_representor_match(struct mlx5_dev_spawn_data *spawn,
* EEXIST: device is already spawned
*/
static struct rte_eth_dev *
-mlx5_dev_spawn(struct rte_device *dpdk_dev,
- struct mlx5_dev_spawn_data *spawn,
+mlx5_dev_spawn(struct mlx5_dev_spawn_data *spawn,
struct rte_eth_devargs *eth_da,
struct mlx5_kvargs_ctrl *mkvlist)
{
+ struct rte_device *dpdk_dev = spawn->dpdk_dev;
const struct mlx5_switch_info *switch_info = &spawn->info;
struct mlx5_dev_ctx_shared *sh = NULL;
struct ibv_port_attr port_attr = { .state = IBV_PORT_NOP };
@@ -2477,6 +2485,7 @@ calc_nb_uplinks_hpfs(struct ibv_device **ibv_match,
*/
static int
mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
struct rte_eth_devargs *req_eth_da,
uint16_t owner_id, struct mlx5_kvargs_ctrl *mkvlist)
{
@@ -2511,13 +2520,22 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
* >= 0 - MPESW device. Value is the port index of the MPESW owner.
*/
int mpesw = MLX5_MPESW_PORT_INVALID;
- struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(cdev->dev, *pci_dev);
+ struct rte_pci_device *owner_pci_dev;
struct mlx5_dev_spawn_data *list = NULL;
struct rte_eth_devargs eth_da = *req_eth_da;
- struct rte_pci_addr owner_pci = pci_dev->addr; /* Owner PF. */
+ struct rte_pci_addr owner_pci; /* Owner PF. */
struct mlx5_bond_info bond_info;
int ret = -1;
+ if (!mlx5_dev_is_pci(cdev->dev)) {
+ DRV_LOG(ERR, "Owner device is not PCI: dev %s owner %s",
+ dev->name, cdev->dev->name);
+ rte_errno = EINVAL;
+ return -rte_errno;
+ }
+ owner_pci_dev = RTE_BUS_DEVICE(cdev->dev, *owner_pci_dev);
+ owner_pci = owner_pci_dev->addr;
+
errno = 0;
ibv_list = mlx5_glue->get_device_list(&ret);
if (!ibv_list) {
@@ -2699,8 +2717,9 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
list[ns].phys_port = i;
list[ns].phys_dev_name = ibv_match[0]->name;
list[ns].eth_dev = NULL;
- list[ns].pci_dev = pci_dev;
+ list[ns].pci_dev = owner_pci_dev;
list[ns].cdev = cdev;
+ list[ns].dpdk_dev = dev;
list[ns].pf_bond = bd;
list[ns].mpesw_port = MLX5_MPESW_PORT_INVALID;
list[ns].ifindex = mlx5_nl_ifindex(nl_rdma,
@@ -2718,7 +2737,7 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
}
ret = -1;
if (nl_route >= 0)
- ret = mlx5_nl_switch_info(nl_route,
+ ret = mlx5_nl_switch_info(cdev, nl_route,
list[ns].ifindex,
&list[ns].info);
if (ret || (!list[ns].info.representor &&
@@ -2731,6 +2750,11 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
ret = mlx5_sysfs_switch_info(list[ns].ifindex,
&list[ns].info);
}
+ /* Allow usage of associated devices only for VIRTUAL devlink ports. */
+ if (!ret &&
+ list[ns].info.name_type != MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL &&
+ cdev->dev != dev)
+ continue;
if (!ret && bd >= 0) {
switch (list[ns].info.name_type) {
case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
@@ -2790,13 +2814,26 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
list[ns].info.mpesw_owner = mpesw;
ns++;
break;
+ case MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL:
+ list[ns].mpesw_port = mpesw;
+ list[ns].info.mpesw_owner = mpesw;
+ /* Spawn the device if and only if it matches. */
+ if (mlx5_dev_matches(list[ns].dpdk_dev,
+ list[ns].info.parent_dev_bus_name,
+ list[ns].info.parent_dev_name))
+ ns++;
+ break;
default:
break;
}
continue;
}
- if (!ret && (list[ns].info.representor ^
- list[ns].info.master))
+ if (!ret && list[ns].info.name_type == MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL) {
+ if (mlx5_dev_matches(list[ns].dpdk_dev,
+ list[ns].info.parent_dev_bus_name,
+ list[ns].info.parent_dev_name))
+ ns++;
+ } else if (!ret && (list[ns].info.representor ^ list[ns].info.master))
ns++;
}
} else {
@@ -2824,8 +2861,9 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
list[ns].phys_port = 1;
list[ns].phys_dev_name = ibv_match[i]->name;
list[ns].eth_dev = NULL;
- list[ns].pci_dev = pci_dev;
+ list[ns].pci_dev = owner_pci_dev;
list[ns].cdev = cdev;
+ list[ns].dpdk_dev = dev;
list[ns].pf_bond = -1;
list[ns].mpesw_port = MLX5_MPESW_PORT_INVALID;
list[ns].ifindex = 0;
@@ -2872,7 +2910,7 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
}
ret = -1;
if (nl_route >= 0)
- ret = mlx5_nl_switch_info(nl_route,
+ ret = mlx5_nl_switch_info(cdev, nl_route,
list[ns].ifindex,
&list[ns].info);
if (ret || (!list[ns].info.representor &&
@@ -2885,6 +2923,11 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
ret = mlx5_sysfs_switch_info(list[ns].ifindex,
&list[ns].info);
}
+ /* Allow usage of associated devices only for VIRTUAL devlink ports. */
+ if (!ret &&
+ list[ns].info.name_type != MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL &&
+ cdev->dev != dev)
+ continue;
if (!ret && (list[ns].info.representor ^
list[ns].info.master)) {
ns++;
@@ -2921,7 +2964,12 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
list[0].info.representor = 0;
}
}
- MLX5_ASSERT(ns);
+ if (ns == 0) {
+ DRV_LOG(ERR, "Unable to match any IB port to probed device");
+ rte_errno = ENOENT;
+ ret = -rte_errno;
+ goto exit;
+ }
/* Calculate number of uplinks and host PFs for each matched IB device. */
calc_nb_uplinks_hpfs(ibv_match, nd, list, ns);
/*
@@ -2934,7 +2982,7 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
if (eth_da.nb_ports == 0 && ns > 0) {
if (list[0].pf_bond >= 0 && list[0].info.representor)
DRV_LOG(WARNING, "Representor on Bonding device should use pf#vf# syntax: %s",
- pci_dev->device.devargs->args);
+ dev->devargs->args);
eth_da.nb_ports = 1;
eth_da.ports[0] = list[0].info.port_name;
}
@@ -2946,8 +2994,7 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
for (i = 0; i != ns; ++i) {
uint32_t restore;
- list[i].eth_dev = mlx5_dev_spawn(cdev->dev, &list[i], ð_da,
- mkvlist);
+ list[i].eth_dev = mlx5_dev_spawn(&list[i], ð_da, mkvlist);
if (!list[i].eth_dev) {
if (rte_errno != EBUSY && rte_errno != EEXIST)
break;
@@ -2955,7 +3002,7 @@ mlx5_os_pci_probe_pf(struct mlx5_common_device *cdev,
continue;
}
restore = list[i].eth_dev->data->dev_flags;
- rte_eth_copy_pci_info(list[i].eth_dev, pci_dev);
+ rte_eth_copy_pci_info(list[i].eth_dev, list[i].pci_dev);
/**
* Each representor has a dedicated interrupts vector.
* rte_eth_copy_pci_info() assigns PF interrupts handle to
@@ -3070,21 +3117,22 @@ mlx5_os_parse_eth_devargs(struct rte_device *dev,
*/
static int
mlx5_os_pci_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
struct mlx5_kvargs_ctrl *mkvlist)
{
- struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(cdev->dev, *pci_dev);
+ struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(dev, *pci_dev);
struct rte_eth_devargs eth_da = { .nb_ports = 0 };
int ret = 0;
uint16_t p;
- ret = mlx5_os_parse_eth_devargs(cdev->dev, ð_da);
+ ret = mlx5_os_parse_eth_devargs(dev, ð_da);
if (ret != 0)
return ret;
if (eth_da.nb_ports > 0) {
/* Iterate all port if devargs pf is range: "pf[0-1]vf[...]". */
for (p = 0; p < eth_da.nb_ports; p++) {
- ret = mlx5_os_pci_probe_pf(cdev, ð_da,
+ ret = mlx5_os_pci_probe_pf(cdev, dev, ð_da,
eth_da.ports[p], mkvlist);
if (ret) {
DRV_LOG(INFO, "Probe of PCI device " PCI_PRI_FMT " "
@@ -3098,7 +3146,7 @@ mlx5_os_pci_probe(struct mlx5_common_device *cdev,
}
}
} else {
- ret = mlx5_os_pci_probe_pf(cdev, ð_da, 0, mkvlist);
+ ret = mlx5_os_pci_probe_pf(cdev, dev, ð_da, 0, mkvlist);
}
return ret;
}
@@ -3106,6 +3154,7 @@ mlx5_os_pci_probe(struct mlx5_common_device *cdev,
/* Probe a single SF device on auxiliary bus, no representor support. */
static int
mlx5_os_auxiliary_probe(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
struct mlx5_kvargs_ctrl *mkvlist)
{
struct rte_eth_devargs eth_da = { .nb_ports = 0 };
@@ -3113,11 +3162,16 @@ mlx5_os_auxiliary_probe(struct mlx5_common_device *cdev,
.pf_bond = -1,
.mpesw_port = MLX5_MPESW_PORT_INVALID,
};
- struct rte_device *dev = cdev->dev;
struct rte_auxiliary_device *adev = RTE_BUS_DEVICE(dev, *adev);
struct rte_eth_dev *eth_dev;
int ret = 0;
+ if (cdev->dev != dev) {
+ DRV_LOG(ERR, "Invalid device %s used to probe common device %s",
+ dev->name, cdev->dev->name);
+ rte_errno = EINVAL;
+ return -rte_errno;
+ }
/* Parse ethdev devargs. */
ret = mlx5_os_parse_eth_devargs(dev, ð_da);
if (ret != 0)
@@ -3133,8 +3187,9 @@ mlx5_os_auxiliary_probe(struct mlx5_common_device *cdev,
}
spawn.ifindex = ret;
spawn.cdev = cdev;
+ spawn.dpdk_dev = dev;
/* Spawn device. */
- eth_dev = mlx5_dev_spawn(dev, &spawn, ð_da, mkvlist);
+ eth_dev = mlx5_dev_spawn(&spawn, ð_da, mkvlist);
if (eth_dev == NULL)
return -rte_errno;
/* Post create. */
@@ -3165,7 +3220,7 @@ mlx5_os_auxiliary_probe(struct mlx5_common_device *cdev,
*/
int
mlx5_os_net_probe(struct mlx5_common_device *cdev,
- struct rte_device *dev __rte_unused,
+ struct rte_device *dev,
struct mlx5_kvargs_ctrl *mkvlist)
{
int ret;
@@ -3184,10 +3239,10 @@ mlx5_os_net_probe(struct mlx5_common_device *cdev,
strerror(rte_errno));
return -rte_errno;
}
- if (mlx5_dev_is_pci(cdev->dev))
- return mlx5_os_pci_probe(cdev, mkvlist);
+ if (mlx5_dev_is_pci(dev))
+ return mlx5_os_pci_probe(cdev, dev, mkvlist);
else
- return mlx5_os_auxiliary_probe(cdev, mkvlist);
+ return mlx5_os_auxiliary_probe(cdev, dev, mkvlist);
}
/**
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 615b2ff943..9dc3402e22 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -3881,7 +3881,7 @@ mlx5_net_remove(struct mlx5_common_device *cdev)
uint16_t port_id;
int ret = 0;
- RTE_ETH_FOREACH_DEV_OF(port_id, cdev->dev) {
+ MLX5_ETH_FOREACH_SIBLING(port_id, cdev) {
/*
* mlx5_dev_close() is not registered to secondary process,
* call the close function explicitly for secondary process.
@@ -3999,6 +3999,7 @@ static struct mlx5_class_driver mlx5_net_driver = {
.probe = mlx5_os_net_probe,
.remove = mlx5_net_remove,
.probe_again = 1,
+ .probe_associated = 1,
.intr_lsc = 1,
.intr_rmv = 1,
};
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index e4ebdd4c2f..de969c0b2e 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -234,6 +234,7 @@ struct mlx5_dev_spawn_data {
const char *phys_dev_name; /**< Name of physical device. */
struct rte_eth_dev *eth_dev; /**< Associated Ethernet device. */
struct rte_pci_device *pci_dev; /**< Backend PCI device. */
+ struct rte_device *dpdk_dev; /**< Backend DPDK device. */
struct mlx5_common_device *cdev; /**< Backend common device. */
struct mlx5_bond_info *bond_info;
};
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index f41724725c..115b67ffdf 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -472,6 +472,8 @@ mlx5_representor_id_encode(const struct mlx5_switch_info *info,
type = RTE_ETH_REPRESENTOR_PF;
pf = info->mpesw_owner;
break;
+ case MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL:
+ return UINT16_MAX;
case MLX5_PHYS_PORT_NAME_TYPE_PFSF:
type = RTE_ETH_REPRESENTOR_SF;
break;
@@ -507,10 +509,13 @@ mlx5_representor_info_count_one(struct mlx5_priv *priv)
case MLX5_PHYS_PORT_NAME_TYPE_PFSF:
/* FALLTHROUGH */
case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
- /* FALLTHROUGH */
- default:
return 1;
+ case MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL:
+ return 0;
}
+
+ /* Suppress "control reaches end of non-void function" warning without adding "default". */
+ return 0;
}
static unsigned int
@@ -606,6 +611,10 @@ mlx5_representor_info_fill_one(struct mlx5_priv *priv,
range->id_end = range->id_base;
snprintf(range->name, sizeof(range->name), "pf%dvf", range->pf);
break;
+ case MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL:
+ /* Rejected by mlx5_representor_info_count_one() */
+ MLX5_ASSERT(false);
+ break;
}
info->nb_ranges += count;
diff --git a/drivers/net/mlx5/mlx5_mac.c b/drivers/net/mlx5/mlx5_mac.c
index 8cbaaf67dd..2ee8580f14 100644
--- a/drivers/net/mlx5/mlx5_mac.c
+++ b/drivers/net/mlx5/mlx5_mac.c
@@ -177,10 +177,12 @@ mlx5_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
* need to skip the special cases:
* - HPF on BlueField,
* - SF representors,
- * - uplink ports when running in MPESW mode.
+ * - uplink ports when running in MPESW mode,
+ * - VIRTUAL switch ports (nested E-Switch).
*/
if (priv->representor && !mlx5_is_hpf(dev) && !mlx5_is_sf_repr(dev) &&
- !priv->mpesw_uplink) {
+ !priv->mpesw_uplink &&
+ priv->port_info.type != MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL) {
DRV_LOG(DEBUG, "VF represented by port %u setting primary MAC address",
dev->data->port_id);
if (priv->pf_bond >= 0) {
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 13/13] net/mlx5: allow multiport auxiliary device probe
2026-10-26 16:26 [PATCH 00/13] net/mlx5: support nested E-Switch Dariusz Sosnowski
` (11 preceding siblings ...)
2026-10-26 16:27 ` [PATCH 12/13] net/mlx5: allow associated devices Dariusz Sosnowski
@ 2026-10-26 16:27 ` Dariusz Sosnowski
12 siblings, 0 replies; 14+ messages in thread
From: Dariusz Sosnowski @ 2026-10-26 16:27 UTC (permalink / raw)
To: Viacheslav Ovsiienko, Bing Zhao, Ori Kam, Suanming Mou,
Matan Azrad; +Cc: dev
Future FW versions for NVIDIA NICs and DPUs will allow
SubFunctions (SFs) to be group into local E-Switch instances.
One of such SFs would serve as a transfer proxy for that E-Switch
while others will be representors.
In this topology, probing in mlx5 networking driver must support
working with associated SF devices.
This patch addresses that by adding necessary check for multiport
IB device on auxiliary device probing. If multiport device is detected,
it'll be treated as E-Switch instance. Probing will be allowed
if and only if probed device belongs to set of network devices
associated with given IB device.
Signed-off-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
drivers/net/mlx5/linux/mlx5_ethdev_os.c | 11 +-
drivers/net/mlx5/linux/mlx5_os.c | 162 +++++++++++++++++++++---
drivers/net/mlx5/linux/mlx5_os.h | 2 +-
3 files changed, 152 insertions(+), 23 deletions(-)
diff --git a/drivers/net/mlx5/linux/mlx5_ethdev_os.c b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
index 55cae148f0..e3b27818ff 100644
--- a/drivers/net/mlx5/linux/mlx5_ethdev_os.c
+++ b/drivers/net/mlx5/linux/mlx5_ethdev_os.c
@@ -48,15 +48,20 @@
#include "mlx5_utils.h"
/* Get interface index from SubFunction device name. */
-int
+unsigned int
mlx5_auxiliary_get_ifindex(const char *sf_name)
{
char if_name[IF_NAMESIZE] = { 0 };
+ unsigned int ifindex;
if (mlx5_auxiliary_get_child_name(sf_name, "/net",
if_name, sizeof(if_name)) != 0)
- return -rte_errno;
- return if_nametoindex(if_name);
+ return 0;
+
+ ifindex = if_nametoindex(if_name);
+ if (ifindex == 0)
+ rte_errno = errno;
+ return ifindex;
}
/**
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 83c9774443..ef89510b6a 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -3151,43 +3151,167 @@ mlx5_os_pci_probe(struct mlx5_common_device *cdev,
return ret;
}
-/* Probe a single SF device on auxiliary bus, no representor support. */
+static int
+mlx5_auxiliary_fill_single_spawn_data(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
+ struct mlx5_dev_spawn_data *spawn)
+{
+ unsigned int ifindex;
+
+ /* Probed device is the primary IB device. */
+ MLX5_ASSERT(cdev->dev == dev);
+ /* IB device is single port. */
+ MLX5_ASSERT(spawn->max_port == 1);
+ /* IB device name is provided. */
+ MLX5_ASSERT(spawn->phys_dev_name != NULL);
+
+ spawn->phys_port = 1;
+ ifindex = mlx5_auxiliary_get_ifindex(dev->name);
+ if (ifindex == 0) {
+ DRV_LOG(ERR, "dev %s failed to get ethdev ifindex (%s)",
+ dev->name, rte_strerror(rte_errno));
+ return -rte_errno;
+ }
+ spawn->ifindex = ifindex;
+ spawn->cdev = cdev;
+ spawn->dpdk_dev = dev;
+
+ return 0;
+}
+
+static int
+mlx5_auxiliary_fill_switch_spawn_data(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
+ int nl_rdma,
+ int nl_route,
+ struct mlx5_dev_spawn_data *spawn)
+{
+ unsigned int dev_ifindex;
+ int ret;
+
+ /* IB device is multi port. */
+ MLX5_ASSERT(spawn->max_port > 1);
+ /* IB device name is provided. */
+ MLX5_ASSERT(spawn->phys_dev_name != NULL);
+
+ dev_ifindex = mlx5_auxiliary_get_ifindex(dev->name);
+ if (dev_ifindex == 0) {
+ DRV_LOG(ERR, "dev %s failed to get ethdev ifindex (%s)",
+ dev->name, rte_strerror(rte_errno));
+ return -rte_errno;
+ }
+
+ for (unsigned int port = 1; port <= spawn->max_port; ++port) {
+ struct mlx5_switch_info switch_info;
+ unsigned int ifindex;
+
+ ifindex = mlx5_nl_ifindex(nl_rdma, spawn->phys_dev_name, port, NULL);
+ if (ifindex == 0)
+ continue;
+
+ if (ifindex != dev_ifindex)
+ continue;
+
+ ret = mlx5_nl_switch_info(cdev, nl_route, ifindex, &switch_info);
+ if (ret < 0)
+ return ret;
+
+ if (switch_info.name_type != MLX5_PHYS_PORT_NAME_TYPE_VIRTUAL)
+ continue;
+
+ /* All checks passed. This IB port can be used. */
+ spawn->phys_port = port;
+ spawn->ifindex = ifindex;
+ spawn->cdev = cdev;
+ spawn->dpdk_dev = dev;
+ spawn->info = switch_info;
+ return 0;
+ }
+
+ /* If no valid port was found, then probed device cannot be used. */
+ rte_errno = ENODEV;
+ return -rte_errno;
+}
+
+static int
+mlx5_auxiliary_fill_spawn_data(struct mlx5_common_device *cdev,
+ struct rte_device *dev,
+ struct mlx5_dev_spawn_data *spawn)
+{
+ const char *phys_dev_name;
+ unsigned int portnum;
+ int nl_route = -1;
+ int nl_rdma = -1;
+ int ret;
+
+ phys_dev_name = mlx5_os_get_ctx_device_name(cdev->ctx);
+ if (phys_dev_name == NULL)
+ return -EINVAL;
+
+ nl_rdma = mlx5_nl_init(NETLINK_RDMA, 0);
+ if (nl_rdma < 0) {
+ /* If NETLINK_RDMA is not available, assume single port for fallback. */
+ DRV_LOG(DEBUG,
+ "cdev %s Unable to open NETLINK_RDMA socket, assume single IB port (%s)",
+ cdev->dev->name, rte_strerror(rte_errno));
+ rte_errno = 0;
+ portnum = 1;
+ goto fill_spawn_data;
+ }
+
+ portnum = mlx5_nl_portnum(nl_rdma, phys_dev_name, &cdev->dev_info);
+ if (portnum == 0) {
+ ret = -rte_errno;
+ goto exit;
+ }
+
+fill_spawn_data:
+ memset(spawn, 0, sizeof(*spawn));
+ spawn->pf_bond = -1;
+ spawn->mpesw_port = MLX5_MPESW_PORT_INVALID;
+ spawn->max_port = portnum;
+ spawn->phys_dev_name = phys_dev_name;
+
+ if (portnum == 1) {
+ ret = mlx5_auxiliary_fill_single_spawn_data(cdev, dev, spawn);
+ } else {
+ nl_route = mlx5_nl_init(NETLINK_ROUTE, 0);
+ if (nl_route < 0) {
+ ret = nl_route;
+ goto exit;
+ }
+ ret = mlx5_auxiliary_fill_switch_spawn_data(cdev, dev, nl_rdma, nl_route, spawn);
+ }
+
+exit:
+ if (nl_route >= 0)
+ close(nl_route);
+ if (nl_rdma >= 0)
+ close(nl_rdma);
+ return ret;
+}
+
static int
mlx5_os_auxiliary_probe(struct mlx5_common_device *cdev,
struct rte_device *dev,
struct mlx5_kvargs_ctrl *mkvlist)
{
struct rte_eth_devargs eth_da = { .nb_ports = 0 };
- struct mlx5_dev_spawn_data spawn = {
- .pf_bond = -1,
- .mpesw_port = MLX5_MPESW_PORT_INVALID,
- };
+ struct mlx5_dev_spawn_data spawn;
struct rte_auxiliary_device *adev = RTE_BUS_DEVICE(dev, *adev);
struct rte_eth_dev *eth_dev;
int ret = 0;
- if (cdev->dev != dev) {
- DRV_LOG(ERR, "Invalid device %s used to probe common device %s",
- dev->name, cdev->dev->name);
- rte_errno = EINVAL;
- return -rte_errno;
- }
/* Parse ethdev devargs. */
ret = mlx5_os_parse_eth_devargs(dev, ð_da);
if (ret != 0)
return ret;
/* Init spawn data. */
- spawn.max_port = 1;
- spawn.phys_port = 1;
- spawn.phys_dev_name = mlx5_os_get_ctx_device_name(cdev->ctx);
- ret = mlx5_auxiliary_get_ifindex(dev->name);
+ ret = mlx5_auxiliary_fill_spawn_data(cdev, dev, &spawn);
if (ret < 0) {
- DRV_LOG(ERR, "failed to get ethdev ifindex: %s", dev->name);
+ DRV_LOG(ERR, "failed to fill spawn data: %s", dev->name);
return ret;
}
- spawn.ifindex = ret;
- spawn.cdev = cdev;
- spawn.dpdk_dev = dev;
/* Spawn device. */
eth_dev = mlx5_dev_spawn(&spawn, ð_da, mkvlist);
if (eth_dev == NULL)
diff --git a/drivers/net/mlx5/linux/mlx5_os.h b/drivers/net/mlx5/linux/mlx5_os.h
index 4d073048fb..c55c9bcefa 100644
--- a/drivers/net/mlx5/linux/mlx5_os.h
+++ b/drivers/net/mlx5/linux/mlx5_os.h
@@ -13,7 +13,7 @@
#define MLX5_NAMESIZE IF_NAMESIZE
-int mlx5_auxiliary_get_ifindex(const char *sf_name);
+unsigned int mlx5_auxiliary_get_ifindex(const char *sf_name);
enum mlx5_sw_parsing_offloads {
--
2.43.0
^ permalink raw reply related [flat|nested] 14+ messages in thread