Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <string.h>
7 : : #include <errno.h>
8 : : #include <stdint.h>
9 : :
10 : : #include <sys/queue.h>
11 : :
12 : : #include <eal_export.h>
13 : : #include <rte_common.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_log.h>
16 : : #include <rte_atomic.h>
17 : : #include <rte_mbuf.h>
18 : : #include <rte_ethdev.h>
19 : :
20 : : #include <rte_bpf_ethdev.h>
21 : : #include "bpf_impl.h"
22 : :
23 : : /*
24 : : * information about installed BPF rx/tx callback
25 : : */
26 : :
27 : : struct __rte_cache_aligned bpf_eth_cbi {
28 : : /* used by both data & control path */
29 : : RTE_ATOMIC(uint32_t) use; /*usage counter */
30 : : const struct rte_eth_rxtx_callback *cb; /* callback handle */
31 : : struct rte_bpf *bpf;
32 : : struct rte_bpf_jit jit;
33 : : /* used by control path only */
34 : : LIST_ENTRY(bpf_eth_cbi) link;
35 : : uint16_t port;
36 : : uint16_t queue;
37 : : };
38 : :
39 : : /*
40 : : * Odd number means that callback is used by datapath.
41 : : * Even number means that callback is not used by datapath.
42 : : */
43 : : #define BPF_ETH_CBI_INUSE 1
44 : :
45 : : /*
46 : : * List to manage RX/TX installed callbacks.
47 : : */
48 : : LIST_HEAD(bpf_eth_cbi_list, bpf_eth_cbi);
49 : :
50 : : enum {
51 : : BPF_ETH_RX,
52 : : BPF_ETH_TX,
53 : : BPF_ETH_NUM,
54 : : };
55 : :
56 : : /*
57 : : * information about all installed BPF rx/tx callbacks
58 : : */
59 : : struct bpf_eth_cbh {
60 : : rte_spinlock_t lock;
61 : : struct bpf_eth_cbi_list list;
62 : : uint32_t type;
63 : : };
64 : :
65 : : static struct bpf_eth_cbh rx_cbh = {
66 : : .lock = RTE_SPINLOCK_INITIALIZER,
67 : : .list = LIST_HEAD_INITIALIZER(list),
68 : : .type = BPF_ETH_RX,
69 : : };
70 : :
71 : : static struct bpf_eth_cbh tx_cbh = {
72 : : .lock = RTE_SPINLOCK_INITIALIZER,
73 : : .list = LIST_HEAD_INITIALIZER(list),
74 : : .type = BPF_ETH_TX,
75 : : };
76 : :
77 : : /*
78 : : * Marks given callback as used by datapath.
79 : : */
80 : : static __rte_always_inline void
81 : : bpf_eth_cbi_inuse(struct bpf_eth_cbi *cbi)
82 : : {
83 : 0 : cbi->use++;
84 : : /* make sure no store/load reordering could happen */
85 : : rte_smp_mb();
86 : : }
87 : :
88 : : /*
89 : : * Marks given callback list as not used by datapath.
90 : : */
91 : : static __rte_always_inline void
92 : : bpf_eth_cbi_unuse(struct bpf_eth_cbi *cbi)
93 : : {
94 : : /* make sure all previous loads are completed */
95 : 0 : rte_smp_rmb();
96 : 0 : cbi->use++;
97 : : }
98 : :
99 : : /*
100 : : * Waits till datapath finished using given callback.
101 : : */
102 : : static void
103 : 0 : bpf_eth_cbi_wait(const struct bpf_eth_cbi *cbi)
104 : : {
105 : : uint32_t puse;
106 : :
107 : : /* make sure all previous loads and stores are completed */
108 : : rte_smp_mb();
109 : :
110 : 0 : puse = cbi->use;
111 : :
112 : : /* in use, busy wait till current RX/TX iteration is finished */
113 [ # # ]: 0 : if ((puse & BPF_ETH_CBI_INUSE) != 0) {
114 [ # # ]: 0 : RTE_WAIT_UNTIL_MASKED((__rte_atomic uint32_t *)(uintptr_t)&cbi->use,
115 : : UINT32_MAX, !=, puse, rte_memory_order_relaxed);
116 : : }
117 : 0 : }
118 : :
119 : : static void
120 : : bpf_eth_cbi_cleanup(struct bpf_eth_cbi *bc)
121 : : {
122 : 0 : bc->bpf = NULL;
123 : 0 : memset(&bc->jit, 0, sizeof(bc->jit));
124 : 0 : }
125 : :
126 : : static struct bpf_eth_cbi *
127 : : bpf_eth_cbh_find(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue)
128 : : {
129 : : struct bpf_eth_cbi *cbi;
130 : :
131 [ # # # # ]: 0 : LIST_FOREACH(cbi, &cbh->list, link) {
132 [ # # # # : 0 : if (cbi->port == port && cbi->queue == queue)
# # # # ]
133 : : break;
134 : : }
135 : : return cbi;
136 : : }
137 : :
138 : : static struct bpf_eth_cbi *
139 : 0 : bpf_eth_cbh_add(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue)
140 : : {
141 : : struct bpf_eth_cbi *cbi;
142 : :
143 : : /* return an existing one */
144 : : cbi = bpf_eth_cbh_find(cbh, port, queue);
145 [ # # ]: 0 : if (cbi != NULL)
146 : : return cbi;
147 : :
148 : 0 : cbi = rte_zmalloc(NULL, sizeof(*cbi), RTE_CACHE_LINE_SIZE);
149 [ # # ]: 0 : if (cbi != NULL) {
150 : 0 : cbi->port = port;
151 : 0 : cbi->queue = queue;
152 [ # # ]: 0 : LIST_INSERT_HEAD(&cbh->list, cbi, link);
153 : : }
154 : : return cbi;
155 : : }
156 : :
157 : : /*
158 : : * BPF packet processing routines.
159 : : */
160 : :
161 : : static inline uint32_t
162 : 0 : apply_filter(struct rte_mbuf *mb[], const uint64_t rc[], uint32_t num,
163 : : uint32_t drop)
164 : : {
165 : : uint32_t i, j, k;
166 : 0 : struct rte_mbuf **dr = alloca(num * sizeof(struct rte_mbuf *));
167 : :
168 [ # # ]: 0 : for (i = 0, j = 0, k = 0; i != num; i++) {
169 : :
170 : : /* filter matches */
171 [ # # ]: 0 : if (rc[i] != 0)
172 : 0 : mb[j++] = mb[i];
173 : : /* no match */
174 : : else
175 : 0 : dr[k++] = mb[i];
176 : : }
177 : :
178 [ # # ]: 0 : if (drop != 0) {
179 : : /* free filtered out mbufs */
180 : 0 : rte_pktmbuf_free_bulk(dr, k);
181 : : } else {
182 : : /* copy filtered out mbufs beyond good ones */
183 [ # # ]: 0 : for (i = 0; i != k; i++)
184 : 0 : mb[j + i] = dr[i];
185 : : }
186 : :
187 : 0 : return j;
188 : : }
189 : :
190 : : static inline uint32_t
191 : 0 : pkt_filter_vm(const struct rte_bpf *bpf, struct rte_mbuf *mb[], uint32_t num,
192 : : uint32_t drop)
193 : : {
194 : : uint32_t i;
195 : 0 : void **dp = alloca(num * sizeof(void *));
196 : 0 : uint64_t *rc = alloca(num * sizeof(uint64_t));
197 : :
198 [ # # ]: 0 : for (i = 0; i != num; i++)
199 : 0 : dp[i] = rte_pktmbuf_mtod(mb[i], void *);
200 : :
201 : 0 : rte_bpf_exec_burst(bpf, dp, rc, num);
202 : 0 : return apply_filter(mb, rc, num, drop);
203 : : }
204 : :
205 : : static inline uint32_t
206 : 0 : pkt_filter_jit(const struct rte_bpf_jit *jit, struct rte_mbuf *mb[],
207 : : uint32_t num, uint32_t drop)
208 : : {
209 : : uint32_t i, n;
210 : : void *dp;
211 : 0 : uint64_t *rc = alloca(num * sizeof(uint64_t));
212 : :
213 : : n = 0;
214 [ # # ]: 0 : for (i = 0; i != num; i++) {
215 : 0 : dp = rte_pktmbuf_mtod(mb[i], void *);
216 : 0 : rc[i] = jit->func(dp);
217 : 0 : n += (rc[i] == 0);
218 : : }
219 : :
220 [ # # ]: 0 : if (n != 0)
221 : 0 : num = apply_filter(mb, rc, num, drop);
222 : :
223 : 0 : return num;
224 : : }
225 : :
226 : : static inline uint32_t
227 : 0 : pkt_filter_mb_vm(const struct rte_bpf *bpf, struct rte_mbuf *mb[], uint32_t num,
228 : : uint32_t drop)
229 : : {
230 : 0 : uint64_t *rc = alloca(num * sizeof(uint64_t));
231 : :
232 : 0 : rte_bpf_exec_burst(bpf, (void **)mb, rc, num);
233 : 0 : return apply_filter(mb, rc, num, drop);
234 : : }
235 : :
236 : : static inline uint32_t
237 : 0 : pkt_filter_mb_jit(const struct rte_bpf_jit *jit, struct rte_mbuf *mb[],
238 : : uint32_t num, uint32_t drop)
239 : : {
240 : : uint32_t i, n;
241 : 0 : uint64_t *rc = alloca(num * sizeof(uint64_t));
242 : :
243 : : n = 0;
244 [ # # ]: 0 : for (i = 0; i != num; i++) {
245 : 0 : rc[i] = jit->func(mb[i]);
246 : 0 : n += (rc[i] == 0);
247 : : }
248 : :
249 [ # # ]: 0 : if (n != 0)
250 : 0 : num = apply_filter(mb, rc, num, drop);
251 : :
252 : 0 : return num;
253 : : }
254 : :
255 : : /*
256 : : * RX/TX callbacks for raw data bpf.
257 : : */
258 : :
259 : : static uint16_t
260 : 0 : bpf_rx_callback_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
261 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
262 : : __rte_unused uint16_t max_pkts, void *user_param)
263 : : {
264 : : struct bpf_eth_cbi *cbi;
265 : : uint16_t rc;
266 : :
267 : : cbi = user_param;
268 : :
269 : : bpf_eth_cbi_inuse(cbi);
270 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
271 : 0 : pkt_filter_vm(cbi->bpf, pkt, nb_pkts, 1) :
272 : : nb_pkts;
273 : : bpf_eth_cbi_unuse(cbi);
274 : 0 : return rc;
275 : : }
276 : :
277 : : static uint16_t
278 : 0 : bpf_rx_callback_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
279 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
280 : : __rte_unused uint16_t max_pkts, void *user_param)
281 : : {
282 : : struct bpf_eth_cbi *cbi;
283 : : uint16_t rc;
284 : :
285 : : cbi = user_param;
286 : : bpf_eth_cbi_inuse(cbi);
287 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
288 : 0 : pkt_filter_jit(&cbi->jit, pkt, nb_pkts, 1) :
289 : : nb_pkts;
290 : : bpf_eth_cbi_unuse(cbi);
291 : 0 : return rc;
292 : : }
293 : :
294 : : static uint16_t
295 : 0 : bpf_tx_callback_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
296 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
297 : : {
298 : : struct bpf_eth_cbi *cbi;
299 : : uint16_t rc;
300 : :
301 : : cbi = user_param;
302 : : bpf_eth_cbi_inuse(cbi);
303 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
304 : 0 : pkt_filter_vm(cbi->bpf, pkt, nb_pkts, 0) :
305 : : nb_pkts;
306 : : bpf_eth_cbi_unuse(cbi);
307 : 0 : return rc;
308 : : }
309 : :
310 : : static uint16_t
311 : 0 : bpf_tx_callback_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
312 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
313 : : {
314 : : struct bpf_eth_cbi *cbi;
315 : : uint16_t rc;
316 : :
317 : : cbi = user_param;
318 : : bpf_eth_cbi_inuse(cbi);
319 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
320 : 0 : pkt_filter_jit(&cbi->jit, pkt, nb_pkts, 0) :
321 : : nb_pkts;
322 : : bpf_eth_cbi_unuse(cbi);
323 : 0 : return rc;
324 : : }
325 : :
326 : : /*
327 : : * RX/TX callbacks for mbuf.
328 : : */
329 : :
330 : : static uint16_t
331 : 0 : bpf_rx_callback_mb_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
332 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
333 : : __rte_unused uint16_t max_pkts, void *user_param)
334 : : {
335 : : struct bpf_eth_cbi *cbi;
336 : : uint16_t rc;
337 : :
338 : : cbi = user_param;
339 : : bpf_eth_cbi_inuse(cbi);
340 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
341 : 0 : pkt_filter_mb_vm(cbi->bpf, pkt, nb_pkts, 1) :
342 : : nb_pkts;
343 : : bpf_eth_cbi_unuse(cbi);
344 : 0 : return rc;
345 : : }
346 : :
347 : : static uint16_t
348 : 0 : bpf_rx_callback_mb_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
349 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
350 : : __rte_unused uint16_t max_pkts, void *user_param)
351 : : {
352 : : struct bpf_eth_cbi *cbi;
353 : : uint16_t rc;
354 : :
355 : : cbi = user_param;
356 : : bpf_eth_cbi_inuse(cbi);
357 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
358 : 0 : pkt_filter_mb_jit(&cbi->jit, pkt, nb_pkts, 1) :
359 : : nb_pkts;
360 : : bpf_eth_cbi_unuse(cbi);
361 : 0 : return rc;
362 : : }
363 : :
364 : : static uint16_t
365 : 0 : bpf_tx_callback_mb_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
366 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
367 : : {
368 : : struct bpf_eth_cbi *cbi;
369 : : uint16_t rc;
370 : :
371 : : cbi = user_param;
372 : : bpf_eth_cbi_inuse(cbi);
373 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
374 : 0 : pkt_filter_mb_vm(cbi->bpf, pkt, nb_pkts, 0) :
375 : : nb_pkts;
376 : : bpf_eth_cbi_unuse(cbi);
377 : 0 : return rc;
378 : : }
379 : :
380 : : static uint16_t
381 : 0 : bpf_tx_callback_mb_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
382 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
383 : : {
384 : : struct bpf_eth_cbi *cbi;
385 : : uint16_t rc;
386 : :
387 : : cbi = user_param;
388 : : bpf_eth_cbi_inuse(cbi);
389 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
390 : 0 : pkt_filter_mb_jit(&cbi->jit, pkt, nb_pkts, 0) :
391 : : nb_pkts;
392 : : bpf_eth_cbi_unuse(cbi);
393 : 0 : return rc;
394 : : }
395 : :
396 : : static rte_rx_callback_fn
397 : : select_rx_callback(enum rte_bpf_arg_type type, uint32_t flags)
398 : : {
399 : 0 : if (flags & RTE_BPF_ETH_F_JIT) {
400 [ # # ]: 0 : if (type == RTE_BPF_ARG_PTR)
401 : : return bpf_rx_callback_jit;
402 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
403 : 0 : return bpf_rx_callback_mb_jit;
404 [ # # ]: 0 : } else if (type == RTE_BPF_ARG_PTR)
405 : : return bpf_rx_callback_vm;
406 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
407 : 0 : return bpf_rx_callback_mb_vm;
408 : :
409 : : return NULL;
410 : : }
411 : :
412 : : static rte_tx_callback_fn
413 : : select_tx_callback(enum rte_bpf_arg_type type, uint32_t flags)
414 : : {
415 : 0 : if (flags & RTE_BPF_ETH_F_JIT) {
416 [ # # ]: 0 : if (type == RTE_BPF_ARG_PTR)
417 : : return bpf_tx_callback_jit;
418 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
419 : 0 : return bpf_tx_callback_mb_jit;
420 [ # # ]: 0 : } else if (type == RTE_BPF_ARG_PTR)
421 : : return bpf_tx_callback_vm;
422 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
423 : 0 : return bpf_tx_callback_mb_vm;
424 : :
425 : : return NULL;
426 : : }
427 : :
428 : : /*
429 : : * helper function to perform BPF unload for given port/queue.
430 : : * have to introduce extra complexity (and possible slowdown) here,
431 : : * as right now there is no safe generic way to remove RX/TX callback
432 : : * while IO is active.
433 : : * Still don't free memory allocated for callback handle itself,
434 : : * again right now there is no safe way to do that without stopping RX/TX
435 : : * on given port/queue first.
436 : : */
437 : : static void
438 : 0 : bpf_eth_cbi_unload(struct bpf_eth_cbi *bc)
439 : : {
440 : : /* mark this cbi as empty */
441 : 0 : bc->cb = NULL;
442 : : rte_smp_mb();
443 : :
444 : : /* make sure datapath doesn't use bpf anymore, then destroy bpf */
445 : 0 : bpf_eth_cbi_wait(bc);
446 : 0 : rte_bpf_destroy(bc->bpf);
447 : : bpf_eth_cbi_cleanup(bc);
448 : 0 : }
449 : :
450 : : static void
451 : 0 : bpf_eth_unload(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue)
452 : : {
453 : : struct bpf_eth_cbi *bc;
454 : :
455 : 0 : bc = bpf_eth_cbh_find(cbh, port, queue);
456 [ # # # # ]: 0 : if (bc == NULL || bc->cb == NULL)
457 : : return;
458 : :
459 [ # # ]: 0 : if (cbh->type == BPF_ETH_RX)
460 : 0 : rte_eth_remove_rx_callback(port, queue, bc->cb);
461 : : else
462 : 0 : rte_eth_remove_tx_callback(port, queue, bc->cb);
463 : :
464 : 0 : bpf_eth_cbi_unload(bc);
465 : : }
466 : :
467 : :
468 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_rx_unload)
469 : : void
470 : 0 : rte_bpf_eth_rx_unload(uint16_t port, uint16_t queue)
471 : : {
472 : : struct bpf_eth_cbh *cbh;
473 : :
474 : : cbh = &rx_cbh;
475 : : rte_spinlock_lock(&cbh->lock);
476 : 0 : bpf_eth_unload(cbh, port, queue);
477 : : rte_spinlock_unlock(&cbh->lock);
478 : 0 : }
479 : :
480 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_tx_unload)
481 : : void
482 : 0 : rte_bpf_eth_tx_unload(uint16_t port, uint16_t queue)
483 : : {
484 : : struct bpf_eth_cbh *cbh;
485 : :
486 : : cbh = &tx_cbh;
487 : : rte_spinlock_lock(&cbh->lock);
488 : 0 : bpf_eth_unload(cbh, port, queue);
489 : : rte_spinlock_unlock(&cbh->lock);
490 : 0 : }
491 : :
492 : : static int
493 : 0 : bpf_eth_elf_load(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue,
494 : : const struct rte_bpf_prm *prm, const char *fname, const char *sname,
495 : : uint32_t flags)
496 : : {
497 : : int32_t rc;
498 : : struct bpf_eth_cbi *bc;
499 : : struct rte_bpf *bpf;
500 : : rte_rx_callback_fn frx;
501 : : rte_tx_callback_fn ftx;
502 : : struct rte_bpf_jit jit;
503 : :
504 : : frx = NULL;
505 : : ftx = NULL;
506 : :
507 [ # # # # : 0 : if (prm == NULL || rte_eth_dev_is_valid_port(port) == 0 ||
# # ]
508 : : queue >= RTE_MAX_QUEUES_PER_PORT)
509 : 0 : return -EINVAL;
510 : :
511 [ # # ]: 0 : if (cbh->type == BPF_ETH_RX)
512 [ # # ]: 0 : frx = select_rx_callback(prm->prog_arg.type, flags);
513 : : else
514 [ # # ]: 0 : ftx = select_tx_callback(prm->prog_arg.type, flags);
515 : :
516 [ # # ]: 0 : if (frx == NULL && ftx == NULL) {
517 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%u, %u): no callback selected;",
518 : : __func__, port, queue);
519 : 0 : return -EINVAL;
520 : : }
521 : :
522 : 0 : bpf = rte_bpf_elf_load(prm, fname, sname);
523 [ # # ]: 0 : if (bpf == NULL)
524 : 0 : return -rte_errno;
525 : :
526 : 0 : rte_bpf_get_jit(bpf, &jit);
527 : :
528 [ # # # # ]: 0 : if ((flags & RTE_BPF_ETH_F_JIT) != 0 && jit.func == NULL) {
529 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%u, %u): no JIT generated;",
530 : : __func__, port, queue);
531 : 0 : rte_bpf_destroy(bpf);
532 : 0 : return -ENOTSUP;
533 : : }
534 : :
535 : : /* setup/update global callback info */
536 : 0 : bc = bpf_eth_cbh_add(cbh, port, queue);
537 [ # # ]: 0 : if (bc == NULL)
538 : : return -ENOMEM;
539 : :
540 : : /* remove old one, if any */
541 [ # # ]: 0 : if (bc->cb != NULL)
542 : 0 : bpf_eth_unload(cbh, port, queue);
543 : :
544 : 0 : bc->bpf = bpf;
545 : 0 : bc->jit = jit;
546 : :
547 [ # # ]: 0 : if (cbh->type == BPF_ETH_RX)
548 : 0 : bc->cb = rte_eth_add_rx_callback(port, queue, frx, bc);
549 : : else
550 : 0 : bc->cb = rte_eth_add_tx_callback(port, queue, ftx, bc);
551 : :
552 [ # # ]: 0 : if (bc->cb == NULL) {
553 : 0 : rc = -rte_errno;
554 : 0 : rte_bpf_destroy(bpf);
555 : : bpf_eth_cbi_cleanup(bc);
556 : : } else
557 : : rc = 0;
558 : :
559 : : return rc;
560 : : }
561 : :
562 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_rx_elf_load)
563 : : int
564 : 0 : rte_bpf_eth_rx_elf_load(uint16_t port, uint16_t queue,
565 : : const struct rte_bpf_prm *prm, const char *fname, const char *sname,
566 : : uint32_t flags)
567 : : {
568 : : int32_t rc;
569 : : struct bpf_eth_cbh *cbh;
570 : :
571 : : cbh = &rx_cbh;
572 : : rte_spinlock_lock(&cbh->lock);
573 : 0 : rc = bpf_eth_elf_load(cbh, port, queue, prm, fname, sname, flags);
574 : : rte_spinlock_unlock(&cbh->lock);
575 : :
576 : 0 : return rc;
577 : : }
578 : :
579 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_tx_elf_load)
580 : : int
581 : 0 : rte_bpf_eth_tx_elf_load(uint16_t port, uint16_t queue,
582 : : const struct rte_bpf_prm *prm, const char *fname, const char *sname,
583 : : uint32_t flags)
584 : : {
585 : : int32_t rc;
586 : : struct bpf_eth_cbh *cbh;
587 : :
588 : : cbh = &tx_cbh;
589 : : rte_spinlock_lock(&cbh->lock);
590 : 0 : rc = bpf_eth_elf_load(cbh, port, queue, prm, fname, sname, flags);
591 : : rte_spinlock_unlock(&cbh->lock);
592 : :
593 : 0 : return rc;
594 : : }
|