Skip to content

Commit 90a9693

Browse files
ameryhungKernel Patches Daemon
authored andcommitted
net/mlx5e: Fix generating skb from nonlinear xdp_buff
xdp programs can change the layout of an xdp_buff through bpf_xdp_adjust_tail(), bpf_xdp_adjust_head(). Therefore, the driver cannot assume the size of the linear data area nor fragments. Fix the bug in mlx5e driver by generating skb according to xdp_buff layout. Currently, when handling multi-buf xdp, the mlx5e driver assumes the layout of an xdp_buff to be unchanged. That is, the linear data area continues to be empty and the fragments remains the same. This may cause the driver to generate erroneous skb or triggering a kernel warning. When an xdp program added linear data through bpf_xdp_adjust_head() the linear data will be ignored as mlx5e_build_linear_skb() builds an skb with empty linear data and then pull data from fragments to fill the linear data area. When an xdp program has shrunk the nonlinear data through bpf_xdp_adjust_tail(), the delta passed to __pskb_pull_tail() may exceed the actual nonlinear data size and trigger the BUG_ON in it. To fix the issue, first build the skb with linear data area matching the xdp_buff. Then, call __pskb_pull_tail() to fill the linear data for up to MLX5E_RX_MAX_HEAD bytes. In addition, recalculate nr_frags and truesize after xdp program runs. Fixes: f52ac70 ("net/mlx5e: RX, Add XDP multi-buffer support in Striding RQ") Signed-off-by: Amery Hung <[email protected]>
1 parent 07f2c0d commit 90a9693

File tree

1 file changed

+43
-16
lines changed
  • drivers/net/ethernet/mellanox/mlx5/core

1 file changed

+43
-16
lines changed

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

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,16 +1725,17 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
17251725
struct mlx5_cqe64 *cqe, u32 cqe_bcnt)
17261726
{
17271727
struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0];
1728+
struct mlx5e_wqe_frag_info *pwi, *head_wi = wi;
17281729
struct mlx5e_xdp_buff *mxbuf = &rq->mxbuf;
1729-
struct mlx5e_wqe_frag_info *head_wi = wi;
17301730
u16 rx_headroom = rq->buff.headroom;
17311731
struct mlx5e_frag_page *frag_page;
17321732
struct skb_shared_info *sinfo;
1733-
u32 frag_consumed_bytes;
1733+
u32 frag_consumed_bytes, i;
17341734
struct bpf_prog *prog;
17351735
struct sk_buff *skb;
17361736
dma_addr_t addr;
17371737
u32 truesize;
1738+
u8 nr_frags;
17381739
void *va;
17391740

17401741
frag_page = wi->frag_page;
@@ -1775,14 +1776,26 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
17751776
prog = rcu_dereference(rq->xdp_prog);
17761777
if (prog && mlx5e_xdp_handle(rq, prog, mxbuf)) {
17771778
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
1778-
struct mlx5e_wqe_frag_info *pwi;
1779+
pwi = head_wi;
1780+
while (pwi->frag_page->netmem != sinfo->frags[0].netmem && pwi < wi)
1781+
pwi++;
17791782

1780-
for (pwi = head_wi; pwi < wi; pwi++)
1783+
for (i = 0; i < sinfo->nr_frags; i++, pwi++)
17811784
pwi->frag_page->frags++;
17821785
}
17831786
return NULL; /* page/packet was consumed by XDP */
17841787
}
17851788

