162306a36Sopenharmony_ci// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * AF_XDP user-space access library. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright(c) 2018 - 2019 Intel Corporation. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author(s): Magnus Karlsson <magnus.karlsson@intel.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <errno.h> 1262306a36Sopenharmony_ci#include <stdlib.h> 1362306a36Sopenharmony_ci#include <string.h> 1462306a36Sopenharmony_ci#include <unistd.h> 1562306a36Sopenharmony_ci#include <arpa/inet.h> 1662306a36Sopenharmony_ci#include <asm/barrier.h> 1762306a36Sopenharmony_ci#include <linux/compiler.h> 1862306a36Sopenharmony_ci#include <linux/ethtool.h> 1962306a36Sopenharmony_ci#include <linux/filter.h> 2062306a36Sopenharmony_ci#include <linux/if_ether.h> 2162306a36Sopenharmony_ci#include <linux/if_link.h> 2262306a36Sopenharmony_ci#include <linux/if_packet.h> 2362306a36Sopenharmony_ci#include <linux/if_xdp.h> 2462306a36Sopenharmony_ci#include <linux/kernel.h> 2562306a36Sopenharmony_ci#include <linux/list.h> 2662306a36Sopenharmony_ci#include <linux/netlink.h> 2762306a36Sopenharmony_ci#include <linux/rtnetlink.h> 2862306a36Sopenharmony_ci#include <linux/sockios.h> 2962306a36Sopenharmony_ci#include <net/if.h> 3062306a36Sopenharmony_ci#include <sys/ioctl.h> 3162306a36Sopenharmony_ci#include <sys/mman.h> 3262306a36Sopenharmony_ci#include <sys/socket.h> 3362306a36Sopenharmony_ci#include <sys/types.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <bpf/bpf.h> 3662306a36Sopenharmony_ci#include <bpf/libbpf.h> 3762306a36Sopenharmony_ci#include "xsk.h" 3862306a36Sopenharmony_ci#include "bpf_util.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#ifndef SOL_XDP 4162306a36Sopenharmony_ci #define SOL_XDP 283 4262306a36Sopenharmony_ci#endif 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#ifndef AF_XDP 4562306a36Sopenharmony_ci #define AF_XDP 44 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#ifndef PF_XDP 4962306a36Sopenharmony_ci #define PF_XDP AF_XDP 5062306a36Sopenharmony_ci#endif 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define pr_warn(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define XSKMAP_SIZE 1 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct xsk_umem { 5762306a36Sopenharmony_ci struct xsk_ring_prod *fill_save; 5862306a36Sopenharmony_ci struct xsk_ring_cons *comp_save; 5962306a36Sopenharmony_ci char *umem_area; 6062306a36Sopenharmony_ci struct xsk_umem_config config; 6162306a36Sopenharmony_ci int fd; 6262306a36Sopenharmony_ci int refcount; 6362306a36Sopenharmony_ci struct list_head ctx_list; 6462306a36Sopenharmony_ci bool rx_ring_setup_done; 6562306a36Sopenharmony_ci bool tx_ring_setup_done; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct xsk_ctx { 6962306a36Sopenharmony_ci struct xsk_ring_prod *fill; 7062306a36Sopenharmony_ci struct xsk_ring_cons *comp; 7162306a36Sopenharmony_ci __u32 queue_id; 7262306a36Sopenharmony_ci struct xsk_umem *umem; 7362306a36Sopenharmony_ci int refcount; 7462306a36Sopenharmony_ci int ifindex; 7562306a36Sopenharmony_ci struct list_head list; 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct xsk_socket { 7962306a36Sopenharmony_ci struct xsk_ring_cons *rx; 8062306a36Sopenharmony_ci struct xsk_ring_prod *tx; 8162306a36Sopenharmony_ci struct xsk_ctx *ctx; 8262306a36Sopenharmony_ci struct xsk_socket_config config; 8362306a36Sopenharmony_ci int fd; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistruct nl_mtu_req { 8762306a36Sopenharmony_ci struct nlmsghdr nh; 8862306a36Sopenharmony_ci struct ifinfomsg msg; 8962306a36Sopenharmony_ci char buf[512]; 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciint xsk_umem__fd(const struct xsk_umem *umem) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return umem ? umem->fd : -EINVAL; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciint xsk_socket__fd(const struct xsk_socket *xsk) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return xsk ? xsk->fd : -EINVAL; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic bool xsk_page_aligned(void *buffer) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci unsigned long addr = (unsigned long)buffer; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return !(addr & (getpagesize() - 1)); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void xsk_set_umem_config(struct xsk_umem_config *cfg, 11062306a36Sopenharmony_ci const struct xsk_umem_config *usr_cfg) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci if (!usr_cfg) { 11362306a36Sopenharmony_ci cfg->fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; 11462306a36Sopenharmony_ci cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS; 11562306a36Sopenharmony_ci cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; 11662306a36Sopenharmony_ci cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM; 11762306a36Sopenharmony_ci cfg->flags = XSK_UMEM__DEFAULT_FLAGS; 11862306a36Sopenharmony_ci return; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci cfg->fill_size = usr_cfg->fill_size; 12262306a36Sopenharmony_ci cfg->comp_size = usr_cfg->comp_size; 12362306a36Sopenharmony_ci cfg->frame_size = usr_cfg->frame_size; 12462306a36Sopenharmony_ci cfg->frame_headroom = usr_cfg->frame_headroom; 12562306a36Sopenharmony_ci cfg->flags = usr_cfg->flags; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg, 12962306a36Sopenharmony_ci const struct xsk_socket_config *usr_cfg) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci if (!usr_cfg) { 13262306a36Sopenharmony_ci cfg->rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS; 13362306a36Sopenharmony_ci cfg->tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS; 13462306a36Sopenharmony_ci cfg->bind_flags = 0; 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci cfg->rx_size = usr_cfg->rx_size; 13962306a36Sopenharmony_ci cfg->tx_size = usr_cfg->tx_size; 14062306a36Sopenharmony_ci cfg->bind_flags = usr_cfg->bind_flags; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int xsk_get_mmap_offsets(int fd, struct xdp_mmap_offsets *off) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci socklen_t optlen; 14862306a36Sopenharmony_ci int err; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci optlen = sizeof(*off); 15162306a36Sopenharmony_ci err = getsockopt(fd, SOL_XDP, XDP_MMAP_OFFSETS, off, &optlen); 15262306a36Sopenharmony_ci if (err) 15362306a36Sopenharmony_ci return err; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (optlen == sizeof(*off)) 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return -EINVAL; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int xsk_create_umem_rings(struct xsk_umem *umem, int fd, 16262306a36Sopenharmony_ci struct xsk_ring_prod *fill, 16362306a36Sopenharmony_ci struct xsk_ring_cons *comp) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct xdp_mmap_offsets off; 16662306a36Sopenharmony_ci void *map; 16762306a36Sopenharmony_ci int err; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci err = setsockopt(fd, SOL_XDP, XDP_UMEM_FILL_RING, 17062306a36Sopenharmony_ci &umem->config.fill_size, 17162306a36Sopenharmony_ci sizeof(umem->config.fill_size)); 17262306a36Sopenharmony_ci if (err) 17362306a36Sopenharmony_ci return -errno; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci err = setsockopt(fd, SOL_XDP, XDP_UMEM_COMPLETION_RING, 17662306a36Sopenharmony_ci &umem->config.comp_size, 17762306a36Sopenharmony_ci sizeof(umem->config.comp_size)); 17862306a36Sopenharmony_ci if (err) 17962306a36Sopenharmony_ci return -errno; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci err = xsk_get_mmap_offsets(fd, &off); 18262306a36Sopenharmony_ci if (err) 18362306a36Sopenharmony_ci return -errno; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci map = mmap(NULL, off.fr.desc + umem->config.fill_size * sizeof(__u64), 18662306a36Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, 18762306a36Sopenharmony_ci XDP_UMEM_PGOFF_FILL_RING); 18862306a36Sopenharmony_ci if (map == MAP_FAILED) 18962306a36Sopenharmony_ci return -errno; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci fill->mask = umem->config.fill_size - 1; 19262306a36Sopenharmony_ci fill->size = umem->config.fill_size; 19362306a36Sopenharmony_ci fill->producer = map + off.fr.producer; 19462306a36Sopenharmony_ci fill->consumer = map + off.fr.consumer; 19562306a36Sopenharmony_ci fill->flags = map + off.fr.flags; 19662306a36Sopenharmony_ci fill->ring = map + off.fr.desc; 19762306a36Sopenharmony_ci fill->cached_cons = umem->config.fill_size; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci map = mmap(NULL, off.cr.desc + umem->config.comp_size * sizeof(__u64), 20062306a36Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, 20162306a36Sopenharmony_ci XDP_UMEM_PGOFF_COMPLETION_RING); 20262306a36Sopenharmony_ci if (map == MAP_FAILED) { 20362306a36Sopenharmony_ci err = -errno; 20462306a36Sopenharmony_ci goto out_mmap; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci comp->mask = umem->config.comp_size - 1; 20862306a36Sopenharmony_ci comp->size = umem->config.comp_size; 20962306a36Sopenharmony_ci comp->producer = map + off.cr.producer; 21062306a36Sopenharmony_ci comp->consumer = map + off.cr.consumer; 21162306a36Sopenharmony_ci comp->flags = map + off.cr.flags; 21262306a36Sopenharmony_ci comp->ring = map + off.cr.desc; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ciout_mmap: 21762306a36Sopenharmony_ci munmap(map, off.fr.desc + umem->config.fill_size * sizeof(__u64)); 21862306a36Sopenharmony_ci return err; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ciint xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, 22262306a36Sopenharmony_ci __u64 size, struct xsk_ring_prod *fill, 22362306a36Sopenharmony_ci struct xsk_ring_cons *comp, 22462306a36Sopenharmony_ci const struct xsk_umem_config *usr_config) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct xdp_umem_reg mr; 22762306a36Sopenharmony_ci struct xsk_umem *umem; 22862306a36Sopenharmony_ci int err; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (!umem_area || !umem_ptr || !fill || !comp) 23162306a36Sopenharmony_ci return -EFAULT; 23262306a36Sopenharmony_ci if (!size && !xsk_page_aligned(umem_area)) 23362306a36Sopenharmony_ci return -EINVAL; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci umem = calloc(1, sizeof(*umem)); 23662306a36Sopenharmony_ci if (!umem) 23762306a36Sopenharmony_ci return -ENOMEM; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci umem->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0); 24062306a36Sopenharmony_ci if (umem->fd < 0) { 24162306a36Sopenharmony_ci err = -errno; 24262306a36Sopenharmony_ci goto out_umem_alloc; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci umem->umem_area = umem_area; 24662306a36Sopenharmony_ci INIT_LIST_HEAD(&umem->ctx_list); 24762306a36Sopenharmony_ci xsk_set_umem_config(&umem->config, usr_config); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci memset(&mr, 0, sizeof(mr)); 25062306a36Sopenharmony_ci mr.addr = (uintptr_t)umem_area; 25162306a36Sopenharmony_ci mr.len = size; 25262306a36Sopenharmony_ci mr.chunk_size = umem->config.frame_size; 25362306a36Sopenharmony_ci mr.headroom = umem->config.frame_headroom; 25462306a36Sopenharmony_ci mr.flags = umem->config.flags; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr)); 25762306a36Sopenharmony_ci if (err) { 25862306a36Sopenharmony_ci err = -errno; 25962306a36Sopenharmony_ci goto out_socket; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci err = xsk_create_umem_rings(umem, umem->fd, fill, comp); 26362306a36Sopenharmony_ci if (err) 26462306a36Sopenharmony_ci goto out_socket; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci umem->fill_save = fill; 26762306a36Sopenharmony_ci umem->comp_save = comp; 26862306a36Sopenharmony_ci *umem_ptr = umem; 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciout_socket: 27262306a36Sopenharmony_ci close(umem->fd); 27362306a36Sopenharmony_ciout_umem_alloc: 27462306a36Sopenharmony_ci free(umem); 27562306a36Sopenharmony_ci return err; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cibool xsk_is_in_mode(u32 ifindex, int mode) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci LIBBPF_OPTS(bpf_xdp_query_opts, opts); 28162306a36Sopenharmony_ci int ret; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci ret = bpf_xdp_query(ifindex, mode, &opts); 28462306a36Sopenharmony_ci if (ret) { 28562306a36Sopenharmony_ci printf("XDP mode query returned error %s\n", strerror(errno)); 28662306a36Sopenharmony_ci return false; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (mode == XDP_FLAGS_DRV_MODE) 29062306a36Sopenharmony_ci return opts.attach_mode == XDP_ATTACHED_DRV; 29162306a36Sopenharmony_ci else if (mode == XDP_FLAGS_SKB_MODE) 29262306a36Sopenharmony_ci return opts.attach_mode == XDP_ATTACHED_SKB; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return false; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* Lifted from netlink.c in tools/lib/bpf */ 29862306a36Sopenharmony_cistatic int netlink_recvmsg(int sock, struct msghdr *mhdr, int flags) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int len; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci do { 30362306a36Sopenharmony_ci len = recvmsg(sock, mhdr, flags); 30462306a36Sopenharmony_ci } while (len < 0 && (errno == EINTR || errno == EAGAIN)); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (len < 0) 30762306a36Sopenharmony_ci return -errno; 30862306a36Sopenharmony_ci return len; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* Lifted from netlink.c in tools/lib/bpf */ 31262306a36Sopenharmony_cistatic int alloc_iov(struct iovec *iov, int len) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci void *nbuf; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci nbuf = realloc(iov->iov_base, len); 31762306a36Sopenharmony_ci if (!nbuf) 31862306a36Sopenharmony_ci return -ENOMEM; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci iov->iov_base = nbuf; 32162306a36Sopenharmony_ci iov->iov_len = len; 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* Original version lifted from netlink.c in tools/lib/bpf */ 32662306a36Sopenharmony_cistatic int netlink_recv(int sock) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct iovec iov = {}; 32962306a36Sopenharmony_ci struct msghdr mhdr = { 33062306a36Sopenharmony_ci .msg_iov = &iov, 33162306a36Sopenharmony_ci .msg_iovlen = 1, 33262306a36Sopenharmony_ci }; 33362306a36Sopenharmony_ci bool multipart = true; 33462306a36Sopenharmony_ci struct nlmsgerr *err; 33562306a36Sopenharmony_ci struct nlmsghdr *nh; 33662306a36Sopenharmony_ci int len, ret; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci ret = alloc_iov(&iov, 4096); 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci goto done; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci while (multipart) { 34362306a36Sopenharmony_ci multipart = false; 34462306a36Sopenharmony_ci len = netlink_recvmsg(sock, &mhdr, MSG_PEEK | MSG_TRUNC); 34562306a36Sopenharmony_ci if (len < 0) { 34662306a36Sopenharmony_ci ret = len; 34762306a36Sopenharmony_ci goto done; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (len > iov.iov_len) { 35162306a36Sopenharmony_ci ret = alloc_iov(&iov, len); 35262306a36Sopenharmony_ci if (ret) 35362306a36Sopenharmony_ci goto done; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci len = netlink_recvmsg(sock, &mhdr, 0); 35762306a36Sopenharmony_ci if (len < 0) { 35862306a36Sopenharmony_ci ret = len; 35962306a36Sopenharmony_ci goto done; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (len == 0) 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci for (nh = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(nh, len); 36662306a36Sopenharmony_ci nh = NLMSG_NEXT(nh, len)) { 36762306a36Sopenharmony_ci if (nh->nlmsg_flags & NLM_F_MULTI) 36862306a36Sopenharmony_ci multipart = true; 36962306a36Sopenharmony_ci switch (nh->nlmsg_type) { 37062306a36Sopenharmony_ci case NLMSG_ERROR: 37162306a36Sopenharmony_ci err = (struct nlmsgerr *)NLMSG_DATA(nh); 37262306a36Sopenharmony_ci if (!err->error) 37362306a36Sopenharmony_ci continue; 37462306a36Sopenharmony_ci ret = err->error; 37562306a36Sopenharmony_ci goto done; 37662306a36Sopenharmony_ci case NLMSG_DONE: 37762306a36Sopenharmony_ci ret = 0; 37862306a36Sopenharmony_ci goto done; 37962306a36Sopenharmony_ci default: 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci ret = 0; 38562306a36Sopenharmony_cidone: 38662306a36Sopenharmony_ci free(iov.iov_base); 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ciint xsk_set_mtu(int ifindex, int mtu) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct nl_mtu_req req; 39362306a36Sopenharmony_ci struct rtattr *rta; 39462306a36Sopenharmony_ci int fd, ret; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 39762306a36Sopenharmony_ci if (fd < 0) 39862306a36Sopenharmony_ci return fd; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci memset(&req, 0, sizeof(req)); 40162306a36Sopenharmony_ci req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 40262306a36Sopenharmony_ci req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 40362306a36Sopenharmony_ci req.nh.nlmsg_type = RTM_NEWLINK; 40462306a36Sopenharmony_ci req.msg.ifi_family = AF_UNSPEC; 40562306a36Sopenharmony_ci req.msg.ifi_index = ifindex; 40662306a36Sopenharmony_ci rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nh.nlmsg_len)); 40762306a36Sopenharmony_ci rta->rta_type = IFLA_MTU; 40862306a36Sopenharmony_ci rta->rta_len = RTA_LENGTH(sizeof(unsigned int)); 40962306a36Sopenharmony_ci req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_LENGTH(sizeof(mtu)); 41062306a36Sopenharmony_ci memcpy(RTA_DATA(rta), &mtu, sizeof(mtu)); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ret = send(fd, &req, req.nh.nlmsg_len, 0); 41362306a36Sopenharmony_ci if (ret < 0) { 41462306a36Sopenharmony_ci close(fd); 41562306a36Sopenharmony_ci return errno; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = netlink_recv(fd); 41962306a36Sopenharmony_ci close(fd); 42062306a36Sopenharmony_ci return ret; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ciint xsk_attach_xdp_program(struct bpf_program *prog, int ifindex, u32 xdp_flags) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci int prog_fd; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci prog_fd = bpf_program__fd(prog); 42862306a36Sopenharmony_ci return bpf_xdp_attach(ifindex, prog_fd, xdp_flags, NULL); 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_civoid xsk_detach_xdp_program(int ifindex, u32 xdp_flags) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci bpf_xdp_detach(ifindex, xdp_flags, NULL); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_civoid xsk_clear_xskmap(struct bpf_map *map) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci u32 index = 0; 43962306a36Sopenharmony_ci int map_fd; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci map_fd = bpf_map__fd(map); 44262306a36Sopenharmony_ci bpf_map_delete_elem(map_fd, &index); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ciint xsk_update_xskmap(struct bpf_map *map, struct xsk_socket *xsk) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci int map_fd, sock_fd; 44862306a36Sopenharmony_ci u32 index = 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci map_fd = bpf_map__fd(map); 45162306a36Sopenharmony_ci sock_fd = xsk_socket__fd(xsk); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return bpf_map_update_elem(map_fd, &index, &sock_fd, 0); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex, 45762306a36Sopenharmony_ci __u32 queue_id) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct xsk_ctx *ctx; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (list_empty(&umem->ctx_list)) 46262306a36Sopenharmony_ci return NULL; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci list_for_each_entry(ctx, &umem->ctx_list, list) { 46562306a36Sopenharmony_ci if (ctx->ifindex == ifindex && ctx->queue_id == queue_id) { 46662306a36Sopenharmony_ci ctx->refcount++; 46762306a36Sopenharmony_ci return ctx; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return NULL; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic void xsk_put_ctx(struct xsk_ctx *ctx, bool unmap) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct xsk_umem *umem = ctx->umem; 47762306a36Sopenharmony_ci struct xdp_mmap_offsets off; 47862306a36Sopenharmony_ci int err; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (--ctx->refcount) 48162306a36Sopenharmony_ci return; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (!unmap) 48462306a36Sopenharmony_ci goto out_free; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci err = xsk_get_mmap_offsets(umem->fd, &off); 48762306a36Sopenharmony_ci if (err) 48862306a36Sopenharmony_ci goto out_free; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci munmap(ctx->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size * 49162306a36Sopenharmony_ci sizeof(__u64)); 49262306a36Sopenharmony_ci munmap(ctx->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size * 49362306a36Sopenharmony_ci sizeof(__u64)); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ciout_free: 49662306a36Sopenharmony_ci list_del(&ctx->list); 49762306a36Sopenharmony_ci free(ctx); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk, 50162306a36Sopenharmony_ci struct xsk_umem *umem, int ifindex, 50262306a36Sopenharmony_ci __u32 queue_id, 50362306a36Sopenharmony_ci struct xsk_ring_prod *fill, 50462306a36Sopenharmony_ci struct xsk_ring_cons *comp) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct xsk_ctx *ctx; 50762306a36Sopenharmony_ci int err; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ctx = calloc(1, sizeof(*ctx)); 51062306a36Sopenharmony_ci if (!ctx) 51162306a36Sopenharmony_ci return NULL; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (!umem->fill_save) { 51462306a36Sopenharmony_ci err = xsk_create_umem_rings(umem, xsk->fd, fill, comp); 51562306a36Sopenharmony_ci if (err) { 51662306a36Sopenharmony_ci free(ctx); 51762306a36Sopenharmony_ci return NULL; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci } else if (umem->fill_save != fill || umem->comp_save != comp) { 52062306a36Sopenharmony_ci /* Copy over rings to new structs. */ 52162306a36Sopenharmony_ci memcpy(fill, umem->fill_save, sizeof(*fill)); 52262306a36Sopenharmony_ci memcpy(comp, umem->comp_save, sizeof(*comp)); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci ctx->ifindex = ifindex; 52662306a36Sopenharmony_ci ctx->refcount = 1; 52762306a36Sopenharmony_ci ctx->umem = umem; 52862306a36Sopenharmony_ci ctx->queue_id = queue_id; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci ctx->fill = fill; 53162306a36Sopenharmony_ci ctx->comp = comp; 53262306a36Sopenharmony_ci list_add(&ctx->list, &umem->ctx_list); 53362306a36Sopenharmony_ci return ctx; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ciint xsk_socket__create_shared(struct xsk_socket **xsk_ptr, 53762306a36Sopenharmony_ci int ifindex, 53862306a36Sopenharmony_ci __u32 queue_id, struct xsk_umem *umem, 53962306a36Sopenharmony_ci struct xsk_ring_cons *rx, 54062306a36Sopenharmony_ci struct xsk_ring_prod *tx, 54162306a36Sopenharmony_ci struct xsk_ring_prod *fill, 54262306a36Sopenharmony_ci struct xsk_ring_cons *comp, 54362306a36Sopenharmony_ci const struct xsk_socket_config *usr_config) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci bool unmap, rx_setup_done = false, tx_setup_done = false; 54662306a36Sopenharmony_ci void *rx_map = NULL, *tx_map = NULL; 54762306a36Sopenharmony_ci struct sockaddr_xdp sxdp = {}; 54862306a36Sopenharmony_ci struct xdp_mmap_offsets off; 54962306a36Sopenharmony_ci struct xsk_socket *xsk; 55062306a36Sopenharmony_ci struct xsk_ctx *ctx; 55162306a36Sopenharmony_ci int err; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (!umem || !xsk_ptr || !(rx || tx)) 55462306a36Sopenharmony_ci return -EFAULT; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci unmap = umem->fill_save != fill; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci xsk = calloc(1, sizeof(*xsk)); 55962306a36Sopenharmony_ci if (!xsk) 56062306a36Sopenharmony_ci return -ENOMEM; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci err = xsk_set_xdp_socket_config(&xsk->config, usr_config); 56362306a36Sopenharmony_ci if (err) 56462306a36Sopenharmony_ci goto out_xsk_alloc; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (umem->refcount++ > 0) { 56762306a36Sopenharmony_ci xsk->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0); 56862306a36Sopenharmony_ci if (xsk->fd < 0) { 56962306a36Sopenharmony_ci err = -errno; 57062306a36Sopenharmony_ci goto out_xsk_alloc; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci } else { 57362306a36Sopenharmony_ci xsk->fd = umem->fd; 57462306a36Sopenharmony_ci rx_setup_done = umem->rx_ring_setup_done; 57562306a36Sopenharmony_ci tx_setup_done = umem->tx_ring_setup_done; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ctx = xsk_get_ctx(umem, ifindex, queue_id); 57962306a36Sopenharmony_ci if (!ctx) { 58062306a36Sopenharmony_ci if (!fill || !comp) { 58162306a36Sopenharmony_ci err = -EFAULT; 58262306a36Sopenharmony_ci goto out_socket; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci ctx = xsk_create_ctx(xsk, umem, ifindex, queue_id, fill, comp); 58662306a36Sopenharmony_ci if (!ctx) { 58762306a36Sopenharmony_ci err = -ENOMEM; 58862306a36Sopenharmony_ci goto out_socket; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci xsk->ctx = ctx; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (rx && !rx_setup_done) { 59462306a36Sopenharmony_ci err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING, 59562306a36Sopenharmony_ci &xsk->config.rx_size, 59662306a36Sopenharmony_ci sizeof(xsk->config.rx_size)); 59762306a36Sopenharmony_ci if (err) { 59862306a36Sopenharmony_ci err = -errno; 59962306a36Sopenharmony_ci goto out_put_ctx; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci if (xsk->fd == umem->fd) 60262306a36Sopenharmony_ci umem->rx_ring_setup_done = true; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci if (tx && !tx_setup_done) { 60562306a36Sopenharmony_ci err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING, 60662306a36Sopenharmony_ci &xsk->config.tx_size, 60762306a36Sopenharmony_ci sizeof(xsk->config.tx_size)); 60862306a36Sopenharmony_ci if (err) { 60962306a36Sopenharmony_ci err = -errno; 61062306a36Sopenharmony_ci goto out_put_ctx; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci if (xsk->fd == umem->fd) 61362306a36Sopenharmony_ci umem->tx_ring_setup_done = true; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci err = xsk_get_mmap_offsets(xsk->fd, &off); 61762306a36Sopenharmony_ci if (err) { 61862306a36Sopenharmony_ci err = -errno; 61962306a36Sopenharmony_ci goto out_put_ctx; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (rx) { 62362306a36Sopenharmony_ci rx_map = mmap(NULL, off.rx.desc + 62462306a36Sopenharmony_ci xsk->config.rx_size * sizeof(struct xdp_desc), 62562306a36Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, 62662306a36Sopenharmony_ci xsk->fd, XDP_PGOFF_RX_RING); 62762306a36Sopenharmony_ci if (rx_map == MAP_FAILED) { 62862306a36Sopenharmony_ci err = -errno; 62962306a36Sopenharmony_ci goto out_put_ctx; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci rx->mask = xsk->config.rx_size - 1; 63362306a36Sopenharmony_ci rx->size = xsk->config.rx_size; 63462306a36Sopenharmony_ci rx->producer = rx_map + off.rx.producer; 63562306a36Sopenharmony_ci rx->consumer = rx_map + off.rx.consumer; 63662306a36Sopenharmony_ci rx->flags = rx_map + off.rx.flags; 63762306a36Sopenharmony_ci rx->ring = rx_map + off.rx.desc; 63862306a36Sopenharmony_ci rx->cached_prod = *rx->producer; 63962306a36Sopenharmony_ci rx->cached_cons = *rx->consumer; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci xsk->rx = rx; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (tx) { 64462306a36Sopenharmony_ci tx_map = mmap(NULL, off.tx.desc + 64562306a36Sopenharmony_ci xsk->config.tx_size * sizeof(struct xdp_desc), 64662306a36Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, 64762306a36Sopenharmony_ci xsk->fd, XDP_PGOFF_TX_RING); 64862306a36Sopenharmony_ci if (tx_map == MAP_FAILED) { 64962306a36Sopenharmony_ci err = -errno; 65062306a36Sopenharmony_ci goto out_mmap_rx; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci tx->mask = xsk->config.tx_size - 1; 65462306a36Sopenharmony_ci tx->size = xsk->config.tx_size; 65562306a36Sopenharmony_ci tx->producer = tx_map + off.tx.producer; 65662306a36Sopenharmony_ci tx->consumer = tx_map + off.tx.consumer; 65762306a36Sopenharmony_ci tx->flags = tx_map + off.tx.flags; 65862306a36Sopenharmony_ci tx->ring = tx_map + off.tx.desc; 65962306a36Sopenharmony_ci tx->cached_prod = *tx->producer; 66062306a36Sopenharmony_ci /* cached_cons is r->size bigger than the real consumer pointer 66162306a36Sopenharmony_ci * See xsk_prod_nb_free 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci tx->cached_cons = *tx->consumer + xsk->config.tx_size; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci xsk->tx = tx; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci sxdp.sxdp_family = PF_XDP; 66862306a36Sopenharmony_ci sxdp.sxdp_ifindex = ctx->ifindex; 66962306a36Sopenharmony_ci sxdp.sxdp_queue_id = ctx->queue_id; 67062306a36Sopenharmony_ci if (umem->refcount > 1) { 67162306a36Sopenharmony_ci sxdp.sxdp_flags |= XDP_SHARED_UMEM; 67262306a36Sopenharmony_ci sxdp.sxdp_shared_umem_fd = umem->fd; 67362306a36Sopenharmony_ci } else { 67462306a36Sopenharmony_ci sxdp.sxdp_flags = xsk->config.bind_flags; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci err = bind(xsk->fd, (struct sockaddr *)&sxdp, sizeof(sxdp)); 67862306a36Sopenharmony_ci if (err) { 67962306a36Sopenharmony_ci err = -errno; 68062306a36Sopenharmony_ci goto out_mmap_tx; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci *xsk_ptr = xsk; 68462306a36Sopenharmony_ci umem->fill_save = NULL; 68562306a36Sopenharmony_ci umem->comp_save = NULL; 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ciout_mmap_tx: 68962306a36Sopenharmony_ci if (tx) 69062306a36Sopenharmony_ci munmap(tx_map, off.tx.desc + 69162306a36Sopenharmony_ci xsk->config.tx_size * sizeof(struct xdp_desc)); 69262306a36Sopenharmony_ciout_mmap_rx: 69362306a36Sopenharmony_ci if (rx) 69462306a36Sopenharmony_ci munmap(rx_map, off.rx.desc + 69562306a36Sopenharmony_ci xsk->config.rx_size * sizeof(struct xdp_desc)); 69662306a36Sopenharmony_ciout_put_ctx: 69762306a36Sopenharmony_ci xsk_put_ctx(ctx, unmap); 69862306a36Sopenharmony_ciout_socket: 69962306a36Sopenharmony_ci if (--umem->refcount) 70062306a36Sopenharmony_ci close(xsk->fd); 70162306a36Sopenharmony_ciout_xsk_alloc: 70262306a36Sopenharmony_ci free(xsk); 70362306a36Sopenharmony_ci return err; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ciint xsk_socket__create(struct xsk_socket **xsk_ptr, int ifindex, 70762306a36Sopenharmony_ci __u32 queue_id, struct xsk_umem *umem, 70862306a36Sopenharmony_ci struct xsk_ring_cons *rx, struct xsk_ring_prod *tx, 70962306a36Sopenharmony_ci const struct xsk_socket_config *usr_config) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci if (!umem) 71262306a36Sopenharmony_ci return -EFAULT; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return xsk_socket__create_shared(xsk_ptr, ifindex, queue_id, umem, 71562306a36Sopenharmony_ci rx, tx, umem->fill_save, 71662306a36Sopenharmony_ci umem->comp_save, usr_config); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ciint xsk_umem__delete(struct xsk_umem *umem) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct xdp_mmap_offsets off; 72262306a36Sopenharmony_ci int err; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (!umem) 72562306a36Sopenharmony_ci return 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (umem->refcount) 72862306a36Sopenharmony_ci return -EBUSY; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci err = xsk_get_mmap_offsets(umem->fd, &off); 73162306a36Sopenharmony_ci if (!err && umem->fill_save && umem->comp_save) { 73262306a36Sopenharmony_ci munmap(umem->fill_save->ring - off.fr.desc, 73362306a36Sopenharmony_ci off.fr.desc + umem->config.fill_size * sizeof(__u64)); 73462306a36Sopenharmony_ci munmap(umem->comp_save->ring - off.cr.desc, 73562306a36Sopenharmony_ci off.cr.desc + umem->config.comp_size * sizeof(__u64)); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci close(umem->fd); 73962306a36Sopenharmony_ci free(umem); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_civoid xsk_socket__delete(struct xsk_socket *xsk) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci size_t desc_sz = sizeof(struct xdp_desc); 74762306a36Sopenharmony_ci struct xdp_mmap_offsets off; 74862306a36Sopenharmony_ci struct xsk_umem *umem; 74962306a36Sopenharmony_ci struct xsk_ctx *ctx; 75062306a36Sopenharmony_ci int err; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (!xsk) 75362306a36Sopenharmony_ci return; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci ctx = xsk->ctx; 75662306a36Sopenharmony_ci umem = ctx->umem; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci xsk_put_ctx(ctx, true); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci err = xsk_get_mmap_offsets(xsk->fd, &off); 76162306a36Sopenharmony_ci if (!err) { 76262306a36Sopenharmony_ci if (xsk->rx) { 76362306a36Sopenharmony_ci munmap(xsk->rx->ring - off.rx.desc, 76462306a36Sopenharmony_ci off.rx.desc + xsk->config.rx_size * desc_sz); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci if (xsk->tx) { 76762306a36Sopenharmony_ci munmap(xsk->tx->ring - off.tx.desc, 76862306a36Sopenharmony_ci off.tx.desc + xsk->config.tx_size * desc_sz); 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci umem->refcount--; 77362306a36Sopenharmony_ci /* Do not close an fd that also has an associated umem connected 77462306a36Sopenharmony_ci * to it. 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ci if (xsk->fd != umem->fd) 77762306a36Sopenharmony_ci close(xsk->fd); 77862306a36Sopenharmony_ci free(xsk); 77962306a36Sopenharmony_ci} 780