Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2019-2020 Intel Corporation.
3 : : */
4 : : #include <unistd.h>
5 : : #include <errno.h>
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <netinet/in.h>
9 : : #include <net/if.h>
10 : : #include <sys/un.h>
11 : : #include <sys/socket.h>
12 : : #include <sys/ioctl.h>
13 : : #include <linux/if_ether.h>
14 : : #include <linux/if_xdp.h>
15 : : #include <linux/if_link.h>
16 : : #include <linux/ethtool.h>
17 : : #include <linux/sockios.h>
18 : : #include "af_xdp_deps.h"
19 : :
20 : : #include <rte_ethdev.h>
21 : : #include <ethdev_driver.h>
22 : : #include <ethdev_vdev.h>
23 : : #include <rte_kvargs.h>
24 : : #include <bus_vdev_driver.h>
25 : : #include <rte_string_fns.h>
26 : : #include <rte_branch_prediction.h>
27 : : #include <rte_common.h>
28 : : #include <dev_driver.h>
29 : : #include <rte_eal.h>
30 : : #include <rte_ether.h>
31 : : #include <rte_lcore.h>
32 : : #include <rte_log.h>
33 : : #include <rte_memory.h>
34 : : #include <rte_memzone.h>
35 : : #include <rte_mempool.h>
36 : : #include <rte_mbuf.h>
37 : : #include <rte_malloc.h>
38 : : #include <rte_ring.h>
39 : : #include <rte_spinlock.h>
40 : : #include <rte_power_intrinsics.h>
41 : :
42 : : #include "compat.h"
43 : : #include "eal_filesystem.h"
44 : :
45 : : #ifndef SO_PREFER_BUSY_POLL
46 : : #define SO_PREFER_BUSY_POLL 69
47 : : #endif
48 : : #ifndef SO_BUSY_POLL_BUDGET
49 : : #define SO_BUSY_POLL_BUDGET 70
50 : : #endif
51 : :
52 : :
53 : : #ifndef SOL_XDP
54 : : #define SOL_XDP 283
55 : : #endif
56 : :
57 : : #ifndef AF_XDP
58 : : #define AF_XDP 44
59 : : #endif
60 : :
61 : : #ifndef PF_XDP
62 : : #define PF_XDP AF_XDP
63 : : #endif
64 : :
65 [ - + ]: 238 : RTE_LOG_REGISTER_DEFAULT(af_xdp_logtype, NOTICE);
66 : :
67 : : #define AF_XDP_LOG(level, fmt, args...) \
68 : : rte_log(RTE_LOG_ ## level, af_xdp_logtype, \
69 : : "%s(): " fmt, __func__, ##args)
70 : :
71 : : #define ETH_AF_XDP_FRAME_SIZE 2048
72 : : #define ETH_AF_XDP_NUM_BUFFERS 4096
73 : : #define ETH_AF_XDP_DFLT_NUM_DESCS XSK_RING_CONS__DEFAULT_NUM_DESCS
74 : : #define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0
75 : : #define ETH_AF_XDP_DFLT_QUEUE_COUNT 1
76 : : #define ETH_AF_XDP_DFLT_BUSY_BUDGET 64
77 : : #define ETH_AF_XDP_DFLT_BUSY_TIMEOUT 20
78 : :
79 : : #define ETH_AF_XDP_RX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCS
80 : : #define ETH_AF_XDP_TX_BATCH_SIZE XSK_RING_CONS__DEFAULT_NUM_DESCS
81 : :
82 : : #define ETH_AF_XDP_ETH_OVERHEAD (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN)
83 : :
84 : : #define ETH_AF_XDP_MP_KEY "afxdp_mp_send_fds"
85 : :
86 : : #define MAX_LONG_OPT_SZ 64
87 : : #define UDS_MAX_FD_NUM 2
88 : : #define UDS_MAX_CMD_LEN 64
89 : : #define UDS_MAX_CMD_RESP 128
90 : : #define UDS_XSK_MAP_FD_MSG "/xsk_map_fd"
91 : : #define UDS_SOCK "/tmp/afxdp.sock"
92 : : #define UDS_CONNECT_MSG "/connect"
93 : : #define UDS_HOST_OK_MSG "/host_ok"
94 : : #define UDS_HOST_NAK_MSG "/host_nak"
95 : : #define UDS_VERSION_MSG "/version"
96 : : #define UDS_XSK_MAP_FD_MSG "/xsk_map_fd"
97 : : #define UDS_XSK_SOCKET_MSG "/xsk_socket"
98 : : #define UDS_FD_ACK_MSG "/fd_ack"
99 : : #define UDS_FD_NAK_MSG "/fd_nak"
100 : : #define UDS_FIN_MSG "/fin"
101 : : #define UDS_FIN_ACK_MSG "/fin_ack"
102 : :
103 : : static int afxdp_dev_count;
104 : :
105 : : /* Message header to synchronize fds via IPC */
106 : : struct ipc_hdr {
107 : : char port_name[RTE_DEV_NAME_MAX_LEN];
108 : : /* The file descriptors are in the dedicated part
109 : : * of the Unix message to be translated by the kernel.
110 : : */
111 : : };
112 : :
113 : : struct xsk_umem_info {
114 : : struct xsk_umem *umem;
115 : : struct rte_ring *buf_ring;
116 : : const struct rte_memzone *mz;
117 : : struct rte_mempool *mb_pool;
118 : : void *buffer;
119 : : uint8_t refcnt;
120 : : uint32_t max_xsks;
121 : : };
122 : :
123 : : struct rx_stats {
124 : : uint64_t rx_pkts;
125 : : uint64_t rx_bytes;
126 : : uint64_t rx_dropped;
127 : : };
128 : :
129 : : struct pkt_rx_queue {
130 : : struct xsk_ring_cons rx;
131 : : struct xsk_umem_info *umem;
132 : : struct xsk_socket *xsk;
133 : : struct rte_mempool *mb_pool;
134 : :
135 : : struct rx_stats stats;
136 : :
137 : : struct xsk_ring_prod fq;
138 : : struct xsk_ring_cons cq;
139 : :
140 : : struct pkt_tx_queue *pair;
141 : : struct pollfd fds[1];
142 : : int xsk_queue_idx;
143 : : int busy_budget;
144 : : };
145 : :
146 : : struct tx_stats {
147 : : uint64_t tx_pkts;
148 : : uint64_t tx_bytes;
149 : : uint64_t tx_dropped;
150 : : };
151 : :
152 : : struct pkt_tx_queue {
153 : : struct xsk_ring_prod tx;
154 : : struct xsk_umem_info *umem;
155 : :
156 : : struct tx_stats stats;
157 : :
158 : : struct pkt_rx_queue *pair;
159 : : int xsk_queue_idx;
160 : : };
161 : :
162 : : struct pmd_internals {
163 : : int if_index;
164 : : char if_name[IFNAMSIZ];
165 : : int start_queue_idx;
166 : : int queue_cnt;
167 : : int max_queue_cnt;
168 : : int combined_queue_cnt;
169 : : bool shared_umem;
170 : : char prog_path[PATH_MAX];
171 : : bool custom_prog_configured;
172 : : bool force_copy;
173 : : bool use_cni;
174 : : struct bpf_map *map;
175 : :
176 : : struct rte_ether_addr eth_addr;
177 : :
178 : : struct pkt_rx_queue *rx_queues;
179 : : struct pkt_tx_queue *tx_queues;
180 : : };
181 : :
182 : : struct pmd_process_private {
183 : : int rxq_xsk_fds[RTE_MAX_QUEUES_PER_PORT];
184 : : };
185 : :
186 : : #define ETH_AF_XDP_IFACE_ARG "iface"
187 : : #define ETH_AF_XDP_START_QUEUE_ARG "start_queue"
188 : : #define ETH_AF_XDP_QUEUE_COUNT_ARG "queue_count"
189 : : #define ETH_AF_XDP_SHARED_UMEM_ARG "shared_umem"
190 : : #define ETH_AF_XDP_PROG_ARG "xdp_prog"
191 : : #define ETH_AF_XDP_BUDGET_ARG "busy_budget"
192 : : #define ETH_AF_XDP_FORCE_COPY_ARG "force_copy"
193 : : #define ETH_AF_XDP_USE_CNI_ARG "use_cni"
194 : :
195 : : static const char * const valid_arguments[] = {
196 : : ETH_AF_XDP_IFACE_ARG,
197 : : ETH_AF_XDP_START_QUEUE_ARG,
198 : : ETH_AF_XDP_QUEUE_COUNT_ARG,
199 : : ETH_AF_XDP_SHARED_UMEM_ARG,
200 : : ETH_AF_XDP_PROG_ARG,
201 : : ETH_AF_XDP_BUDGET_ARG,
202 : : ETH_AF_XDP_FORCE_COPY_ARG,
203 : : ETH_AF_XDP_USE_CNI_ARG,
204 : : NULL
205 : : };
206 : :
207 : : static const struct rte_eth_link pmd_link = {
208 : : .link_speed = RTE_ETH_SPEED_NUM_10G,
209 : : .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
210 : : .link_status = RTE_ETH_LINK_DOWN,
211 : : .link_autoneg = RTE_ETH_LINK_AUTONEG
212 : : };
213 : :
214 : : /* List which tracks PMDs to facilitate sharing UMEMs across them. */
215 : : struct internal_list {
216 : : TAILQ_ENTRY(internal_list) next;
217 : : struct rte_eth_dev *eth_dev;
218 : : };
219 : :
220 : : TAILQ_HEAD(internal_list_head, internal_list);
221 : : static struct internal_list_head internal_list =
222 : : TAILQ_HEAD_INITIALIZER(internal_list);
223 : :
224 : : static pthread_mutex_t internal_list_lock = PTHREAD_MUTEX_INITIALIZER;
225 : :
226 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
227 : : static inline int
228 : 0 : reserve_fill_queue_zc(struct xsk_umem_info *umem, uint16_t reserve_size,
229 : : struct rte_mbuf **bufs, struct xsk_ring_prod *fq)
230 : : {
231 : : uint32_t idx;
232 : : uint16_t i;
233 : :
234 [ # # # # ]: 0 : if (unlikely(!xsk_ring_prod__reserve(fq, reserve_size, &idx))) {
235 [ # # ]: 0 : for (i = 0; i < reserve_size; i++)
236 : 0 : rte_pktmbuf_free(bufs[i]);
237 : 0 : AF_XDP_LOG(DEBUG, "Failed to reserve enough fq descs.\n");
238 : 0 : return -1;
239 : : }
240 : :
241 [ # # ]: 0 : for (i = 0; i < reserve_size; i++) {
242 : : __u64 *fq_addr;
243 : : uint64_t addr;
244 : :
245 : 0 : fq_addr = xsk_ring_prod__fill_addr(fq, idx++);
246 : 0 : addr = (uint64_t)bufs[i] - (uint64_t)umem->buffer -
247 : 0 : umem->mb_pool->header_size;
248 : 0 : *fq_addr = addr;
249 : : }
250 : :
251 : : xsk_ring_prod__submit(fq, reserve_size);
252 : :
253 : 0 : return 0;
254 : : }
255 : : #else
256 : : static inline int
257 : : reserve_fill_queue_cp(struct xsk_umem_info *umem, uint16_t reserve_size,
258 : : struct rte_mbuf **bufs __rte_unused,
259 : : struct xsk_ring_prod *fq)
260 : : {
261 : : void *addrs[reserve_size];
262 : : uint32_t idx;
263 : : uint16_t i;
264 : :
265 : : if (rte_ring_dequeue_bulk(umem->buf_ring, addrs, reserve_size, NULL)
266 : : != reserve_size) {
267 : : AF_XDP_LOG(DEBUG, "Failed to get enough buffers for fq.\n");
268 : : return -1;
269 : : }
270 : :
271 : : if (unlikely(!xsk_ring_prod__reserve(fq, reserve_size, &idx))) {
272 : : AF_XDP_LOG(DEBUG, "Failed to reserve enough fq descs.\n");
273 : : rte_ring_enqueue_bulk(umem->buf_ring, addrs,
274 : : reserve_size, NULL);
275 : : return -1;
276 : : }
277 : :
278 : : for (i = 0; i < reserve_size; i++) {
279 : : __u64 *fq_addr;
280 : :
281 : : fq_addr = xsk_ring_prod__fill_addr(fq, idx++);
282 : : *fq_addr = (uint64_t)addrs[i];
283 : : }
284 : :
285 : : xsk_ring_prod__submit(fq, reserve_size);
286 : :
287 : : return 0;
288 : : }
289 : : #endif
290 : :
291 : : static inline int
292 : : reserve_fill_queue(struct xsk_umem_info *umem, uint16_t reserve_size,
293 : : struct rte_mbuf **bufs, struct xsk_ring_prod *fq)
294 : : {
295 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
296 : 0 : return reserve_fill_queue_zc(umem, reserve_size, bufs, fq);
297 : : #else
298 : : return reserve_fill_queue_cp(umem, reserve_size, bufs, fq);
299 : : #endif
300 : : }
301 : :
302 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
303 : : static uint16_t
304 : 0 : af_xdp_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
305 : : {
306 : : struct pkt_rx_queue *rxq = queue;
307 : : struct xsk_ring_cons *rx = &rxq->rx;
308 : 0 : struct xsk_ring_prod *fq = &rxq->fq;
309 : 0 : struct xsk_umem_info *umem = rxq->umem;
310 : : uint32_t idx_rx = 0;
311 : : unsigned long rx_bytes = 0;
312 : : int i;
313 : : struct rte_mbuf *fq_bufs[ETH_AF_XDP_RX_BATCH_SIZE];
314 : :
315 [ # # ]: 0 : nb_pkts = xsk_ring_cons__peek(rx, nb_pkts, &idx_rx);
316 : :
317 [ # # ]: 0 : if (nb_pkts == 0) {
318 : : /* we can assume a kernel >= 5.11 is in use if busy polling is
319 : : * enabled and thus we can safely use the recvfrom() syscall
320 : : * which is only supported for AF_XDP sockets in kernels >=
321 : : * 5.11.
322 : : */
323 [ # # ]: 0 : if (rxq->busy_budget) {
324 : 0 : (void)recvfrom(xsk_socket__fd(rxq->xsk), NULL, 0,
325 : : MSG_DONTWAIT, NULL, NULL);
326 [ # # ]: 0 : } else if (xsk_ring_prod__needs_wakeup(fq)) {
327 [ # # ]: 0 : (void)poll(&rxq->fds[0], 1, 1000);
328 : : }
329 : :
330 : 0 : return 0;
331 : : }
332 : :
333 : : /* allocate bufs for fill queue replenishment after rx */
334 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(umem->mb_pool, fq_bufs, nb_pkts)) {
335 : 0 : AF_XDP_LOG(DEBUG,
336 : : "Failed to get enough buffers for fq.\n");
337 : : /* rollback cached_cons which is added by
338 : : * xsk_ring_cons__peek
339 : : */
340 : 0 : rx->cached_cons -= nb_pkts;
341 : 0 : return 0;
342 : : }
343 : :
344 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
345 : : const struct xdp_desc *desc;
346 : : uint64_t addr;
347 : : uint32_t len;
348 : : uint64_t offset;
349 : :
350 [ # # ]: 0 : desc = xsk_ring_cons__rx_desc(rx, idx_rx++);
351 : 0 : addr = desc->addr;
352 [ # # ]: 0 : len = desc->len;
353 : :
354 : : offset = xsk_umem__extract_offset(addr);
355 : : addr = xsk_umem__extract_addr(addr);
356 : :
357 : 0 : bufs[i] = (struct rte_mbuf *)
358 : 0 : xsk_umem__get_data(umem->buffer, addr +
359 [ # # ]: 0 : umem->mb_pool->header_size);
360 [ # # ]: 0 : bufs[i]->data_off = offset - sizeof(struct rte_mbuf) -
361 : 0 : rte_pktmbuf_priv_size(umem->mb_pool) -
362 : : umem->mb_pool->header_size;
363 : :
364 : 0 : rte_pktmbuf_pkt_len(bufs[i]) = len;
365 : 0 : rte_pktmbuf_data_len(bufs[i]) = len;
366 : 0 : rx_bytes += len;
367 : : }
368 : :
369 : : xsk_ring_cons__release(rx, nb_pkts);
370 : : (void)reserve_fill_queue(umem, nb_pkts, fq_bufs, fq);
371 : :
372 : : /* statistics */
373 : 0 : rxq->stats.rx_pkts += nb_pkts;
374 : 0 : rxq->stats.rx_bytes += rx_bytes;
375 : :
376 : 0 : return nb_pkts;
377 : : }
378 : : #else
379 : : static uint16_t
380 : : af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
381 : : {
382 : : struct pkt_rx_queue *rxq = queue;
383 : : struct xsk_ring_cons *rx = &rxq->rx;
384 : : struct xsk_umem_info *umem = rxq->umem;
385 : : struct xsk_ring_prod *fq = &rxq->fq;
386 : : uint32_t idx_rx = 0;
387 : : unsigned long rx_bytes = 0;
388 : : int i;
389 : : uint32_t free_thresh = fq->size >> 1;
390 : : struct rte_mbuf *mbufs[ETH_AF_XDP_RX_BATCH_SIZE];
391 : :
392 : : if (xsk_prod_nb_free(fq, free_thresh) >= free_thresh)
393 : : (void)reserve_fill_queue(umem, nb_pkts, NULL, fq);
394 : :
395 : : nb_pkts = xsk_ring_cons__peek(rx, nb_pkts, &idx_rx);
396 : : if (nb_pkts == 0) {
397 : : #if defined(XDP_USE_NEED_WAKEUP)
398 : : if (xsk_ring_prod__needs_wakeup(fq))
399 : : (void)poll(rxq->fds, 1, 1000);
400 : : #endif
401 : : return 0;
402 : : }
403 : :
404 : : if (unlikely(rte_pktmbuf_alloc_bulk(rxq->mb_pool, mbufs, nb_pkts))) {
405 : : /* rollback cached_cons which is added by
406 : : * xsk_ring_cons__peek
407 : : */
408 : : rx->cached_cons -= nb_pkts;
409 : : return 0;
410 : : }
411 : :
412 : : for (i = 0; i < nb_pkts; i++) {
413 : : const struct xdp_desc *desc;
414 : : uint64_t addr;
415 : : uint32_t len;
416 : : void *pkt;
417 : :
418 : : desc = xsk_ring_cons__rx_desc(rx, idx_rx++);
419 : : addr = desc->addr;
420 : : len = desc->len;
421 : : pkt = xsk_umem__get_data(rxq->umem->mz->addr, addr);
422 : :
423 : : rte_memcpy(rte_pktmbuf_mtod(mbufs[i], void *), pkt, len);
424 : : rte_ring_enqueue(umem->buf_ring, (void *)addr);
425 : : rte_pktmbuf_pkt_len(mbufs[i]) = len;
426 : : rte_pktmbuf_data_len(mbufs[i]) = len;
427 : : rx_bytes += len;
428 : : bufs[i] = mbufs[i];
429 : : }
430 : :
431 : : xsk_ring_cons__release(rx, nb_pkts);
432 : :
433 : : /* statistics */
434 : : rxq->stats.rx_pkts += nb_pkts;
435 : : rxq->stats.rx_bytes += rx_bytes;
436 : :
437 : : return nb_pkts;
438 : : }
439 : : #endif
440 : :
441 : : static uint16_t
442 : : af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
443 : : {
444 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
445 : 0 : return af_xdp_rx_zc(queue, bufs, nb_pkts);
446 : : #else
447 : : return af_xdp_rx_cp(queue, bufs, nb_pkts);
448 : : #endif
449 : : }
450 : :
451 : : static uint16_t
452 : 0 : eth_af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
453 : : {
454 : : uint16_t nb_rx;
455 : :
456 [ # # ]: 0 : if (likely(nb_pkts <= ETH_AF_XDP_RX_BATCH_SIZE))
457 : 0 : return af_xdp_rx(queue, bufs, nb_pkts);
458 : :
459 : : /* Split larger batch into smaller batches of size
460 : : * ETH_AF_XDP_RX_BATCH_SIZE or less.
461 : : */
462 : : nb_rx = 0;
463 [ # # ]: 0 : while (nb_pkts) {
464 : : uint16_t ret, n;
465 : :
466 : 0 : n = (uint16_t)RTE_MIN(nb_pkts, ETH_AF_XDP_RX_BATCH_SIZE);
467 : 0 : ret = af_xdp_rx(queue, &bufs[nb_rx], n);
468 : 0 : nb_rx = (uint16_t)(nb_rx + ret);
469 : 0 : nb_pkts = (uint16_t)(nb_pkts - ret);
470 [ # # ]: 0 : if (ret < n)
471 : : break;
472 : : }
473 : :
474 : : return nb_rx;
475 : : }
476 : :
477 : : static void
478 : 0 : pull_umem_cq(struct xsk_umem_info *umem, int size, struct xsk_ring_cons *cq)
479 : : {
480 : : size_t i, n;
481 : : uint32_t idx_cq = 0;
482 : :
483 [ # # ]: 0 : n = xsk_ring_cons__peek(cq, size, &idx_cq);
484 : :
485 [ # # ]: 0 : for (i = 0; i < n; i++) {
486 : : uint64_t addr;
487 : 0 : addr = *xsk_ring_cons__comp_addr(cq, idx_cq++);
488 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
489 : : addr = xsk_umem__extract_addr(addr);
490 : 0 : rte_pktmbuf_free((struct rte_mbuf *)
491 : 0 : xsk_umem__get_data(umem->buffer,
492 : 0 : addr + umem->mb_pool->header_size));
493 : : #else
494 : : rte_ring_enqueue(umem->buf_ring, (void *)addr);
495 : : #endif
496 : : }
497 : :
498 : : xsk_ring_cons__release(cq, n);
499 : 0 : }
500 : :
501 : : static void
502 : 0 : kick_tx(struct pkt_tx_queue *txq, struct xsk_ring_cons *cq)
503 : : {
504 : 0 : struct xsk_umem_info *umem = txq->umem;
505 : :
506 : 0 : pull_umem_cq(umem, XSK_RING_CONS__DEFAULT_NUM_DESCS, cq);
507 : :
508 [ # # ]: 0 : if (tx_syscall_needed(&txq->tx))
509 : 0 : while (send(xsk_socket__fd(txq->pair->xsk), NULL,
510 [ # # ]: 0 : 0, MSG_DONTWAIT) < 0) {
511 : : /* some thing unexpected */
512 [ # # # # ]: 0 : if (errno != EBUSY && errno != EAGAIN && errno != EINTR)
513 : : break;
514 : :
515 : : /* pull from completion queue to leave more space */
516 [ # # ]: 0 : if (errno == EAGAIN)
517 : 0 : pull_umem_cq(umem,
518 : : XSK_RING_CONS__DEFAULT_NUM_DESCS,
519 : : cq);
520 : : }
521 : 0 : }
522 : :
523 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
524 : : static uint16_t
525 : 0 : af_xdp_tx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
526 : : {
527 : : struct pkt_tx_queue *txq = queue;
528 : 0 : struct xsk_umem_info *umem = txq->umem;
529 : : struct rte_mbuf *mbuf;
530 : : unsigned long tx_bytes = 0;
531 : : int i;
532 : : uint32_t idx_tx;
533 : : uint16_t count = 0;
534 : : struct xdp_desc *desc;
535 : : uint64_t addr, offset;
536 : 0 : struct xsk_ring_cons *cq = &txq->pair->cq;
537 [ # # ]: 0 : uint32_t free_thresh = cq->size >> 1;
538 : :
539 [ # # ]: 0 : if (xsk_cons_nb_avail(cq, free_thresh) >= free_thresh)
540 : 0 : pull_umem_cq(umem, XSK_RING_CONS__DEFAULT_NUM_DESCS, cq);
541 : :
542 [ # # ]: 0 : for (i = 0; i < nb_pkts; i++) {
543 : 0 : mbuf = bufs[i];
544 : :
545 [ # # ]: 0 : if (mbuf->pool == umem->mb_pool) {
546 : : if (!xsk_ring_prod__reserve(&txq->tx, 1, &idx_tx)) {
547 : 0 : kick_tx(txq, cq);
548 : : if (!xsk_ring_prod__reserve(&txq->tx, 1,
549 : : &idx_tx))
550 : 0 : goto out;
551 : : }
552 : : desc = xsk_ring_prod__tx_desc(&txq->tx, idx_tx);
553 : 0 : desc->len = mbuf->pkt_len;
554 : 0 : addr = (uint64_t)mbuf - (uint64_t)umem->buffer -
555 : 0 : umem->mb_pool->header_size;
556 : 0 : offset = rte_pktmbuf_mtod(mbuf, uint64_t) -
557 : : (uint64_t)mbuf +
558 : : umem->mb_pool->header_size;
559 : 0 : offset = offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT;
560 : 0 : desc->addr = addr | offset;
561 : 0 : count++;
562 : : } else {
563 : : struct rte_mbuf *local_mbuf =
564 : 0 : rte_pktmbuf_alloc(umem->mb_pool);
565 : : void *pkt;
566 : :
567 [ # # ]: 0 : if (local_mbuf == NULL)
568 : 0 : goto out;
569 : :
570 : : if (!xsk_ring_prod__reserve(&txq->tx, 1, &idx_tx)) {
571 : 0 : rte_pktmbuf_free(local_mbuf);
572 : 0 : goto out;
573 : : }
574 : :
575 : : desc = xsk_ring_prod__tx_desc(&txq->tx, idx_tx);
576 : 0 : desc->len = mbuf->pkt_len;
577 : :
578 : 0 : addr = (uint64_t)local_mbuf - (uint64_t)umem->buffer -
579 : 0 : umem->mb_pool->header_size;
580 : 0 : offset = rte_pktmbuf_mtod(local_mbuf, uint64_t) -
581 : : (uint64_t)local_mbuf +
582 : : umem->mb_pool->header_size;
583 [ # # ]: 0 : pkt = xsk_umem__get_data(umem->buffer, addr + offset);
584 : 0 : offset = offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT;
585 : 0 : desc->addr = addr | offset;
586 [ # # ]: 0 : rte_memcpy(pkt, rte_pktmbuf_mtod(mbuf, void *),
587 : : desc->len);
588 : 0 : rte_pktmbuf_free(mbuf);
589 : 0 : count++;
590 : : }
591 : :
592 : 0 : tx_bytes += mbuf->pkt_len;
593 : : }
594 : :
595 : 0 : out:
596 : 0 : xsk_ring_prod__submit(&txq->tx, count);
597 : 0 : kick_tx(txq, cq);
598 : :
599 : 0 : txq->stats.tx_pkts += count;
600 : 0 : txq->stats.tx_bytes += tx_bytes;
601 : 0 : txq->stats.tx_dropped += nb_pkts - count;
602 : :
603 : 0 : return count;
604 : : }
605 : : #else
606 : : static uint16_t
607 : : af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
608 : : {
609 : : struct pkt_tx_queue *txq = queue;
610 : : struct xsk_umem_info *umem = txq->umem;
611 : : struct rte_mbuf *mbuf;
612 : : void *addrs[ETH_AF_XDP_TX_BATCH_SIZE];
613 : : unsigned long tx_bytes = 0;
614 : : int i;
615 : : uint32_t idx_tx;
616 : : struct xsk_ring_cons *cq = &txq->pair->cq;
617 : :
618 : : pull_umem_cq(umem, nb_pkts, cq);
619 : :
620 : : nb_pkts = rte_ring_dequeue_bulk(umem->buf_ring, addrs,
621 : : nb_pkts, NULL);
622 : : if (nb_pkts == 0)
623 : : return 0;
624 : :
625 : : if (xsk_ring_prod__reserve(&txq->tx, nb_pkts, &idx_tx) != nb_pkts) {
626 : : kick_tx(txq, cq);
627 : : rte_ring_enqueue_bulk(umem->buf_ring, addrs, nb_pkts, NULL);
628 : : return 0;
629 : : }
630 : :
631 : : for (i = 0; i < nb_pkts; i++) {
632 : : struct xdp_desc *desc;
633 : : void *pkt;
634 : :
635 : : desc = xsk_ring_prod__tx_desc(&txq->tx, idx_tx + i);
636 : : mbuf = bufs[i];
637 : : desc->len = mbuf->pkt_len;
638 : :
639 : : desc->addr = (uint64_t)addrs[i];
640 : : pkt = xsk_umem__get_data(umem->mz->addr,
641 : : desc->addr);
642 : : rte_memcpy(pkt, rte_pktmbuf_mtod(mbuf, void *), desc->len);
643 : : tx_bytes += mbuf->pkt_len;
644 : : rte_pktmbuf_free(mbuf);
645 : : }
646 : :
647 : : xsk_ring_prod__submit(&txq->tx, nb_pkts);
648 : :
649 : : kick_tx(txq, cq);
650 : :
651 : : txq->stats.tx_pkts += nb_pkts;
652 : : txq->stats.tx_bytes += tx_bytes;
653 : :
654 : : return nb_pkts;
655 : : }
656 : :
657 : : static uint16_t
658 : : af_xdp_tx_cp_batch(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
659 : : {
660 : : uint16_t nb_tx;
661 : :
662 : : if (likely(nb_pkts <= ETH_AF_XDP_TX_BATCH_SIZE))
663 : : return af_xdp_tx_cp(queue, bufs, nb_pkts);
664 : :
665 : : nb_tx = 0;
666 : : while (nb_pkts) {
667 : : uint16_t ret, n;
668 : :
669 : : /* Split larger batch into smaller batches of size
670 : : * ETH_AF_XDP_TX_BATCH_SIZE or less.
671 : : */
672 : : n = (uint16_t)RTE_MIN(nb_pkts, ETH_AF_XDP_TX_BATCH_SIZE);
673 : : ret = af_xdp_tx_cp(queue, &bufs[nb_tx], n);
674 : : nb_tx = (uint16_t)(nb_tx + ret);
675 : : nb_pkts = (uint16_t)(nb_pkts - ret);
676 : : if (ret < n)
677 : : break;
678 : : }
679 : :
680 : : return nb_tx;
681 : : }
682 : : #endif
683 : :
684 : : static uint16_t
685 : 0 : eth_af_xdp_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
686 : : {
687 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
688 : 0 : return af_xdp_tx_zc(queue, bufs, nb_pkts);
689 : : #else
690 : : return af_xdp_tx_cp_batch(queue, bufs, nb_pkts);
691 : : #endif
692 : : }
693 : :
694 : : static int
695 : 0 : eth_dev_start(struct rte_eth_dev *dev)
696 : : {
697 : : uint16_t i;
698 : :
699 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
700 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
701 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
702 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
703 : : }
704 : :
705 : 0 : return 0;
706 : : }
707 : :
708 : : /* This function gets called when the current port gets stopped. */
709 : : static int
710 : 0 : eth_dev_stop(struct rte_eth_dev *dev)
711 : : {
712 : : uint16_t i;
713 : :
714 : 0 : dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
715 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
716 : 0 : dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
717 : 0 : dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
718 : : }
719 : :
720 : 0 : return 0;
721 : : }
722 : :
723 : : /* Find ethdev in list */
724 : : static inline struct internal_list *
725 : 0 : find_internal_resource(struct pmd_internals *port_int)
726 : : {
727 : : int found = 0;
728 : : struct internal_list *list = NULL;
729 : :
730 [ # # ]: 0 : if (port_int == NULL)
731 : : return NULL;
732 : :
733 : 0 : pthread_mutex_lock(&internal_list_lock);
734 : :
735 [ # # ]: 0 : TAILQ_FOREACH(list, &internal_list, next) {
736 : 0 : struct pmd_internals *list_int =
737 : 0 : list->eth_dev->data->dev_private;
738 [ # # ]: 0 : if (list_int == port_int) {
739 : : found = 1;
740 : : break;
741 : : }
742 : : }
743 : :
744 : 0 : pthread_mutex_unlock(&internal_list_lock);
745 : :
746 [ # # ]: 0 : if (!found)
747 : 0 : return NULL;
748 : :
749 : : return list;
750 : : }
751 : :
752 : : static int
753 : 0 : eth_dev_configure(struct rte_eth_dev *dev)
754 : : {
755 : 0 : struct pmd_internals *internal = dev->data->dev_private;
756 : :
757 : : /* rx/tx must be paired */
758 [ # # ]: 0 : if (dev->data->nb_rx_queues != dev->data->nb_tx_queues)
759 : : return -EINVAL;
760 : :
761 [ # # ]: 0 : if (internal->shared_umem) {
762 : : struct internal_list *list = NULL;
763 : 0 : const char *name = dev->device->name;
764 : :
765 : : /* Ensure PMD is not already inserted into the list */
766 : 0 : list = find_internal_resource(internal);
767 [ # # ]: 0 : if (list)
768 : : return 0;
769 : :
770 : 0 : list = rte_zmalloc_socket(name, sizeof(*list), 0,
771 : 0 : dev->device->numa_node);
772 [ # # ]: 0 : if (list == NULL)
773 : : return -1;
774 : :
775 : 0 : list->eth_dev = dev;
776 : 0 : pthread_mutex_lock(&internal_list_lock);
777 : 0 : TAILQ_INSERT_TAIL(&internal_list, list, next);
778 : 0 : pthread_mutex_unlock(&internal_list_lock);
779 : : }
780 : :
781 : : return 0;
782 : : }
783 : :
784 : : #define CLB_VAL_IDX 0
785 : : static int
786 : 0 : eth_monitor_callback(const uint64_t value,
787 : : const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
788 : : {
789 : 0 : const uint64_t v = opaque[CLB_VAL_IDX];
790 : : const uint64_t m = (uint32_t)~0;
791 : :
792 : : /* if the value has changed, abort entering power optimized state */
793 [ # # ]: 0 : return (value & m) == v ? 0 : -1;
794 : : }
795 : :
796 : : static int
797 : 0 : eth_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
798 : : {
799 : : struct pkt_rx_queue *rxq = rx_queue;
800 : 0 : unsigned int *prod = rxq->rx.producer;
801 : 0 : const uint32_t cur_val = rxq->rx.cached_prod; /* use cached value */
802 : :
803 : : /* watch for changes in producer ring */
804 : 0 : pmc->addr = (void *)prod;
805 : :
806 : : /* store current value */
807 : 0 : pmc->opaque[CLB_VAL_IDX] = cur_val;
808 : 0 : pmc->fn = eth_monitor_callback;
809 : :
810 : : /* AF_XDP producer ring index is 32-bit */
811 : 0 : pmc->size = sizeof(uint32_t);
812 : :
813 : 0 : return 0;
814 : : }
815 : :
816 : : static int
817 : 0 : eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
818 : : {
819 : 0 : struct pmd_internals *internals = dev->data->dev_private;
820 : :
821 : 0 : dev_info->if_index = internals->if_index;
822 : 0 : dev_info->max_mac_addrs = 1;
823 : 0 : dev_info->max_rx_queues = internals->queue_cnt;
824 : 0 : dev_info->max_tx_queues = internals->queue_cnt;
825 : :
826 : 0 : dev_info->min_mtu = RTE_ETHER_MIN_MTU;
827 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
828 : 0 : dev_info->max_rx_pktlen = getpagesize() -
829 : : sizeof(struct rte_mempool_objhdr) -
830 : : sizeof(struct rte_mbuf) -
831 : 0 : RTE_PKTMBUF_HEADROOM - XDP_PACKET_HEADROOM;
832 : : #else
833 : : dev_info->max_rx_pktlen = ETH_AF_XDP_FRAME_SIZE - XDP_PACKET_HEADROOM;
834 : : #endif
835 : 0 : dev_info->max_mtu = dev_info->max_rx_pktlen - ETH_AF_XDP_ETH_OVERHEAD;
836 : :
837 : 0 : dev_info->default_rxportconf.burst_size = ETH_AF_XDP_DFLT_BUSY_BUDGET;
838 : 0 : dev_info->default_txportconf.burst_size = ETH_AF_XDP_DFLT_BUSY_BUDGET;
839 : 0 : dev_info->default_rxportconf.nb_queues = 1;
840 : 0 : dev_info->default_txportconf.nb_queues = 1;
841 : 0 : dev_info->default_rxportconf.ring_size = ETH_AF_XDP_DFLT_NUM_DESCS;
842 : 0 : dev_info->default_txportconf.ring_size = ETH_AF_XDP_DFLT_NUM_DESCS;
843 : :
844 : 0 : return 0;
845 : : }
846 : :
847 : : static int
848 : 0 : eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
849 : : {
850 : 0 : struct pmd_internals *internals = dev->data->dev_private;
851 : 0 : struct pmd_process_private *process_private = dev->process_private;
852 : : struct xdp_statistics xdp_stats;
853 : : struct pkt_rx_queue *rxq;
854 : : struct pkt_tx_queue *txq;
855 : : socklen_t optlen;
856 : : int i, ret, fd;
857 : :
858 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
859 : 0 : optlen = sizeof(struct xdp_statistics);
860 : 0 : rxq = &internals->rx_queues[i];
861 : 0 : txq = rxq->pair;
862 : 0 : stats->q_ipackets[i] = rxq->stats.rx_pkts;
863 : 0 : stats->q_ibytes[i] = rxq->stats.rx_bytes;
864 : :
865 : 0 : stats->q_opackets[i] = txq->stats.tx_pkts;
866 : 0 : stats->q_obytes[i] = txq->stats.tx_bytes;
867 : :
868 : 0 : stats->ipackets += stats->q_ipackets[i];
869 : 0 : stats->ibytes += stats->q_ibytes[i];
870 : 0 : stats->imissed += rxq->stats.rx_dropped;
871 : 0 : stats->oerrors += txq->stats.tx_dropped;
872 : 0 : fd = process_private->rxq_xsk_fds[i];
873 : 0 : ret = fd >= 0 ? getsockopt(fd, SOL_XDP, XDP_STATISTICS,
874 [ # # ]: 0 : &xdp_stats, &optlen) : -1;
875 [ # # ]: 0 : if (ret != 0) {
876 : 0 : AF_XDP_LOG(ERR, "getsockopt() failed for XDP_STATISTICS.\n");
877 : 0 : return -1;
878 : : }
879 : 0 : stats->imissed += xdp_stats.rx_dropped;
880 : :
881 : 0 : stats->opackets += stats->q_opackets[i];
882 : 0 : stats->obytes += stats->q_obytes[i];
883 : : }
884 : :
885 : : return 0;
886 : : }
887 : :
888 : : static int
889 : 0 : eth_stats_reset(struct rte_eth_dev *dev)
890 : : {
891 : 0 : struct pmd_internals *internals = dev->data->dev_private;
892 : : int i;
893 : :
894 [ # # ]: 0 : for (i = 0; i < internals->queue_cnt; i++) {
895 : 0 : memset(&internals->rx_queues[i].stats, 0,
896 : : sizeof(struct rx_stats));
897 : 0 : memset(&internals->tx_queues[i].stats, 0,
898 : : sizeof(struct tx_stats));
899 : : }
900 : :
901 : 0 : return 0;
902 : : }
903 : :
904 : : #ifdef RTE_NET_AF_XDP_LIBBPF_XDP_ATTACH
905 : :
906 : : static int link_xdp_prog_with_dev(int ifindex, int fd, __u32 flags)
907 : : {
908 : : return bpf_xdp_attach(ifindex, fd, flags, NULL);
909 : : }
910 : :
911 : : static int
912 : : remove_xdp_program(struct pmd_internals *internals)
913 : : {
914 : : uint32_t curr_prog_id = 0;
915 : : int ret;
916 : :
917 : : ret = bpf_xdp_query_id(internals->if_index, XDP_FLAGS_UPDATE_IF_NOEXIST,
918 : : &curr_prog_id);
919 : : if (ret != 0) {
920 : : AF_XDP_LOG(ERR, "bpf_xdp_query_id failed\n");
921 : : return ret;
922 : : }
923 : :
924 : : ret = bpf_xdp_detach(internals->if_index, XDP_FLAGS_UPDATE_IF_NOEXIST,
925 : : NULL);
926 : : if (ret != 0)
927 : : AF_XDP_LOG(ERR, "bpf_xdp_detach failed\n");
928 : : return ret;
929 : : }
930 : :
931 : : #else
932 : :
933 : : static int link_xdp_prog_with_dev(int ifindex, int fd, __u32 flags)
934 : : {
935 : 0 : return bpf_set_link_xdp_fd(ifindex, fd, flags);
936 : : }
937 : :
938 : : static int
939 : 0 : remove_xdp_program(struct pmd_internals *internals)
940 : : {
941 : 0 : uint32_t curr_prog_id = 0;
942 : : int ret;
943 : :
944 : 0 : ret = bpf_get_link_xdp_id(internals->if_index, &curr_prog_id,
945 : : XDP_FLAGS_UPDATE_IF_NOEXIST);
946 [ # # ]: 0 : if (ret != 0) {
947 : 0 : AF_XDP_LOG(ERR, "bpf_get_link_xdp_id failed\n");
948 : 0 : return ret;
949 : : }
950 : :
951 : 0 : ret = bpf_set_link_xdp_fd(internals->if_index, -1,
952 : : XDP_FLAGS_UPDATE_IF_NOEXIST);
953 [ # # ]: 0 : if (ret != 0)
954 : 0 : AF_XDP_LOG(ERR, "bpf_set_link_xdp_fd failed\n");
955 : : return ret;
956 : : }
957 : :
958 : : #endif
959 : :
960 : : static void
961 : : xdp_umem_destroy(struct xsk_umem_info *umem)
962 : : {
963 : 0 : (void)xsk_umem__delete(umem->umem);
964 : 0 : umem->umem = NULL;
965 : :
966 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
967 : 0 : umem->mb_pool = NULL;
968 : : #else
969 : : rte_memzone_free(umem->mz);
970 : : umem->mz = NULL;
971 : :
972 : : rte_ring_free(umem->buf_ring);
973 : : umem->buf_ring = NULL;
974 : : #endif
975 : :
976 : 0 : rte_free(umem);
977 : 0 : }
978 : :
979 : : static int
980 : 0 : eth_dev_close(struct rte_eth_dev *dev)
981 : : {
982 : 0 : struct pmd_internals *internals = dev->data->dev_private;
983 : : struct pkt_rx_queue *rxq;
984 : : int i;
985 : :
986 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
987 : 0 : goto out;
988 : :
989 : 0 : AF_XDP_LOG(INFO, "Closing AF_XDP ethdev on numa socket %u\n",
990 : : rte_socket_id());
991 : :
992 [ # # ]: 0 : for (i = 0; i < internals->queue_cnt; i++) {
993 : 0 : rxq = &internals->rx_queues[i];
994 [ # # ]: 0 : if (rxq->umem == NULL)
995 : : break;
996 : 0 : xsk_socket__delete(rxq->xsk);
997 : :
998 [ # # ]: 0 : if (__atomic_fetch_sub(&rxq->umem->refcnt, 1, __ATOMIC_ACQUIRE) - 1 == 0)
999 : 0 : xdp_umem_destroy(rxq->umem);
1000 : :
1001 : : /* free pkt_tx_queue */
1002 : 0 : rte_free(rxq->pair);
1003 : 0 : rte_free(rxq);
1004 : : }
1005 : :
1006 : : /*
1007 : : * MAC is not allocated dynamically, setting it to NULL would prevent
1008 : : * from releasing it in rte_eth_dev_release_port.
1009 : : */
1010 : 0 : dev->data->mac_addrs = NULL;
1011 : :
1012 [ # # ]: 0 : if (remove_xdp_program(internals) != 0)
1013 : 0 : AF_XDP_LOG(ERR, "Error while removing XDP program.\n");
1014 : :
1015 [ # # ]: 0 : if (internals->shared_umem) {
1016 : : struct internal_list *list;
1017 : :
1018 : : /* Remove ethdev from list used to track and share UMEMs */
1019 : 0 : list = find_internal_resource(internals);
1020 [ # # ]: 0 : if (list) {
1021 : 0 : pthread_mutex_lock(&internal_list_lock);
1022 [ # # ]: 0 : TAILQ_REMOVE(&internal_list, list, next);
1023 : 0 : pthread_mutex_unlock(&internal_list_lock);
1024 : 0 : rte_free(list);
1025 : : }
1026 : : }
1027 : :
1028 : 0 : out:
1029 : 0 : rte_free(dev->process_private);
1030 : :
1031 : 0 : return 0;
1032 : : }
1033 : :
1034 : : static int
1035 : 0 : eth_link_update(struct rte_eth_dev *dev __rte_unused,
1036 : : int wait_to_complete __rte_unused)
1037 : : {
1038 : 0 : return 0;
1039 : : }
1040 : :
1041 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
1042 : : static inline uintptr_t get_base_addr(struct rte_mempool *mp, uint64_t *align)
1043 : : {
1044 : : struct rte_mempool_memhdr *memhdr;
1045 : : uintptr_t memhdr_addr, aligned_addr;
1046 : :
1047 : 0 : memhdr = STAILQ_FIRST(&mp->mem_list);
1048 : 0 : memhdr_addr = (uintptr_t)memhdr->addr;
1049 : 0 : aligned_addr = memhdr_addr & ~(getpagesize() - 1);
1050 : 0 : *align = memhdr_addr - aligned_addr;
1051 : :
1052 : : return aligned_addr;
1053 : : }
1054 : :
1055 : : /* Check if the netdev,qid context already exists */
1056 : : static inline bool
1057 : 0 : ctx_exists(struct pkt_rx_queue *rxq, const char *ifname,
1058 : : struct pkt_rx_queue *list_rxq, const char *list_ifname)
1059 : : {
1060 : : bool exists = false;
1061 : :
1062 [ # # ]: 0 : if (rxq->xsk_queue_idx == list_rxq->xsk_queue_idx &&
1063 [ # # ]: 0 : !strncmp(ifname, list_ifname, IFNAMSIZ)) {
1064 : 0 : AF_XDP_LOG(ERR, "ctx %s,%i already exists, cannot share umem\n",
1065 : : ifname, rxq->xsk_queue_idx);
1066 : : exists = true;
1067 : : }
1068 : :
1069 : 0 : return exists;
1070 : : }
1071 : :
1072 : : /* Get a pointer to an existing UMEM which overlays the rxq's mb_pool */
1073 : : static inline int
1074 : 0 : get_shared_umem(struct pkt_rx_queue *rxq, const char *ifname,
1075 : : struct xsk_umem_info **umem)
1076 : : {
1077 : : struct internal_list *list;
1078 : : struct pmd_internals *internals;
1079 : : int i = 0, ret = 0;
1080 : 0 : struct rte_mempool *mb_pool = rxq->mb_pool;
1081 : :
1082 [ # # ]: 0 : if (mb_pool == NULL)
1083 : : return ret;
1084 : :
1085 : 0 : pthread_mutex_lock(&internal_list_lock);
1086 : :
1087 [ # # ]: 0 : TAILQ_FOREACH(list, &internal_list, next) {
1088 : 0 : internals = list->eth_dev->data->dev_private;
1089 [ # # ]: 0 : for (i = 0; i < internals->queue_cnt; i++) {
1090 : 0 : struct pkt_rx_queue *list_rxq =
1091 : 0 : &internals->rx_queues[i];
1092 [ # # ]: 0 : if (rxq == list_rxq)
1093 : 0 : continue;
1094 [ # # ]: 0 : if (mb_pool == internals->rx_queues[i].mb_pool) {
1095 [ # # ]: 0 : if (ctx_exists(rxq, ifname, list_rxq,
1096 : 0 : internals->if_name)) {
1097 : : ret = -1;
1098 : 0 : goto out;
1099 : : }
1100 [ # # ]: 0 : if (__atomic_load_n(&internals->rx_queues[i].umem->refcnt,
1101 : : __ATOMIC_ACQUIRE)) {
1102 : 0 : *umem = internals->rx_queues[i].umem;
1103 : 0 : goto out;
1104 : : }
1105 : : }
1106 : : }
1107 : : }
1108 : :
1109 : 0 : out:
1110 : 0 : pthread_mutex_unlock(&internal_list_lock);
1111 : :
1112 : 0 : return ret;
1113 : : }
1114 : :
1115 : : static struct
1116 : 0 : xsk_umem_info *xdp_umem_configure(struct pmd_internals *internals,
1117 : : struct pkt_rx_queue *rxq)
1118 : : {
1119 : 0 : struct xsk_umem_info *umem = NULL;
1120 : : int ret;
1121 : 0 : struct xsk_umem_config usr_config = {
1122 : : .fill_size = ETH_AF_XDP_DFLT_NUM_DESCS * 2,
1123 : : .comp_size = ETH_AF_XDP_DFLT_NUM_DESCS,
1124 : : .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG};
1125 : : void *base_addr = NULL;
1126 : 0 : struct rte_mempool *mb_pool = rxq->mb_pool;
1127 : : uint64_t umem_size, align = 0;
1128 : :
1129 [ # # ]: 0 : if (internals->shared_umem) {
1130 [ # # ]: 0 : if (get_shared_umem(rxq, internals->if_name, &umem) < 0)
1131 : : return NULL;
1132 : :
1133 [ # # ]: 0 : if (umem != NULL &&
1134 : 0 : __atomic_load_n(&umem->refcnt, __ATOMIC_ACQUIRE) <
1135 [ # # ]: 0 : umem->max_xsks) {
1136 : 0 : AF_XDP_LOG(INFO, "%s,qid%i sharing UMEM\n",
1137 : : internals->if_name, rxq->xsk_queue_idx);
1138 : 0 : __atomic_fetch_add(&umem->refcnt, 1, __ATOMIC_ACQUIRE);
1139 : : }
1140 : : }
1141 : :
1142 [ # # ]: 0 : if (umem == NULL) {
1143 : 0 : usr_config.frame_size =
1144 : 0 : rte_mempool_calc_obj_size(mb_pool->elt_size,
1145 : : mb_pool->flags, NULL);
1146 [ # # ]: 0 : usr_config.frame_headroom = mb_pool->header_size +
1147 : 0 : sizeof(struct rte_mbuf) +
1148 : 0 : rte_pktmbuf_priv_size(mb_pool) +
1149 : : RTE_PKTMBUF_HEADROOM;
1150 : :
1151 : 0 : umem = rte_zmalloc_socket("umem", sizeof(*umem), 0,
1152 : 0 : rte_socket_id());
1153 [ # # ]: 0 : if (umem == NULL) {
1154 : 0 : AF_XDP_LOG(ERR, "Failed to allocate umem info\n");
1155 : 0 : return NULL;
1156 : : }
1157 : :
1158 : 0 : umem->mb_pool = mb_pool;
1159 : 0 : base_addr = (void *)get_base_addr(mb_pool, &align);
1160 : 0 : umem_size = (uint64_t)mb_pool->populated_size *
1161 : 0 : (uint64_t)usr_config.frame_size +
1162 : : align;
1163 : :
1164 : 0 : ret = xsk_umem__create(&umem->umem, base_addr, umem_size,
1165 : : &rxq->fq, &rxq->cq, &usr_config);
1166 [ # # ]: 0 : if (ret) {
1167 : 0 : AF_XDP_LOG(ERR, "Failed to create umem [%d]: [%s]\n",
1168 : : errno, strerror(errno));
1169 : 0 : goto err;
1170 : : }
1171 : 0 : umem->buffer = base_addr;
1172 : :
1173 [ # # ]: 0 : if (internals->shared_umem) {
1174 : 0 : umem->max_xsks = mb_pool->populated_size /
1175 : : ETH_AF_XDP_NUM_BUFFERS;
1176 : 0 : AF_XDP_LOG(INFO, "Max xsks for UMEM %s: %u\n",
1177 : : mb_pool->name, umem->max_xsks);
1178 : : }
1179 : :
1180 : 0 : __atomic_store_n(&umem->refcnt, 1, __ATOMIC_RELEASE);
1181 : : }
1182 : :
1183 : 0 : return umem;
1184 : :
1185 : : err:
1186 : : xdp_umem_destroy(umem);
1187 : 0 : return NULL;
1188 : : }
1189 : : #else
1190 : : static struct
1191 : : xsk_umem_info *xdp_umem_configure(struct pmd_internals *internals,
1192 : : struct pkt_rx_queue *rxq)
1193 : : {
1194 : : struct xsk_umem_info *umem;
1195 : : const struct rte_memzone *mz;
1196 : : struct xsk_umem_config usr_config = {
1197 : : .fill_size = ETH_AF_XDP_DFLT_NUM_DESCS,
1198 : : .comp_size = ETH_AF_XDP_DFLT_NUM_DESCS,
1199 : : .frame_size = ETH_AF_XDP_FRAME_SIZE,
1200 : : .frame_headroom = 0 };
1201 : : char ring_name[RTE_RING_NAMESIZE];
1202 : : char mz_name[RTE_MEMZONE_NAMESIZE];
1203 : : int ret;
1204 : : uint64_t i;
1205 : :
1206 : : umem = rte_zmalloc_socket("umem", sizeof(*umem), 0, rte_socket_id());
1207 : : if (umem == NULL) {
1208 : : AF_XDP_LOG(ERR, "Failed to allocate umem info\n");
1209 : : return NULL;
1210 : : }
1211 : :
1212 : : snprintf(ring_name, sizeof(ring_name), "af_xdp_ring_%s_%u",
1213 : : internals->if_name, rxq->xsk_queue_idx);
1214 : : umem->buf_ring = rte_ring_create(ring_name,
1215 : : ETH_AF_XDP_NUM_BUFFERS,
1216 : : rte_socket_id(),
1217 : : 0x0);
1218 : : if (umem->buf_ring == NULL) {
1219 : : AF_XDP_LOG(ERR, "Failed to create rte_ring\n");
1220 : : goto err;
1221 : : }
1222 : :
1223 : : for (i = 0; i < ETH_AF_XDP_NUM_BUFFERS; i++)
1224 : : rte_ring_enqueue(umem->buf_ring,
1225 : : (void *)(i * ETH_AF_XDP_FRAME_SIZE));
1226 : :
1227 : : snprintf(mz_name, sizeof(mz_name), "af_xdp_umem_%s_%u",
1228 : : internals->if_name, rxq->xsk_queue_idx);
1229 : : mz = rte_memzone_reserve_aligned(mz_name,
1230 : : ETH_AF_XDP_NUM_BUFFERS * ETH_AF_XDP_FRAME_SIZE,
1231 : : rte_socket_id(), RTE_MEMZONE_IOVA_CONTIG,
1232 : : getpagesize());
1233 : : if (mz == NULL) {
1234 : : AF_XDP_LOG(ERR, "Failed to reserve memzone for af_xdp umem.\n");
1235 : : goto err;
1236 : : }
1237 : : umem->mz = mz;
1238 : :
1239 : : ret = xsk_umem__create(&umem->umem, mz->addr,
1240 : : ETH_AF_XDP_NUM_BUFFERS * ETH_AF_XDP_FRAME_SIZE,
1241 : : &rxq->fq, &rxq->cq,
1242 : : &usr_config);
1243 : :
1244 : : if (ret) {
1245 : : AF_XDP_LOG(ERR, "Failed to create umem\n");
1246 : : goto err;
1247 : : }
1248 : :
1249 : : return umem;
1250 : :
1251 : : err:
1252 : : xdp_umem_destroy(umem);
1253 : : return NULL;
1254 : : }
1255 : : #endif
1256 : :
1257 : : static int
1258 : 0 : load_custom_xdp_prog(const char *prog_path, int if_index, struct bpf_map **map)
1259 : : {
1260 : : int ret, prog_fd;
1261 : : struct bpf_object *obj;
1262 : :
1263 : : prog_fd = load_program(prog_path, &obj);
1264 [ # # ]: 0 : if (prog_fd < 0) {
1265 : 0 : AF_XDP_LOG(ERR, "Failed to load program %s\n", prog_path);
1266 : 0 : return -1;
1267 : : }
1268 : :
1269 : : /*
1270 : : * The loaded program must provision for a map of xsks, such that some
1271 : : * traffic can be redirected to userspace.
1272 : : */
1273 : 0 : *map = bpf_object__find_map_by_name(obj, "xsks_map");
1274 [ # # ]: 0 : if (!*map) {
1275 : 0 : AF_XDP_LOG(ERR, "Failed to find xsks_map in %s\n", prog_path);
1276 : 0 : return -1;
1277 : : }
1278 : :
1279 : : /* Link the program with the given network device */
1280 : : ret = link_xdp_prog_with_dev(if_index, prog_fd,
1281 : : XDP_FLAGS_UPDATE_IF_NOEXIST);
1282 [ # # ]: 0 : if (ret) {
1283 : 0 : AF_XDP_LOG(ERR, "Failed to set prog fd %d on interface\n",
1284 : : prog_fd);
1285 : 0 : return -1;
1286 : : }
1287 : :
1288 : 0 : AF_XDP_LOG(INFO, "Successfully loaded XDP program %s with fd %d\n",
1289 : : prog_path, prog_fd);
1290 : :
1291 : 0 : return 0;
1292 : : }
1293 : :
1294 : : /* Detect support for busy polling through setsockopt(). */
1295 : : static int
1296 : 0 : configure_preferred_busy_poll(struct pkt_rx_queue *rxq)
1297 : : {
1298 : 0 : int sock_opt = 1;
1299 : 0 : int fd = xsk_socket__fd(rxq->xsk);
1300 : : int ret = 0;
1301 : :
1302 : 0 : ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL,
1303 : : (void *)&sock_opt, sizeof(sock_opt));
1304 [ # # ]: 0 : if (ret < 0) {
1305 : 0 : AF_XDP_LOG(DEBUG, "Failed to set SO_PREFER_BUSY_POLL\n");
1306 : 0 : goto err_prefer;
1307 : : }
1308 : :
1309 : 0 : sock_opt = ETH_AF_XDP_DFLT_BUSY_TIMEOUT;
1310 : 0 : ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void *)&sock_opt,
1311 : : sizeof(sock_opt));
1312 [ # # ]: 0 : if (ret < 0) {
1313 : 0 : AF_XDP_LOG(DEBUG, "Failed to set SO_BUSY_POLL\n");
1314 : 0 : goto err_timeout;
1315 : : }
1316 : :
1317 : 0 : sock_opt = rxq->busy_budget;
1318 : 0 : ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL_BUDGET,
1319 : : (void *)&sock_opt, sizeof(sock_opt));
1320 [ # # ]: 0 : if (ret < 0) {
1321 : 0 : AF_XDP_LOG(DEBUG, "Failed to set SO_BUSY_POLL_BUDGET\n");
1322 : : } else {
1323 : 0 : AF_XDP_LOG(INFO, "Busy polling budget set to: %u\n",
1324 : : rxq->busy_budget);
1325 : 0 : return 0;
1326 : : }
1327 : :
1328 : : /* setsockopt failure - attempt to restore xsk to default state and
1329 : : * proceed without busy polling support.
1330 : : */
1331 : 0 : sock_opt = 0;
1332 : 0 : ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void *)&sock_opt,
1333 : : sizeof(sock_opt));
1334 [ # # ]: 0 : if (ret < 0) {
1335 : 0 : AF_XDP_LOG(ERR, "Failed to unset SO_BUSY_POLL\n");
1336 : 0 : return -1;
1337 : : }
1338 : :
1339 : 0 : err_timeout:
1340 : 0 : sock_opt = 0;
1341 : 0 : ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL,
1342 : : (void *)&sock_opt, sizeof(sock_opt));
1343 [ # # ]: 0 : if (ret < 0) {
1344 : 0 : AF_XDP_LOG(ERR, "Failed to unset SO_PREFER_BUSY_POLL\n");
1345 : 0 : return -1;
1346 : : }
1347 : :
1348 : 0 : err_prefer:
1349 : 0 : rxq->busy_budget = 0;
1350 : 0 : return 0;
1351 : : }
1352 : :
1353 : : static int
1354 : 0 : init_uds_sock(struct sockaddr_un *server)
1355 : : {
1356 : : int sock;
1357 : :
1358 : 0 : sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
1359 [ # # ]: 0 : if (sock < 0) {
1360 : 0 : AF_XDP_LOG(ERR, "Failed to opening stream socket\n");
1361 : 0 : return -1;
1362 : : }
1363 : :
1364 : 0 : server->sun_family = AF_UNIX;
1365 : 0 : strlcpy(server->sun_path, UDS_SOCK, sizeof(server->sun_path));
1366 : :
1367 [ # # ]: 0 : if (connect(sock, (struct sockaddr *)server, sizeof(struct sockaddr_un)) < 0) {
1368 : 0 : close(sock);
1369 : 0 : AF_XDP_LOG(ERR, "Error connecting stream socket errno = [%d]: [%s]\n",
1370 : : errno, strerror(errno));
1371 : 0 : return -1;
1372 : : }
1373 : :
1374 : : return sock;
1375 : : }
1376 : :
1377 : : struct msg_internal {
1378 : : char response[UDS_MAX_CMD_RESP];
1379 : : int len_param;
1380 : : int num_fds;
1381 : : int fds[UDS_MAX_FD_NUM];
1382 : : };
1383 : :
1384 : : static int
1385 : 0 : send_msg(int sock, char *request, int *fd)
1386 : : {
1387 : : int snd;
1388 : : struct iovec iov;
1389 : : struct msghdr msgh;
1390 : : struct cmsghdr *cmsg;
1391 : : struct sockaddr_un dst;
1392 : : char control[CMSG_SPACE(sizeof(*fd))];
1393 : :
1394 : : memset(&dst, 0, sizeof(dst));
1395 : 0 : dst.sun_family = AF_UNIX;
1396 : : strlcpy(dst.sun_path, UDS_SOCK, sizeof(dst.sun_path));
1397 : :
1398 : : /* Initialize message header structure */
1399 : : memset(&msgh, 0, sizeof(msgh));
1400 : : memset(control, 0, sizeof(control));
1401 : 0 : iov.iov_base = request;
1402 : 0 : iov.iov_len = strlen(request);
1403 : :
1404 : 0 : msgh.msg_name = &dst;
1405 : 0 : msgh.msg_namelen = sizeof(dst);
1406 : 0 : msgh.msg_iov = &iov;
1407 : 0 : msgh.msg_iovlen = 1;
1408 : 0 : msgh.msg_control = control;
1409 : 0 : msgh.msg_controllen = sizeof(control);
1410 : :
1411 : : /* Translate the FD. */
1412 : : cmsg = CMSG_FIRSTHDR(&msgh);
1413 : 0 : cmsg->cmsg_len = CMSG_LEN(sizeof(*fd));
1414 : 0 : cmsg->cmsg_level = SOL_SOCKET;
1415 : 0 : cmsg->cmsg_type = SCM_RIGHTS;
1416 : : memcpy(CMSG_DATA(cmsg), fd, sizeof(*fd));
1417 : :
1418 : : /* Send the request message. */
1419 : : do {
1420 : 0 : snd = sendmsg(sock, &msgh, 0);
1421 [ # # # # ]: 0 : } while (snd < 0 && errno == EINTR);
1422 : :
1423 : 0 : return snd;
1424 : : }
1425 : :
1426 : : static int
1427 : 0 : read_msg(int sock, char *response, struct sockaddr_un *s, int *fd)
1428 : : {
1429 : : int msglen;
1430 : : struct msghdr msgh;
1431 : : struct iovec iov;
1432 : : char control[CMSG_SPACE(sizeof(*fd))];
1433 : : struct cmsghdr *cmsg;
1434 : :
1435 : : /* Initialize message header structure */
1436 : : memset(&msgh, 0, sizeof(msgh));
1437 : 0 : iov.iov_base = response;
1438 : 0 : iov.iov_len = UDS_MAX_CMD_RESP;
1439 : :
1440 : 0 : msgh.msg_name = s;
1441 : 0 : msgh.msg_namelen = sizeof(*s);
1442 : 0 : msgh.msg_iov = &iov;
1443 : 0 : msgh.msg_iovlen = 1;
1444 : 0 : msgh.msg_control = control;
1445 : 0 : msgh.msg_controllen = sizeof(control);
1446 : :
1447 : 0 : msglen = recvmsg(sock, &msgh, 0);
1448 : :
1449 : : /* zero length message means socket was closed */
1450 [ # # ]: 0 : if (msglen == 0)
1451 : : return 0;
1452 : :
1453 [ # # ]: 0 : if (msglen < 0) {
1454 : 0 : AF_XDP_LOG(ERR, "recvmsg failed, %s\n", strerror(errno));
1455 : 0 : return -1;
1456 : : }
1457 : :
1458 : : /* read auxiliary FDs if any */
1459 [ # # # # ]: 0 : for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
1460 : : cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
1461 [ # # ]: 0 : if (cmsg->cmsg_level == SOL_SOCKET &&
1462 : : cmsg->cmsg_type == SCM_RIGHTS) {
1463 : 0 : memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
1464 : : break;
1465 : : }
1466 : : }
1467 : :
1468 : 0 : response[msglen] = '\0';
1469 : 0 : return msglen;
1470 : : }
1471 : :
1472 : : static int
1473 : 0 : make_request_cni(int sock, struct sockaddr_un *server, char *request,
1474 : : int *req_fd, char *response, int *out_fd)
1475 : : {
1476 : : int rval;
1477 : :
1478 : 0 : AF_XDP_LOG(DEBUG, "Request: [%s]\n", request);
1479 : :
1480 : : /* if no file descriptor to send then directly write to socket.
1481 : : * else use sendmsg() to send the file descriptor.
1482 : : */
1483 [ # # ]: 0 : if (req_fd == NULL)
1484 : 0 : rval = write(sock, request, strlen(request));
1485 : : else
1486 : 0 : rval = send_msg(sock, request, req_fd);
1487 : :
1488 [ # # ]: 0 : if (rval < 0) {
1489 : 0 : AF_XDP_LOG(ERR, "Write error %s\n", strerror(errno));
1490 : 0 : return -1;
1491 : : }
1492 : :
1493 : 0 : rval = read_msg(sock, response, server, out_fd);
1494 [ # # ]: 0 : if (rval <= 0) {
1495 : 0 : AF_XDP_LOG(ERR, "Read error %d\n", rval);
1496 : 0 : return -1;
1497 : : }
1498 : 0 : AF_XDP_LOG(DEBUG, "Response: [%s]\n", request);
1499 : :
1500 : 0 : return 0;
1501 : : }
1502 : :
1503 : : static int
1504 : : check_response(char *response, char *exp_resp, long size)
1505 : : {
1506 : 0 : return strncmp(response, exp_resp, size);
1507 : : }
1508 : :
1509 : : static int
1510 : 0 : get_cni_fd(char *if_name)
1511 : : {
1512 : : char request[UDS_MAX_CMD_LEN], response[UDS_MAX_CMD_RESP];
1513 : : char hostname[MAX_LONG_OPT_SZ], exp_resp[UDS_MAX_CMD_RESP];
1514 : : struct sockaddr_un server;
1515 : 0 : int xsk_map_fd = -1, out_fd = 0;
1516 : : int sock, err;
1517 : :
1518 : : err = gethostname(hostname, MAX_LONG_OPT_SZ - 1);
1519 [ # # ]: 0 : if (err)
1520 : : return -1;
1521 : :
1522 : : memset(&server, 0, sizeof(server));
1523 : 0 : sock = init_uds_sock(&server);
1524 [ # # ]: 0 : if (sock < 0)
1525 : : return -1;
1526 : :
1527 : : /* Initiates handshake to CNI send: /connect,hostname */
1528 : : snprintf(request, sizeof(request), "%s,%s", UDS_CONNECT_MSG, hostname);
1529 : : memset(response, 0, sizeof(response));
1530 [ # # ]: 0 : if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
1531 : 0 : AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
1532 : 0 : goto err_close;
1533 : : }
1534 : :
1535 : : /* Expect /host_ok */
1536 : : strlcpy(exp_resp, UDS_HOST_OK_MSG, UDS_MAX_CMD_LEN);
1537 [ # # ]: 0 : if (check_response(response, exp_resp, strlen(exp_resp)) < 0) {
1538 : 0 : AF_XDP_LOG(ERR, "Unexpected response [%s]\n", response);
1539 : 0 : goto err_close;
1540 : : }
1541 : : /* Request for "/version" */
1542 : : strlcpy(request, UDS_VERSION_MSG, UDS_MAX_CMD_LEN);
1543 : : memset(response, 0, sizeof(response));
1544 [ # # ]: 0 : if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
1545 : 0 : AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
1546 : 0 : goto err_close;
1547 : : }
1548 : :
1549 : : /* Request for file descriptor for netdev name*/
1550 : : snprintf(request, sizeof(request), "%s,%s", UDS_XSK_MAP_FD_MSG, if_name);
1551 : : memset(response, 0, sizeof(response));
1552 [ # # ]: 0 : if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
1553 : 0 : AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
1554 : 0 : goto err_close;
1555 : : }
1556 : :
1557 [ # # ]: 0 : if (out_fd < 0) {
1558 : 0 : AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
1559 : 0 : goto err_close;
1560 : : }
1561 : :
1562 : : xsk_map_fd = out_fd;
1563 : :
1564 : : /* Expect fd_ack with file descriptor */
1565 : : strlcpy(exp_resp, UDS_FD_ACK_MSG, UDS_MAX_CMD_LEN);
1566 [ # # ]: 0 : if (check_response(response, exp_resp, strlen(exp_resp)) < 0) {
1567 : 0 : AF_XDP_LOG(ERR, "Unexpected response [%s]\n", response);
1568 : 0 : goto err_close;
1569 : : }
1570 : :
1571 : : /* Initiate close connection */
1572 : : strlcpy(request, UDS_FIN_MSG, UDS_MAX_CMD_LEN);
1573 : : memset(response, 0, sizeof(response));
1574 [ # # ]: 0 : if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
1575 : 0 : AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
1576 : 0 : goto err_close;
1577 : : }
1578 : :
1579 : : /* Connection close */
1580 : : strlcpy(exp_resp, UDS_FIN_ACK_MSG, UDS_MAX_CMD_LEN);
1581 [ # # ]: 0 : if (check_response(response, exp_resp, strlen(exp_resp)) < 0) {
1582 : 0 : AF_XDP_LOG(ERR, "Unexpected response [%s]\n", response);
1583 : 0 : goto err_close;
1584 : : }
1585 : 0 : close(sock);
1586 : :
1587 : 0 : return xsk_map_fd;
1588 : :
1589 : 0 : err_close:
1590 : 0 : close(sock);
1591 : 0 : return -1;
1592 : : }
1593 : :
1594 : : static int
1595 : 0 : xsk_configure(struct pmd_internals *internals, struct pkt_rx_queue *rxq,
1596 : : int ring_size)
1597 : 0 : {
1598 : : struct xsk_socket_config cfg;
1599 : 0 : struct pkt_tx_queue *txq = rxq->pair;
1600 : : int ret = 0;
1601 : : int reserve_size = ETH_AF_XDP_DFLT_NUM_DESCS;
1602 : 0 : struct rte_mbuf *fq_bufs[reserve_size];
1603 : : bool reserve_before;
1604 : :
1605 : 0 : rxq->umem = xdp_umem_configure(internals, rxq);
1606 [ # # ]: 0 : if (rxq->umem == NULL)
1607 : : return -ENOMEM;
1608 : 0 : txq->umem = rxq->umem;
1609 : 0 : reserve_before = __atomic_load_n(&rxq->umem->refcnt, __ATOMIC_ACQUIRE) <= 1;
1610 : :
1611 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
1612 : 0 : ret = rte_pktmbuf_alloc_bulk(rxq->umem->mb_pool, fq_bufs, reserve_size);
1613 [ # # ]: 0 : if (ret) {
1614 : 0 : AF_XDP_LOG(DEBUG, "Failed to get enough buffers for fq.\n");
1615 : 0 : goto out_umem;
1616 : : }
1617 : : #endif
1618 : :
1619 : : /* reserve fill queue of queues not (yet) sharing UMEM */
1620 [ # # ]: 0 : if (reserve_before) {
1621 : 0 : ret = reserve_fill_queue(rxq->umem, reserve_size, fq_bufs, &rxq->fq);
1622 [ # # ]: 0 : if (ret) {
1623 : 0 : AF_XDP_LOG(ERR, "Failed to reserve fill queue.\n");
1624 : 0 : goto out_umem;
1625 : : }
1626 : : }
1627 : :
1628 : 0 : cfg.rx_size = ring_size;
1629 : 0 : cfg.tx_size = ring_size;
1630 : 0 : cfg.libbpf_flags = 0;
1631 : 0 : cfg.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
1632 : 0 : cfg.bind_flags = 0;
1633 : :
1634 : : /* Force AF_XDP socket into copy mode when users want it */
1635 [ # # ]: 0 : if (internals->force_copy)
1636 : 0 : cfg.bind_flags |= XDP_COPY;
1637 : :
1638 : : #if defined(XDP_USE_NEED_WAKEUP)
1639 : 0 : cfg.bind_flags |= XDP_USE_NEED_WAKEUP;
1640 : : #endif
1641 : :
1642 : : /* Disable libbpf from loading XDP program */
1643 [ # # ]: 0 : if (internals->use_cni)
1644 : 0 : cfg.libbpf_flags |= XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
1645 : :
1646 [ # # ]: 0 : if (strnlen(internals->prog_path, PATH_MAX)) {
1647 [ # # ]: 0 : if (!internals->custom_prog_configured) {
1648 : 0 : ret = load_custom_xdp_prog(internals->prog_path,
1649 : : internals->if_index,
1650 : : &internals->map);
1651 [ # # ]: 0 : if (ret) {
1652 : 0 : AF_XDP_LOG(ERR, "Failed to load custom XDP program %s\n",
1653 : : internals->prog_path);
1654 : 0 : goto out_umem;
1655 : : }
1656 : 0 : internals->custom_prog_configured = 1;
1657 : : }
1658 : 0 : cfg.libbpf_flags |= XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
1659 : : }
1660 : :
1661 [ # # ]: 0 : if (internals->shared_umem)
1662 : 0 : ret = create_shared_socket(&rxq->xsk, internals->if_name,
1663 : 0 : rxq->xsk_queue_idx, rxq->umem->umem, &rxq->rx,
1664 : : &txq->tx, &rxq->fq, &rxq->cq, &cfg);
1665 : : else
1666 : 0 : ret = xsk_socket__create(&rxq->xsk, internals->if_name,
1667 : 0 : rxq->xsk_queue_idx, rxq->umem->umem, &rxq->rx,
1668 : : &txq->tx, &cfg);
1669 : :
1670 [ # # ]: 0 : if (ret) {
1671 : 0 : AF_XDP_LOG(ERR, "Failed to create xsk socket.\n");
1672 : 0 : goto out_umem;
1673 : : }
1674 : :
1675 [ # # ]: 0 : if (!reserve_before) {
1676 : : /* reserve fill queue of queues sharing UMEM */
1677 : 0 : ret = reserve_fill_queue(rxq->umem, reserve_size, fq_bufs, &rxq->fq);
1678 [ # # ]: 0 : if (ret) {
1679 : 0 : AF_XDP_LOG(ERR, "Failed to reserve fill queue.\n");
1680 : 0 : goto out_xsk;
1681 : : }
1682 : : }
1683 : :
1684 : : /* insert the xsk into the xsks_map */
1685 [ # # ]: 0 : if (internals->custom_prog_configured) {
1686 : : int err, fd;
1687 : :
1688 : 0 : fd = xsk_socket__fd(rxq->xsk);
1689 : 0 : err = bpf_map_update_elem(bpf_map__fd(internals->map),
1690 : 0 : &rxq->xsk_queue_idx, &fd, 0);
1691 [ # # ]: 0 : if (err) {
1692 : 0 : AF_XDP_LOG(ERR, "Failed to insert xsk in map.\n");
1693 : 0 : goto out_xsk;
1694 : : }
1695 : : }
1696 : :
1697 [ # # ]: 0 : if (internals->use_cni) {
1698 : : int err, fd, map_fd;
1699 : :
1700 : : /* get socket fd from CNI plugin */
1701 : 0 : map_fd = get_cni_fd(internals->if_name);
1702 [ # # ]: 0 : if (map_fd < 0) {
1703 : 0 : AF_XDP_LOG(ERR, "Failed to receive CNI plugin fd\n");
1704 : 0 : goto out_xsk;
1705 : : }
1706 : : /* get socket fd */
1707 : 0 : fd = xsk_socket__fd(rxq->xsk);
1708 : 0 : err = bpf_map_update_elem(map_fd, &rxq->xsk_queue_idx, &fd, 0);
1709 [ # # ]: 0 : if (err) {
1710 : 0 : AF_XDP_LOG(ERR, "Failed to insert unprivileged xsk in map.\n");
1711 : 0 : goto out_xsk;
1712 : : }
1713 [ # # ]: 0 : } else if (rxq->busy_budget) {
1714 : 0 : ret = configure_preferred_busy_poll(rxq);
1715 [ # # ]: 0 : if (ret) {
1716 : 0 : AF_XDP_LOG(ERR, "Failed configure busy polling.\n");
1717 : 0 : goto out_xsk;
1718 : : }
1719 : : }
1720 : :
1721 : : return 0;
1722 : :
1723 : 0 : out_xsk:
1724 : 0 : xsk_socket__delete(rxq->xsk);
1725 : 0 : out_umem:
1726 [ # # ]: 0 : if (__atomic_fetch_sub(&rxq->umem->refcnt, 1, __ATOMIC_ACQUIRE) - 1 == 0)
1727 : 0 : xdp_umem_destroy(rxq->umem);
1728 : :
1729 : : return ret;
1730 : : }
1731 : :
1732 : : static int
1733 : 0 : eth_rx_queue_setup(struct rte_eth_dev *dev,
1734 : : uint16_t rx_queue_id,
1735 : : uint16_t nb_rx_desc,
1736 : : unsigned int socket_id __rte_unused,
1737 : : const struct rte_eth_rxconf *rx_conf __rte_unused,
1738 : : struct rte_mempool *mb_pool)
1739 : : {
1740 : 0 : struct pmd_internals *internals = dev->data->dev_private;
1741 : 0 : struct pmd_process_private *process_private = dev->process_private;
1742 : : struct pkt_rx_queue *rxq;
1743 : : int ret;
1744 : :
1745 : 0 : rxq = &internals->rx_queues[rx_queue_id];
1746 : :
1747 : 0 : AF_XDP_LOG(INFO, "Set up rx queue, rx queue id: %d, xsk queue id: %d\n",
1748 : : rx_queue_id, rxq->xsk_queue_idx);
1749 : :
1750 : : #ifndef XDP_UMEM_UNALIGNED_CHUNK_FLAG
1751 : : uint32_t buf_size, data_size;
1752 : :
1753 : : /* Now get the space available for data in the mbuf */
1754 : : buf_size = rte_pktmbuf_data_room_size(mb_pool) -
1755 : : RTE_PKTMBUF_HEADROOM;
1756 : : data_size = ETH_AF_XDP_FRAME_SIZE;
1757 : :
1758 : : if (data_size > buf_size) {
1759 : : AF_XDP_LOG(ERR, "%s: %d bytes will not fit in mbuf (%d bytes)\n",
1760 : : dev->device->name, data_size, buf_size);
1761 : : ret = -ENOMEM;
1762 : : goto err;
1763 : : }
1764 : : #endif
1765 : :
1766 : 0 : rxq->mb_pool = mb_pool;
1767 : :
1768 [ # # ]: 0 : if (xsk_configure(internals, rxq, nb_rx_desc)) {
1769 : 0 : AF_XDP_LOG(ERR, "Failed to configure xdp socket\n");
1770 : : ret = -EINVAL;
1771 : 0 : goto err;
1772 : : }
1773 : :
1774 [ # # ]: 0 : if (!rxq->busy_budget)
1775 : 0 : AF_XDP_LOG(DEBUG, "Preferred busy polling not enabled\n");
1776 : :
1777 : 0 : rxq->fds[0].fd = xsk_socket__fd(rxq->xsk);
1778 : 0 : rxq->fds[0].events = POLLIN;
1779 : :
1780 : 0 : process_private->rxq_xsk_fds[rx_queue_id] = rxq->fds[0].fd;
1781 : :
1782 : 0 : dev->data->rx_queues[rx_queue_id] = rxq;
1783 : 0 : return 0;
1784 : :
1785 : : err:
1786 : 0 : return ret;
1787 : : }
1788 : :
1789 : : static int
1790 : 0 : eth_tx_queue_setup(struct rte_eth_dev *dev,
1791 : : uint16_t tx_queue_id,
1792 : : uint16_t nb_tx_desc __rte_unused,
1793 : : unsigned int socket_id __rte_unused,
1794 : : const struct rte_eth_txconf *tx_conf __rte_unused)
1795 : : {
1796 : 0 : struct pmd_internals *internals = dev->data->dev_private;
1797 : : struct pkt_tx_queue *txq;
1798 : :
1799 : 0 : txq = &internals->tx_queues[tx_queue_id];
1800 : :
1801 : 0 : dev->data->tx_queues[tx_queue_id] = txq;
1802 : 0 : return 0;
1803 : : }
1804 : :
1805 : : static int
1806 : 0 : eth_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
1807 : : {
1808 : 0 : struct pmd_internals *internals = dev->data->dev_private;
1809 : 0 : struct ifreq ifr = { .ifr_mtu = mtu };
1810 : : int ret;
1811 : : int s;
1812 : :
1813 : 0 : s = socket(PF_INET, SOCK_DGRAM, 0);
1814 [ # # ]: 0 : if (s < 0)
1815 : : return -EINVAL;
1816 : :
1817 : 0 : strlcpy(ifr.ifr_name, internals->if_name, IFNAMSIZ);
1818 : 0 : ret = ioctl(s, SIOCSIFMTU, &ifr);
1819 : 0 : close(s);
1820 : :
1821 [ # # ]: 0 : return (ret < 0) ? -errno : 0;
1822 : : }
1823 : :
1824 : : static int
1825 : 0 : eth_dev_change_flags(char *if_name, uint32_t flags, uint32_t mask)
1826 : : {
1827 : : struct ifreq ifr;
1828 : : int ret = 0;
1829 : : int s;
1830 : :
1831 : 0 : s = socket(PF_INET, SOCK_DGRAM, 0);
1832 [ # # ]: 0 : if (s < 0)
1833 : 0 : return -errno;
1834 : :
1835 : : strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
1836 [ # # ]: 0 : if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
1837 : 0 : ret = -errno;
1838 : 0 : goto out;
1839 : : }
1840 : 0 : ifr.ifr_flags &= mask;
1841 : 0 : ifr.ifr_flags |= flags;
1842 [ # # ]: 0 : if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
1843 : 0 : ret = -errno;
1844 : 0 : goto out;
1845 : : }
1846 : 0 : out:
1847 : 0 : close(s);
1848 : 0 : return ret;
1849 : : }
1850 : :
1851 : : static int
1852 : 0 : eth_dev_promiscuous_enable(struct rte_eth_dev *dev)
1853 : : {
1854 : 0 : struct pmd_internals *internals = dev->data->dev_private;
1855 : :
1856 : 0 : return eth_dev_change_flags(internals->if_name, IFF_PROMISC, ~0);
1857 : : }
1858 : :
1859 : : static int
1860 : 0 : eth_dev_promiscuous_disable(struct rte_eth_dev *dev)
1861 : : {
1862 : 0 : struct pmd_internals *internals = dev->data->dev_private;
1863 : :
1864 : 0 : return eth_dev_change_flags(internals->if_name, 0, ~IFF_PROMISC);
1865 : : }
1866 : :
1867 : : static const struct eth_dev_ops ops = {
1868 : : .dev_start = eth_dev_start,
1869 : : .dev_stop = eth_dev_stop,
1870 : : .dev_close = eth_dev_close,
1871 : : .dev_configure = eth_dev_configure,
1872 : : .dev_infos_get = eth_dev_info,
1873 : : .mtu_set = eth_dev_mtu_set,
1874 : : .promiscuous_enable = eth_dev_promiscuous_enable,
1875 : : .promiscuous_disable = eth_dev_promiscuous_disable,
1876 : : .rx_queue_setup = eth_rx_queue_setup,
1877 : : .tx_queue_setup = eth_tx_queue_setup,
1878 : : .link_update = eth_link_update,
1879 : : .stats_get = eth_stats_get,
1880 : : .stats_reset = eth_stats_reset,
1881 : : .get_monitor_addr = eth_get_monitor_addr,
1882 : : };
1883 : :
1884 : : /* CNI option works in unprivileged container environment
1885 : : * and ethernet device functionality will be reduced. So
1886 : : * additional customiszed eth_dev_ops struct is needed
1887 : : * for cni. Promiscuous enable and disable functionality
1888 : : * is removed.
1889 : : **/
1890 : : static const struct eth_dev_ops ops_cni = {
1891 : : .dev_start = eth_dev_start,
1892 : : .dev_stop = eth_dev_stop,
1893 : : .dev_close = eth_dev_close,
1894 : : .dev_configure = eth_dev_configure,
1895 : : .dev_infos_get = eth_dev_info,
1896 : : .mtu_set = eth_dev_mtu_set,
1897 : : .rx_queue_setup = eth_rx_queue_setup,
1898 : : .tx_queue_setup = eth_tx_queue_setup,
1899 : : .link_update = eth_link_update,
1900 : : .stats_get = eth_stats_get,
1901 : : .stats_reset = eth_stats_reset,
1902 : : .get_monitor_addr = eth_get_monitor_addr,
1903 : : };
1904 : :
1905 : : /** parse busy_budget argument */
1906 : : static int
1907 : 0 : parse_budget_arg(const char *key __rte_unused,
1908 : : const char *value, void *extra_args)
1909 : : {
1910 : : int *i = (int *)extra_args;
1911 : : char *end;
1912 : :
1913 : 0 : *i = strtol(value, &end, 10);
1914 [ # # ]: 0 : if (*i < 0 || *i > UINT16_MAX) {
1915 : 0 : AF_XDP_LOG(ERR, "Invalid busy_budget %i, must be >= 0 and <= %u\n",
1916 : : *i, UINT16_MAX);
1917 : 0 : return -EINVAL;
1918 : : }
1919 : :
1920 : : return 0;
1921 : : }
1922 : :
1923 : : /** parse integer from integer argument */
1924 : : static int
1925 : 0 : parse_integer_arg(const char *key __rte_unused,
1926 : : const char *value, void *extra_args)
1927 : : {
1928 : : int *i = (int *)extra_args;
1929 : : char *end;
1930 : :
1931 : 0 : *i = strtol(value, &end, 10);
1932 [ # # ]: 0 : if (*i < 0) {
1933 : 0 : AF_XDP_LOG(ERR, "Argument has to be positive.\n");
1934 : 0 : return -EINVAL;
1935 : : }
1936 : :
1937 : : return 0;
1938 : : }
1939 : :
1940 : : /** parse name argument */
1941 : : static int
1942 : 0 : parse_name_arg(const char *key __rte_unused,
1943 : : const char *value, void *extra_args)
1944 : : {
1945 : : char *name = extra_args;
1946 : :
1947 [ # # ]: 0 : if (strnlen(value, IFNAMSIZ) > IFNAMSIZ - 1) {
1948 : 0 : AF_XDP_LOG(ERR, "Invalid name %s, should be less than %u bytes.\n",
1949 : : value, IFNAMSIZ);
1950 : 0 : return -EINVAL;
1951 : : }
1952 : :
1953 : : strlcpy(name, value, IFNAMSIZ);
1954 : :
1955 : 0 : return 0;
1956 : : }
1957 : :
1958 : : /** parse xdp prog argument */
1959 : : static int
1960 : 0 : parse_prog_arg(const char *key __rte_unused,
1961 : : const char *value, void *extra_args)
1962 : : {
1963 : : char *path = extra_args;
1964 : :
1965 [ # # ]: 0 : if (strnlen(value, PATH_MAX) == PATH_MAX) {
1966 : 0 : AF_XDP_LOG(ERR, "Invalid path %s, should be less than %u bytes.\n",
1967 : : value, PATH_MAX);
1968 : 0 : return -EINVAL;
1969 : : }
1970 : :
1971 [ # # ]: 0 : if (access(value, F_OK) != 0) {
1972 : 0 : AF_XDP_LOG(ERR, "Error accessing %s: %s\n",
1973 : : value, strerror(errno));
1974 : 0 : return -EINVAL;
1975 : : }
1976 : :
1977 : : strlcpy(path, value, PATH_MAX);
1978 : :
1979 : 0 : return 0;
1980 : : }
1981 : :
1982 : : static int
1983 : 0 : xdp_get_channels_info(const char *if_name, int *max_queues,
1984 : : int *combined_queues)
1985 : : {
1986 : : struct ethtool_channels channels;
1987 : : struct ifreq ifr;
1988 : : int fd, ret;
1989 : :
1990 : 0 : fd = socket(AF_INET, SOCK_DGRAM, 0);
1991 [ # # ]: 0 : if (fd < 0)
1992 : : return -1;
1993 : :
1994 : 0 : channels.cmd = ETHTOOL_GCHANNELS;
1995 : 0 : ifr.ifr_data = (void *)&channels;
1996 : : strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
1997 : 0 : ret = ioctl(fd, SIOCETHTOOL, &ifr);
1998 [ # # ]: 0 : if (ret) {
1999 [ # # ]: 0 : if (errno == EOPNOTSUPP) {
2000 : : ret = 0;
2001 : : } else {
2002 : 0 : ret = -errno;
2003 : 0 : goto out;
2004 : : }
2005 : : }
2006 : :
2007 [ # # # # ]: 0 : if (channels.max_combined == 0 || errno == EOPNOTSUPP) {
2008 : : /* If the device says it has no channels, then all traffic
2009 : : * is sent to a single stream, so max queues = 1.
2010 : : */
2011 : 0 : *max_queues = 1;
2012 : 0 : *combined_queues = 1;
2013 : : } else {
2014 : 0 : *max_queues = channels.max_combined;
2015 : 0 : *combined_queues = channels.combined_count;
2016 : : }
2017 : :
2018 : 0 : out:
2019 : 0 : close(fd);
2020 : 0 : return ret;
2021 : : }
2022 : :
2023 : : static int
2024 : 0 : parse_parameters(struct rte_kvargs *kvlist, char *if_name, int *start_queue,
2025 : : int *queue_cnt, int *shared_umem, char *prog_path,
2026 : : int *busy_budget, int *force_copy, int *use_cni)
2027 : : {
2028 : : int ret;
2029 : :
2030 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_IFACE_ARG,
2031 : : &parse_name_arg, if_name);
2032 [ # # ]: 0 : if (ret < 0)
2033 : 0 : goto free_kvlist;
2034 : :
2035 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_START_QUEUE_ARG,
2036 : : &parse_integer_arg, start_queue);
2037 [ # # ]: 0 : if (ret < 0)
2038 : 0 : goto free_kvlist;
2039 : :
2040 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_QUEUE_COUNT_ARG,
2041 : : &parse_integer_arg, queue_cnt);
2042 [ # # # # ]: 0 : if (ret < 0 || *queue_cnt <= 0) {
2043 : : ret = -EINVAL;
2044 : 0 : goto free_kvlist;
2045 : : }
2046 : :
2047 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_SHARED_UMEM_ARG,
2048 : : &parse_integer_arg, shared_umem);
2049 [ # # ]: 0 : if (ret < 0)
2050 : 0 : goto free_kvlist;
2051 : :
2052 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_PROG_ARG,
2053 : : &parse_prog_arg, prog_path);
2054 [ # # ]: 0 : if (ret < 0)
2055 : 0 : goto free_kvlist;
2056 : :
2057 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_BUDGET_ARG,
2058 : : &parse_budget_arg, busy_budget);
2059 [ # # ]: 0 : if (ret < 0)
2060 : 0 : goto free_kvlist;
2061 : :
2062 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_FORCE_COPY_ARG,
2063 : : &parse_integer_arg, force_copy);
2064 [ # # ]: 0 : if (ret < 0)
2065 : 0 : goto free_kvlist;
2066 : :
2067 : 0 : ret = rte_kvargs_process(kvlist, ETH_AF_XDP_USE_CNI_ARG,
2068 : : &parse_integer_arg, use_cni);
2069 [ # # ]: 0 : if (ret < 0)
2070 : 0 : goto free_kvlist;
2071 : :
2072 : 0 : free_kvlist:
2073 : 0 : rte_kvargs_free(kvlist);
2074 : 0 : return ret;
2075 : : }
2076 : :
2077 : : static int
2078 : 0 : get_iface_info(const char *if_name,
2079 : : struct rte_ether_addr *eth_addr,
2080 : : int *if_index)
2081 : : {
2082 : : struct ifreq ifr;
2083 : 0 : int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
2084 : :
2085 [ # # ]: 0 : if (sock < 0)
2086 : : return -1;
2087 : :
2088 : : strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
2089 [ # # ]: 0 : if (ioctl(sock, SIOCGIFINDEX, &ifr))
2090 : 0 : goto error;
2091 : :
2092 : 0 : *if_index = ifr.ifr_ifindex;
2093 : :
2094 [ # # ]: 0 : if (ioctl(sock, SIOCGIFHWADDR, &ifr))
2095 : 0 : goto error;
2096 : :
2097 : : rte_memcpy(eth_addr, ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
2098 : :
2099 : 0 : close(sock);
2100 : 0 : return 0;
2101 : :
2102 : 0 : error:
2103 : 0 : close(sock);
2104 : 0 : return -1;
2105 : : }
2106 : :
2107 : : static struct rte_eth_dev *
2108 [ # # ]: 0 : init_internals(struct rte_vdev_device *dev, const char *if_name,
2109 : : int start_queue_idx, int queue_cnt, int shared_umem,
2110 : : const char *prog_path, int busy_budget, int force_copy,
2111 : : int use_cni)
2112 : : {
2113 : : const char *name = rte_vdev_device_name(dev);
2114 : 0 : const unsigned int numa_node = dev->device.numa_node;
2115 : : struct pmd_process_private *process_private;
2116 : : struct pmd_internals *internals;
2117 : : struct rte_eth_dev *eth_dev;
2118 : : int ret;
2119 : : int i;
2120 : :
2121 : 0 : internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
2122 [ # # ]: 0 : if (internals == NULL)
2123 : : return NULL;
2124 : :
2125 : 0 : internals->start_queue_idx = start_queue_idx;
2126 : 0 : internals->queue_cnt = queue_cnt;
2127 : 0 : strlcpy(internals->if_name, if_name, IFNAMSIZ);
2128 : 0 : strlcpy(internals->prog_path, prog_path, PATH_MAX);
2129 : 0 : internals->custom_prog_configured = 0;
2130 : :
2131 : : #ifndef ETH_AF_XDP_SHARED_UMEM
2132 : : if (shared_umem) {
2133 : : AF_XDP_LOG(ERR, "Shared UMEM feature not available. "
2134 : : "Check kernel and libbpf version\n");
2135 : : goto err_free_internals;
2136 : : }
2137 : : #endif
2138 : 0 : internals->shared_umem = shared_umem;
2139 : 0 : internals->force_copy = force_copy;
2140 : 0 : internals->use_cni = use_cni;
2141 : :
2142 [ # # ]: 0 : if (xdp_get_channels_info(if_name, &internals->max_queue_cnt,
2143 : : &internals->combined_queue_cnt)) {
2144 : 0 : AF_XDP_LOG(ERR, "Failed to get channel info of interface: %s\n",
2145 : : if_name);
2146 : 0 : goto err_free_internals;
2147 : : }
2148 : :
2149 [ # # ]: 0 : if (queue_cnt > internals->combined_queue_cnt) {
2150 : 0 : AF_XDP_LOG(ERR, "Specified queue count %d is larger than combined queue count %d.\n",
2151 : : queue_cnt, internals->combined_queue_cnt);
2152 : 0 : goto err_free_internals;
2153 : : }
2154 : :
2155 : 0 : internals->rx_queues = rte_zmalloc_socket(NULL,
2156 : : sizeof(struct pkt_rx_queue) * queue_cnt,
2157 : : 0, numa_node);
2158 [ # # ]: 0 : if (internals->rx_queues == NULL) {
2159 : 0 : AF_XDP_LOG(ERR, "Failed to allocate memory for rx queues.\n");
2160 : 0 : goto err_free_internals;
2161 : : }
2162 : :
2163 : 0 : internals->tx_queues = rte_zmalloc_socket(NULL,
2164 : : sizeof(struct pkt_tx_queue) * queue_cnt,
2165 : : 0, numa_node);
2166 [ # # ]: 0 : if (internals->tx_queues == NULL) {
2167 : 0 : AF_XDP_LOG(ERR, "Failed to allocate memory for tx queues.\n");
2168 : 0 : goto err_free_rx;
2169 : : }
2170 [ # # ]: 0 : for (i = 0; i < queue_cnt; i++) {
2171 : 0 : internals->tx_queues[i].pair = &internals->rx_queues[i];
2172 : 0 : internals->rx_queues[i].pair = &internals->tx_queues[i];
2173 : 0 : internals->rx_queues[i].xsk_queue_idx = start_queue_idx + i;
2174 : 0 : internals->tx_queues[i].xsk_queue_idx = start_queue_idx + i;
2175 : 0 : internals->rx_queues[i].busy_budget = busy_budget;
2176 : : }
2177 : :
2178 : 0 : ret = get_iface_info(if_name, &internals->eth_addr,
2179 : : &internals->if_index);
2180 [ # # ]: 0 : if (ret)
2181 : 0 : goto err_free_tx;
2182 : :
2183 : : process_private = (struct pmd_process_private *)
2184 : 0 : rte_zmalloc_socket(name, sizeof(struct pmd_process_private),
2185 : : RTE_CACHE_LINE_SIZE, numa_node);
2186 [ # # ]: 0 : if (process_private == NULL) {
2187 : 0 : AF_XDP_LOG(ERR, "Failed to alloc memory for process private\n");
2188 : 0 : goto err_free_tx;
2189 : : }
2190 : :
2191 : 0 : eth_dev = rte_eth_vdev_allocate(dev, 0);
2192 [ # # ]: 0 : if (eth_dev == NULL)
2193 : 0 : goto err_free_pp;
2194 : :
2195 : 0 : eth_dev->data->dev_private = internals;
2196 : 0 : eth_dev->data->dev_link = pmd_link;
2197 : 0 : eth_dev->data->mac_addrs = &internals->eth_addr;
2198 : 0 : eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
2199 [ # # ]: 0 : if (!internals->use_cni)
2200 : 0 : eth_dev->dev_ops = &ops;
2201 : : else
2202 : 0 : eth_dev->dev_ops = &ops_cni;
2203 : :
2204 : 0 : eth_dev->rx_pkt_burst = eth_af_xdp_rx;
2205 : 0 : eth_dev->tx_pkt_burst = eth_af_xdp_tx;
2206 : 0 : eth_dev->process_private = process_private;
2207 : :
2208 [ # # ]: 0 : for (i = 0; i < queue_cnt; i++)
2209 : 0 : process_private->rxq_xsk_fds[i] = -1;
2210 : :
2211 : : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
2212 : 0 : AF_XDP_LOG(INFO, "Zero copy between umem and mbuf enabled.\n");
2213 : : #endif
2214 : :
2215 : 0 : return eth_dev;
2216 : :
2217 : : err_free_pp:
2218 : 0 : rte_free(process_private);
2219 : 0 : err_free_tx:
2220 : 0 : rte_free(internals->tx_queues);
2221 : 0 : err_free_rx:
2222 : 0 : rte_free(internals->rx_queues);
2223 : 0 : err_free_internals:
2224 : 0 : rte_free(internals);
2225 : 0 : return NULL;
2226 : : }
2227 : :
2228 : : /* Secondary process requests rxq fds from primary. */
2229 : : static int
2230 : 0 : afxdp_mp_request_fds(const char *name, struct rte_eth_dev *dev)
2231 : : {
2232 : 0 : struct pmd_process_private *process_private = dev->process_private;
2233 : 0 : struct timespec timeout = {.tv_sec = 1, .tv_nsec = 0};
2234 : : struct rte_mp_msg request, *reply;
2235 : : struct rte_mp_reply replies;
2236 : : struct ipc_hdr *request_param = (struct ipc_hdr *)request.param;
2237 : : int i, ret;
2238 : :
2239 : : /* Prepare the request */
2240 : : memset(&request, 0, sizeof(request));
2241 : : strlcpy(request.name, ETH_AF_XDP_MP_KEY, sizeof(request.name));
2242 : : strlcpy(request_param->port_name, name,
2243 : : sizeof(request_param->port_name));
2244 : 0 : request.len_param = sizeof(*request_param);
2245 : :
2246 : : /* Send the request and receive the reply */
2247 : 0 : AF_XDP_LOG(DEBUG, "Sending multi-process IPC request for %s\n", name);
2248 : 0 : ret = rte_mp_request_sync(&request, &replies, &timeout);
2249 [ # # # # ]: 0 : if (ret < 0 || replies.nb_received != 1) {
2250 : 0 : AF_XDP_LOG(ERR, "Failed to request fds from primary: %d\n",
2251 : : rte_errno);
2252 : 0 : return -1;
2253 : : }
2254 : 0 : reply = replies.msgs;
2255 : 0 : AF_XDP_LOG(DEBUG, "Received multi-process IPC reply for %s\n", name);
2256 [ # # ]: 0 : if (dev->data->nb_rx_queues != reply->num_fds) {
2257 : 0 : AF_XDP_LOG(ERR, "Incorrect number of fds received: %d != %d\n",
2258 : : reply->num_fds, dev->data->nb_rx_queues);
2259 : 0 : return -EINVAL;
2260 : : }
2261 : :
2262 [ # # ]: 0 : for (i = 0; i < reply->num_fds; i++)
2263 : 0 : process_private->rxq_xsk_fds[i] = reply->fds[i];
2264 : :
2265 : 0 : free(reply);
2266 : 0 : return 0;
2267 : : }
2268 : :
2269 : : /* Primary process sends rxq fds to secondary. */
2270 : : static int
2271 : 0 : afxdp_mp_send_fds(const struct rte_mp_msg *request, const void *peer)
2272 : : {
2273 : : struct rte_eth_dev *dev;
2274 : : struct pmd_process_private *process_private;
2275 : : struct rte_mp_msg reply;
2276 : : const struct ipc_hdr *request_param =
2277 : : (const struct ipc_hdr *)request->param;
2278 : : struct ipc_hdr *reply_param =
2279 : : (struct ipc_hdr *)reply.param;
2280 : 0 : const char *request_name = request_param->port_name;
2281 : : int i;
2282 : :
2283 : 0 : AF_XDP_LOG(DEBUG, "Received multi-process IPC request for %s\n",
2284 : : request_name);
2285 : :
2286 : : /* Find the requested port */
2287 : 0 : dev = rte_eth_dev_get_by_name(request_name);
2288 [ # # ]: 0 : if (!dev) {
2289 : 0 : AF_XDP_LOG(ERR, "Failed to get port id for %s\n", request_name);
2290 : 0 : return -1;
2291 : : }
2292 : 0 : process_private = dev->process_private;
2293 : :
2294 : : /* Populate the reply with the xsk fd for each queue */
2295 : 0 : reply.num_fds = 0;
2296 [ # # ]: 0 : if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
2297 : 0 : AF_XDP_LOG(ERR, "Number of rx queues (%d) exceeds max number of fds (%d)\n",
2298 : : dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
2299 : 0 : return -EINVAL;
2300 : : }
2301 : :
2302 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++)
2303 : 0 : reply.fds[reply.num_fds++] = process_private->rxq_xsk_fds[i];
2304 : :
2305 : : /* Send the reply */
2306 : 0 : strlcpy(reply.name, request->name, sizeof(reply.name));
2307 : : strlcpy(reply_param->port_name, request_name,
2308 : : sizeof(reply_param->port_name));
2309 : 0 : reply.len_param = sizeof(*reply_param);
2310 : 0 : AF_XDP_LOG(DEBUG, "Sending multi-process IPC reply for %s\n",
2311 : : reply_param->port_name);
2312 [ # # ]: 0 : if (rte_mp_reply(&reply, peer) < 0) {
2313 : 0 : AF_XDP_LOG(ERR, "Failed to reply to multi-process IPC request\n");
2314 : 0 : return -1;
2315 : : }
2316 : : return 0;
2317 : : }
2318 : :
2319 : : static int
2320 : 0 : rte_pmd_af_xdp_probe(struct rte_vdev_device *dev)
2321 : : {
2322 : : struct rte_kvargs *kvlist;
2323 : 0 : char if_name[IFNAMSIZ] = {'\0'};
2324 : 0 : int xsk_start_queue_idx = ETH_AF_XDP_DFLT_START_QUEUE_IDX;
2325 : 0 : int xsk_queue_cnt = ETH_AF_XDP_DFLT_QUEUE_COUNT;
2326 : 0 : int shared_umem = 0;
2327 : 0 : char prog_path[PATH_MAX] = {'\0'};
2328 : 0 : int busy_budget = -1, ret;
2329 : 0 : int force_copy = 0;
2330 [ # # ]: 0 : int use_cni = 0;
2331 : : struct rte_eth_dev *eth_dev = NULL;
2332 : : const char *name = rte_vdev_device_name(dev);
2333 : :
2334 : 0 : AF_XDP_LOG(INFO, "Initializing pmd_af_xdp for %s\n", name);
2335 : :
2336 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
2337 : 0 : eth_dev = rte_eth_dev_attach_secondary(name);
2338 [ # # ]: 0 : if (eth_dev == NULL) {
2339 : 0 : AF_XDP_LOG(ERR, "Failed to probe %s\n", name);
2340 : 0 : return -EINVAL;
2341 : : }
2342 : 0 : eth_dev->dev_ops = &ops;
2343 : 0 : eth_dev->device = &dev->device;
2344 : 0 : eth_dev->rx_pkt_burst = rte_eth_pkt_burst_dummy;
2345 : 0 : eth_dev->tx_pkt_burst = rte_eth_pkt_burst_dummy;
2346 : 0 : eth_dev->process_private = (struct pmd_process_private *)
2347 : 0 : rte_zmalloc_socket(name,
2348 : : sizeof(struct pmd_process_private),
2349 : : RTE_CACHE_LINE_SIZE,
2350 : : eth_dev->device->numa_node);
2351 [ # # ]: 0 : if (eth_dev->process_private == NULL) {
2352 : 0 : AF_XDP_LOG(ERR,
2353 : : "Failed to alloc memory for process private\n");
2354 : 0 : return -ENOMEM;
2355 : : }
2356 : :
2357 : : /* Obtain the xsk fds from the primary process. */
2358 [ # # ]: 0 : if (afxdp_mp_request_fds(name, eth_dev))
2359 : : return -1;
2360 : :
2361 : 0 : rte_eth_dev_probing_finish(eth_dev);
2362 : 0 : return 0;
2363 : : }
2364 : :
2365 : 0 : kvlist = rte_kvargs_parse(rte_vdev_device_args(dev), valid_arguments);
2366 [ # # ]: 0 : if (kvlist == NULL) {
2367 : 0 : AF_XDP_LOG(ERR, "Invalid kvargs key\n");
2368 : 0 : return -EINVAL;
2369 : : }
2370 : :
2371 [ # # ]: 0 : if (parse_parameters(kvlist, if_name, &xsk_start_queue_idx,
2372 : : &xsk_queue_cnt, &shared_umem, prog_path,
2373 : : &busy_budget, &force_copy, &use_cni) < 0) {
2374 : 0 : AF_XDP_LOG(ERR, "Invalid kvargs value\n");
2375 : 0 : return -EINVAL;
2376 : : }
2377 : :
2378 [ # # # # ]: 0 : if (use_cni && busy_budget > 0) {
2379 : 0 : AF_XDP_LOG(ERR, "When '%s' parameter is used, '%s' parameter is not valid\n",
2380 : : ETH_AF_XDP_USE_CNI_ARG, ETH_AF_XDP_BUDGET_ARG);
2381 : 0 : return -EINVAL;
2382 : : }
2383 : :
2384 [ # # # # ]: 0 : if (use_cni && strnlen(prog_path, PATH_MAX)) {
2385 : 0 : AF_XDP_LOG(ERR, "When '%s' parameter is used, '%s' parameter is not valid\n",
2386 : : ETH_AF_XDP_USE_CNI_ARG, ETH_AF_XDP_PROG_ARG);
2387 : 0 : return -EINVAL;
2388 : : }
2389 : :
2390 [ # # ]: 0 : if (strlen(if_name) == 0) {
2391 : 0 : AF_XDP_LOG(ERR, "Network interface must be specified\n");
2392 : 0 : return -EINVAL;
2393 : : }
2394 : :
2395 : : /* get numa node id from net sysfs */
2396 [ # # ]: 0 : if (dev->device.numa_node == SOCKET_ID_ANY) {
2397 : 0 : unsigned long numa = 0;
2398 : : char numa_path[PATH_MAX];
2399 : :
2400 : : snprintf(numa_path, sizeof(numa_path), "/sys/class/net/%s/device/numa_node",
2401 : : if_name);
2402 [ # # # # ]: 0 : if (access(numa_path, R_OK) != 0 || eal_parse_sysfs_value(numa_path, &numa) != 0)
2403 : 0 : dev->device.numa_node = rte_socket_id();
2404 : : else
2405 : 0 : dev->device.numa_node = numa;
2406 : : }
2407 : :
2408 [ # # ]: 0 : busy_budget = busy_budget == -1 ? ETH_AF_XDP_DFLT_BUSY_BUDGET :
2409 : : busy_budget;
2410 : :
2411 : 0 : eth_dev = init_internals(dev, if_name, xsk_start_queue_idx,
2412 : : xsk_queue_cnt, shared_umem, prog_path,
2413 : : busy_budget, force_copy, use_cni);
2414 [ # # ]: 0 : if (eth_dev == NULL) {
2415 : 0 : AF_XDP_LOG(ERR, "Failed to init internals\n");
2416 : 0 : return -1;
2417 : : }
2418 : :
2419 : : /* Register IPC callback which shares xsk fds from primary to secondary */
2420 [ # # ]: 0 : if (!afxdp_dev_count) {
2421 : 0 : ret = rte_mp_action_register(ETH_AF_XDP_MP_KEY, afxdp_mp_send_fds);
2422 [ # # # # ]: 0 : if (ret < 0 && rte_errno != ENOTSUP) {
2423 : 0 : AF_XDP_LOG(ERR, "%s: Failed to register multi-process IPC callback: %s\n",
2424 : : name, strerror(rte_errno));
2425 : 0 : return -1;
2426 : : }
2427 : : }
2428 : 0 : afxdp_dev_count++;
2429 : :
2430 : 0 : rte_eth_dev_probing_finish(eth_dev);
2431 : :
2432 : 0 : return 0;
2433 : : }
2434 : :
2435 : : static int
2436 : 0 : rte_pmd_af_xdp_remove(struct rte_vdev_device *dev)
2437 : : {
2438 : : struct rte_eth_dev *eth_dev = NULL;
2439 : :
2440 : 0 : AF_XDP_LOG(INFO, "Removing AF_XDP ethdev on numa socket %u\n",
2441 : : rte_socket_id());
2442 : :
2443 [ # # ]: 0 : if (dev == NULL)
2444 : : return -1;
2445 : :
2446 : : /* find the ethdev entry */
2447 : 0 : eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
2448 [ # # ]: 0 : if (eth_dev == NULL)
2449 : : return 0;
2450 : :
2451 : 0 : eth_dev_close(eth_dev);
2452 [ # # ]: 0 : if (afxdp_dev_count == 1)
2453 : 0 : rte_mp_action_unregister(ETH_AF_XDP_MP_KEY);
2454 : 0 : afxdp_dev_count--;
2455 : 0 : rte_eth_dev_release_port(eth_dev);
2456 : :
2457 : 0 : return 0;
2458 : : }
2459 : :
2460 : : static struct rte_vdev_driver pmd_af_xdp_drv = {
2461 : : .probe = rte_pmd_af_xdp_probe,
2462 : : .remove = rte_pmd_af_xdp_remove,
2463 : : };
2464 : :
2465 : 238 : RTE_PMD_REGISTER_VDEV(net_af_xdp, pmd_af_xdp_drv);
2466 : : RTE_PMD_REGISTER_PARAM_STRING(net_af_xdp,
2467 : : "iface=<string> "
2468 : : "start_queue=<int> "
2469 : : "queue_count=<int> "
2470 : : "shared_umem=<int> "
2471 : : "xdp_prog=<string> "
2472 : : "busy_budget=<int> "
2473 : : "force_copy=<int> "
2474 : : "use_cni=<int> ");
|