1789+
nr_frags = sinfo->nr_frags;
1790+
pwi = head_wi + 1;
1791+
1792+
if (prog) {
1793+
truesize = sinfo->nr_frags * frag_info->frag_stride;
1794+
1795+
while (pwi->frag_page->netmem != sinfo->frags[0].netmem && pwi < wi)
1796+
pwi++;
1797+
}
1798+
17861799
skb = mlx5e_build_linear_skb(
17871800
rq, mxbuf->xdp.data_hard_start, rq->buff.frame0_sz,
17881801
mxbuf->xdp.data - mxbuf->xdp.data_hard_start,
@@ -1796,12 +1809,12 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi
17961809

17971810
if (xdp_buff_has_frags(&mxbuf->xdp)) {
17981811
/* sinfo->nr_frags is reset by build_skb, calculate again. */
1799-
xdp_update_skb_shared_info(skb, wi - head_wi - 1,
1812+
xdp_update_skb_shared_info(skb, nr_frags,
18001813
sinfo->xdp_frags_size, truesize,
18011814
xdp_buff_is_frag_pfmemalloc(
18021815
&mxbuf->xdp));
18031816

1804-
for (struct mlx5e_wqe_frag_info *pwi = head_wi + 1; pwi < wi; pwi++)
1817+
for (i = 0; i < nr_frags; i++, pwi++)
18051818
pwi->frag_page->frags++;
18061819
}
18071820

@@ -2073,12 +2086,18 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
20732086
}
20742087

20752088
if (prog) {
2089+
u8 nr_frags;
2090+
u32 len, i;
2091+
20762092
if (mlx5e_xdp_handle(rq, prog, mxbuf)) {
20772093
if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) {
2078-
struct mlx5e_frag_page *pfp;
2094+
struct mlx5e_frag_page *pagep = head_page;
2095+
2096+
while (pagep->netmem != sinfo->frags[0].netmem && pagep < frag_page)
2097+
pagep++;
20792098

2080-
for (pfp = head_page; pfp < frag_page; pfp++)
2081-
pfp->frags++;
2099+
for (i = 0; i < sinfo->nr_frags; i++)
2100+
pagep->frags++;
20822101

20832102
wi->linear_page.frags++;
20842103
}
@@ -2087,9 +2106,12 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
20872106
return NULL; /* page/packet was consumed by XDP */
20882107
}
20892108

2109+
len = mxbuf->xdp.data_end - mxbuf->xdp.data;
2110+
nr_frags = sinfo->nr_frags;
2111+
20902112
skb = mlx5e_build_linear_skb(
20912113
rq, mxbuf->xdp.data_hard_start, linear_frame_sz,
2092-
mxbuf->xdp.data - mxbuf->xdp.data_hard_start, 0,
2114+
mxbuf->xdp.data - mxbuf->xdp.data_hard_start, len,
20932115
mxbuf->xdp.data - mxbuf->xdp.data_meta);
20942116
if (unlikely(!skb)) {
20952117
mlx5e_page_release_fragmented(rq->page_pool,
@@ -2102,20 +2124,25 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w
21022124
mlx5e_page_release_fragmented(rq->page_pool, &wi->linear_page);
21032125

21042126
if (xdp_buff_has_frags(&mxbuf->xdp)) {
2105-
struct mlx5e_frag_page *pagep;
2127+
struct mlx5e_frag_page *pagep = head_page;
2128+
2129+
truesize = nr_frags * PAGE_SIZE;
21062130

21072131
/* sinfo->nr_frags is reset by build_skb, calculate again. */
2108-
xdp_update_skb_shared_info(skb, frag_page - head_page,
2132+
xdp_update_skb_shared_info(skb, nr_frags,
21092133
sinfo->xdp_frags_size, truesize,
21102134
xdp_buff_is_frag_pfmemalloc(
21112135
&mxbuf->xdp));
21122136

2113-
pagep = head_page;
2114-
do
2137+
while (pagep->netmem != sinfo->frags[0].netmem && pagep < frag_page)
2138+
pagep++;
2139+
2140+
for (i = 0; i < nr_frags; i++, pagep++)
21152141
pagep->frags++;
2116-
while (++pagep < frag_page);
2142+
2143+
headlen = min_t(u16, MLX5E_RX_MAX_HEAD - len, sinfo->xdp_frags_size);
2144+
__pskb_pull_tail(skb, headlen);
21172145
}
2118-
__pskb_pull_tail(skb, headlen);
21192146
} else {
21202147
dma_addr_t addr;
21212148

0 commit comments

Comments
 (0)