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 : 0 : {
165 : : uint32_t i, j, k;
166 : 0 : struct rte_mbuf *dr[num];
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 : for (i = 0; i != k; i++)
181 : 0 : rte_pktmbuf_free(dr[i]);
182 : : } else {
183 : : /* copy filtered out mbufs beyond good ones */
184 [ # # ]: 0 : for (i = 0; i != k; i++)
185 : 0 : mb[j + i] = dr[i];
186 : : }
187 : :
188 : 0 : return j;
189 : : }
190 : :
191 : : static inline uint32_t
192 : 0 : pkt_filter_vm(const struct rte_bpf *bpf, struct rte_mbuf *mb[], uint32_t num,
193 : : uint32_t drop)
194 : 0 : {
195 : : uint32_t i;
196 : 0 : void *dp[num];
197 : 0 : uint64_t rc[num];
198 : :
199 [ # # ]: 0 : for (i = 0; i != num; i++)
200 : 0 : dp[i] = rte_pktmbuf_mtod(mb[i], void *);
201 : :
202 : 0 : rte_bpf_exec_burst(bpf, dp, rc, num);
203 : 0 : return apply_filter(mb, rc, num, drop);
204 : : }
205 : :
206 : : static inline uint32_t
207 : 0 : pkt_filter_jit(const struct rte_bpf_jit *jit, struct rte_mbuf *mb[],
208 : : uint32_t num, uint32_t drop)
209 : 0 : {
210 : : uint32_t i, n;
211 : : void *dp;
212 : 0 : uint64_t rc[num];
213 : :
214 : : n = 0;
215 [ # # ]: 0 : for (i = 0; i != num; i++) {
216 : 0 : dp = rte_pktmbuf_mtod(mb[i], void *);
217 : 0 : rc[i] = jit->func(dp);
218 : 0 : n += (rc[i] == 0);
219 : : }
220 : :
221 [ # # ]: 0 : if (n != 0)
222 : 0 : num = apply_filter(mb, rc, num, drop);
223 : :
224 : 0 : return num;
225 : : }
226 : :
227 : : static inline uint32_t
228 : 0 : pkt_filter_mb_vm(const struct rte_bpf *bpf, struct rte_mbuf *mb[], uint32_t num,
229 : : uint32_t drop)
230 : 0 : {
231 : 0 : uint64_t rc[num];
232 : :
233 : 0 : rte_bpf_exec_burst(bpf, (void **)mb, rc, num);
234 : 0 : return apply_filter(mb, rc, num, drop);
235 : : }
236 : :
237 : : static inline uint32_t
238 : 0 : pkt_filter_mb_jit(const struct rte_bpf_jit *jit, struct rte_mbuf *mb[],
239 : : uint32_t num, uint32_t drop)
240 : 0 : {
241 : : uint32_t i, n;
242 : 0 : uint64_t rc[num];
243 : :
244 : : n = 0;
245 [ # # ]: 0 : for (i = 0; i != num; i++) {
246 : 0 : rc[i] = jit->func(mb[i]);
247 : 0 : n += (rc[i] == 0);
248 : : }
249 : :
250 [ # # ]: 0 : if (n != 0)
251 : 0 : num = apply_filter(mb, rc, num, drop);
252 : :
253 : 0 : return num;
254 : : }
255 : :
256 : : /*
257 : : * RX/TX callbacks for raw data bpf.
258 : : */
259 : :
260 : : static uint16_t
261 : 0 : bpf_rx_callback_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
262 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
263 : : __rte_unused uint16_t max_pkts, void *user_param)
264 : : {
265 : : struct bpf_eth_cbi *cbi;
266 : : uint16_t rc;
267 : :
268 : : cbi = user_param;
269 : :
270 : : bpf_eth_cbi_inuse(cbi);
271 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
272 : 0 : pkt_filter_vm(cbi->bpf, pkt, nb_pkts, 1) :
273 : : nb_pkts;
274 : : bpf_eth_cbi_unuse(cbi);
275 : 0 : return rc;
276 : : }
277 : :
278 : : static uint16_t
279 : 0 : bpf_rx_callback_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
280 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
281 : : __rte_unused uint16_t max_pkts, void *user_param)
282 : : {
283 : : struct bpf_eth_cbi *cbi;
284 : : uint16_t rc;
285 : :
286 : : cbi = user_param;
287 : : bpf_eth_cbi_inuse(cbi);
288 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
289 : 0 : pkt_filter_jit(&cbi->jit, pkt, nb_pkts, 1) :
290 : : nb_pkts;
291 : : bpf_eth_cbi_unuse(cbi);
292 : 0 : return rc;
293 : : }
294 : :
295 : : static uint16_t
296 : 0 : bpf_tx_callback_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
297 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
298 : : {
299 : : struct bpf_eth_cbi *cbi;
300 : : uint16_t rc;
301 : :
302 : : cbi = user_param;
303 : : bpf_eth_cbi_inuse(cbi);
304 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
305 : 0 : pkt_filter_vm(cbi->bpf, pkt, nb_pkts, 0) :
306 : : nb_pkts;
307 : : bpf_eth_cbi_unuse(cbi);
308 : 0 : return rc;
309 : : }
310 : :
311 : : static uint16_t
312 : 0 : bpf_tx_callback_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
313 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
314 : : {
315 : : struct bpf_eth_cbi *cbi;
316 : : uint16_t rc;
317 : :
318 : : cbi = user_param;
319 : : bpf_eth_cbi_inuse(cbi);
320 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
321 : 0 : pkt_filter_jit(&cbi->jit, pkt, nb_pkts, 0) :
322 : : nb_pkts;
323 : : bpf_eth_cbi_unuse(cbi);
324 : 0 : return rc;
325 : : }
326 : :
327 : : /*
328 : : * RX/TX callbacks for mbuf.
329 : : */
330 : :
331 : : static uint16_t
332 : 0 : bpf_rx_callback_mb_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
333 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
334 : : __rte_unused uint16_t max_pkts, void *user_param)
335 : : {
336 : : struct bpf_eth_cbi *cbi;
337 : : uint16_t rc;
338 : :
339 : : cbi = user_param;
340 : : bpf_eth_cbi_inuse(cbi);
341 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
342 : 0 : pkt_filter_mb_vm(cbi->bpf, pkt, nb_pkts, 1) :
343 : : nb_pkts;
344 : : bpf_eth_cbi_unuse(cbi);
345 : 0 : return rc;
346 : : }
347 : :
348 : : static uint16_t
349 : 0 : bpf_rx_callback_mb_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
350 : : struct rte_mbuf *pkt[], uint16_t nb_pkts,
351 : : __rte_unused uint16_t max_pkts, void *user_param)
352 : : {
353 : : struct bpf_eth_cbi *cbi;
354 : : uint16_t rc;
355 : :
356 : : cbi = user_param;
357 : : bpf_eth_cbi_inuse(cbi);
358 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
359 : 0 : pkt_filter_mb_jit(&cbi->jit, pkt, nb_pkts, 1) :
360 : : nb_pkts;
361 : : bpf_eth_cbi_unuse(cbi);
362 : 0 : return rc;
363 : : }
364 : :
365 : : static uint16_t
366 : 0 : bpf_tx_callback_mb_vm(__rte_unused uint16_t port, __rte_unused uint16_t queue,
367 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
368 : : {
369 : : struct bpf_eth_cbi *cbi;
370 : : uint16_t rc;
371 : :
372 : : cbi = user_param;
373 : : bpf_eth_cbi_inuse(cbi);
374 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
375 : 0 : pkt_filter_mb_vm(cbi->bpf, pkt, nb_pkts, 0) :
376 : : nb_pkts;
377 : : bpf_eth_cbi_unuse(cbi);
378 : 0 : return rc;
379 : : }
380 : :
381 : : static uint16_t
382 : 0 : bpf_tx_callback_mb_jit(__rte_unused uint16_t port, __rte_unused uint16_t queue,
383 : : struct rte_mbuf *pkt[], uint16_t nb_pkts, void *user_param)
384 : : {
385 : : struct bpf_eth_cbi *cbi;
386 : : uint16_t rc;
387 : :
388 : : cbi = user_param;
389 : : bpf_eth_cbi_inuse(cbi);
390 [ # # ]: 0 : rc = (cbi->cb != NULL) ?
391 : 0 : pkt_filter_mb_jit(&cbi->jit, pkt, nb_pkts, 0) :
392 : : nb_pkts;
393 : : bpf_eth_cbi_unuse(cbi);
394 : 0 : return rc;
395 : : }
396 : :
397 : : static rte_rx_callback_fn
398 : : select_rx_callback(enum rte_bpf_arg_type type, uint32_t flags)
399 : : {
400 : 0 : if (flags & RTE_BPF_ETH_F_JIT) {
401 [ # # ]: 0 : if (type == RTE_BPF_ARG_PTR)
402 : : return bpf_rx_callback_jit;
403 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
404 : 0 : return bpf_rx_callback_mb_jit;
405 [ # # ]: 0 : } else if (type == RTE_BPF_ARG_PTR)
406 : : return bpf_rx_callback_vm;
407 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
408 : 0 : return bpf_rx_callback_mb_vm;
409 : :
410 : : return NULL;
411 : : }
412 : :
413 : : static rte_tx_callback_fn
414 : : select_tx_callback(enum rte_bpf_arg_type type, uint32_t flags)
415 : : {
416 : 0 : if (flags & RTE_BPF_ETH_F_JIT) {
417 [ # # ]: 0 : if (type == RTE_BPF_ARG_PTR)
418 : : return bpf_tx_callback_jit;
419 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
420 : 0 : return bpf_tx_callback_mb_jit;
421 [ # # ]: 0 : } else if (type == RTE_BPF_ARG_PTR)
422 : : return bpf_tx_callback_vm;
423 [ # # ]: 0 : else if (type == RTE_BPF_ARG_PTR_MBUF)
424 : 0 : return bpf_tx_callback_mb_vm;
425 : :
426 : : return NULL;
427 : : }
428 : :
429 : : /*
430 : : * helper function to perform BPF unload for given port/queue.
431 : : * have to introduce extra complexity (and possible slowdown) here,
432 : : * as right now there is no safe generic way to remove RX/TX callback
433 : : * while IO is active.
434 : : * Still don't free memory allocated for callback handle itself,
435 : : * again right now there is no safe way to do that without stopping RX/TX
436 : : * on given port/queue first.
437 : : */
438 : : static void
439 : 0 : bpf_eth_cbi_unload(struct bpf_eth_cbi *bc)
440 : : {
441 : : /* mark this cbi as empty */
442 : 0 : bc->cb = NULL;
443 : : rte_smp_mb();
444 : :
445 : : /* make sure datapath doesn't use bpf anymore, then destroy bpf */
446 : 0 : bpf_eth_cbi_wait(bc);
447 : 0 : rte_bpf_destroy(bc->bpf);
448 : : bpf_eth_cbi_cleanup(bc);
449 : 0 : }
450 : :
451 : : static void
452 : 0 : bpf_eth_unload(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue)
453 : : {
454 : : struct bpf_eth_cbi *bc;
455 : :
456 : 0 : bc = bpf_eth_cbh_find(cbh, port, queue);
457 [ # # # # ]: 0 : if (bc == NULL || bc->cb == NULL)
458 : : return;
459 : :
460 [ # # ]: 0 : if (cbh->type == BPF_ETH_RX)
461 : 0 : rte_eth_remove_rx_callback(port, queue, bc->cb);
462 : : else
463 : 0 : rte_eth_remove_tx_callback(port, queue, bc->cb);
464 : :
465 : 0 : bpf_eth_cbi_unload(bc);
466 : : }
467 : :
468 : :
469 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_rx_unload)
470 : : void
471 : 0 : rte_bpf_eth_rx_unload(uint16_t port, uint16_t queue)
472 : : {
473 : : struct bpf_eth_cbh *cbh;
474 : :
475 : : cbh = &rx_cbh;
476 : : rte_spinlock_lock(&cbh->lock);
477 : 0 : bpf_eth_unload(cbh, port, queue);
478 : : rte_spinlock_unlock(&cbh->lock);
479 : 0 : }
480 : :
481 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_tx_unload)
482 : : void
483 : 0 : rte_bpf_eth_tx_unload(uint16_t port, uint16_t queue)
484 : : {
485 : : struct bpf_eth_cbh *cbh;
486 : :
487 : : cbh = &tx_cbh;
488 : : rte_spinlock_lock(&cbh->lock);
489 : 0 : bpf_eth_unload(cbh, port, queue);
490 : : rte_spinlock_unlock(&cbh->lock);
491 : 0 : }
492 : :
493 : : static int
494 : 0 : bpf_eth_elf_load(struct bpf_eth_cbh *cbh, uint16_t port, uint16_t queue,
495 : : const struct rte_bpf_prm *prm, const char *fname, const char *sname,
496 : : uint32_t flags)
497 : : {
498 : : int32_t rc;
499 : : struct bpf_eth_cbi *bc;
500 : : struct rte_bpf *bpf;
501 : : rte_rx_callback_fn frx;
502 : : rte_tx_callback_fn ftx;
503 : : struct rte_bpf_jit jit;
504 : :
505 : : frx = NULL;
506 : : ftx = NULL;
507 : :
508 [ # # # # : 0 : if (prm == NULL || rte_eth_dev_is_valid_port(port) == 0 ||
# # ]
509 : : queue >= RTE_MAX_QUEUES_PER_PORT)
510 : 0 : return -EINVAL;
511 : :
512 [ # # ]: 0 : if (cbh->type == BPF_ETH_RX)
513 [ # # ]: 0 : frx = select_rx_callback(prm->prog_arg.type, flags);
514 : : else
515 [ # # ]: 0 : ftx = select_tx_callback(prm->prog_arg.type, flags);
516 : :
517 [ # # ]: 0 : if (frx == NULL && ftx == NULL) {
518 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%u, %u): no callback selected;",
519 : : __func__, port, queue);
520 : 0 : return -EINVAL;
521 : : }
522 : :
523 : 0 : bpf = rte_bpf_elf_load(prm, fname, sname);
524 [ # # ]: 0 : if (bpf == NULL)
525 : 0 : return -rte_errno;
526 : :
527 : 0 : rte_bpf_get_jit(bpf, &jit);
528 : :
529 [ # # # # ]: 0 : if ((flags & RTE_BPF_ETH_F_JIT) != 0 && jit.func == NULL) {
530 : 0 : RTE_BPF_LOG_LINE(ERR, "%s(%u, %u): no JIT generated;",
531 : : __func__, port, queue);
532 : 0 : rte_bpf_destroy(bpf);
533 : 0 : return -ENOTSUP;
534 : : }
535 : :
536 : : /* setup/update global callback info */
537 : 0 : bc = bpf_eth_cbh_add(cbh, port, queue);
538 [ # # ]: 0 : if (bc == NULL)
539 : : return -ENOMEM;
540 : :
541 : : /* remove old one, if any */
542 [ # # ]: 0 : if (bc->cb != NULL)
543 : 0 : bpf_eth_unload(cbh, port, queue);
544 : :
545 : 0 : bc->bpf = bpf;
546 : 0 : bc->jit = jit;
547 : :
548 [ # # ]: 0 : if (cbh->type == BPF_ETH_RX)
549 : 0 : bc->cb = rte_eth_add_rx_callback(port, queue, frx, bc);
550 : : else
551 : 0 : bc->cb = rte_eth_add_tx_callback(port, queue, ftx, bc);
552 : :
553 [ # # ]: 0 : if (bc->cb == NULL) {
554 : 0 : rc = -rte_errno;
555 : 0 : rte_bpf_destroy(bpf);
556 : : bpf_eth_cbi_cleanup(bc);
557 : : } else
558 : : rc = 0;
559 : :
560 : : return rc;
561 : : }
562 : :
563 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_rx_elf_load)
564 : : int
565 : 0 : rte_bpf_eth_rx_elf_load(uint16_t port, uint16_t queue,
566 : : const struct rte_bpf_prm *prm, const char *fname, const char *sname,
567 : : uint32_t flags)
568 : : {
569 : : int32_t rc;
570 : : struct bpf_eth_cbh *cbh;
571 : :
572 : : cbh = &rx_cbh;
573 : : rte_spinlock_lock(&cbh->lock);
574 : 0 : rc = bpf_eth_elf_load(cbh, port, queue, prm, fname, sname, flags);
575 : : rte_spinlock_unlock(&cbh->lock);
576 : :
577 : 0 : return rc;
578 : : }
579 : :
580 : : RTE_EXPORT_SYMBOL(rte_bpf_eth_tx_elf_load)
581 : : int
582 : 0 : rte_bpf_eth_tx_elf_load(uint16_t port, uint16_t queue,
583 : : const struct rte_bpf_prm *prm, const char *fname, const char *sname,
584 : : uint32_t flags)
585 : : {
586 : : int32_t rc;
587 : : struct bpf_eth_cbh *cbh;
588 : :
589 : : cbh = &tx_cbh;
590 : : rte_spinlock_lock(&cbh->lock);
591 : 0 : rc = bpf_eth_elf_load(cbh, port, queue, prm, fname, sname, flags);
592 : : rte_spinlock_unlock(&cbh->lock);
593 : :
594 : 0 : return rc;
595 : : }
|