xref: /dpdk/lib/bpf/bpf_pkt.c (revision c6552d9a8deffa448de2d5e2e726f50508c1efd2)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2018 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <stdio.h>
699a2dd95SBruce Richardson #include <string.h>
799a2dd95SBruce Richardson #include <errno.h>
899a2dd95SBruce Richardson #include <stdint.h>
999a2dd95SBruce Richardson 
1099a2dd95SBruce Richardson #include <sys/queue.h>
1199a2dd95SBruce Richardson 
1299a2dd95SBruce Richardson #include <rte_common.h>
1399a2dd95SBruce Richardson #include <rte_malloc.h>
1499a2dd95SBruce Richardson #include <rte_log.h>
1599a2dd95SBruce Richardson #include <rte_atomic.h>
1699a2dd95SBruce Richardson #include <rte_mbuf.h>
1799a2dd95SBruce Richardson #include <rte_ethdev.h>
1899a2dd95SBruce Richardson 
1999a2dd95SBruce Richardson #include <rte_bpf_ethdev.h>
2099a2dd95SBruce Richardson #include "bpf_impl.h"
2199a2dd95SBruce Richardson 
2299a2dd95SBruce Richardson /*
2399a2dd95SBruce Richardson  * information about installed BPF rx/tx callback
2499a2dd95SBruce Richardson  */
2599a2dd95SBruce Richardson 
26*c6552d9aSTyler Retzlaff struct __rte_cache_aligned bpf_eth_cbi {
2799a2dd95SBruce Richardson 	/* used by both data & control path */
286e999364STyler Retzlaff 	RTE_ATOMIC(uint32_t) use;    /*usage counter */
2999a2dd95SBruce Richardson 	const struct rte_eth_rxtx_callback *cb;  /* callback handle */
3099a2dd95SBruce Richardson 	struct rte_bpf *bpf;
3199a2dd95SBruce Richardson 	struct rte_bpf_jit jit;
3299a2dd95SBruce Richardson 	/* used by control path only */
3399a2dd95SBruce Richardson 	LIST_ENTRY(bpf_eth_cbi) link;
3499a2dd95SBruce Richardson 	uint16_t port;
3599a2dd95SBruce Richardson 	uint16_t queue;
36*c6552d9aSTyler Retzlaff };
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson /*
3999a2dd95SBruce Richardson  * Odd number means that callback is used by datapath.
4099a2dd95SBruce Richardson  * Even number means that callback is not used by datapath.
4199a2dd95SBruce Richardson  */
4299a2dd95SBruce Richardson #define BPF_ETH_CBI_INUSE  1
4399a2dd95SBruce Richardson 
4499a2dd95SBruce Richardson /*
4599a2dd95SBruce Richardson  * List to manage RX/TX installed callbacks.
4699a2dd95SBruce Richardson  */
4799a2dd95SBruce Richardson LIST_HEAD(bpf_eth_cbi_list, bpf_eth_cbi);
4899a2dd95SBruce Richardson 
4999a2dd95SBruce Richardson enum {
5099a2dd95SBruce Richardson 	BPF_ETH_RX,
5199a2dd95SBruce Richardson 	BPF_ETH_TX,
5299a2dd95SBruce Richardson 	BPF_ETH_NUM,
5399a2dd95SBruce Richardson };
5499a2dd95SBruce Richardson 
5599a2dd95SBruce Richardson /*
5699a2dd95SBruce Richardson  * information about all installed BPF rx/tx callbacks
5799a2dd95SBruce Richardson  */
5899a2dd95SBruce Richardson struct bpf_eth_cbh {
5999a2dd95SBruce Richardson 	rte_spinlock_t lock;
6099a2dd95SBruce Richardson 	struct bpf_eth_cbi_list list;
6199a2dd95SBruce Richardson 	uint32_t type;
6299a2dd95SBruce Richardson };
6399a2dd95SBruce Richardson 
6499a2dd95SBruce Richardson static struct bpf_eth_cbh rx_cbh = {
6599a2dd95SBruce Richardson 	.lock = RTE_SPINLOCK_INITIALIZER,
6699a2dd95SBruce Richardson 	.list = LIST_HEAD_INITIALIZER(list),
6799a2dd95SBruce Richardson 	.type = BPF_ETH_RX,
6899a2dd95SBruce Richardson };
6999a2dd95SBruce Richardson 
7099a2dd95SBruce Richardson static struct bpf_eth_cbh tx_cbh = {
7199a2dd95SBruce Richardson 	.lock = RTE_SPINLOCK_INITIALIZER,
7299a2dd95SBruce Richardson 	.list = LIST_HEAD_INITIALIZER(list),
7399a2dd95SBruce Richardson 	.type = BPF_ETH_TX,
7499a2dd95SBruce Richardson };
7599a2dd95SBruce Richardson 
7699a2dd95SBruce Richardson /*
7799a2dd95SBruce Richardson  * Marks given callback as used by datapath.
7899a2dd95SBruce Richardson  */
7999a2dd95SBruce Richardson static __rte_always_inline void
bpf_eth_cbi_inuse(struct bpf_eth_cbi * cbi)8099a2dd95SBruce Richardson bpf_eth_cbi_inuse(struct bpf_eth_cbi *cbi)
8199a2dd95SBruce Richardson {
8299a2dd95SBruce Richardson 	cbi->use++;
8399a2dd95SBruce Richardson 	/* make sure no store/load reordering could happen */
8499a2dd95SBruce Richardson 	rte_smp_mb();
8599a2dd95SBruce Richardson }
8699a2dd95SBruce Richardson 
8799a2dd95SBruce Richardson /*
8899a2dd95SBruce Richardson  * Marks given callback list as not used by datapath.
8999a2dd95SBruce Richardson  */
9099a2dd95SBruce Richardson static __rte_always_inline void
bpf_eth_cbi_unuse(struct bpf_eth_cbi * cbi)9199a2dd95SBruce Richardson bpf_eth_cbi_unuse(struct bpf_eth_cbi *cbi)
9299a2dd95SBruce Richardson {
9399a2dd95SBruce Richardson 	/* make sure all previous loads are completed */
9499a2dd95SBruce Richardson 	rte_smp_rmb();
9599a2dd95SBruce Richardson 	cbi->use++;
9699a2dd95SBruce Richardson }
9799a2dd95SBruce Richardson 
9899a2dd95SBruce Richardson /*
9999a2dd95SBruce Richardson  * Waits till datapath finished using given callback.
10099a2dd95SBruce Richardson  */
10199a2dd95SBruce Richardson static void
bpf_eth_cbi_wait(const struct bpf_eth_cbi * cbi)10299a2dd95SBruce Richardson bpf_eth_cbi_wait(const struct bpf_eth_cbi *cbi)
10399a2dd95SBruce Richardson {
104388bee69SFeifei Wang 	uint32_t puse;
10599a2dd95SBruce Richardson 
10699a2dd95SBruce Richardson 	/* make sure all previous loads and stores are completed */
10799a2dd95SBruce Richardson 	rte_smp_mb();
10899a2dd95SBruce Richardson 
10999a2dd95SBruce Richardson 	puse = cbi->use;
11099a2dd95SBruce Richardson 
11199a2dd95SBruce Richardson 	/* in use, busy wait till current RX/TX iteration is finished */
11299a2dd95SBruce Richardson 	if ((puse & BPF_ETH_CBI_INUSE) != 0) {
1136e999364STyler Retzlaff 		RTE_WAIT_UNTIL_MASKED((__rte_atomic uint32_t *)(uintptr_t)&cbi->use,
1146e999364STyler Retzlaff 			UINT32_MAX, !=, puse, rte_memory_order_relaxed);
11599a2dd95SBruce Richardson 	}
11699a2dd95SBruce Richardson }
11799a2dd95SBruce Richardson 
11899a2dd95SBruce Richardson static void
bpf_eth_cbi_cleanup(struct bpf_eth_cbi * bc)11999a2dd95SBruce Richardson bpf_eth_cbi_cleanup(struct bpf_eth_cbi *bc)
12099a2dd95SBruce Richardson {
12199a2dd95SBruce Richardson 	bc->bpf = NULL;
12299a2dd95SBruce Richardson 	memset(&bc->jit, 0, sizeof(bc->jit));
12399a2dd95SBruce Richardson }
12499a2dd95SBruce Richardson 
12599a2dd95SBruce Richardson static struct bpf_eth_cbi *
bpf_eth_cbh_find(struct bpf_eth_cbh * cbh,uint16_t port,uint16_t queue)12699a2dd95SBruce Richardson bpf_eth_cbh_find(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue)
12799a2dd95SBruce Richardson {
12899a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
12999a2dd95SBruce Richardson 
13099a2dd95SBruce Richardson 	LIST_FOREACH(cbi, &cbh->list, link) {
13199a2dd95SBruce Richardson 		if (cbi->port == port && cbi->queue == queue)
13299a2dd95SBruce Richardson 			break;
13399a2dd95SBruce Richardson 	}
13499a2dd95SBruce Richardson 	return cbi;
13599a2dd95SBruce Richardson }
13699a2dd95SBruce Richardson 
13799a2dd95SBruce Richardson static struct bpf_eth_cbi *
bpf_eth_cbh_add(struct bpf_eth_cbh * cbh,uint16_t port,uint16_t queue)13899a2dd95SBruce Richardson bpf_eth_cbh_add(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue)
13999a2dd95SBruce Richardson {
14099a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
14199a2dd95SBruce Richardson 
14299a2dd95SBruce Richardson 	/* return an existing one */
14399a2dd95SBruce Richardson 	cbi = bpf_eth_cbh_find(cbh, port, queue);
14499a2dd95SBruce Richardson 	if (cbi != NULL)
14599a2dd95SBruce Richardson 		return cbi;
14699a2dd95SBruce Richardson 
14799a2dd95SBruce Richardson 	cbi = rte_zmalloc(NULL, sizeof(*cbi), RTE_CACHE_LINE_SIZE);
14899a2dd95SBruce Richardson 	if (cbi != NULL) {
14999a2dd95SBruce Richardson 		cbi->port = port;
15099a2dd95SBruce Richardson 		cbi->queue = queue;
15199a2dd95SBruce Richardson 		LIST_INSERT_HEAD(&cbh->list, cbi, link);
15299a2dd95SBruce Richardson 	}
15399a2dd95SBruce Richardson 	return cbi;
15499a2dd95SBruce Richardson }
15599a2dd95SBruce Richardson 
15699a2dd95SBruce Richardson /*
1574a6672c2SStephen Hemminger  * BPF packet processing routines.
15899a2dd95SBruce Richardson  */
15999a2dd95SBruce Richardson 
16099a2dd95SBruce Richardson static inline uint32_t
apply_filter(struct rte_mbuf * mb[],const uint64_t rc[],uint32_t num,uint32_t drop)16199a2dd95SBruce Richardson apply_filter(struct rte_mbuf *mb[], const uint64_t rc[], uint32_t num,
16299a2dd95SBruce Richardson 	uint32_t drop)
16399a2dd95SBruce Richardson {
16499a2dd95SBruce Richardson 	uint32_t i, j, k;
16599a2dd95SBruce Richardson 	struct rte_mbuf *dr[num];
16699a2dd95SBruce Richardson 
16799a2dd95SBruce Richardson 	for (i = 0, j = 0, k = 0; i != num; i++) {
16899a2dd95SBruce Richardson 
16999a2dd95SBruce Richardson 		/* filter matches */
17099a2dd95SBruce Richardson 		if (rc[i] != 0)
17199a2dd95SBruce Richardson 			mb[j++] = mb[i];
17299a2dd95SBruce Richardson 		/* no match */
17399a2dd95SBruce Richardson 		else
17499a2dd95SBruce Richardson 			dr[k++] = mb[i];
17599a2dd95SBruce Richardson 	}
17699a2dd95SBruce Richardson 
17799a2dd95SBruce Richardson 	if (drop != 0) {
17899a2dd95SBruce Richardson 		/* free filtered out mbufs */
17999a2dd95SBruce Richardson 		for (i = 0; i != k; i++)
18099a2dd95SBruce Richardson 			rte_pktmbuf_free(dr[i]);
18199a2dd95SBruce Richardson 	} else {
18299a2dd95SBruce Richardson 		/* copy filtered out mbufs beyond good ones */
18399a2dd95SBruce Richardson 		for (i = 0; i != k; i++)
18499a2dd95SBruce Richardson 			mb[j + i] = dr[i];
18599a2dd95SBruce Richardson 	}
18699a2dd95SBruce Richardson 
18799a2dd95SBruce Richardson 	return j;
18899a2dd95SBruce Richardson }
18999a2dd95SBruce Richardson 
19099a2dd95SBruce Richardson static inline uint32_t
pkt_filter_vm(const struct rte_bpf * bpf,struct rte_mbuf * mb[],uint32_t num,uint32_t drop)19199a2dd95SBruce Richardson pkt_filter_vm(const struct rte_bpf *bpf, struct rte_mbuf *mb[], uint32_t num,
19299a2dd95SBruce Richardson 	uint32_t drop)
19399a2dd95SBruce Richardson {
19499a2dd95SBruce Richardson 	uint32_t i;
19599a2dd95SBruce Richardson 	void *dp[num];
19699a2dd95SBruce Richardson 	uint64_t rc[num];
19799a2dd95SBruce Richardson 
19899a2dd95SBruce Richardson 	for (i = 0; i != num; i++)
19999a2dd95SBruce Richardson 		dp[i] = rte_pktmbuf_mtod(mb[i], void *);
20099a2dd95SBruce Richardson 
20199a2dd95SBruce Richardson 	rte_bpf_exec_burst(bpf, dp, rc, num);
20299a2dd95SBruce Richardson 	return apply_filter(mb, rc, num, drop);
20399a2dd95SBruce Richardson }
20499a2dd95SBruce Richardson 
20599a2dd95SBruce Richardson static inline uint32_t
pkt_filter_jit(const struct rte_bpf_jit * jit,struct rte_mbuf * mb[],uint32_t num,uint32_t drop)20699a2dd95SBruce Richardson pkt_filter_jit(const struct rte_bpf_jit *jit, struct rte_mbuf *mb[],
20799a2dd95SBruce Richardson 	uint32_t num, uint32_t drop)
20899a2dd95SBruce Richardson {
20999a2dd95SBruce Richardson 	uint32_t i, n;
21099a2dd95SBruce Richardson 	void *dp;
21199a2dd95SBruce Richardson 	uint64_t rc[num];
21299a2dd95SBruce Richardson 
21399a2dd95SBruce Richardson 	n = 0;
21499a2dd95SBruce Richardson 	for (i = 0; i != num; i++) {
21599a2dd95SBruce Richardson 		dp = rte_pktmbuf_mtod(mb[i], void *);
21699a2dd95SBruce Richardson 		rc[i] = jit->func(dp);
21799a2dd95SBruce Richardson 		n += (rc[i] == 0);
21899a2dd95SBruce Richardson 	}
21999a2dd95SBruce Richardson 
22099a2dd95SBruce Richardson 	if (n != 0)
22199a2dd95SBruce Richardson 		num = apply_filter(mb, rc, num, drop);
22299a2dd95SBruce Richardson 
22399a2dd95SBruce Richardson 	return num;
22499a2dd95SBruce Richardson }
22599a2dd95SBruce Richardson 
22699a2dd95SBruce Richardson static inline uint32_t
pkt_filter_mb_vm(const struct rte_bpf * bpf,struct rte_mbuf * mb[],uint32_t num,uint32_t drop)22799a2dd95SBruce Richardson pkt_filter_mb_vm(const struct rte_bpf *bpf, struct rte_mbuf *mb[], uint32_t num,
22899a2dd95SBruce Richardson 	uint32_t drop)
22999a2dd95SBruce Richardson {
23099a2dd95SBruce Richardson 	uint64_t rc[num];
23199a2dd95SBruce Richardson 
23299a2dd95SBruce Richardson 	rte_bpf_exec_burst(bpf, (void **)mb, rc, num);
23399a2dd95SBruce Richardson 	return apply_filter(mb, rc, num, drop);
23499a2dd95SBruce Richardson }
23599a2dd95SBruce Richardson 
23699a2dd95SBruce Richardson static inline uint32_t
pkt_filter_mb_jit(const struct rte_bpf_jit * jit,struct rte_mbuf * mb[],uint32_t num,uint32_t drop)23799a2dd95SBruce Richardson pkt_filter_mb_jit(const struct rte_bpf_jit *jit, struct rte_mbuf *mb[],
23899a2dd95SBruce Richardson 	uint32_t num, uint32_t drop)
23999a2dd95SBruce Richardson {
24099a2dd95SBruce Richardson 	uint32_t i, n;
24199a2dd95SBruce Richardson 	uint64_t rc[num];
24299a2dd95SBruce Richardson 
24399a2dd95SBruce Richardson 	n = 0;
24499a2dd95SBruce Richardson 	for (i = 0; i != num; i++) {
24599a2dd95SBruce Richardson 		rc[i] = jit->func(mb[i]);
24699a2dd95SBruce Richardson 		n += (rc[i] == 0);
24799a2dd95SBruce Richardson 	}
24899a2dd95SBruce Richardson 
24999a2dd95SBruce Richardson 	if (n != 0)
25099a2dd95SBruce Richardson 		num = apply_filter(mb, rc, num, drop);
25199a2dd95SBruce Richardson 
25299a2dd95SBruce Richardson 	return num;
25399a2dd95SBruce Richardson }
25499a2dd95SBruce Richardson 
25599a2dd95SBruce Richardson /*
25699a2dd95SBruce Richardson  * RX/TX callbacks for raw data bpf.
25799a2dd95SBruce Richardson  */
25899a2dd95SBruce Richardson 
25999a2dd95SBruce Richardson static uint16_t
bpf_rx_callback_vm(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,__rte_unused uint16_t max_pkts,void * user_param)26099a2dd95SBruce Richardson bpf_rx_callback_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
26199a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts,
26299a2dd95SBruce Richardson 	__rte_unused uint16_t max_pkts, void *user_param)
26399a2dd95SBruce Richardson {
26499a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
26599a2dd95SBruce Richardson 	uint16_t rc;
26699a2dd95SBruce Richardson 
26799a2dd95SBruce Richardson 	cbi = user_param;
26899a2dd95SBruce Richardson 
26999a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
27099a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
27199a2dd95SBruce Richardson 		pkt_filter_vm(cbi->bpf, pkt, nb_pkts, 1) :
27299a2dd95SBruce Richardson 		nb_pkts;
27399a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
27499a2dd95SBruce Richardson 	return rc;
27599a2dd95SBruce Richardson }
27699a2dd95SBruce Richardson 
27799a2dd95SBruce Richardson static uint16_t
bpf_rx_callback_jit(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,__rte_unused uint16_t max_pkts,void * user_param)27899a2dd95SBruce Richardson bpf_rx_callback_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
27999a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts,
28099a2dd95SBruce Richardson 	__rte_unused uint16_t max_pkts, void *user_param)
28199a2dd95SBruce Richardson {
28299a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
28399a2dd95SBruce Richardson 	uint16_t rc;
28499a2dd95SBruce Richardson 
28599a2dd95SBruce Richardson 	cbi = user_param;
28699a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
28799a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
28899a2dd95SBruce Richardson 		pkt_filter_jit(&cbi->jit, pkt, nb_pkts, 1) :
28999a2dd95SBruce Richardson 		nb_pkts;
29099a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
29199a2dd95SBruce Richardson 	return rc;
29299a2dd95SBruce Richardson }
29399a2dd95SBruce Richardson 
29499a2dd95SBruce Richardson static uint16_t
bpf_tx_callback_vm(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,void * user_param)29599a2dd95SBruce Richardson bpf_tx_callback_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
29699a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
29799a2dd95SBruce Richardson {
29899a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
29999a2dd95SBruce Richardson 	uint16_t rc;
30099a2dd95SBruce Richardson 
30199a2dd95SBruce Richardson 	cbi = user_param;
30299a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
30399a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
30499a2dd95SBruce Richardson 		pkt_filter_vm(cbi->bpf, pkt, nb_pkts, 0) :
30599a2dd95SBruce Richardson 		nb_pkts;
30699a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
30799a2dd95SBruce Richardson 	return rc;
30899a2dd95SBruce Richardson }
30999a2dd95SBruce Richardson 
31099a2dd95SBruce Richardson static uint16_t
bpf_tx_callback_jit(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,void * user_param)31199a2dd95SBruce Richardson bpf_tx_callback_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
31299a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
31399a2dd95SBruce Richardson {
31499a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
31599a2dd95SBruce Richardson 	uint16_t rc;
31699a2dd95SBruce Richardson 
31799a2dd95SBruce Richardson 	cbi = user_param;
31899a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
31999a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
32099a2dd95SBruce Richardson 		pkt_filter_jit(&cbi->jit, pkt, nb_pkts, 0) :
32199a2dd95SBruce Richardson 		nb_pkts;
32299a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
32399a2dd95SBruce Richardson 	return rc;
32499a2dd95SBruce Richardson }
32599a2dd95SBruce Richardson 
32699a2dd95SBruce Richardson /*
32799a2dd95SBruce Richardson  * RX/TX callbacks for mbuf.
32899a2dd95SBruce Richardson  */
32999a2dd95SBruce Richardson 
33099a2dd95SBruce Richardson static uint16_t
bpf_rx_callback_mb_vm(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,__rte_unused uint16_t max_pkts,void * user_param)33199a2dd95SBruce Richardson bpf_rx_callback_mb_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
33299a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts,
33399a2dd95SBruce Richardson 	__rte_unused uint16_t max_pkts, void *user_param)
33499a2dd95SBruce Richardson {
33599a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
33699a2dd95SBruce Richardson 	uint16_t rc;
33799a2dd95SBruce Richardson 
33899a2dd95SBruce Richardson 	cbi = user_param;
33999a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
34099a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
34199a2dd95SBruce Richardson 		pkt_filter_mb_vm(cbi->bpf, pkt, nb_pkts, 1) :
34299a2dd95SBruce Richardson 		nb_pkts;
34399a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
34499a2dd95SBruce Richardson 	return rc;
34599a2dd95SBruce Richardson }
34699a2dd95SBruce Richardson 
34799a2dd95SBruce Richardson static uint16_t
bpf_rx_callback_mb_jit(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,__rte_unused uint16_t max_pkts,void * user_param)34899a2dd95SBruce Richardson bpf_rx_callback_mb_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
34999a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts,
35099a2dd95SBruce Richardson 	__rte_unused uint16_t max_pkts, void *user_param)
35199a2dd95SBruce Richardson {
35299a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
35399a2dd95SBruce Richardson 	uint16_t rc;
35499a2dd95SBruce Richardson 
35599a2dd95SBruce Richardson 	cbi = user_param;
35699a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
35799a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
35899a2dd95SBruce Richardson 		pkt_filter_mb_jit(&cbi->jit, pkt, nb_pkts, 1) :
35999a2dd95SBruce Richardson 		nb_pkts;
36099a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
36199a2dd95SBruce Richardson 	return rc;
36299a2dd95SBruce Richardson }
36399a2dd95SBruce Richardson 
36499a2dd95SBruce Richardson static uint16_t
bpf_tx_callback_mb_vm(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,void * user_param)36599a2dd95SBruce Richardson bpf_tx_callback_mb_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
36699a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
36799a2dd95SBruce Richardson {
36899a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
36999a2dd95SBruce Richardson 	uint16_t rc;
37099a2dd95SBruce Richardson 
37199a2dd95SBruce Richardson 	cbi = user_param;
37299a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
37399a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
37499a2dd95SBruce Richardson 		pkt_filter_mb_vm(cbi->bpf, pkt, nb_pkts, 0) :
37599a2dd95SBruce Richardson 		nb_pkts;
37699a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
37799a2dd95SBruce Richardson 	return rc;
37899a2dd95SBruce Richardson }
37999a2dd95SBruce Richardson 
38099a2dd95SBruce Richardson static uint16_t
bpf_tx_callback_mb_jit(__rte_unused uint16_t port,__rte_unused uint16_t queue,struct rte_mbuf * pkt[],uint16_t nb_pkts,void * user_param)38199a2dd95SBruce Richardson bpf_tx_callback_mb_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
38299a2dd95SBruce Richardson 	struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
38399a2dd95SBruce Richardson {
38499a2dd95SBruce Richardson 	struct bpf_eth_cbi *cbi;
38599a2dd95SBruce Richardson 	uint16_t rc;
38699a2dd95SBruce Richardson 
38799a2dd95SBruce Richardson 	cbi = user_param;
38899a2dd95SBruce Richardson 	bpf_eth_cbi_inuse(cbi);
38999a2dd95SBruce Richardson 	rc = (cbi->cb != NULL) ?
39099a2dd95SBruce Richardson 		pkt_filter_mb_jit(&cbi->jit, pkt, nb_pkts, 0) :
39199a2dd95SBruce Richardson 		nb_pkts;
39299a2dd95SBruce Richardson 	bpf_eth_cbi_unuse(cbi);
39399a2dd95SBruce Richardson 	return rc;
39499a2dd95SBruce Richardson }
39599a2dd95SBruce Richardson 
39699a2dd95SBruce Richardson static rte_rx_callback_fn
select_rx_callback(enum rte_bpf_arg_type type,uint32_t flags)39799a2dd95SBruce Richardson select_rx_callback(enum rte_bpf_arg_type type, uint32_t flags)
39899a2dd95SBruce Richardson {
39999a2dd95SBruce Richardson 	if (flags & RTE_BPF_ETH_F_JIT) {
40099a2dd95SBruce Richardson 		if (type == RTE_BPF_ARG_PTR)
40199a2dd95SBruce Richardson 			return bpf_rx_callback_jit;
40299a2dd95SBruce Richardson 		else if (type == RTE_BPF_ARG_PTR_MBUF)
40399a2dd95SBruce Richardson 			return bpf_rx_callback_mb_jit;
40499a2dd95SBruce Richardson 	} else if (type == RTE_BPF_ARG_PTR)
40599a2dd95SBruce Richardson 		return bpf_rx_callback_vm;
40699a2dd95SBruce Richardson 	else if (type == RTE_BPF_ARG_PTR_MBUF)
40799a2dd95SBruce Richardson 		return bpf_rx_callback_mb_vm;
40899a2dd95SBruce Richardson 
40999a2dd95SBruce Richardson 	return NULL;
41099a2dd95SBruce Richardson }
41199a2dd95SBruce Richardson 
41299a2dd95SBruce Richardson static rte_tx_callback_fn
select_tx_callback(enum rte_bpf_arg_type type,uint32_t flags)41399a2dd95SBruce Richardson select_tx_callback(enum rte_bpf_arg_type type, uint32_t flags)
41499a2dd95SBruce Richardson {
41599a2dd95SBruce Richardson 	if (flags & RTE_BPF_ETH_F_JIT) {
41699a2dd95SBruce Richardson 		if (type == RTE_BPF_ARG_PTR)
41799a2dd95SBruce Richardson 			return bpf_tx_callback_jit;
41899a2dd95SBruce Richardson 		else if (type == RTE_BPF_ARG_PTR_MBUF)
41999a2dd95SBruce Richardson 			return bpf_tx_callback_mb_jit;
42099a2dd95SBruce Richardson 	} else if (type == RTE_BPF_ARG_PTR)
42199a2dd95SBruce Richardson 		return bpf_tx_callback_vm;
42299a2dd95SBruce Richardson 	else if (type == RTE_BPF_ARG_PTR_MBUF)
42399a2dd95SBruce Richardson 		return bpf_tx_callback_mb_vm;
42499a2dd95SBruce Richardson 
42599a2dd95SBruce Richardson 	return NULL;
42699a2dd95SBruce Richardson }
42799a2dd95SBruce Richardson 
42899a2dd95SBruce Richardson /*
42999a2dd95SBruce Richardson  * helper function to perform BPF unload for given port/queue.
43099a2dd95SBruce Richardson  * have to introduce extra complexity (and possible slowdown) here,
43199a2dd95SBruce Richardson  * as right now there is no safe generic way to remove RX/TX callback
43299a2dd95SBruce Richardson  * while IO is active.
43399a2dd95SBruce Richardson  * Still don't free memory allocated for callback handle itself,
43499a2dd95SBruce Richardson  * again right now there is no safe way to do that without stopping RX/TX
43599a2dd95SBruce Richardson  * on given port/queue first.
43699a2dd95SBruce Richardson  */
43799a2dd95SBruce Richardson static void
bpf_eth_cbi_unload(struct bpf_eth_cbi * bc)43899a2dd95SBruce Richardson bpf_eth_cbi_unload(struct bpf_eth_cbi *bc)
43999a2dd95SBruce Richardson {
44099a2dd95SBruce Richardson 	/* mark this cbi as empty */
44199a2dd95SBruce Richardson 	bc->cb = NULL;
44299a2dd95SBruce Richardson 	rte_smp_mb();
44399a2dd95SBruce Richardson 
44499a2dd95SBruce Richardson 	/* make sure datapath doesn't use bpf anymore, then destroy bpf */
44599a2dd95SBruce Richardson 	bpf_eth_cbi_wait(bc);
44699a2dd95SBruce Richardson 	rte_bpf_destroy(bc->bpf);
44799a2dd95SBruce Richardson 	bpf_eth_cbi_cleanup(bc);
44899a2dd95SBruce Richardson }
44999a2dd95SBruce Richardson 
45099a2dd95SBruce Richardson static void
bpf_eth_unload(struct bpf_eth_cbh * cbh,uint16_t port,uint16_t queue)45199a2dd95SBruce Richardson bpf_eth_unload(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue)
45299a2dd95SBruce Richardson {
45399a2dd95SBruce Richardson 	struct bpf_eth_cbi *bc;
45499a2dd95SBruce Richardson 
45599a2dd95SBruce Richardson 	bc = bpf_eth_cbh_find(cbh, port, queue);
45699a2dd95SBruce Richardson 	if (bc == NULL || bc->cb == NULL)
45799a2dd95SBruce Richardson 		return;
45899a2dd95SBruce Richardson 
45999a2dd95SBruce Richardson 	if (cbh->type == BPF_ETH_RX)
46099a2dd95SBruce Richardson 		rte_eth_remove_rx_callback(port, queue, bc->cb);
46199a2dd95SBruce Richardson 	else
46299a2dd95SBruce Richardson 		rte_eth_remove_tx_callback(port, queue, bc->cb);
46399a2dd95SBruce Richardson 
46499a2dd95SBruce Richardson 	bpf_eth_cbi_unload(bc);
46599a2dd95SBruce Richardson }
46699a2dd95SBruce Richardson 
46799a2dd95SBruce Richardson 
46899a2dd95SBruce Richardson void
rte_bpf_eth_rx_unload(uint16_t port,uint16_t queue)46999a2dd95SBruce Richardson rte_bpf_eth_rx_unload(uint16_t port, uint16_t queue)
47099a2dd95SBruce Richardson {
47199a2dd95SBruce Richardson 	struct bpf_eth_cbh *cbh;
47299a2dd95SBruce Richardson 
47399a2dd95SBruce Richardson 	cbh = &rx_cbh;
47499a2dd95SBruce Richardson 	rte_spinlock_lock(&cbh->lock);
47599a2dd95SBruce Richardson 	bpf_eth_unload(cbh, port, queue);
47699a2dd95SBruce Richardson 	rte_spinlock_unlock(&cbh->lock);
47799a2dd95SBruce Richardson }
47899a2dd95SBruce Richardson 
47999a2dd95SBruce Richardson void
rte_bpf_eth_tx_unload(uint16_t port,uint16_t queue)48099a2dd95SBruce Richardson rte_bpf_eth_tx_unload(uint16_t port, uint16_t queue)
48199a2dd95SBruce Richardson {
48299a2dd95SBruce Richardson 	struct bpf_eth_cbh *cbh;
48399a2dd95SBruce Richardson 
48499a2dd95SBruce Richardson 	cbh = &tx_cbh;
48599a2dd95SBruce Richardson 	rte_spinlock_lock(&cbh->lock);
48699a2dd95SBruce Richardson 	bpf_eth_unload(cbh, port, queue);
48799a2dd95SBruce Richardson 	rte_spinlock_unlock(&cbh->lock);
48899a2dd95SBruce Richardson }
48999a2dd95SBruce Richardson 
49099a2dd95SBruce Richardson static int
bpf_eth_elf_load(struct bpf_eth_cbh * cbh,uint16_t port,uint16_t queue,const struct rte_bpf_prm * prm,const char * fname,const char * sname,uint32_t flags)49199a2dd95SBruce Richardson bpf_eth_elf_load(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue,
49299a2dd95SBruce Richardson 	const struct rte_bpf_prm *prm, const char *fname, const char *sname,
49399a2dd95SBruce Richardson 	uint32_t flags)
49499a2dd95SBruce Richardson {
49599a2dd95SBruce Richardson 	int32_t rc;
49699a2dd95SBruce Richardson 	struct bpf_eth_cbi *bc;
49799a2dd95SBruce Richardson 	struct rte_bpf *bpf;
49899a2dd95SBruce Richardson 	rte_rx_callback_fn frx;
49999a2dd95SBruce Richardson 	rte_tx_callback_fn ftx;
50099a2dd95SBruce Richardson 	struct rte_bpf_jit jit;
50199a2dd95SBruce Richardson 
50299a2dd95SBruce Richardson 	frx = NULL;
50399a2dd95SBruce Richardson 	ftx = NULL;
50499a2dd95SBruce Richardson 
50599a2dd95SBruce Richardson 	if (prm == NULL || rte_eth_dev_is_valid_port(port) == 0 ||
50699a2dd95SBruce Richardson 			queue >= RTE_MAX_QUEUES_PER_PORT)
50799a2dd95SBruce Richardson 		return -EINVAL;
50899a2dd95SBruce Richardson 
50999a2dd95SBruce Richardson 	if (cbh->type == BPF_ETH_RX)
51099a2dd95SBruce Richardson 		frx = select_rx_callback(prm->prog_arg.type, flags);
51199a2dd95SBruce Richardson 	else
51299a2dd95SBruce Richardson 		ftx = select_tx_callback(prm->prog_arg.type, flags);
51399a2dd95SBruce Richardson 
51499a2dd95SBruce Richardson 	if (frx == NULL && ftx == NULL) {
5150e21c7c0SDavid Marchand 		RTE_BPF_LOG_LINE(ERR, "%s(%u, %u): no callback selected;",
51699a2dd95SBruce Richardson 			__func__, port, queue);
51799a2dd95SBruce Richardson 		return -EINVAL;
51899a2dd95SBruce Richardson 	}
51999a2dd95SBruce Richardson 
52099a2dd95SBruce Richardson 	bpf = rte_bpf_elf_load(prm, fname, sname);
52199a2dd95SBruce Richardson 	if (bpf == NULL)
52299a2dd95SBruce Richardson 		return -rte_errno;
52399a2dd95SBruce Richardson 
52499a2dd95SBruce Richardson 	rte_bpf_get_jit(bpf, &jit);
52599a2dd95SBruce Richardson 
52699a2dd95SBruce Richardson 	if ((flags & RTE_BPF_ETH_F_JIT) != 0 && jit.func == NULL) {
5270e21c7c0SDavid Marchand 		RTE_BPF_LOG_LINE(ERR, "%s(%u, %u): no JIT generated;",
52899a2dd95SBruce Richardson 			__func__, port, queue);
52999a2dd95SBruce Richardson 		rte_bpf_destroy(bpf);
53099a2dd95SBruce Richardson 		return -ENOTSUP;
53199a2dd95SBruce Richardson 	}
53299a2dd95SBruce Richardson 
53399a2dd95SBruce Richardson 	/* setup/update global callback info */
53499a2dd95SBruce Richardson 	bc = bpf_eth_cbh_add(cbh, port, queue);
53599a2dd95SBruce Richardson 	if (bc == NULL)
53699a2dd95SBruce Richardson 		return -ENOMEM;
53799a2dd95SBruce Richardson 
53899a2dd95SBruce Richardson 	/* remove old one, if any */
53999a2dd95SBruce Richardson 	if (bc->cb != NULL)
54099a2dd95SBruce Richardson 		bpf_eth_unload(cbh, port, queue);
54199a2dd95SBruce Richardson 
54299a2dd95SBruce Richardson 	bc->bpf = bpf;
54399a2dd95SBruce Richardson 	bc->jit = jit;
54499a2dd95SBruce Richardson 
54599a2dd95SBruce Richardson 	if (cbh->type == BPF_ETH_RX)
54699a2dd95SBruce Richardson 		bc->cb = rte_eth_add_rx_callback(port, queue, frx, bc);
54799a2dd95SBruce Richardson 	else
54899a2dd95SBruce Richardson 		bc->cb = rte_eth_add_tx_callback(port, queue, ftx, bc);
54999a2dd95SBruce Richardson 
55099a2dd95SBruce Richardson 	if (bc->cb == NULL) {
55199a2dd95SBruce Richardson 		rc = -rte_errno;
55299a2dd95SBruce Richardson 		rte_bpf_destroy(bpf);
55399a2dd95SBruce Richardson 		bpf_eth_cbi_cleanup(bc);
55499a2dd95SBruce Richardson 	} else
55599a2dd95SBruce Richardson 		rc = 0;
55699a2dd95SBruce Richardson 
55799a2dd95SBruce Richardson 	return rc;
55899a2dd95SBruce Richardson }
55999a2dd95SBruce Richardson 
56099a2dd95SBruce Richardson int
rte_bpf_eth_rx_elf_load(uint16_t port,uint16_t queue,const struct rte_bpf_prm * prm,const char * fname,const char * sname,uint32_t flags)56199a2dd95SBruce Richardson rte_bpf_eth_rx_elf_load(uint16_t port, uint16_t queue,
56299a2dd95SBruce Richardson 	const struct rte_bpf_prm *prm, const char *fname, const char *sname,
56399a2dd95SBruce Richardson 	uint32_t flags)
56499a2dd95SBruce Richardson {
56599a2dd95SBruce Richardson 	int32_t rc;
56699a2dd95SBruce Richardson 	struct bpf_eth_cbh *cbh;
56799a2dd95SBruce Richardson 
56899a2dd95SBruce Richardson 	cbh = &rx_cbh;
56999a2dd95SBruce Richardson 	rte_spinlock_lock(&cbh->lock);
57099a2dd95SBruce Richardson 	rc = bpf_eth_elf_load(cbh, port, queue, prm, fname, sname, flags);
57199a2dd95SBruce Richardson 	rte_spinlock_unlock(&cbh->lock);
57299a2dd95SBruce Richardson 
57399a2dd95SBruce Richardson 	return rc;
57499a2dd95SBruce Richardson }
57599a2dd95SBruce Richardson 
57699a2dd95SBruce Richardson int
rte_bpf_eth_tx_elf_load(uint16_t port,uint16_t queue,const struct rte_bpf_prm * prm,const char * fname,const char * sname,uint32_t flags)57799a2dd95SBruce Richardson rte_bpf_eth_tx_elf_load(uint16_t port, uint16_t queue,
57899a2dd95SBruce Richardson 	const struct rte_bpf_prm *prm, const char *fname, const char *sname,
57999a2dd95SBruce Richardson 	uint32_t flags)
58099a2dd95SBruce Richardson {
58199a2dd95SBruce Richardson 	int32_t rc;
58299a2dd95SBruce Richardson 	struct bpf_eth_cbh *cbh;
58399a2dd95SBruce Richardson 
58499a2dd95SBruce Richardson 	cbh = &tx_cbh;
58599a2dd95SBruce Richardson 	rte_spinlock_lock(&cbh->lock);
58699a2dd95SBruce Richardson 	rc = bpf_eth_elf_load(cbh, port, queue, prm, fname, sname, flags);
58799a2dd95SBruce Richardson 	rte_spinlock_unlock(&cbh->lock);
58899a2dd95SBruce Richardson 
58999a2dd95SBruce Richardson 	return rc;
59099a2dd95SBruce Richardson }
591