18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * AF_XDP user-space access library. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright(c) 2018 - 2019 Intel Corporation. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author(s): Magnus Karlsson <magnus.karlsson@intel.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#ifndef __LIBBPF_XSK_H 128c2ecf20Sopenharmony_ci#define __LIBBPF_XSK_H 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <stdio.h> 158c2ecf20Sopenharmony_ci#include <stdint.h> 168c2ecf20Sopenharmony_ci#include <linux/if_xdp.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "libbpf.h" 198c2ecf20Sopenharmony_ci#include "libbpf_util.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#ifdef __cplusplus 228c2ecf20Sopenharmony_ciextern "C" { 238c2ecf20Sopenharmony_ci#endif 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Do not access these members directly. Use the functions below. */ 268c2ecf20Sopenharmony_ci#define DEFINE_XSK_RING(name) \ 278c2ecf20Sopenharmony_cistruct name { \ 288c2ecf20Sopenharmony_ci __u32 cached_prod; \ 298c2ecf20Sopenharmony_ci __u32 cached_cons; \ 308c2ecf20Sopenharmony_ci __u32 mask; \ 318c2ecf20Sopenharmony_ci __u32 size; \ 328c2ecf20Sopenharmony_ci __u32 *producer; \ 338c2ecf20Sopenharmony_ci __u32 *consumer; \ 348c2ecf20Sopenharmony_ci void *ring; \ 358c2ecf20Sopenharmony_ci __u32 *flags; \ 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciDEFINE_XSK_RING(xsk_ring_prod); 398c2ecf20Sopenharmony_ciDEFINE_XSK_RING(xsk_ring_cons); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* For a detailed explanation on the memory barriers associated with the 428c2ecf20Sopenharmony_ci * ring, please take a look at net/xdp/xsk_queue.h. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct xsk_umem; 468c2ecf20Sopenharmony_cistruct xsk_socket; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline __u64 *xsk_ring_prod__fill_addr(struct xsk_ring_prod *fill, 498c2ecf20Sopenharmony_ci __u32 idx) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci __u64 *addrs = (__u64 *)fill->ring; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return &addrs[idx & fill->mask]; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline const __u64 * 578c2ecf20Sopenharmony_cixsk_ring_cons__comp_addr(const struct xsk_ring_cons *comp, __u32 idx) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci const __u64 *addrs = (const __u64 *)comp->ring; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return &addrs[idx & comp->mask]; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic inline struct xdp_desc *xsk_ring_prod__tx_desc(struct xsk_ring_prod *tx, 658c2ecf20Sopenharmony_ci __u32 idx) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct xdp_desc *descs = (struct xdp_desc *)tx->ring; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return &descs[idx & tx->mask]; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic inline const struct xdp_desc * 738c2ecf20Sopenharmony_cixsk_ring_cons__rx_desc(const struct xsk_ring_cons *rx, __u32 idx) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci const struct xdp_desc *descs = (const struct xdp_desc *)rx->ring; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return &descs[idx & rx->mask]; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic inline int xsk_ring_prod__needs_wakeup(const struct xsk_ring_prod *r) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return *r->flags & XDP_RING_NEED_WAKEUP; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline __u32 xsk_prod_nb_free(struct xsk_ring_prod *r, __u32 nb) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci __u32 free_entries = r->cached_cons - r->cached_prod; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (free_entries >= nb) 908c2ecf20Sopenharmony_ci return free_entries; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* Refresh the local tail pointer. 938c2ecf20Sopenharmony_ci * cached_cons is r->size bigger than the real consumer pointer so 948c2ecf20Sopenharmony_ci * that this addition can be avoided in the more frequently 958c2ecf20Sopenharmony_ci * executed code that computs free_entries in the beginning of 968c2ecf20Sopenharmony_ci * this function. Without this optimization it whould have been 978c2ecf20Sopenharmony_ci * free_entries = r->cached_prod - r->cached_cons + r->size. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci r->cached_cons = *r->consumer + r->size; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return r->cached_cons - r->cached_prod; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic inline __u32 xsk_cons_nb_avail(struct xsk_ring_cons *r, __u32 nb) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci __u32 entries = r->cached_prod - r->cached_cons; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (entries == 0) { 1098c2ecf20Sopenharmony_ci r->cached_prod = *r->producer; 1108c2ecf20Sopenharmony_ci entries = r->cached_prod - r->cached_cons; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return (entries > nb) ? nb : entries; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic inline size_t xsk_ring_prod__reserve(struct xsk_ring_prod *prod, 1178c2ecf20Sopenharmony_ci size_t nb, __u32 *idx) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci if (xsk_prod_nb_free(prod, nb) < nb) 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci *idx = prod->cached_prod; 1238c2ecf20Sopenharmony_ci prod->cached_prod += nb; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return nb; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, size_t nb) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci /* Make sure everything has been written to the ring before indicating 1318c2ecf20Sopenharmony_ci * this to the kernel by writing the producer pointer. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci libbpf_smp_wmb(); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci *prod->producer += nb; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic inline size_t xsk_ring_cons__peek(struct xsk_ring_cons *cons, 1398c2ecf20Sopenharmony_ci size_t nb, __u32 *idx) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci size_t entries = xsk_cons_nb_avail(cons, nb); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (entries > 0) { 1448c2ecf20Sopenharmony_ci /* Make sure we do not speculatively read the data before 1458c2ecf20Sopenharmony_ci * we have received the packet buffers from the ring. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci libbpf_smp_rmb(); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci *idx = cons->cached_cons; 1508c2ecf20Sopenharmony_ci cons->cached_cons += entries; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return entries; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline void xsk_ring_cons__release(struct xsk_ring_cons *cons, size_t nb) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci /* Make sure data has been read before indicating we are done 1598c2ecf20Sopenharmony_ci * with the entries by updating the consumer pointer. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci libbpf_smp_rwmb(); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci *cons->consumer += nb; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic inline void *xsk_umem__get_data(void *umem_area, __u64 addr) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci return &((char *)umem_area)[addr]; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic inline __u64 xsk_umem__extract_addr(__u64 addr) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return addr & XSK_UNALIGNED_BUF_ADDR_MASK; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic inline __u64 xsk_umem__extract_offset(__u64 addr) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return addr >> XSK_UNALIGNED_BUF_OFFSET_SHIFT; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic inline __u64 xsk_umem__add_offset_to_addr(__u64 addr) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return xsk_umem__extract_addr(addr) + xsk_umem__extract_offset(addr); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciLIBBPF_API int xsk_umem__fd(const struct xsk_umem *umem); 1878c2ecf20Sopenharmony_ciLIBBPF_API int xsk_socket__fd(const struct xsk_socket *xsk); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#define XSK_RING_CONS__DEFAULT_NUM_DESCS 2048 1908c2ecf20Sopenharmony_ci#define XSK_RING_PROD__DEFAULT_NUM_DESCS 2048 1918c2ecf20Sopenharmony_ci#define XSK_UMEM__DEFAULT_FRAME_SHIFT 12 /* 4096 bytes */ 1928c2ecf20Sopenharmony_ci#define XSK_UMEM__DEFAULT_FRAME_SIZE (1 << XSK_UMEM__DEFAULT_FRAME_SHIFT) 1938c2ecf20Sopenharmony_ci#define XSK_UMEM__DEFAULT_FRAME_HEADROOM 0 1948c2ecf20Sopenharmony_ci#define XSK_UMEM__DEFAULT_FLAGS 0 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistruct xsk_umem_config { 1978c2ecf20Sopenharmony_ci __u32 fill_size; 1988c2ecf20Sopenharmony_ci __u32 comp_size; 1998c2ecf20Sopenharmony_ci __u32 frame_size; 2008c2ecf20Sopenharmony_ci __u32 frame_headroom; 2018c2ecf20Sopenharmony_ci __u32 flags; 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* Flags for the libbpf_flags field. */ 2058c2ecf20Sopenharmony_ci#define XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD (1 << 0) 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistruct xsk_socket_config { 2088c2ecf20Sopenharmony_ci __u32 rx_size; 2098c2ecf20Sopenharmony_ci __u32 tx_size; 2108c2ecf20Sopenharmony_ci __u32 libbpf_flags; 2118c2ecf20Sopenharmony_ci __u32 xdp_flags; 2128c2ecf20Sopenharmony_ci __u16 bind_flags; 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* Set config to NULL to get the default configuration. */ 2168c2ecf20Sopenharmony_ciLIBBPF_API int xsk_umem__create(struct xsk_umem **umem, 2178c2ecf20Sopenharmony_ci void *umem_area, __u64 size, 2188c2ecf20Sopenharmony_ci struct xsk_ring_prod *fill, 2198c2ecf20Sopenharmony_ci struct xsk_ring_cons *comp, 2208c2ecf20Sopenharmony_ci const struct xsk_umem_config *config); 2218c2ecf20Sopenharmony_ciLIBBPF_API int xsk_umem__create_v0_0_2(struct xsk_umem **umem, 2228c2ecf20Sopenharmony_ci void *umem_area, __u64 size, 2238c2ecf20Sopenharmony_ci struct xsk_ring_prod *fill, 2248c2ecf20Sopenharmony_ci struct xsk_ring_cons *comp, 2258c2ecf20Sopenharmony_ci const struct xsk_umem_config *config); 2268c2ecf20Sopenharmony_ciLIBBPF_API int xsk_umem__create_v0_0_4(struct xsk_umem **umem, 2278c2ecf20Sopenharmony_ci void *umem_area, __u64 size, 2288c2ecf20Sopenharmony_ci struct xsk_ring_prod *fill, 2298c2ecf20Sopenharmony_ci struct xsk_ring_cons *comp, 2308c2ecf20Sopenharmony_ci const struct xsk_umem_config *config); 2318c2ecf20Sopenharmony_ciLIBBPF_API int xsk_socket__create(struct xsk_socket **xsk, 2328c2ecf20Sopenharmony_ci const char *ifname, __u32 queue_id, 2338c2ecf20Sopenharmony_ci struct xsk_umem *umem, 2348c2ecf20Sopenharmony_ci struct xsk_ring_cons *rx, 2358c2ecf20Sopenharmony_ci struct xsk_ring_prod *tx, 2368c2ecf20Sopenharmony_ci const struct xsk_socket_config *config); 2378c2ecf20Sopenharmony_ciLIBBPF_API int 2388c2ecf20Sopenharmony_cixsk_socket__create_shared(struct xsk_socket **xsk_ptr, 2398c2ecf20Sopenharmony_ci const char *ifname, 2408c2ecf20Sopenharmony_ci __u32 queue_id, struct xsk_umem *umem, 2418c2ecf20Sopenharmony_ci struct xsk_ring_cons *rx, 2428c2ecf20Sopenharmony_ci struct xsk_ring_prod *tx, 2438c2ecf20Sopenharmony_ci struct xsk_ring_prod *fill, 2448c2ecf20Sopenharmony_ci struct xsk_ring_cons *comp, 2458c2ecf20Sopenharmony_ci const struct xsk_socket_config *config); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* Returns 0 for success and -EBUSY if the umem is still in use. */ 2488c2ecf20Sopenharmony_ciLIBBPF_API int xsk_umem__delete(struct xsk_umem *umem); 2498c2ecf20Sopenharmony_ciLIBBPF_API void xsk_socket__delete(struct xsk_socket *xsk); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#ifdef __cplusplus 2528c2ecf20Sopenharmony_ci} /* extern "C" */ 2538c2ecf20Sopenharmony_ci#endif 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci#endif /* __LIBBPF_XSK_H */ 256