Skip to content

Commit 1392134

Browse files
nvmmaxkuba-moo
authored andcommitted
net/mlx5e: xsk: Use KLM to protect frame overrun in unaligned mode
XSK RQs support striding RQ linear mode, but the stride size may be bigger than the XSK frame size, because: 1. The stride size must be a power of two. 2. The stride size must be equal to the UMR page size. Each XSK frame is treated as a separate page, because they aren't necessarily adjacent in physical memory, so the driver can't put more than one stride per page. 3. The minimal MTT page size is 4096 on older firmware. That means that if XSK frame size is 2048 or not a power of two, the strides may be bigger than XSK frames. Normally, it's not a problem if the hardware enforces the MTU. However, traffic between vports skips the hardware MTU check, and oversized packets may be received. If an oversized packet is bigger than the XSK frame but not bigger than the stride, it will cause overwriting of the adjacent UMEM region. If the packet takes more than one stride, they can be recycled for reuse, so it's not a problem when the XSK frame size matches the stride size. Work around the above issue by leveraging KLM to make a more fine-grained mapping. The beginning of each stride is mapped to the frame memory, and the padding up to the closest power of two is mapped to the overflow page that doesn't belong to UMEM. This way, application data corruption won't happen upon receiving packets bigger than MTU. Signed-off-by: Maxim Mikityanskiy <[email protected]> Reviewed-by: Tariq Toukan <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 9f123f7 commit 1392134

File tree

4 files changed

+90
-10
lines changed

4 files changed

