Commit 51a83391 authored by Dimitris Michailidis's avatar Dimitris Michailidis Committed by Paolo Abeni

net/funeth: Fix fun_xdp_tx() and XDP packet reclaim

The current implementation of fun_xdp_tx(), used for XPD_TX, is
incorrect in that it takes an address/length pair and later releases it
with page_frag_free(). It is OK for XDP_TX but the same code is used by
ndo_xdp_xmit. In that case it loses the XDP memory type and releases the
packet incorrectly for some of the types. Assorted breakage follows.

Change fun_xdp_tx() to take xdp_frame and rely on xdp_return_frame() in
reclaim.

Fixes: db37bc17 ("net/funeth: add the data path")
Signed-off-by: default avatarDimitris Michailidis <dmichail@fungible.com>
Link: https://lore.kernel.org/r/20220726215923.7887-1-dmichail@fungible.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent bf84719d
...@@ -142,6 +142,7 @@ static void *fun_run_xdp(struct funeth_rxq *q, skb_frag_t *frags, void *buf_va, ...@@ -142,6 +142,7 @@ static void *fun_run_xdp(struct funeth_rxq *q, skb_frag_t *frags, void *buf_va,
int ref_ok, struct funeth_txq *xdp_q) int ref_ok, struct funeth_txq *xdp_q)
{ {
struct bpf_prog *xdp_prog; struct bpf_prog *xdp_prog;
struct xdp_frame *xdpf;
struct xdp_buff xdp; struct xdp_buff xdp;
u32 act; u32 act;
...@@ -163,7 +164,9 @@ static void *fun_run_xdp(struct funeth_rxq *q, skb_frag_t *frags, void *buf_va, ...@@ -163,7 +164,9 @@ static void *fun_run_xdp(struct funeth_rxq *q, skb_frag_t *frags, void *buf_va,
case XDP_TX: case XDP_TX:
if (unlikely(!ref_ok)) if (unlikely(!ref_ok))
goto pass; goto pass;
if (!fun_xdp_tx(xdp_q, xdp.data, xdp.data_end - xdp.data))
xdpf = xdp_convert_buff_to_frame(&xdp);
if (!xdpf || !fun_xdp_tx(xdp_q, xdpf))
goto xdp_error; goto xdp_error;
FUN_QSTAT_INC(q, xdp_tx); FUN_QSTAT_INC(q, xdp_tx);
q->xdp_flush |= FUN_XDP_FLUSH_TX; q->xdp_flush |= FUN_XDP_FLUSH_TX;
......
...@@ -466,7 +466,7 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget) ...@@ -466,7 +466,7 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget)
do { do {
fun_xdp_unmap(q, reclaim_idx); fun_xdp_unmap(q, reclaim_idx);
page_frag_free(q->info[reclaim_idx].vaddr); xdp_return_frame(q->info[reclaim_idx].xdpf);
trace_funeth_tx_free(q, reclaim_idx, 1, head); trace_funeth_tx_free(q, reclaim_idx, 1, head);
...@@ -479,11 +479,11 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget) ...@@ -479,11 +479,11 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget)
return npkts; return npkts;
} }
bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len) bool fun_xdp_tx(struct funeth_txq *q, struct xdp_frame *xdpf)
{ {
struct fun_eth_tx_req *req; struct fun_eth_tx_req *req;
struct fun_dataop_gl *gle; struct fun_dataop_gl *gle;
unsigned int idx; unsigned int idx, len;
dma_addr_t dma; dma_addr_t dma;
if (fun_txq_avail(q) < FUN_XDP_CLEAN_THRES) if (fun_txq_avail(q) < FUN_XDP_CLEAN_THRES)
...@@ -494,7 +494,8 @@ bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len) ...@@ -494,7 +494,8 @@ bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len)
return false; return false;
} }
dma = dma_map_single(q->dma_dev, data, len, DMA_TO_DEVICE); len = xdpf->len;
dma = dma_map_single(q->dma_dev, xdpf->data, len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(q->dma_dev, dma))) { if (unlikely(dma_mapping_error(q->dma_dev, dma))) {
FUN_QSTAT_INC(q, tx_map_err); FUN_QSTAT_INC(q, tx_map_err);
return false; return false;
...@@ -514,7 +515,7 @@ bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len) ...@@ -514,7 +515,7 @@ bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len)
gle = (struct fun_dataop_gl *)req->dataop.imm; gle = (struct fun_dataop_gl *)req->dataop.imm;
fun_dataop_gl_init(gle, 0, 0, len, dma); fun_dataop_gl_init(gle, 0, 0, len, dma);
q->info[idx].vaddr = data; q->info[idx].xdpf = xdpf;
u64_stats_update_begin(&q->syncp); u64_stats_update_begin(&q->syncp);
q->stats.tx_bytes += len; q->stats.tx_bytes += len;
...@@ -545,12 +546,9 @@ int fun_xdp_xmit_frames(struct net_device *dev, int n, ...@@ -545,12 +546,9 @@ int fun_xdp_xmit_frames(struct net_device *dev, int n,
if (unlikely(q_idx >= fp->num_xdpqs)) if (unlikely(q_idx >= fp->num_xdpqs))
return -ENXIO; return -ENXIO;
for (q = xdpqs[q_idx], i = 0; i < n; i++) { for (q = xdpqs[q_idx], i = 0; i < n; i++)
const struct xdp_frame *xdpf = frames[i]; if (!fun_xdp_tx(q, frames[i]))
if (!fun_xdp_tx(q, xdpf->data, xdpf->len))
break; break;
}
if (unlikely(flags & XDP_XMIT_FLUSH)) if (unlikely(flags & XDP_XMIT_FLUSH))
fun_txq_wr_db(q); fun_txq_wr_db(q);
...@@ -577,7 +575,7 @@ static void fun_xdpq_purge(struct funeth_txq *q) ...@@ -577,7 +575,7 @@ static void fun_xdpq_purge(struct funeth_txq *q)
unsigned int idx = q->cons_cnt & q->mask; unsigned int idx = q->cons_cnt & q->mask;
fun_xdp_unmap(q, idx); fun_xdp_unmap(q, idx);
page_frag_free(q->info[idx].vaddr); xdp_return_frame(q->info[idx].xdpf);
q->cons_cnt++; q->cons_cnt++;
} }
} }
......
...@@ -95,8 +95,8 @@ struct funeth_txq_stats { /* per Tx queue SW counters */ ...@@ -95,8 +95,8 @@ struct funeth_txq_stats { /* per Tx queue SW counters */
struct funeth_tx_info { /* per Tx descriptor state */ struct funeth_tx_info { /* per Tx descriptor state */
union { union {
struct sk_buff *skb; /* associated packet */ struct sk_buff *skb; /* associated packet (sk_buff path) */
void *vaddr; /* start address for XDP */ struct xdp_frame *xdpf; /* associated XDP frame (XDP path) */
}; };
}; };
...@@ -245,7 +245,7 @@ static inline int fun_irq_node(const struct fun_irq *p) ...@@ -245,7 +245,7 @@ static inline int fun_irq_node(const struct fun_irq *p)
int fun_rxq_napi_poll(struct napi_struct *napi, int budget); int fun_rxq_napi_poll(struct napi_struct *napi, int budget);
int fun_txq_napi_poll(struct napi_struct *napi, int budget); int fun_txq_napi_poll(struct napi_struct *napi, int budget);
netdev_tx_t fun_start_xmit(struct sk_buff *skb, struct net_device *netdev); netdev_tx_t fun_start_xmit(struct sk_buff *skb, struct net_device *netdev);
bool fun_xdp_tx(struct funeth_txq *q, void *data, unsigned int len); bool fun_xdp_tx(struct funeth_txq *q, struct xdp_frame *xdpf);
int fun_xdp_xmit_frames(struct net_device *dev, int n, int fun_xdp_xmit_frames(struct net_device *dev, int n,
struct xdp_frame **frames, u32 flags); struct xdp_frame **frames, u32 flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment