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