1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
4 * AF_XDP user-space access library.
6 * Copyright(c) 2018 - 2019 Intel Corporation.
8 * Author(s): Magnus Karlsson <magnus.karlsson@intel.com>
15 #include <arpa/inet.h>
16 #include <asm/barrier.h>
17 #include <linux/compiler.h>
18 #include <linux/ethtool.h>
19 #include <linux/filter.h>
20 #include <linux/if_ether.h>
21 #include <linux/if_packet.h>
22 #include <linux/if_xdp.h>
23 #include <linux/kernel.h>
24 #include <linux/list.h>
25 #include <linux/sockios.h>
27 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <linux/if_link.h>
35 #include "libbpf_internal.h"
38 /* entire xsk.h and xsk.c is going away in libbpf 1.0, so ignore all internal
39 * uses of deprecated APIs
41 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
57 XSK_PROG_REDIRECT_FLAGS,
61 struct xsk_ring_prod *fill_save;
62 struct xsk_ring_cons *comp_save;
64 struct xsk_umem_config config;
67 struct list_head ctx_list;
68 bool rx_ring_setup_done;
69 bool tx_ring_setup_done;
73 struct xsk_ring_prod *fill;
74 struct xsk_ring_cons *comp;
76 struct xsk_umem *umem;
79 struct list_head list;
83 char ifname[IFNAMSIZ];
88 struct xsk_ring_cons *rx;
89 struct xsk_ring_prod *tx;
92 struct xsk_socket_config config;
97 bool xdp_prog_attached;
102 /* Up until and including Linux 5.3 */
103 struct xdp_ring_offset_v1 {
109 /* Up until and including Linux 5.3 */
110 struct xdp_mmap_offsets_v1 {
111 struct xdp_ring_offset_v1 rx;
112 struct xdp_ring_offset_v1 tx;
113 struct xdp_ring_offset_v1 fr;
114 struct xdp_ring_offset_v1 cr;
117 int xsk_umem__fd(const struct xsk_umem *umem)
119 return umem ? umem->fd : -EINVAL;
122 int xsk_socket__fd(const struct xsk_socket *xsk)
124 return xsk ? xsk->fd : -EINVAL;
127 static bool xsk_page_aligned(void *buffer)
129 unsigned long addr = (unsigned long)buffer;
131 return !(addr & (getpagesize() - 1));
134 static void xsk_set_umem_config(struct xsk_umem_config *cfg,
135 const struct xsk_umem_config *usr_cfg)
138 cfg->fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
139 cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
140 cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
141 cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
142 cfg->flags = XSK_UMEM__DEFAULT_FLAGS;
146 cfg->fill_size = usr_cfg->fill_size;
147 cfg->comp_size = usr_cfg->comp_size;
148 cfg->frame_size = usr_cfg->frame_size;
149 cfg->frame_headroom = usr_cfg->frame_headroom;
150 cfg->flags = usr_cfg->flags;
153 static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
154 const struct xsk_socket_config *usr_cfg)
157 cfg->rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
158 cfg->tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
159 cfg->libbpf_flags = 0;
165 if (usr_cfg->libbpf_flags & ~XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)
168 cfg->rx_size = usr_cfg->rx_size;
169 cfg->tx_size = usr_cfg->tx_size;
170 cfg->libbpf_flags = usr_cfg->libbpf_flags;
171 cfg->xdp_flags = usr_cfg->xdp_flags;
172 cfg->bind_flags = usr_cfg->bind_flags;
177 static void xsk_mmap_offsets_v1(struct xdp_mmap_offsets *off)
179 struct xdp_mmap_offsets_v1 off_v1;
181 /* getsockopt on a kernel <= 5.3 has no flags fields.
182 * Copy over the offsets to the correct places in the >=5.4 format
183 * and put the flags where they would have been on that kernel.
185 memcpy(&off_v1, off, sizeof(off_v1));
187 off->rx.producer = off_v1.rx.producer;
188 off->rx.consumer = off_v1.rx.consumer;
189 off->rx.desc = off_v1.rx.desc;
190 off->rx.flags = off_v1.rx.consumer + sizeof(__u32);
192 off->tx.producer = off_v1.tx.producer;
193 off->tx.consumer = off_v1.tx.consumer;
194 off->tx.desc = off_v1.tx.desc;
195 off->tx.flags = off_v1.tx.consumer + sizeof(__u32);
197 off->fr.producer = off_v1.fr.producer;
198 off->fr.consumer = off_v1.fr.consumer;
199 off->fr.desc = off_v1.fr.desc;
200 off->fr.flags = off_v1.fr.consumer + sizeof(__u32);
202 off->cr.producer = off_v1.cr.producer;
203 off->cr.consumer = off_v1.cr.consumer;
204 off->cr.desc = off_v1.cr.desc;
205 off->cr.flags = off_v1.cr.consumer + sizeof(__u32);
208 static int xsk_get_mmap_offsets(int fd, struct xdp_mmap_offsets *off)
213 optlen = sizeof(*off);
214 err = getsockopt(fd, SOL_XDP, XDP_MMAP_OFFSETS, off, &optlen);
218 if (optlen == sizeof(*off))
221 if (optlen == sizeof(struct xdp_mmap_offsets_v1)) {
222 xsk_mmap_offsets_v1(off);
229 static int xsk_create_umem_rings(struct xsk_umem *umem, int fd,
230 struct xsk_ring_prod *fill,
231 struct xsk_ring_cons *comp)
233 struct xdp_mmap_offsets off;
237 err = setsockopt(fd, SOL_XDP, XDP_UMEM_FILL_RING,
238 &umem->config.fill_size,
239 sizeof(umem->config.fill_size));
243 err = setsockopt(fd, SOL_XDP, XDP_UMEM_COMPLETION_RING,
244 &umem->config.comp_size,
245 sizeof(umem->config.comp_size));
249 err = xsk_get_mmap_offsets(fd, &off);
253 map = mmap(NULL, off.fr.desc + umem->config.fill_size * sizeof(__u64),
254 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd,
255 XDP_UMEM_PGOFF_FILL_RING);
256 if (map == MAP_FAILED)
259 fill->mask = umem->config.fill_size - 1;
260 fill->size = umem->config.fill_size;
261 fill->producer = map + off.fr.producer;
262 fill->consumer = map + off.fr.consumer;
263 fill->flags = map + off.fr.flags;
264 fill->ring = map + off.fr.desc;
265 fill->cached_cons = umem->config.fill_size;
267 map = mmap(NULL, off.cr.desc + umem->config.comp_size * sizeof(__u64),
268 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd,
269 XDP_UMEM_PGOFF_COMPLETION_RING);
270 if (map == MAP_FAILED) {
275 comp->mask = umem->config.comp_size - 1;
276 comp->size = umem->config.comp_size;
277 comp->producer = map + off.cr.producer;
278 comp->consumer = map + off.cr.consumer;
279 comp->flags = map + off.cr.flags;
280 comp->ring = map + off.cr.desc;
285 munmap(map, off.fr.desc + umem->config.fill_size * sizeof(__u64));
289 DEFAULT_VERSION(xsk_umem__create_v0_0_4, xsk_umem__create, LIBBPF_0.0.4)
290 int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area,
291 __u64 size, struct xsk_ring_prod *fill,
292 struct xsk_ring_cons *comp,
293 const struct xsk_umem_config *usr_config)
295 struct xdp_umem_reg mr;
296 struct xsk_umem *umem;
299 if (!umem_area || !umem_ptr || !fill || !comp)
301 if (!size && !xsk_page_aligned(umem_area))
304 umem = calloc(1, sizeof(*umem));
308 umem->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0);
314 umem->umem_area = umem_area;
315 INIT_LIST_HEAD(&umem->ctx_list);
316 xsk_set_umem_config(&umem->config, usr_config);
318 memset(&mr, 0, sizeof(mr));
319 mr.addr = (uintptr_t)umem_area;
321 mr.chunk_size = umem->config.frame_size;
322 mr.headroom = umem->config.frame_headroom;
323 mr.flags = umem->config.flags;
325 err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
331 err = xsk_create_umem_rings(umem, umem->fd, fill, comp);
335 umem->fill_save = fill;
336 umem->comp_save = comp;
347 struct xsk_umem_config_v1 {
351 __u32 frame_headroom;
354 COMPAT_VERSION(xsk_umem__create_v0_0_2, xsk_umem__create, LIBBPF_0.0.2)
355 int xsk_umem__create_v0_0_2(struct xsk_umem **umem_ptr, void *umem_area,
356 __u64 size, struct xsk_ring_prod *fill,
357 struct xsk_ring_cons *comp,
358 const struct xsk_umem_config *usr_config)
360 struct xsk_umem_config config;
362 memcpy(&config, usr_config, sizeof(struct xsk_umem_config_v1));
365 return xsk_umem__create_v0_0_4(umem_ptr, umem_area, size, fill, comp,
369 static enum xsk_prog get_xsk_prog(void)
371 enum xsk_prog detected = XSK_PROG_FALLBACK;
372 __u32 size_out, retval, duration;
373 char data_in = 0, data_out;
374 struct bpf_insn insns[] = {
375 BPF_LD_MAP_FD(BPF_REG_1, 0),
376 BPF_MOV64_IMM(BPF_REG_2, 0),
377 BPF_MOV64_IMM(BPF_REG_3, XDP_PASS),
378 BPF_EMIT_CALL(BPF_FUNC_redirect_map),
381 int prog_fd, map_fd, ret, insn_cnt = ARRAY_SIZE(insns);
383 map_fd = bpf_map_create(BPF_MAP_TYPE_XSKMAP, NULL, sizeof(int), sizeof(int), 1, NULL);
387 insns[0].imm = map_fd;
389 prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL);
395 ret = bpf_prog_test_run(prog_fd, 0, &data_in, 1, &data_out, &size_out, &retval, &duration);
396 if (!ret && retval == XDP_PASS)
397 detected = XSK_PROG_REDIRECT_FLAGS;
403 static int xsk_load_xdp_prog(struct xsk_socket *xsk)
405 static const int log_buf_size = 16 * 1024;
406 struct xsk_ctx *ctx = xsk->ctx;
407 char log_buf[log_buf_size];
410 /* This is the fallback C-program:
411 * SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
413 * int ret, index = ctx->rx_queue_index;
415 * // A set entry here means that the correspnding queue_id
416 * // has an active AF_XDP socket bound to it.
417 * ret = bpf_redirect_map(&xsks_map, index, XDP_PASS);
421 * // Fallback for pre-5.3 kernels, not supporting default
422 * // action in the flags parameter.
423 * if (bpf_map_lookup_elem(&xsks_map, &index))
424 * return bpf_redirect_map(&xsks_map, index, 0);
428 struct bpf_insn prog[] = {
429 /* r2 = *(u32 *)(r1 + 16) */
430 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 16),
431 /* *(u32 *)(r10 - 4) = r2 */
432 BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_2, -4),
434 BPF_LD_MAP_FD(BPF_REG_1, ctx->xsks_map_fd),
436 BPF_MOV64_IMM(BPF_REG_3, 2),
437 /* call bpf_redirect_map */
438 BPF_EMIT_CALL(BPF_FUNC_redirect_map),
439 /* if w0 != 0 goto pc+13 */
440 BPF_JMP32_IMM(BPF_JSGT, BPF_REG_0, 0, 13),
442 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
444 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
446 BPF_LD_MAP_FD(BPF_REG_1, ctx->xsks_map_fd),
447 /* call bpf_map_lookup_elem */
448 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
450 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
452 BPF_MOV64_IMM(BPF_REG_0, 2),
453 /* if r1 == 0 goto pc+5 */
454 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 5),
455 /* r2 = *(u32 *)(r10 - 4) */
456 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, -4),
458 BPF_LD_MAP_FD(BPF_REG_1, ctx->xsks_map_fd),
460 BPF_MOV64_IMM(BPF_REG_3, 0),
461 /* call bpf_redirect_map */
462 BPF_EMIT_CALL(BPF_FUNC_redirect_map),
463 /* The jumps are to this instruction */
467 /* This is the post-5.3 kernel C-program:
468 * SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
470 * return bpf_redirect_map(&xsks_map, ctx->rx_queue_index, XDP_PASS);
473 struct bpf_insn prog_redirect_flags[] = {
474 /* r2 = *(u32 *)(r1 + 16) */
475 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 16),
477 BPF_LD_MAP_FD(BPF_REG_1, ctx->xsks_map_fd),
479 BPF_MOV64_IMM(BPF_REG_3, 2),
480 /* call bpf_redirect_map */
481 BPF_EMIT_CALL(BPF_FUNC_redirect_map),
484 size_t insns_cnt[] = {ARRAY_SIZE(prog),
485 ARRAY_SIZE(prog_redirect_flags),
487 struct bpf_insn *progs[] = {prog, prog_redirect_flags};
488 enum xsk_prog option = get_xsk_prog();
489 LIBBPF_OPTS(bpf_prog_load_opts, opts,
491 .log_size = log_buf_size,
494 prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "LGPL-2.1 or BSD-2-Clause",
495 progs[option], insns_cnt[option], &opts);
497 pr_warn("BPF log buffer:\n%s", log_buf);
501 ctx->prog_fd = prog_fd;
505 static int xsk_create_bpf_link(struct xsk_socket *xsk)
507 DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);
508 struct xsk_ctx *ctx = xsk->ctx;
513 err = bpf_get_link_xdp_id(ctx->ifindex, &prog_id, xsk->config.xdp_flags);
515 pr_warn("getting XDP prog id failed\n");
519 /* if there's a netlink-based XDP prog loaded on interface, bail out
520 * and ask user to do the removal by himself
523 pr_warn("Netlink-based XDP prog detected, please unload it in order to launch AF_XDP prog\n");
527 opts.flags = xsk->config.xdp_flags & ~(XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_REPLACE);
529 link_fd = bpf_link_create(ctx->prog_fd, ctx->ifindex, BPF_XDP, &opts);
531 pr_warn("bpf_link_create failed: %s\n", strerror(errno));
535 ctx->link_fd = link_fd;
539 static int xsk_get_max_queues(struct xsk_socket *xsk)
541 struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS };
542 struct xsk_ctx *ctx = xsk->ctx;
543 struct ifreq ifr = {};
546 fd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0);
550 ifr.ifr_data = (void *)&channels;
551 libbpf_strlcpy(ifr.ifr_name, ctx->ifname, IFNAMSIZ);
552 err = ioctl(fd, SIOCETHTOOL, &ifr);
553 if (err && errno != EOPNOTSUPP) {
559 /* If the device says it has no channels, then all traffic
560 * is sent to a single stream, so max queues = 1.
564 /* Take the max of rx, tx, combined. Drivers return
565 * the number of channels in different ways.
567 ret = max(channels.max_rx, channels.max_tx);
568 ret = max(ret, (int)channels.max_combined);
576 static int xsk_create_bpf_maps(struct xsk_socket *xsk)
578 struct xsk_ctx *ctx = xsk->ctx;
582 max_queues = xsk_get_max_queues(xsk);
586 fd = bpf_map_create(BPF_MAP_TYPE_XSKMAP, "xsks_map",
587 sizeof(int), sizeof(int), max_queues, NULL);
591 ctx->xsks_map_fd = fd;
596 static void xsk_delete_bpf_maps(struct xsk_socket *xsk)
598 struct xsk_ctx *ctx = xsk->ctx;
600 bpf_map_delete_elem(ctx->xsks_map_fd, &ctx->queue_id);
601 close(ctx->xsks_map_fd);
604 static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
606 __u32 i, *map_ids, num_maps, prog_len = sizeof(struct bpf_prog_info);
607 __u32 map_len = sizeof(struct bpf_map_info);
608 struct bpf_prog_info prog_info = {};
609 struct xsk_ctx *ctx = xsk->ctx;
610 struct bpf_map_info map_info;
613 err = bpf_obj_get_info_by_fd(ctx->prog_fd, &prog_info, &prog_len);
617 num_maps = prog_info.nr_map_ids;
619 map_ids = calloc(prog_info.nr_map_ids, sizeof(*map_ids));
623 memset(&prog_info, 0, prog_len);
624 prog_info.nr_map_ids = num_maps;
625 prog_info.map_ids = (__u64)(unsigned long)map_ids;
627 err = bpf_obj_get_info_by_fd(ctx->prog_fd, &prog_info, &prog_len);
631 ctx->xsks_map_fd = -1;
633 for (i = 0; i < prog_info.nr_map_ids; i++) {
634 fd = bpf_map_get_fd_by_id(map_ids[i]);
638 memset(&map_info, 0, map_len);
639 err = bpf_obj_get_info_by_fd(fd, &map_info, &map_len);
645 if (!strncmp(map_info.name, "xsks_map", sizeof(map_info.name))) {
646 ctx->xsks_map_fd = fd;
653 if (ctx->xsks_map_fd == -1)
661 static int xsk_set_bpf_maps(struct xsk_socket *xsk)
663 struct xsk_ctx *ctx = xsk->ctx;
665 return bpf_map_update_elem(ctx->xsks_map_fd, &ctx->queue_id,
669 static int xsk_link_lookup(int ifindex, __u32 *prog_id, int *link_fd)
671 struct bpf_link_info link_info;
678 err = bpf_link_get_next_id(id, &id);
680 if (errno == ENOENT) {
684 pr_warn("can't get next link: %s\n", strerror(errno));
688 fd = bpf_link_get_fd_by_id(id);
692 pr_warn("can't get link by id (%u): %s\n", id, strerror(errno));
697 link_len = sizeof(struct bpf_link_info);
698 memset(&link_info, 0, link_len);
699 err = bpf_obj_get_info_by_fd(fd, &link_info, &link_len);
701 pr_warn("can't get link info: %s\n", strerror(errno));
705 if (link_info.type == BPF_LINK_TYPE_XDP) {
706 if (link_info.xdp.ifindex == ifindex) {
709 *prog_id = link_info.prog_id;
719 static bool xsk_probe_bpf_link(void)
721 LIBBPF_OPTS(bpf_link_create_opts, opts, .flags = XDP_FLAGS_SKB_MODE);
722 struct bpf_insn insns[2] = {
723 BPF_MOV64_IMM(BPF_REG_0, XDP_PASS),
726 int prog_fd, link_fd = -1, insn_cnt = ARRAY_SIZE(insns);
731 err = xsk_link_lookup(ifindex_lo, NULL, &link_fd);
738 prog_fd = bpf_prog_load(BPF_PROG_TYPE_XDP, NULL, "GPL", insns, insn_cnt, NULL);
742 link_fd = bpf_link_create(prog_fd, ifindex_lo, BPF_XDP, &opts);
753 static int xsk_create_xsk_struct(int ifindex, struct xsk_socket *xsk)
755 char ifname[IFNAMSIZ];
759 ctx = calloc(1, sizeof(*ctx));
763 interface = if_indextoname(ifindex, &ifname[0]);
769 ctx->ifindex = ifindex;
770 libbpf_strlcpy(ctx->ifname, ifname, IFNAMSIZ);
773 xsk->ctx->has_bpf_link = xsk_probe_bpf_link();
778 static int xsk_init_xdp_res(struct xsk_socket *xsk,
781 struct xsk_ctx *ctx = xsk->ctx;
784 err = xsk_create_bpf_maps(xsk);
788 err = xsk_load_xdp_prog(xsk);
790 goto err_load_xdp_prog;
792 if (ctx->has_bpf_link)
793 err = xsk_create_bpf_link(xsk);
795 err = bpf_set_link_xdp_fd(xsk->ctx->ifindex, ctx->prog_fd,
796 xsk->config.xdp_flags);
799 goto err_attach_xdp_prog;
804 err = xsk_set_bpf_maps(xsk);
806 goto err_set_bpf_maps;
811 if (ctx->has_bpf_link)
814 bpf_set_link_xdp_fd(ctx->ifindex, -1, 0);
818 xsk_delete_bpf_maps(xsk);
822 static int xsk_lookup_xdp_res(struct xsk_socket *xsk, int *xsks_map_fd, int prog_id)
824 struct xsk_ctx *ctx = xsk->ctx;
827 ctx->prog_fd = bpf_prog_get_fd_by_id(prog_id);
828 if (ctx->prog_fd < 0) {
832 err = xsk_lookup_bpf_maps(xsk);
834 goto err_lookup_maps;
839 err = xsk_set_bpf_maps(xsk);
846 close(ctx->xsks_map_fd);
850 if (ctx->has_bpf_link)
855 static int __xsk_setup_xdp_prog(struct xsk_socket *_xdp, int *xsks_map_fd)
857 struct xsk_socket *xsk = _xdp;
858 struct xsk_ctx *ctx = xsk->ctx;
862 if (ctx->has_bpf_link)
863 err = xsk_link_lookup(ctx->ifindex, &prog_id, &ctx->link_fd);
865 err = bpf_get_link_xdp_id(ctx->ifindex, &prog_id, xsk->config.xdp_flags);
870 err = !prog_id ? xsk_init_xdp_res(xsk, xsks_map_fd) :
871 xsk_lookup_xdp_res(xsk, xsks_map_fd, prog_id);
873 if (!err && xsks_map_fd)
874 *xsks_map_fd = ctx->xsks_map_fd;
879 static struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex,
884 if (list_empty(&umem->ctx_list))
887 list_for_each_entry(ctx, &umem->ctx_list, list) {
888 if (ctx->ifindex == ifindex && ctx->queue_id == queue_id) {
897 static void xsk_put_ctx(struct xsk_ctx *ctx, bool unmap)
899 struct xsk_umem *umem = ctx->umem;
900 struct xdp_mmap_offsets off;
909 err = xsk_get_mmap_offsets(umem->fd, &off);
913 munmap(ctx->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size *
915 munmap(ctx->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size *
919 list_del(&ctx->list);
923 static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
924 struct xsk_umem *umem, int ifindex,
925 const char *ifname, __u32 queue_id,
926 struct xsk_ring_prod *fill,
927 struct xsk_ring_cons *comp)
932 ctx = calloc(1, sizeof(*ctx));
936 if (!umem->fill_save) {
937 err = xsk_create_umem_rings(umem, xsk->fd, fill, comp);
942 } else if (umem->fill_save != fill || umem->comp_save != comp) {
943 /* Copy over rings to new structs. */
944 memcpy(fill, umem->fill_save, sizeof(*fill));
945 memcpy(comp, umem->comp_save, sizeof(*comp));
948 ctx->ifindex = ifindex;
951 ctx->queue_id = queue_id;
952 libbpf_strlcpy(ctx->ifname, ifname, IFNAMSIZ);
956 list_add(&ctx->list, &umem->ctx_list);
960 static void xsk_destroy_xsk_struct(struct xsk_socket *xsk)
966 int xsk_socket__update_xskmap(struct xsk_socket *xsk, int fd)
968 xsk->ctx->xsks_map_fd = fd;
969 return xsk_set_bpf_maps(xsk);
972 int xsk_setup_xdp_prog(int ifindex, int *xsks_map_fd)
974 struct xsk_socket *xsk;
977 xsk = calloc(1, sizeof(*xsk));
981 res = xsk_create_xsk_struct(ifindex, xsk);
987 res = __xsk_setup_xdp_prog(xsk, xsks_map_fd);
989 xsk_destroy_xsk_struct(xsk);
994 int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
996 __u32 queue_id, struct xsk_umem *umem,
997 struct xsk_ring_cons *rx,
998 struct xsk_ring_prod *tx,
999 struct xsk_ring_prod *fill,
1000 struct xsk_ring_cons *comp,
1001 const struct xsk_socket_config *usr_config)
1003 bool unmap, rx_setup_done = false, tx_setup_done = false;
1004 void *rx_map = NULL, *tx_map = NULL;
1005 struct sockaddr_xdp sxdp = {};
1006 struct xdp_mmap_offsets off;
1007 struct xsk_socket *xsk;
1008 struct xsk_ctx *ctx;
1011 if (!umem || !xsk_ptr || !(rx || tx))
1014 unmap = umem->fill_save != fill;
1016 xsk = calloc(1, sizeof(*xsk));
1020 err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
1024 xsk->outstanding_tx = 0;
1025 ifindex = if_nametoindex(ifname);
1031 if (umem->refcount++ > 0) {
1032 xsk->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0);
1039 rx_setup_done = umem->rx_ring_setup_done;
1040 tx_setup_done = umem->tx_ring_setup_done;
1043 ctx = xsk_get_ctx(umem, ifindex, queue_id);
1045 if (!fill || !comp) {
1050 ctx = xsk_create_ctx(xsk, umem, ifindex, ifname, queue_id,
1058 xsk->ctx->has_bpf_link = xsk_probe_bpf_link();
1060 if (rx && !rx_setup_done) {
1061 err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
1062 &xsk->config.rx_size,
1063 sizeof(xsk->config.rx_size));
1068 if (xsk->fd == umem->fd)
1069 umem->rx_ring_setup_done = true;
1071 if (tx && !tx_setup_done) {
1072 err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING,
1073 &xsk->config.tx_size,
1074 sizeof(xsk->config.tx_size));
1079 if (xsk->fd == umem->fd)
1080 umem->tx_ring_setup_done = true;
1083 err = xsk_get_mmap_offsets(xsk->fd, &off);
1090 rx_map = mmap(NULL, off.rx.desc +
1091 xsk->config.rx_size * sizeof(struct xdp_desc),
1092 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
1093 xsk->fd, XDP_PGOFF_RX_RING);
1094 if (rx_map == MAP_FAILED) {
1099 rx->mask = xsk->config.rx_size - 1;
1100 rx->size = xsk->config.rx_size;
1101 rx->producer = rx_map + off.rx.producer;
1102 rx->consumer = rx_map + off.rx.consumer;
1103 rx->flags = rx_map + off.rx.flags;
1104 rx->ring = rx_map + off.rx.desc;
1105 rx->cached_prod = *rx->producer;
1106 rx->cached_cons = *rx->consumer;
1111 tx_map = mmap(NULL, off.tx.desc +
1112 xsk->config.tx_size * sizeof(struct xdp_desc),
1113 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
1114 xsk->fd, XDP_PGOFF_TX_RING);
1115 if (tx_map == MAP_FAILED) {
1120 tx->mask = xsk->config.tx_size - 1;
1121 tx->size = xsk->config.tx_size;
1122 tx->producer = tx_map + off.tx.producer;
1123 tx->consumer = tx_map + off.tx.consumer;
1124 tx->flags = tx_map + off.tx.flags;
1125 tx->ring = tx_map + off.tx.desc;
1126 tx->cached_prod = *tx->producer;
1127 /* cached_cons is r->size bigger than the real consumer pointer
1128 * See xsk_prod_nb_free
1130 tx->cached_cons = *tx->consumer + xsk->config.tx_size;
1134 sxdp.sxdp_family = PF_XDP;
1135 sxdp.sxdp_ifindex = ctx->ifindex;
1136 sxdp.sxdp_queue_id = ctx->queue_id;
1137 if (umem->refcount > 1) {
1138 sxdp.sxdp_flags |= XDP_SHARED_UMEM;
1139 sxdp.sxdp_shared_umem_fd = umem->fd;
1141 sxdp.sxdp_flags = xsk->config.bind_flags;
1144 err = bind(xsk->fd, (struct sockaddr *)&sxdp, sizeof(sxdp));
1152 if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
1153 err = __xsk_setup_xdp_prog(xsk, NULL);
1159 umem->fill_save = NULL;
1160 umem->comp_save = NULL;
1165 munmap(tx_map, off.tx.desc +
1166 xsk->config.tx_size * sizeof(struct xdp_desc));
1169 munmap(rx_map, off.rx.desc +
1170 xsk->config.rx_size * sizeof(struct xdp_desc));
1172 xsk_put_ctx(ctx, unmap);
1174 if (--umem->refcount)
1181 int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
1182 __u32 queue_id, struct xsk_umem *umem,
1183 struct xsk_ring_cons *rx, struct xsk_ring_prod *tx,
1184 const struct xsk_socket_config *usr_config)
1189 return xsk_socket__create_shared(xsk_ptr, ifname, queue_id, umem,
1190 rx, tx, umem->fill_save,
1191 umem->comp_save, usr_config);
1194 int xsk_umem__delete(struct xsk_umem *umem)
1196 struct xdp_mmap_offsets off;
1205 err = xsk_get_mmap_offsets(umem->fd, &off);
1206 if (!err && umem->fill_save && umem->comp_save) {
1207 munmap(umem->fill_save->ring - off.fr.desc,
1208 off.fr.desc + umem->config.fill_size * sizeof(__u64));
1209 munmap(umem->comp_save->ring - off.cr.desc,
1210 off.cr.desc + umem->config.comp_size * sizeof(__u64));
1219 void xsk_socket__delete(struct xsk_socket *xsk)
1221 size_t desc_sz = sizeof(struct xdp_desc);
1222 struct xdp_mmap_offsets off;
1223 struct xsk_umem *umem;
1224 struct xsk_ctx *ctx;
1232 if (ctx->prog_fd != -1) {
1233 xsk_delete_bpf_maps(xsk);
1234 close(ctx->prog_fd);
1235 if (ctx->has_bpf_link)
1236 close(ctx->link_fd);
1239 err = xsk_get_mmap_offsets(xsk->fd, &off);
1242 munmap(xsk->rx->ring - off.rx.desc,
1243 off.rx.desc + xsk->config.rx_size * desc_sz);
1246 munmap(xsk->tx->ring - off.tx.desc,
1247 off.tx.desc + xsk->config.tx_size * desc_sz);
1251 xsk_put_ctx(ctx, true);
1254 /* Do not close an fd that also has an associated umem connected
1257 if (xsk->fd != umem->fd)