libbpf: remove unnecessary cast-to-void
[linux-2.6-microblaze.git] / tools / lib / bpf / xsk.c
1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2
3 /*
4  * AF_XDP user-space access library.
5  *
6  * Copyright(c) 2018 - 2019 Intel Corporation.
7  *
8  * Author(s): Magnus Karlsson <magnus.karlsson@intel.com>
9  */
10
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
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/sockios.h>
24 #include <net/if.h>
25 #include <sys/ioctl.h>
26 #include <sys/mman.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29
30 #include "bpf.h"
31 #include "libbpf.h"
32 #include "libbpf_util.h"
33 #include "xsk.h"
34
35 #ifndef SOL_XDP
36  #define SOL_XDP 283
37 #endif
38
39 #ifndef AF_XDP
40  #define AF_XDP 44
41 #endif
42
43 #ifndef PF_XDP
44  #define PF_XDP AF_XDP
45 #endif
46
47 struct xsk_umem {
48         struct xsk_ring_prod *fill;
49         struct xsk_ring_cons *comp;
50         char *umem_area;
51         struct xsk_umem_config config;
52         int fd;
53         int refcount;
54 };
55
56 struct xsk_socket {
57         struct xsk_ring_cons *rx;
58         struct xsk_ring_prod *tx;
59         __u64 outstanding_tx;
60         struct xsk_umem *umem;
61         struct xsk_socket_config config;
62         int fd;
63         int xsks_map;
64         int ifindex;
65         int prog_fd;
66         int qidconf_map_fd;
67         int xsks_map_fd;
68         __u32 queue_id;
69         char ifname[IFNAMSIZ];
70 };
71
72 struct xsk_nl_info {
73         bool xdp_prog_attached;
74         int ifindex;
75         int fd;
76 };
77
78 /* For 32-bit systems, we need to use mmap2 as the offsets are 64-bit.
79  * Unfortunately, it is not part of glibc.
80  */
81 static inline void *xsk_mmap(void *addr, size_t length, int prot, int flags,
82                              int fd, __u64 offset)
83 {
84 #ifdef __NR_mmap2
85         unsigned int page_shift = __builtin_ffs(getpagesize()) - 1;
86         long ret = syscall(__NR_mmap2, addr, length, prot, flags, fd,
87                            (off_t)(offset >> page_shift));
88
89         return (void *)ret;
90 #else
91         return mmap(addr, length, prot, flags, fd, offset);
92 #endif
93 }
94
95 int xsk_umem__fd(const struct xsk_umem *umem)
96 {
97         return umem ? umem->fd : -EINVAL;
98 }
99
100 int xsk_socket__fd(const struct xsk_socket *xsk)
101 {
102         return xsk ? xsk->fd : -EINVAL;
103 }
104
105 static bool xsk_page_aligned(void *buffer)
106 {
107         unsigned long addr = (unsigned long)buffer;
108
109         return !(addr & (getpagesize() - 1));
110 }
111
112 static void xsk_set_umem_config(struct xsk_umem_config *cfg,
113                                 const struct xsk_umem_config *usr_cfg)
114 {
115         if (!usr_cfg) {
116                 cfg->fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
117                 cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
118                 cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
119                 cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
120                 return;
121         }
122
123         cfg->fill_size = usr_cfg->fill_size;
124         cfg->comp_size = usr_cfg->comp_size;
125         cfg->frame_size = usr_cfg->frame_size;
126         cfg->frame_headroom = usr_cfg->frame_headroom;
127 }
128
129 static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
130                                      const struct xsk_socket_config *usr_cfg)
131 {
132         if (!usr_cfg) {
133                 cfg->rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
134                 cfg->tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
135                 cfg->libbpf_flags = 0;
136                 cfg->xdp_flags = 0;
137                 cfg->bind_flags = 0;
138                 return 0;
139         }
140
141         if (usr_cfg->libbpf_flags & ~XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)
142                 return -EINVAL;
143
144         cfg->rx_size = usr_cfg->rx_size;
145         cfg->tx_size = usr_cfg->tx_size;
146         cfg->libbpf_flags = usr_cfg->libbpf_flags;
147         cfg->xdp_flags = usr_cfg->xdp_flags;
148         cfg->bind_flags = usr_cfg->bind_flags;
149
150         return 0;
151 }
152
153 int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area, __u64 size,
154                      struct xsk_ring_prod *fill, struct xsk_ring_cons *comp,
155                      const struct xsk_umem_config *usr_config)
156 {
157         struct xdp_mmap_offsets off;
158         struct xdp_umem_reg mr;
159         struct xsk_umem *umem;
160         socklen_t optlen;
161         void *map;
162         int err;
163
164         if (!umem_area || !umem_ptr || !fill || !comp)
165                 return -EFAULT;
166         if (!size && !xsk_page_aligned(umem_area))
167                 return -EINVAL;
168
169         umem = calloc(1, sizeof(*umem));
170         if (!umem)
171                 return -ENOMEM;
172
173         umem->fd = socket(AF_XDP, SOCK_RAW, 0);
174         if (umem->fd < 0) {
175                 err = -errno;
176                 goto out_umem_alloc;
177         }
178
179         umem->umem_area = umem_area;
180         xsk_set_umem_config(&umem->config, usr_config);
181
182         mr.addr = (uintptr_t)umem_area;
183         mr.len = size;
184         mr.chunk_size = umem->config.frame_size;
185         mr.headroom = umem->config.frame_headroom;
186
187         err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
188         if (err) {
189                 err = -errno;
190                 goto out_socket;
191         }
192         err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_FILL_RING,
193                          &umem->config.fill_size,
194                          sizeof(umem->config.fill_size));
195         if (err) {
196                 err = -errno;
197                 goto out_socket;
198         }
199         err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_COMPLETION_RING,
200                          &umem->config.comp_size,
201                          sizeof(umem->config.comp_size));
202         if (err) {
203                 err = -errno;
204                 goto out_socket;
205         }
206
207         optlen = sizeof(off);
208         err = getsockopt(umem->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
209         if (err) {
210                 err = -errno;
211                 goto out_socket;
212         }
213
214         map = xsk_mmap(NULL, off.fr.desc +
215                        umem->config.fill_size * sizeof(__u64),
216                        PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
217                        umem->fd, XDP_UMEM_PGOFF_FILL_RING);
218         if (map == MAP_FAILED) {
219                 err = -errno;
220                 goto out_socket;
221         }
222
223         umem->fill = fill;
224         fill->mask = umem->config.fill_size - 1;
225         fill->size = umem->config.fill_size;
226         fill->producer = map + off.fr.producer;
227         fill->consumer = map + off.fr.consumer;
228         fill->ring = map + off.fr.desc;
229         fill->cached_cons = umem->config.fill_size;
230
231         map = xsk_mmap(NULL,
232                        off.cr.desc + umem->config.comp_size * sizeof(__u64),
233                        PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
234                        umem->fd, XDP_UMEM_PGOFF_COMPLETION_RING);
235         if (map == MAP_FAILED) {
236                 err = -errno;
237                 goto out_mmap;
238         }
239
240         umem->comp = comp;
241         comp->mask = umem->config.comp_size - 1;
242         comp->size = umem->config.comp_size;
243         comp->producer = map + off.cr.producer;
244         comp->consumer = map + off.cr.consumer;
245         comp->ring = map + off.cr.desc;
246
247         *umem_ptr = umem;
248         return 0;
249
250 out_mmap:
251         munmap(map, off.fr.desc + umem->config.fill_size * sizeof(__u64));
252 out_socket:
253         close(umem->fd);
254 out_umem_alloc:
255         free(umem);
256         return err;
257 }
258
259 static int xsk_load_xdp_prog(struct xsk_socket *xsk)
260 {
261         static const int log_buf_size = 16 * 1024;
262         char log_buf[log_buf_size];
263         int err, prog_fd;
264
265         /* This is the C-program:
266          * SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx)
267          * {
268          *     int *qidconf, index = ctx->rx_queue_index;
269          *
270          *     // A set entry here means that the correspnding queue_id
271          *     // has an active AF_XDP socket bound to it.
272          *     qidconf = bpf_map_lookup_elem(&qidconf_map, &index);
273          *     if (!qidconf)
274          *         return XDP_ABORTED;
275          *
276          *     if (*qidconf)
277          *         return bpf_redirect_map(&xsks_map, index, 0);
278          *
279          *     return XDP_PASS;
280          * }
281          */
282         struct bpf_insn prog[] = {
283                 /* r1 = *(u32 *)(r1 + 16) */
284                 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, 16),
285                 /* *(u32 *)(r10 - 4) = r1 */
286                 BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_1, -4),
287                 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
288                 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4),
289                 BPF_LD_MAP_FD(BPF_REG_1, xsk->qidconf_map_fd),
290                 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
291                 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
292                 BPF_MOV32_IMM(BPF_REG_0, 0),
293                 /* if r1 == 0 goto +8 */
294                 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 8),
295                 BPF_MOV32_IMM(BPF_REG_0, 2),
296                 /* r1 = *(u32 *)(r1 + 0) */
297                 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, 0),
298                 /* if r1 == 0 goto +5 */
299                 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 5),
300                 /* r2 = *(u32 *)(r10 - 4) */
301                 BPF_LD_MAP_FD(BPF_REG_1, xsk->xsks_map_fd),
302                 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_10, -4),
303                 BPF_MOV32_IMM(BPF_REG_3, 0),
304                 BPF_EMIT_CALL(BPF_FUNC_redirect_map),
305                 /* The jumps are to this instruction */
306                 BPF_EXIT_INSN(),
307         };
308         size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
309
310         prog_fd = bpf_load_program(BPF_PROG_TYPE_XDP, prog, insns_cnt,
311                                    "LGPL-2.1 or BSD-2-Clause", 0, log_buf,
312                                    log_buf_size);
313         if (prog_fd < 0) {
314                 pr_warning("BPF log buffer:\n%s", log_buf);
315                 return prog_fd;
316         }
317
318         err = bpf_set_link_xdp_fd(xsk->ifindex, prog_fd, xsk->config.xdp_flags);
319         if (err) {
320                 close(prog_fd);
321                 return err;
322         }
323
324         xsk->prog_fd = prog_fd;
325         return 0;
326 }
327
328 static int xsk_get_max_queues(struct xsk_socket *xsk)
329 {
330         struct ethtool_channels channels;
331         struct ifreq ifr;
332         int fd, err, ret;
333
334         fd = socket(AF_INET, SOCK_DGRAM, 0);
335         if (fd < 0)
336                 return -errno;
337
338         channels.cmd = ETHTOOL_GCHANNELS;
339         ifr.ifr_data = (void *)&channels;
340         strncpy(ifr.ifr_name, xsk->ifname, IFNAMSIZ);
341         err = ioctl(fd, SIOCETHTOOL, &ifr);
342         if (err && errno != EOPNOTSUPP) {
343                 ret = -errno;
344                 goto out;
345         }
346
347         if (channels.max_combined == 0 || errno == EOPNOTSUPP)
348                 /* If the device says it has no channels, then all traffic
349                  * is sent to a single stream, so max queues = 1.
350                  */
351                 ret = 1;
352         else
353                 ret = channels.max_combined;
354
355 out:
356         close(fd);
357         return ret;
358 }
359
360 static int xsk_create_bpf_maps(struct xsk_socket *xsk)
361 {
362         int max_queues;
363         int fd;
364
365         max_queues = xsk_get_max_queues(xsk);
366         if (max_queues < 0)
367                 return max_queues;
368
369         fd = bpf_create_map_name(BPF_MAP_TYPE_ARRAY, "qidconf_map",
370                                  sizeof(int), sizeof(int), max_queues, 0);
371         if (fd < 0)
372                 return fd;
373         xsk->qidconf_map_fd = fd;
374
375         fd = bpf_create_map_name(BPF_MAP_TYPE_XSKMAP, "xsks_map",
376                                  sizeof(int), sizeof(int), max_queues, 0);
377         if (fd < 0) {
378                 close(xsk->qidconf_map_fd);
379                 return fd;
380         }
381         xsk->xsks_map_fd = fd;
382
383         return 0;
384 }
385
386 static void xsk_delete_bpf_maps(struct xsk_socket *xsk)
387 {
388         close(xsk->qidconf_map_fd);
389         close(xsk->xsks_map_fd);
390         xsk->qidconf_map_fd = -1;
391         xsk->xsks_map_fd = -1;
392 }
393
394 static int xsk_lookup_bpf_maps(struct xsk_socket *xsk)
395 {
396         __u32 i, *map_ids, num_maps, prog_len = sizeof(struct bpf_prog_info);
397         __u32 map_len = sizeof(struct bpf_map_info);
398         struct bpf_prog_info prog_info = {};
399         struct bpf_map_info map_info;
400         int fd, err;
401
402         err = bpf_obj_get_info_by_fd(xsk->prog_fd, &prog_info, &prog_len);
403         if (err)
404                 return err;
405
406         num_maps = prog_info.nr_map_ids;
407
408         map_ids = calloc(prog_info.nr_map_ids, sizeof(*map_ids));
409         if (!map_ids)
410                 return -ENOMEM;
411
412         memset(&prog_info, 0, prog_len);
413         prog_info.nr_map_ids = num_maps;
414         prog_info.map_ids = (__u64)(unsigned long)map_ids;
415
416         err = bpf_obj_get_info_by_fd(xsk->prog_fd, &prog_info, &prog_len);
417         if (err)
418                 goto out_map_ids;
419
420         for (i = 0; i < prog_info.nr_map_ids; i++) {
421                 if (xsk->qidconf_map_fd != -1 && xsk->xsks_map_fd != -1)
422                         break;
423
424                 fd = bpf_map_get_fd_by_id(map_ids[i]);
425                 if (fd < 0)
426                         continue;
427
428                 err = bpf_obj_get_info_by_fd(fd, &map_info, &map_len);
429                 if (err) {
430                         close(fd);
431                         continue;
432                 }
433
434                 if (!strcmp(map_info.name, "qidconf_map")) {
435                         xsk->qidconf_map_fd = fd;
436                         continue;
437                 }
438
439                 if (!strcmp(map_info.name, "xsks_map")) {
440                         xsk->xsks_map_fd = fd;
441                         continue;
442                 }
443
444                 close(fd);
445         }
446
447         err = 0;
448         if (xsk->qidconf_map_fd < 0 || xsk->xsks_map_fd < 0) {
449                 err = -ENOENT;
450                 xsk_delete_bpf_maps(xsk);
451         }
452
453 out_map_ids:
454         free(map_ids);
455         return err;
456 }
457
458 static void xsk_clear_bpf_maps(struct xsk_socket *xsk)
459 {
460         int qid = false;
461
462         bpf_map_update_elem(xsk->qidconf_map_fd, &xsk->queue_id, &qid, 0);
463         bpf_map_delete_elem(xsk->xsks_map_fd, &xsk->queue_id);
464 }
465
466 static int xsk_set_bpf_maps(struct xsk_socket *xsk)
467 {
468         int qid = true, fd = xsk->fd, err;
469
470         err = bpf_map_update_elem(xsk->qidconf_map_fd, &xsk->queue_id, &qid, 0);
471         if (err)
472                 goto out;
473
474         err = bpf_map_update_elem(xsk->xsks_map_fd, &xsk->queue_id, &fd, 0);
475         if (err)
476                 goto out;
477
478         return 0;
479 out:
480         xsk_clear_bpf_maps(xsk);
481         return err;
482 }
483
484 static int xsk_setup_xdp_prog(struct xsk_socket *xsk)
485 {
486         __u32 prog_id = 0;
487         int err;
488
489         err = bpf_get_link_xdp_id(xsk->ifindex, &prog_id,
490                                   xsk->config.xdp_flags);
491         if (err)
492                 return err;
493
494         if (!prog_id) {
495                 err = xsk_create_bpf_maps(xsk);
496                 if (err)
497                         return err;
498
499                 err = xsk_load_xdp_prog(xsk);
500                 if (err)
501                         goto out_maps;
502         } else {
503                 xsk->prog_fd = bpf_prog_get_fd_by_id(prog_id);
504                 err = xsk_lookup_bpf_maps(xsk);
505                 if (err)
506                         goto out_load;
507         }
508
509         err = xsk_set_bpf_maps(xsk);
510         if (err)
511                 goto out_load;
512
513         return 0;
514
515 out_load:
516         close(xsk->prog_fd);
517 out_maps:
518         xsk_delete_bpf_maps(xsk);
519         return err;
520 }
521
522 int xsk_socket__create(struct xsk_socket **xsk_ptr, const char *ifname,
523                        __u32 queue_id, struct xsk_umem *umem,
524                        struct xsk_ring_cons *rx, struct xsk_ring_prod *tx,
525                        const struct xsk_socket_config *usr_config)
526 {
527         void *rx_map = NULL, *tx_map = NULL;
528         struct sockaddr_xdp sxdp = {};
529         struct xdp_mmap_offsets off;
530         struct xsk_socket *xsk;
531         socklen_t optlen;
532         int err;
533
534         if (!umem || !xsk_ptr || !rx || !tx)
535                 return -EFAULT;
536
537         if (umem->refcount) {
538                 pr_warning("Error: shared umems not supported by libbpf.\n");
539                 return -EBUSY;
540         }
541
542         xsk = calloc(1, sizeof(*xsk));
543         if (!xsk)
544                 return -ENOMEM;
545
546         if (umem->refcount++ > 0) {
547                 xsk->fd = socket(AF_XDP, SOCK_RAW, 0);
548                 if (xsk->fd < 0) {
549                         err = -errno;
550                         goto out_xsk_alloc;
551                 }
552         } else {
553                 xsk->fd = umem->fd;
554         }
555
556         xsk->outstanding_tx = 0;
557         xsk->queue_id = queue_id;
558         xsk->umem = umem;
559         xsk->ifindex = if_nametoindex(ifname);
560         if (!xsk->ifindex) {
561                 err = -errno;
562                 goto out_socket;
563         }
564         strncpy(xsk->ifname, ifname, IFNAMSIZ);
565
566         err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
567         if (err)
568                 goto out_socket;
569
570         if (rx) {
571                 err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
572                                  &xsk->config.rx_size,
573                                  sizeof(xsk->config.rx_size));
574                 if (err) {
575                         err = -errno;
576                         goto out_socket;
577                 }
578         }
579         if (tx) {
580                 err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING,
581                                  &xsk->config.tx_size,
582                                  sizeof(xsk->config.tx_size));
583                 if (err) {
584                         err = -errno;
585                         goto out_socket;
586                 }
587         }
588
589         optlen = sizeof(off);
590         err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
591         if (err) {
592                 err = -errno;
593                 goto out_socket;
594         }
595
596         if (rx) {
597                 rx_map = xsk_mmap(NULL, off.rx.desc +
598                                   xsk->config.rx_size * sizeof(struct xdp_desc),
599                                   PROT_READ | PROT_WRITE,
600                                   MAP_SHARED | MAP_POPULATE,
601                                   xsk->fd, XDP_PGOFF_RX_RING);
602                 if (rx_map == MAP_FAILED) {
603                         err = -errno;
604                         goto out_socket;
605                 }
606
607                 rx->mask = xsk->config.rx_size - 1;
608                 rx->size = xsk->config.rx_size;
609                 rx->producer = rx_map + off.rx.producer;
610                 rx->consumer = rx_map + off.rx.consumer;
611                 rx->ring = rx_map + off.rx.desc;
612         }
613         xsk->rx = rx;
614
615         if (tx) {
616                 tx_map = xsk_mmap(NULL, off.tx.desc +
617                                   xsk->config.tx_size * sizeof(struct xdp_desc),
618                                   PROT_READ | PROT_WRITE,
619                                   MAP_SHARED | MAP_POPULATE,
620                                   xsk->fd, XDP_PGOFF_TX_RING);
621                 if (tx_map == MAP_FAILED) {
622                         err = -errno;
623                         goto out_mmap_rx;
624                 }
625
626                 tx->mask = xsk->config.tx_size - 1;
627                 tx->size = xsk->config.tx_size;
628                 tx->producer = tx_map + off.tx.producer;
629                 tx->consumer = tx_map + off.tx.consumer;
630                 tx->ring = tx_map + off.tx.desc;
631                 tx->cached_cons = xsk->config.tx_size;
632         }
633         xsk->tx = tx;
634
635         sxdp.sxdp_family = PF_XDP;
636         sxdp.sxdp_ifindex = xsk->ifindex;
637         sxdp.sxdp_queue_id = xsk->queue_id;
638         sxdp.sxdp_flags = xsk->config.bind_flags;
639
640         err = bind(xsk->fd, (struct sockaddr *)&sxdp, sizeof(sxdp));
641         if (err) {
642                 err = -errno;
643                 goto out_mmap_tx;
644         }
645
646         xsk->qidconf_map_fd = -1;
647         xsk->xsks_map_fd = -1;
648
649         if (!(xsk->config.libbpf_flags & XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD)) {
650                 err = xsk_setup_xdp_prog(xsk);
651                 if (err)
652                         goto out_mmap_tx;
653         }
654
655         *xsk_ptr = xsk;
656         return 0;
657
658 out_mmap_tx:
659         if (tx)
660                 munmap(tx_map, off.tx.desc +
661                        xsk->config.tx_size * sizeof(struct xdp_desc));
662 out_mmap_rx:
663         if (rx)
664                 munmap(rx_map, off.rx.desc +
665                        xsk->config.rx_size * sizeof(struct xdp_desc));
666 out_socket:
667         if (--umem->refcount)
668                 close(xsk->fd);
669 out_xsk_alloc:
670         free(xsk);
671         return err;
672 }
673
674 int xsk_umem__delete(struct xsk_umem *umem)
675 {
676         struct xdp_mmap_offsets off;
677         socklen_t optlen;
678         int err;
679
680         if (!umem)
681                 return 0;
682
683         if (umem->refcount)
684                 return -EBUSY;
685
686         optlen = sizeof(off);
687         err = getsockopt(umem->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
688         if (!err) {
689                 munmap(umem->fill->ring - off.fr.desc,
690                        off.fr.desc + umem->config.fill_size * sizeof(__u64));
691                 munmap(umem->comp->ring - off.cr.desc,
692                        off.cr.desc + umem->config.comp_size * sizeof(__u64));
693         }
694
695         close(umem->fd);
696         free(umem);
697
698         return 0;
699 }
700
701 void xsk_socket__delete(struct xsk_socket *xsk)
702 {
703         size_t desc_sz = sizeof(struct xdp_desc);
704         struct xdp_mmap_offsets off;
705         socklen_t optlen;
706         int err;
707
708         if (!xsk)
709                 return;
710
711         xsk_clear_bpf_maps(xsk);
712         xsk_delete_bpf_maps(xsk);
713
714         optlen = sizeof(off);
715         err = getsockopt(xsk->fd, SOL_XDP, XDP_MMAP_OFFSETS, &off, &optlen);
716         if (!err) {
717                 if (xsk->rx) {
718                         munmap(xsk->rx->ring - off.rx.desc,
719                                off.rx.desc + xsk->config.rx_size * desc_sz);
720                 }
721                 if (xsk->tx) {
722                         munmap(xsk->tx->ring - off.tx.desc,
723                                off.tx.desc + xsk->config.tx_size * desc_sz);
724                 }
725
726         }
727
728         xsk->umem->refcount--;
729         /* Do not close an fd that also has an associated umem connected
730          * to it.
731          */
732         if (xsk->fd != xsk->umem->fd)
733                 close(xsk->fd);
734         free(xsk);
735 }