From 1b97b1e5996228581b094bb4a0323090cf886120 Mon Sep 17 00:00:00 2001 From: Jonny Date: Fri, 28 Aug 2026 15:15:55 +0100 Subject: [PATCH] rdma/mlx5_dv: stamp RoCE IPv4 TOS from nvme/nvmf transport opts. Hardcoding TOS 96 made the canary work but ignored dataEngineRdmaPriorityClass. Copy transport_tos / nvmf tos onto the provider QP and into the RTR AV (tclass=tos, sl=tos>>5). TOS 0 leaves the AV untagged. Co-authored-by: Cursor --- include/spdk_internal/rdma_provider.h | 3 +++ lib/nvme/nvme_rdma.c | 1 + lib/nvmf/rdma.c | 2 ++ lib/rdma_provider/rdma_provider_mlx5_dv.c | 31 +++++++++++------------ lib/rdma_provider/rdma_provider_verbs.c | 1 + 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/include/spdk_internal/rdma_provider.h b/include/spdk_internal/rdma_provider.h index fb0a8eb701d..39babcdab5f 100644 --- a/include/spdk_internal/rdma_provider.h +++ b/include/spdk_internal/rdma_provider.h @@ -36,6 +36,8 @@ struct spdk_rdma_provider_qp_init_attr { struct ibv_pd *pd; struct spdk_rdma_provider_qp_stats *stats; spdk_memory_domain_transfer_data_cb domain_transfer; + /* IPv4 TOS / IPv6 TCLASS. 0 = untagged (rdma-core default). */ + uint8_t tos; }; struct spdk_rdma_provider_send_wr_list { @@ -56,6 +58,7 @@ struct spdk_rdma_provider_qp { struct spdk_rdma_provider_recv_wr_list recv_wrs; struct spdk_rdma_provider_qp_stats *stats; bool shared_stats; + uint8_t tos; }; struct spdk_rdma_provider_srq_init_attr { diff --git a/lib/nvme/nvme_rdma.c b/lib/nvme/nvme_rdma.c index 577ee8910d6..0e04a8c2cba 100644 --- a/lib/nvme/nvme_rdma.c +++ b/lib/nvme/nvme_rdma.c @@ -819,6 +819,7 @@ nvme_rdma_qpair_init(struct nvme_rdma_qpair *rqpair) attr.cap.max_recv_sge = spdk_min(NVME_RDMA_DEFAULT_RX_SGE, dev_attr.max_sge); attr.domain_transfer = spdk_rdma_provider_accel_sequence_supported() ? nvme_rdma_memory_domain_transfer_data : NULL; + attr.tos = rqpair->qpair.ctrlr->opts.transport_tos; rqpair->rdma_qp = spdk_rdma_provider_qp_create(rqpair->cm_id, &attr); diff --git a/lib/nvmf/rdma.c b/lib/nvmf/rdma.c index 9237a6a0181..b561c23754b 100644 --- a/lib/nvmf/rdma.c +++ b/lib/nvmf/rdma.c @@ -1042,6 +1042,7 @@ nvmf_rdma_qpair_initialize(struct spdk_nvmf_qpair *qpair) rqpair = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_rdma_qpair, qpair); device = rqpair->device; + rtransport = SPDK_CONTAINEROF(qpair->transport, struct spdk_nvmf_rdma_transport, transport); qp_init_attr.qp_context = rqpair; qp_init_attr.pd = device->pd; @@ -1059,6 +1060,7 @@ nvmf_rdma_qpair_initialize(struct spdk_nvmf_qpair *qpair) qp_init_attr.cap.max_send_sge = spdk_min((uint32_t)device->attr.max_sge, NVMF_DEFAULT_TX_SGE); qp_init_attr.cap.max_recv_sge = spdk_min((uint32_t)device->attr.max_sge, NVMF_DEFAULT_RX_SGE); qp_init_attr.stats = &rqpair->poller->stat.qp_stats; + qp_init_attr.tos = rtransport->rdma_opts.tos; if (rqpair->srq == NULL && nvmf_rdma_resize_cq(rqpair, device) < 0) { SPDK_ERRLOG("Failed to resize the completion queue. Cannot initialize qpair.\n"); diff --git a/lib/rdma_provider/rdma_provider_mlx5_dv.c b/lib/rdma_provider/rdma_provider_mlx5_dv.c index e0df58f200a..d5da5d41db0 100644 --- a/lib/rdma_provider/rdma_provider_mlx5_dv.c +++ b/lib/rdma_provider/rdma_provider_mlx5_dv.c @@ -26,30 +26,28 @@ struct spdk_rdma_mlx5_dv_qp { /* * rdma_set_option(RDMA_OPTION_ID_TOS) programs SL (SQ / tx_prio). mlx5_dv * moves the QP itself via ibv_modify_qp, so ConnectX builds the RoCEv2 - * IPv4 header from the RTR AV traffic_class. Inferring TOS from ah_attr.sl - * is a no-op: the RTR AV often has sl=0 even when the SQ is prio 3. - * - * Force IEEE 802.1p class 3 → TOS 96 / DSCP 24 (CS3), matching Longhorn - * dataEngineRdmaPriorityClass v2=3. Do not add IBV_QP_AV if the kernel - * did not already supply a full AV. + * IPv4 header from the RTR AV traffic_class. Copy the caller-configured + * TOS (nvme transport_tos / nvmf tos) into that AV. Do not add IBV_QP_AV + * if the kernel did not already supply a full AV. TOS 0 leaves the AV + * untagged. */ -#define RDMA_MLX5_DV_ROCE_TOS 96 -#define RDMA_MLX5_DV_ROCE_SL 3 - static void -rdma_mlx5_dv_fill_roce_tos(struct ibv_qp_attr *qp_attr, int qp_attr_mask) +rdma_mlx5_dv_fill_roce_tos(struct ibv_qp_attr *qp_attr, int qp_attr_mask, uint8_t tos) { + if (tos == 0) { + return; + } if ((qp_attr_mask & IBV_QP_AV) == 0) { - SPDK_NOTICELOG("RoCE RTR missing IBV_QP_AV, cannot set TOS (mask=0x%x)\n", - qp_attr_mask); + SPDK_NOTICELOG("RoCE RTR missing IBV_QP_AV, cannot set TOS %u (mask=0x%x)\n", + tos, qp_attr_mask); return; } - qp_attr->ah_attr.sl = RDMA_MLX5_DV_ROCE_SL; - qp_attr->ah_attr.grh.traffic_class = RDMA_MLX5_DV_ROCE_TOS; + qp_attr->ah_attr.sl = tos >> 5; + qp_attr->ah_attr.grh.traffic_class = tos; SPDK_NOTICELOG("RoCE RTR TOS %u sl %u tclass %u is_global %d mask=0x%x\n", - RDMA_MLX5_DV_ROCE_TOS, + tos, qp_attr->ah_attr.sl, qp_attr->ah_attr.grh.traffic_class, qp_attr->ah_attr.is_global, @@ -82,7 +80,7 @@ rdma_mlx5_dv_init_qpair(struct spdk_rdma_mlx5_dv_qp *mlx5_qp) return rc; } - rdma_mlx5_dv_fill_roce_tos(&qp_attr, qp_attr_mask); + rdma_mlx5_dv_fill_roce_tos(&qp_attr, qp_attr_mask, mlx5_qp->common.tos); rc = ibv_modify_qp(mlx5_qp->common.qp, &qp_attr, qp_attr_mask); if (rc) { @@ -160,6 +158,7 @@ spdk_rdma_provider_qp_create(struct rdma_cm_id *cm_id, mlx5_qp->common.qp = qp; mlx5_qp->common.cm_id = cm_id; + mlx5_qp->common.tos = qp_attr->tos; mlx5_qp->qpex = ibv_qp_to_qp_ex(qp); if (!mlx5_qp->qpex) { diff --git a/lib/rdma_provider/rdma_provider_verbs.c b/lib/rdma_provider/rdma_provider_verbs.c index 0527f4c0c53..5b09848e5d3 100644 --- a/lib/rdma_provider/rdma_provider_verbs.c +++ b/lib/rdma_provider/rdma_provider_verbs.c @@ -63,6 +63,7 @@ spdk_rdma_provider_qp_create(struct rdma_cm_id *cm_id, } spdk_rdma_qp->qp = cm_id->qp; spdk_rdma_qp->cm_id = cm_id; + spdk_rdma_qp->tos = qp_attr->tos; spdk_rdma_qp->domain = spdk_rdma_utils_get_memory_domain(qp_attr->pd); if (!spdk_rdma_qp->domain) { spdk_rdma_provider_qp_destroy(spdk_rdma_qp);