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

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.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent bf84719d
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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)
{
	struct bpf_prog *xdp_prog;
	struct xdp_frame *xdpf;
	struct xdp_buff xdp;
	u32 act;

@@ -163,7 +164,9 @@ static void *fun_run_xdp(struct funeth_rxq *q, skb_frag_t *frags, void *buf_va,
	case XDP_TX:
		if (unlikely(!ref_ok))
			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;
		FUN_QSTAT_INC(q, xdp_tx);
		q->xdp_flush |= FUN_XDP_FLUSH_TX;
+9 −11
Original line number Diff line number Diff line
@@ -466,7 +466,7 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget)

		do {
			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);

@@ -479,11 +479,11 @@ static unsigned int fun_xdpq_clean(struct funeth_txq *q, unsigned int budget)
	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_dataop_gl *gle;
	unsigned int idx;
	unsigned int idx, len;
	dma_addr_t dma;

	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)
		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))) {
		FUN_QSTAT_INC(q, tx_map_err);
		return false;
@@ -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;
	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);
	q->stats.tx_bytes += len;
@@ -545,12 +546,9 @@ int fun_xdp_xmit_frames(struct net_device *dev, int n,
	if (unlikely(q_idx >= fp->num_xdpqs))
		return -ENXIO;

	for (q = xdpqs[q_idx], i = 0; i < n; i++) {
		const struct xdp_frame *xdpf = frames[i];

		if (!fun_xdp_tx(q, xdpf->data, xdpf->len))
	for (q = xdpqs[q_idx], i = 0; i < n; i++)
		if (!fun_xdp_tx(q, frames[i]))
			break;
	}

	if (unlikely(flags & XDP_XMIT_FLUSH))
		fun_txq_wr_db(q);
@@ -577,7 +575,7 @@ static void fun_xdpq_purge(struct funeth_txq *q)
		unsigned int idx = q->cons_cnt & q->mask;

		fun_xdp_unmap(q, idx);
		page_frag_free(q->info[idx].vaddr);
		xdp_return_frame(q->info[idx].xdpf);
		q->cons_cnt++;
	}
}
+3 −3
Original line number Diff line number Diff line
@@ -95,8 +95,8 @@ struct funeth_txq_stats { /* per Tx queue SW counters */

struct funeth_tx_info {      /* per Tx descriptor state */
	union {
		struct sk_buff *skb; /* associated packet */
		void *vaddr;         /* start address for XDP */
		struct sk_buff *skb;    /* associated packet (sk_buff path) */
		struct xdp_frame *xdpf; /* associated XDP frame (XDP path) */
	};
};

@@ -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_txq_napi_poll(struct napi_struct *napi, int budget);
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,
			struct xdp_frame **frames, u32 flags);