+90
-10
lines changed

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ struct mlx5e_hw_gro_data {
680680
enum mlx5e_mpwrq_umr_mode {
681681
MLX5E_MPWRQ_UMR_MODE_ALIGNED,
682682
MLX5E_MPWRQ_UMR_MODE_UNALIGNED,
683+
MLX5E_MPWRQ_UMR_MODE_OVERSIZED,
683684
};
684685

685686
struct mlx5e_rq {

drivers/net/ethernet/mellanox/mlx5/core/en/params.c

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,28 @@ mlx5e_mpwrq_umr_mode(struct mlx5_core_dev *mdev, struct mlx5e_xsk_param *xsk)
3636
* 1. MTT - direct mapping in page granularity.
3737
* 2. KSM - indirect mapping to another MKey to arbitrary addresses, but
3838
* all mappings have the same size.
39+
* 3. KLM - indirect mapping to another MKey to arbitrary addresses, and
40+
* mappings can have different sizes.
3941
*/
42+
u8 page_shift = mlx5e_mpwrq_page_shift(mdev, xsk);
4043
bool unaligned = xsk ? xsk->unaligned : false;
44+
bool oversized = false;
45+
46+
if (xsk) {
47+
oversized = xsk->chunk_size < (1 << page_shift);
48+
WARN_ON_ONCE(xsk->chunk_size > (1 << page_shift));
49+
}
50+
51+
/* XSK frame size doesn't match the UMR page size, either because the
52+
* frame size is not a power of two, or it's smaller than the minimal
53+
* page size supported by the firmware.
54+
* It's possible to receive packets bigger than MTU in certain setups.
55+
* To avoid writing over the XSK frame boundary, the top region of each
56+
* stride is mapped to a garbage page, resulting in two mappings of
57+
* different sizes per frame.
58+
*/
59+
if (oversized)
60+
return MLX5E_MPWRQ_UMR_MODE_OVERSIZED;
4161

4262
/* XSK frames can start at arbitrary unaligned locations, but they all
4363
* have the same size which is a power of two. It allows to optimize to
@@ -60,6 +80,8 @@ u8 mlx5e_mpwrq_umr_entry_size(enum mlx5e_mpwrq_umr_mode mode)
6080
return sizeof(struct mlx5_mtt);
6181
case MLX5E_MPWRQ_UMR_MODE_UNALIGNED:
6282
return sizeof(struct mlx5_ksm);
83+
case MLX5E_MPWRQ_UMR_MODE_OVERSIZED:
84+
return sizeof(struct mlx5_klm) * 2;
6385
}
6486
WARN_ONCE(1, "MPWRQ UMR mode %d is not known\n", mode);
6587
return 0;
@@ -145,11 +167,21 @@ u8 mlx5e_mpwrq_mtts_per_wqe(struct mlx5_core_dev *mdev, u8 page_shift,
145167
u32 mlx5e_mpwrq_max_num_entries(struct mlx5_core_dev *mdev,
146168
enum mlx5e_mpwrq_umr_mode umr_mode)
147169
{
148-
if (umr_mode == MLX5E_MPWRQ_UMR_MODE_UNALIGNED)
149-
return min(MLX5E_MAX_RQ_NUM_KSMS,
150-
1 << MLX5_CAP_GEN(mdev, log_max_klm_list_size));
170+
/* Same limits apply to KSMs and KLMs. */
171+
u32 klm_limit = min(MLX5E_MAX_RQ_NUM_KSMS,
172+
1 << MLX5_CAP_GEN(mdev, log_max_klm_list_size));
151173

152-
return MLX5E_MAX_RQ_NUM_MTTS;
174+
switch (umr_mode) {
175+
case MLX5E_MPWRQ_UMR_MODE_ALIGNED:
176+
return MLX5E_MAX_RQ_NUM_MTTS;
177+
case MLX5E_MPWRQ_UMR_MODE_UNALIGNED:
178+
return klm_limit;
179+
case MLX5E_MPWRQ_UMR_MODE_OVERSIZED:
180+
/* Each entry is two KLMs. */
181+
return klm_limit / 2;
182+
}
183+
WARN_ONCE(1, "MPWRQ UMR mode %d is not known\n", umr_mode);
184+
return 0;
153185
}
154186

155187
static u8 mlx5e_mpwrq_max_log_rq_size(struct mlx5_core_dev *mdev, u8 page_shift,
@@ -1084,6 +1116,11 @@ static u8 mlx5e_build_icosq_log_wq_sz(struct mlx5_core_dev *mdev,
10841116
xsk.unaligned = true;
10851117
max_xsk_wqebbs = max(max_xsk_wqebbs,
10861118
mlx5e_mpwrq_total_umr_wqebbs(mdev, params, &xsk));
1119+
1120+
/* XSK unaligned mode, frame size is not equal to stride size. */
1121+
xsk.chunk_size -= 1;
1122+
max_xsk_wqebbs = max(max_xsk_wqebbs,
1123+
mlx5e_mpwrq_total_umr_wqebbs(mdev, params, &xsk));
10871124
}
10881125

10891126
wqebbs += max_xsk_wqebbs;

drivers/net/ethernet/mellanox/mlx5/core/en/xsk/rx.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,15 @@ int mlx5e_xsk_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
4141
umr_wqe = mlx5_wq_cyc_get_wqe(wq, pi);
4242
memcpy(umr_wqe, &rq->mpwqe.umr_wqe, sizeof(struct mlx5e_umr_wqe));
4343

44-
if (unlikely(rq->mpwqe.umr_mode == MLX5E_MPWRQ_UMR_MODE_UNALIGNED)) {
44+
if (likely(rq->mpwqe.umr_mode == MLX5E_MPWRQ_UMR_MODE_ALIGNED)) {
45+
for (i = 0; i < batch; i++) {
46+
dma_addr_t addr = xsk_buff_xdp_get_frame_dma(wi->alloc_units[i].xsk);
47+
48+
umr_wqe->inline_mtts[i] = (struct mlx5_mtt) {
49+
.ptag = cpu_to_be64(addr | MLX5_EN_WR),
50+
};
51+
}
52+
} else if (unlikely(rq->mpwqe.umr_mode == MLX5E_MPWRQ_UMR_MODE_UNALIGNED)) {
4553
for (i = 0; i < batch; i++) {
4654
dma_addr_t addr = xsk_buff_xdp_get_frame_dma(wi->alloc_units[i].xsk);
4755

@@ -51,11 +59,22 @@ int mlx5e_xsk_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
5159
};
5260
}
5361
} else {
62+
__be32 pad_size = cpu_to_be32((1 << rq->mpwqe.page_shift) -
63+
rq->xsk_pool->chunk_size);
64+
__be32 frame_size = cpu_to_be32(rq->xsk_pool->chunk_size);
65+
5466
for (i = 0; i < batch; i++) {
5567
dma_addr_t addr = xsk_buff_xdp_get_frame_dma(wi->alloc_units[i].xsk);
5668

57-
umr_wqe->inline_mtts[i] = (struct mlx5_mtt) {
58-
.ptag = cpu_to_be64(addr | MLX5_EN_WR),
69+
umr_wqe->inline_klms[i << 1] = (struct mlx5_klm) {
70+
.key = rq->mkey_be,
71+
.va = cpu_to_be64(addr),
72+
.bcount = frame_size,
73+
};
74+
umr_wqe->inline_klms[(i << 1) + 1] = (struct mlx5_klm) {
75+
.key = rq->mkey_be,
76+
.va = cpu_to_be64(rq->wqe_overflow.addr),
77+
.bcount = pad_size,
5978
};
6079
}
6180
}
@@ -70,6 +89,8 @@ int mlx5e_xsk_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
7089
offset = ix * rq->mpwqe.mtts_per_wqe;
7190
if (likely(rq->mpwqe.umr_mode == MLX5E_MPWRQ_UMR_MODE_ALIGNED))
7291
offset = offset * sizeof(struct mlx5_mtt) / MLX5_OCTWORD;
92+
else if (unlikely(rq->mpwqe.umr_mode == MLX5E_MPWRQ_UMR_MODE_OVERSIZED))
93+
offset = offset * sizeof(struct mlx5_klm) * 2 / MLX5_OCTWORD;
7394
umr_wqe->uctrl.xlt_offset = cpu_to_be16(offset);
7495

7596
icosq->db.wqe_info[pi] = (struct mlx5e_icosq_wqe_info) {

drivers/net/ethernet/mellanox/mlx5/core/en_main.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ static u8 mlx5e_mpwrq_access_mode(enum mlx5e_mpwrq_umr_mode umr_mode)
299299
return MLX5_MKC_ACCESS_MODE_MTT;
300300
case MLX5E_MPWRQ_UMR_MODE_UNALIGNED:
301301
return MLX5_MKC_ACCESS_MODE_KSM;
302+
case MLX5E_MPWRQ_UMR_MODE_OVERSIZED:
303+
return MLX5_MKC_ACCESS_MODE_KLMS;
302304
}
303305
WARN_ONCE(1, "MPWRQ UMR mode %d is not known\n", umr_mode);
304306
return 0;
@@ -307,10 +309,12 @@ static u8 mlx5e_mpwrq_access_mode(enum mlx5e_mpwrq_umr_mode umr_mode)
307309
static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
308310
u32 npages, u8 page_shift, u32 *umr_mkey,
309311
dma_addr_t filler_addr,
310-
enum mlx5e_mpwrq_umr_mode umr_mode)
312+
enum mlx5e_mpwrq_umr_mode umr_mode,
313+
u32 xsk_chunk_size)
311314
{
312315
struct mlx5_mtt *mtt;
313316
struct mlx5_ksm *ksm;
317+
struct mlx5_klm *klm;
314318
u32 octwords;
315319
int inlen;
316320
void *mkc;
@@ -347,7 +351,8 @@ static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
347351
MLX5_SET(mkc, mkc, pd, mdev->mlx5e_res.hw_objs.pdn);
348352
MLX5_SET64(mkc, mkc, len, npages << page_shift);
349353
MLX5_SET(mkc, mkc, translations_octword_size, octwords);
350-
MLX5_SET(mkc, mkc, log_page_size, page_shift);
354+
if (umr_mode != MLX5E_MPWRQ_UMR_MODE_OVERSIZED)
355+
MLX5_SET(mkc, mkc, log_page_size, page_shift);
351356
MLX5_SET(create_mkey_in, in, translations_octword_actual_size, octwords);
352357

353358
/* Initialize the mkey with all MTTs pointing to a default
@@ -357,6 +362,21 @@ static int mlx5e_create_umr_mkey(struct mlx5_core_dev *mdev,
357362
* to the default page.
358363
*/
359364
switch (umr_mode) {
365+
case MLX5E_MPWRQ_UMR_MODE_OVERSIZED:
366+
klm = MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
367+
for (i = 0; i < npages; i++) {
368+
klm[i << 1] = (struct mlx5_klm) {
369+
.va = cpu_to_be64(filler_addr),
370+
.bcount = cpu_to_be32(xsk_chunk_size),
371+
.key = cpu_to_be32(mdev->mlx5e_res.hw_objs.mkey),
372+
};
373+
klm[(i << 1) + 1] = (struct mlx5_klm) {
374+
.va = cpu_to_be64(filler_addr),
375+
.bcount = cpu_to_be32((1 << page_shift) - xsk_chunk_size),
376+
.key = cpu_to_be32(mdev->mlx5e_res.hw_objs.mkey),
377+
};
378+
}
379+
break;
360380
case MLX5E_MPWRQ_UMR_MODE_UNALIGNED:
361381
ksm = MLX5_ADDR_OF(create_mkey_in, in, klm_pas_mtt);
362382
for (i = 0; i < npages; i++)
@@ -415,6 +435,7 @@ static int mlx5e_create_umr_klm_mkey(struct mlx5_core_dev *mdev,
415435

416436
static int mlx5e_create_rq_umr_mkey(struct mlx5_core_dev *mdev, struct mlx5e_rq *rq)
417437
{
438+
u32 xsk_chunk_size = rq->xsk_pool ? rq->xsk_pool->chunk_size : 0;
418439
u32 wq_size = mlx5_wq_ll_get_size(&rq->mpwqe.wq);
419440
u32 num_entries, max_num_entries;
420441
u32 umr_mkey;
@@ -432,7 +453,7 @@ static int mlx5e_create_rq_umr_mkey(struct mlx5_core_dev *mdev, struct mlx5e_rq
432453

433454
err = mlx5e_create_umr_mkey(mdev, num_entries, rq->mpwqe.page_shift,
434455
&umr_mkey, rq->wqe_overflow.addr,
435-
rq->mpwqe.umr_mode);
456+
rq->mpwqe.umr_mode, xsk_chunk_size);
436457
rq->mpwqe.umr_mkey_be = cpu_to_be32(umr_mkey);
437458
return err;
438459
}

0 commit comments

Comments
 (0)