~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/xsk.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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_link.h>
 22 #include <linux/if_packet.h>
 23 #include <linux/if_xdp.h>
 24 #include <linux/kernel.h>
 25 #include <linux/list.h>
 26 #include <linux/netlink.h>
 27 #include <linux/rtnetlink.h>
 28 #include <linux/sockios.h>
 29 #include <net/if.h>
 30 #include <sys/ioctl.h>
 31 #include <sys/mman.h>
 32 #include <sys/socket.h>
 33 #include <sys/types.h>
 34 
 35 #include <bpf/bpf.h>
 36 #include <bpf/libbpf.h>
 37 #include "xsk.h"
 38 #include "bpf_util.h"
 39 
 40 #ifndef SOL_XDP
 41  #define SOL_XDP 283
 42 #endif
 43 
 44 #ifndef AF_XDP
 45  #define AF_XDP 44
 46 #endif
 47 
 48 #ifndef PF_XDP
 49  #define PF_XDP AF_XDP
 50 #endif
 51 
 52 #define pr_warn(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
 53 
 54 #define XSKMAP_SIZE 1
 55 
 56 struct xsk_umem {
 57         struct xsk_ring_prod *fill_save;
 58         struct xsk_ring_cons *comp_save;
 59         char *umem_area;
 60         struct xsk_umem_config config;
 61         int fd;
 62         int refcount;
 63         struct list_head ctx_list;
 64         bool rx_ring_setup_done;
 65         bool tx_ring_setup_done;
 66 };
 67 
 68 struct xsk_ctx {
 69         struct xsk_ring_prod *fill;
 70         struct xsk_ring_cons *comp;
 71         __u32 queue_id;
 72         struct xsk_umem *umem;
 73         int refcount;
 74         int ifindex;
 75         struct list_head list;
 76 };
 77 
 78 struct xsk_socket {
 79         struct xsk_ring_cons *rx;
 80         struct xsk_ring_prod *tx;
 81         struct xsk_ctx *ctx;
 82         struct xsk_socket_config config;
 83         int fd;
 84 };
 85 
 86 struct nl_mtu_req {
 87         struct nlmsghdr nh;
 88         struct ifinfomsg msg;
 89         char             buf[512];
 90 };
 91 
 92 int xsk_umem__fd(const struct xsk_umem *umem)
 93 {
 94         return umem ? umem->fd : -EINVAL;
 95 }
 96 
 97 int xsk_socket__fd(const struct xsk_socket *xsk)
 98 {
 99         return xsk ? xsk->fd : -EINVAL;
100 }
101 
102 static bool xsk_page_aligned(void *buffer)
103 {
104         unsigned long addr = (unsigned long)buffer;
105 
106         return !(addr & (getpagesize() - 1));
107 }
108 
109 static void xsk_set_umem_config(struct xsk_umem_config *cfg,
110                                 const struct xsk_umem_config *usr_cfg)
111 {
112         if (!usr_cfg) {
113                 cfg->fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
114                 cfg->comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
115                 cfg->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE;
116                 cfg->frame_headroom = XSK_UMEM__DEFAULT_FRAME_HEADROOM;
117                 cfg->flags = XSK_UMEM__DEFAULT_FLAGS;
118                 cfg->tx_metadata_len = 0;
119                 return;
120         }
121 
122         cfg->fill_size = usr_cfg->fill_size;
123         cfg->comp_size = usr_cfg->comp_size;
124         cfg->frame_size = usr_cfg->frame_size;
125         cfg->frame_headroom = usr_cfg->frame_headroom;
126         cfg->flags = usr_cfg->flags;
127         cfg->tx_metadata_len = usr_cfg->tx_metadata_len;
128 }
129 
130 static int xsk_set_xdp_socket_config(struct xsk_socket_config *cfg,
131                                      const struct xsk_socket_config *usr_cfg)
132 {
133         if (!usr_cfg) {
134                 cfg->rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS;
135                 cfg->tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS;
136                 cfg->bind_flags = 0;
137                 return 0;
138         }
139 
140         cfg->rx_size = usr_cfg->rx_size;
141         cfg->tx_size = usr_cfg->tx_size;
142         cfg->bind_flags = usr_cfg->bind_flags;
143 
144         return 0;
145 }
146 
147 static int xsk_get_mmap_offsets(int fd, struct xdp_mmap_offsets *off)
148 {
149         socklen_t optlen;
150         int err;
151 
152         optlen = sizeof(*off);
153         err = getsockopt(fd, SOL_XDP, XDP_MMAP_OFFSETS, off, &optlen);
154         if (err)
155                 return err;
156 
157         if (optlen == sizeof(*off))
158                 return 0;
159 
160         return -EINVAL;
161 }
162 
163 static int xsk_create_umem_rings(struct xsk_umem *umem, int fd,
164                                  struct xsk_ring_prod *fill,
165                                  struct xsk_ring_cons *comp)
166 {
167         struct xdp_mmap_offsets off;
168         void *map;
169         int err;
170 
171         err = setsockopt(fd, SOL_XDP, XDP_UMEM_FILL_RING,
172                          &umem->config.fill_size,
173                          sizeof(umem->config.fill_size));
174         if (err)
175                 return -errno;
176 
177         err = setsockopt(fd, SOL_XDP, XDP_UMEM_COMPLETION_RING,
178                          &umem->config.comp_size,
179                          sizeof(umem->config.comp_size));
180         if (err)
181                 return -errno;
182 
183         err = xsk_get_mmap_offsets(fd, &off);
184         if (err)
185                 return -errno;
186 
187         map = mmap(NULL, off.fr.desc + umem->config.fill_size * sizeof(__u64),
188                    PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd,
189                    XDP_UMEM_PGOFF_FILL_RING);
190         if (map == MAP_FAILED)
191                 return -errno;
192 
193         fill->mask = umem->config.fill_size - 1;
194         fill->size = umem->config.fill_size;
195         fill->producer = map + off.fr.producer;
196         fill->consumer = map + off.fr.consumer;
197         fill->flags = map + off.fr.flags;
198         fill->ring = map + off.fr.desc;
199         fill->cached_cons = umem->config.fill_size;
200 
201         map = mmap(NULL, off.cr.desc + umem->config.comp_size * sizeof(__u64),
202                    PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd,
203                    XDP_UMEM_PGOFF_COMPLETION_RING);
204         if (map == MAP_FAILED) {
205                 err = -errno;
206                 goto out_mmap;
207         }
208 
209         comp->mask = umem->config.comp_size - 1;
210         comp->size = umem->config.comp_size;
211         comp->producer = map + off.cr.producer;
212         comp->consumer = map + off.cr.consumer;
213         comp->flags = map + off.cr.flags;
214         comp->ring = map + off.cr.desc;
215 
216         return 0;
217 
218 out_mmap:
219         munmap(map, off.fr.desc + umem->config.fill_size * sizeof(__u64));
220         return err;
221 }
222 
223 int xsk_umem__create(struct xsk_umem **umem_ptr, void *umem_area,
224                      __u64 size, struct xsk_ring_prod *fill,
225                      struct xsk_ring_cons *comp,
226                      const struct xsk_umem_config *usr_config)
227 {
228         struct xdp_umem_reg mr;
229         struct xsk_umem *umem;
230         int err;
231 
232         if (!umem_area || !umem_ptr || !fill || !comp)
233                 return -EFAULT;
234         if (!size && !xsk_page_aligned(umem_area))
235                 return -EINVAL;
236 
237         umem = calloc(1, sizeof(*umem));
238         if (!umem)
239                 return -ENOMEM;
240 
241         umem->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0);
242         if (umem->fd < 0) {
243                 err = -errno;
244                 goto out_umem_alloc;
245         }
246 
247         umem->umem_area = umem_area;
248         INIT_LIST_HEAD(&umem->ctx_list);
249         xsk_set_umem_config(&umem->config, usr_config);
250 
251         memset(&mr, 0, sizeof(mr));
252         mr.addr = (uintptr_t)umem_area;
253         mr.len = size;
254         mr.chunk_size = umem->config.frame_size;
255         mr.headroom = umem->config.frame_headroom;
256         mr.flags = umem->config.flags;
257         mr.tx_metadata_len = umem->config.tx_metadata_len;
258 
259         err = setsockopt(umem->fd, SOL_XDP, XDP_UMEM_REG, &mr, sizeof(mr));
260         if (err) {
261                 err = -errno;
262                 goto out_socket;
263         }
264 
265         err = xsk_create_umem_rings(umem, umem->fd, fill, comp);
266         if (err)
267                 goto out_socket;
268 
269         umem->fill_save = fill;
270         umem->comp_save = comp;
271         *umem_ptr = umem;
272         return 0;
273 
274 out_socket:
275         close(umem->fd);
276 out_umem_alloc:
277         free(umem);
278         return err;
279 }
280 
281 bool xsk_is_in_mode(u32 ifindex, int mode)
282 {
283         LIBBPF_OPTS(bpf_xdp_query_opts, opts);
284         int ret;
285 
286         ret = bpf_xdp_query(ifindex, mode, &opts);
287         if (ret) {
288                 printf("XDP mode query returned error %s\n", strerror(errno));
289                 return false;
290         }
291 
292         if (mode == XDP_FLAGS_DRV_MODE)
293                 return opts.attach_mode == XDP_ATTACHED_DRV;
294         else if (mode == XDP_FLAGS_SKB_MODE)
295                 return opts.attach_mode == XDP_ATTACHED_SKB;
296 
297         return false;
298 }
299 
300 /* Lifted from netlink.c in tools/lib/bpf */
301 static int netlink_recvmsg(int sock, struct msghdr *mhdr, int flags)
302 {
303         int len;
304 
305         do {
306                 len = recvmsg(sock, mhdr, flags);
307         } while (len < 0 && (errno == EINTR || errno == EAGAIN));
308 
309         if (len < 0)
310                 return -errno;
311         return len;
312 }
313 
314 /* Lifted from netlink.c in tools/lib/bpf */
315 static int alloc_iov(struct iovec *iov, int len)
316 {
317         void *nbuf;
318 
319         nbuf = realloc(iov->iov_base, len);
320         if (!nbuf)
321                 return -ENOMEM;
322 
323         iov->iov_base = nbuf;
324         iov->iov_len = len;
325         return 0;
326 }
327 
328 /* Original version lifted from netlink.c in tools/lib/bpf */
329 static int netlink_recv(int sock)
330 {
331         struct iovec iov = {};
332         struct msghdr mhdr = {
333                 .msg_iov = &iov,
334                 .msg_iovlen = 1,
335         };
336         bool multipart = true;
337         struct nlmsgerr *err;
338         struct nlmsghdr *nh;
339         int len, ret;
340 
341         ret = alloc_iov(&iov, 4096);
342         if (ret)
343                 goto done;
344 
345         while (multipart) {
346                 multipart = false;
347                 len = netlink_recvmsg(sock, &mhdr, MSG_PEEK | MSG_TRUNC);
348                 if (len < 0) {
349                         ret = len;
350                         goto done;
351                 }
352 
353                 if (len > iov.iov_len) {
354                         ret = alloc_iov(&iov, len);
355                         if (ret)
356                                 goto done;
357                 }
358 
359                 len = netlink_recvmsg(sock, &mhdr, 0);
360                 if (len < 0) {
361                         ret = len;
362                         goto done;
363                 }
364 
365                 if (len == 0)
366                         break;
367 
368                 for (nh = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(nh, len);
369                      nh = NLMSG_NEXT(nh, len)) {
370                         if (nh->nlmsg_flags & NLM_F_MULTI)
371                                 multipart = true;
372                         switch (nh->nlmsg_type) {
373                         case NLMSG_ERROR:
374                                 err = (struct nlmsgerr *)NLMSG_DATA(nh);
375                                 if (!err->error)
376                                         continue;
377                                 ret = err->error;
378                                 goto done;
379                         case NLMSG_DONE:
380                                 ret = 0;
381                                 goto done;
382                         default:
383                                 break;
384                         }
385                 }
386         }
387         ret = 0;
388 done:
389         free(iov.iov_base);
390         return ret;
391 }
392 
393 int xsk_set_mtu(int ifindex, int mtu)
394 {
395         struct nl_mtu_req req;
396         struct rtattr *rta;
397         int fd, ret;
398 
399         fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
400         if (fd < 0)
401                 return fd;
402 
403         memset(&req, 0, sizeof(req));
404         req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
405         req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
406         req.nh.nlmsg_type = RTM_NEWLINK;
407         req.msg.ifi_family = AF_UNSPEC;
408         req.msg.ifi_index = ifindex;
409         rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nh.nlmsg_len));
410         rta->rta_type = IFLA_MTU;
411         rta->rta_len = RTA_LENGTH(sizeof(unsigned int));
412         req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_LENGTH(sizeof(mtu));
413         memcpy(RTA_DATA(rta), &mtu, sizeof(mtu));
414 
415         ret = send(fd, &req, req.nh.nlmsg_len, 0);
416         if (ret < 0) {
417                 close(fd);
418                 return errno;
419         }
420 
421         ret = netlink_recv(fd);
422         close(fd);
423         return ret;
424 }
425 
426 int xsk_attach_xdp_program(struct bpf_program *prog, int ifindex, u32 xdp_flags)
427 {
428         int prog_fd;
429 
430         prog_fd = bpf_program__fd(prog);
431         return bpf_xdp_attach(ifindex, prog_fd, xdp_flags, NULL);
432 }
433 
434 void xsk_detach_xdp_program(int ifindex, u32 xdp_flags)
435 {
436         bpf_xdp_detach(ifindex, xdp_flags, NULL);
437 }
438 
439 void xsk_clear_xskmap(struct bpf_map *map)
440 {
441         u32 index = 0;
442         int map_fd;
443 
444         map_fd = bpf_map__fd(map);
445         bpf_map_delete_elem(map_fd, &index);
446 }
447 
448 int xsk_update_xskmap(struct bpf_map *map, struct xsk_socket *xsk, u32 index)
449 {
450         int map_fd, sock_fd;
451 
452         map_fd = bpf_map__fd(map);
453         sock_fd = xsk_socket__fd(xsk);
454 
455         return bpf_map_update_elem(map_fd, &index, &sock_fd, 0);
456 }
457 
458 static struct xsk_ctx *xsk_get_ctx(struct xsk_umem *umem, int ifindex,
459                                    __u32 queue_id)
460 {
461         struct xsk_ctx *ctx;
462 
463         if (list_empty(&umem->ctx_list))
464                 return NULL;
465 
466         list_for_each_entry(ctx, &umem->ctx_list, list) {
467                 if (ctx->ifindex == ifindex && ctx->queue_id == queue_id) {
468                         ctx->refcount++;
469                         return ctx;
470                 }
471         }
472 
473         return NULL;
474 }
475 
476 static void xsk_put_ctx(struct xsk_ctx *ctx, bool unmap)
477 {
478         struct xsk_umem *umem = ctx->umem;
479         struct xdp_mmap_offsets off;
480         int err;
481 
482         if (--ctx->refcount)
483                 return;
484 
485         if (!unmap)
486                 goto out_free;
487 
488         err = xsk_get_mmap_offsets(umem->fd, &off);
489         if (err)
490                 goto out_free;
491 
492         munmap(ctx->fill->ring - off.fr.desc, off.fr.desc + umem->config.fill_size *
493                sizeof(__u64));
494         munmap(ctx->comp->ring - off.cr.desc, off.cr.desc + umem->config.comp_size *
495                sizeof(__u64));
496 
497 out_free:
498         list_del(&ctx->list);
499         free(ctx);
500 }
501 
502 static struct xsk_ctx *xsk_create_ctx(struct xsk_socket *xsk,
503                                       struct xsk_umem *umem, int ifindex,
504                                       __u32 queue_id,
505                                       struct xsk_ring_prod *fill,
506                                       struct xsk_ring_cons *comp)
507 {
508         struct xsk_ctx *ctx;
509         int err;
510 
511         ctx = calloc(1, sizeof(*ctx));
512         if (!ctx)
513                 return NULL;
514 
515         if (!umem->fill_save) {
516                 err = xsk_create_umem_rings(umem, xsk->fd, fill, comp);
517                 if (err) {
518                         free(ctx);
519                         return NULL;
520                 }
521         } else if (umem->fill_save != fill || umem->comp_save != comp) {
522                 /* Copy over rings to new structs. */
523                 memcpy(fill, umem->fill_save, sizeof(*fill));
524                 memcpy(comp, umem->comp_save, sizeof(*comp));
525         }
526 
527         ctx->ifindex = ifindex;
528         ctx->refcount = 1;
529         ctx->umem = umem;
530         ctx->queue_id = queue_id;
531 
532         ctx->fill = fill;
533         ctx->comp = comp;
534         list_add(&ctx->list, &umem->ctx_list);
535         return ctx;
536 }
537 
538 int xsk_socket__create_shared(struct xsk_socket **xsk_ptr,
539                               int ifindex,
540                               __u32 queue_id, struct xsk_umem *umem,
541                               struct xsk_ring_cons *rx,
542                               struct xsk_ring_prod *tx,
543                               struct xsk_ring_prod *fill,
544                               struct xsk_ring_cons *comp,
545                               const struct xsk_socket_config *usr_config)
546 {
547         bool unmap, rx_setup_done = false, tx_setup_done = false;
548         void *rx_map = NULL, *tx_map = NULL;
549         struct sockaddr_xdp sxdp = {};
550         struct xdp_mmap_offsets off;
551         struct xsk_socket *xsk;
552         struct xsk_ctx *ctx;
553         int err;
554 
555         if (!umem || !xsk_ptr || !(rx || tx))
556                 return -EFAULT;
557 
558         unmap = umem->fill_save != fill;
559 
560         xsk = calloc(1, sizeof(*xsk));
561         if (!xsk)
562                 return -ENOMEM;
563 
564         err = xsk_set_xdp_socket_config(&xsk->config, usr_config);
565         if (err)
566                 goto out_xsk_alloc;
567 
568         if (umem->refcount++ > 0) {
569                 xsk->fd = socket(AF_XDP, SOCK_RAW | SOCK_CLOEXEC, 0);
570                 if (xsk->fd < 0) {
571                         err = -errno;
572                         goto out_xsk_alloc;
573                 }
574         } else {
575                 xsk->fd = umem->fd;
576                 rx_setup_done = umem->rx_ring_setup_done;
577                 tx_setup_done = umem->tx_ring_setup_done;
578         }
579 
580         ctx = xsk_get_ctx(umem, ifindex, queue_id);
581         if (!ctx) {
582                 if (!fill || !comp) {
583                         err = -EFAULT;
584                         goto out_socket;
585                 }
586 
587                 ctx = xsk_create_ctx(xsk, umem, ifindex, queue_id, fill, comp);
588                 if (!ctx) {
589                         err = -ENOMEM;
590                         goto out_socket;
591                 }
592         }
593         xsk->ctx = ctx;
594 
595         if (rx && !rx_setup_done) {
596                 err = setsockopt(xsk->fd, SOL_XDP, XDP_RX_RING,
597                                  &xsk->config.rx_size,
598                                  sizeof(xsk->config.rx_size));
599                 if (err) {
600                         err = -errno;
601                         goto out_put_ctx;
602                 }
603                 if (xsk->fd == umem->fd)
604                         umem->rx_ring_setup_done = true;
605         }
606         if (tx && !tx_setup_done) {
607                 err = setsockopt(xsk->fd, SOL_XDP, XDP_TX_RING,
608                                  &xsk->config.tx_size,
609                                  sizeof(xsk->config.tx_size));
610                 if (err) {
611                         err = -errno;
612                         goto out_put_ctx;
613                 }
614                 if (xsk->fd == umem->fd)
615                         umem->tx_ring_setup_done = true;
616         }
617 
618         err = xsk_get_mmap_offsets(xsk->fd, &off);
619         if (err) {
620                 err = -errno;
621                 goto out_put_ctx;
622         }
623 
624         if (rx) {
625                 rx_map = mmap(NULL, off.rx.desc +
626                               xsk->config.rx_size * sizeof(struct xdp_desc),
627                               PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
628                               xsk->fd, XDP_PGOFF_RX_RING);
629                 if (rx_map == MAP_FAILED) {
630                         err = -errno;
631                         goto out_put_ctx;
632                 }
633 
634                 rx->mask = xsk->config.rx_size - 1;
635                 rx->size = xsk->config.rx_size;
636                 rx->producer = rx_map + off.rx.producer;
637                 rx->consumer = rx_map + off.rx.consumer;
638                 rx->flags = rx_map + off.rx.flags;
639                 rx->ring = rx_map + off.rx.desc;
640                 rx->cached_prod = *rx->producer;
641                 rx->cached_cons = *rx->consumer;
642         }
643         xsk->rx = rx;
644 
645         if (tx) {
646                 tx_map = mmap(NULL, off.tx.desc +
647                               xsk->config.tx_size * sizeof(struct xdp_desc),
648                               PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
649                               xsk->fd, XDP_PGOFF_TX_RING);
650                 if (tx_map == MAP_FAILED) {
651                         err = -errno;
652                         goto out_mmap_rx;
653                 }
654 
655                 tx->mask = xsk->config.tx_size - 1;
656                 tx->size = xsk->config.tx_size;
657                 tx->producer = tx_map + off.tx.producer;
658                 tx->consumer = tx_map + off.tx.consumer;
659                 tx->flags = tx_map + off.tx.flags;
660                 tx->ring = tx_map + off.tx.desc;
661                 tx->cached_prod = *tx->producer;
662                 /* cached_cons is r->size bigger than the real consumer pointer
663                  * See xsk_prod_nb_free
664                  */
665                 tx->cached_cons = *tx->consumer + xsk->config.tx_size;
666         }
667         xsk->tx = tx;
668 
669         sxdp.sxdp_family = PF_XDP;
670         sxdp.sxdp_ifindex = ctx->ifindex;
671         sxdp.sxdp_queue_id = ctx->queue_id;
672         if (umem->refcount > 1) {
673                 sxdp.sxdp_flags |= XDP_SHARED_UMEM;
674                 sxdp.sxdp_shared_umem_fd = umem->fd;
675         } else {
676                 sxdp.sxdp_flags = xsk->config.bind_flags;
677         }
678 
679         err = bind(xsk->fd, (struct sockaddr *)&sxdp, sizeof(sxdp));
680         if (err) {
681                 err = -errno;
682                 goto out_mmap_tx;
683         }
684 
685         *xsk_ptr = xsk;
686         umem->fill_save = NULL;
687         umem->comp_save = NULL;
688         return 0;
689 
690 out_mmap_tx:
691         if (tx)
692                 munmap(tx_map, off.tx.desc +
693                        xsk->config.tx_size * sizeof(struct xdp_desc));
694 out_mmap_rx:
695         if (rx)
696                 munmap(rx_map, off.rx.desc +
697                        xsk->config.rx_size * sizeof(struct xdp_desc));
698 out_put_ctx:
699         xsk_put_ctx(ctx, unmap);
700 out_socket:
701         if (--umem->refcount)
702                 close(xsk->fd);
703 out_xsk_alloc:
704         free(xsk);
705         return err;
706 }
707 
708 int xsk_socket__create(struct xsk_socket **xsk_ptr, int ifindex,
709                        __u32 queue_id, struct xsk_umem *umem,
710                        struct xsk_ring_cons *rx, struct xsk_ring_prod *tx,
711                        const struct xsk_socket_config *usr_config)
712 {
713         if (!umem)
714                 return -EFAULT;
715 
716         return xsk_socket__create_shared(xsk_ptr, ifindex, queue_id, umem,
717                                          rx, tx, umem->fill_save,
718                                          umem->comp_save, usr_config);
719 }
720 
721 int xsk_umem__delete(struct xsk_umem *umem)
722 {
723         struct xdp_mmap_offsets off;
724         int err;
725 
726         if (!umem)
727                 return 0;
728 
729         if (umem->refcount)
730                 return -EBUSY;
731 
732         err = xsk_get_mmap_offsets(umem->fd, &off);
733         if (!err && umem->fill_save && umem->comp_save) {
734                 munmap(umem->fill_save->ring - off.fr.desc,
735                        off.fr.desc + umem->config.fill_size * sizeof(__u64));
736                 munmap(umem->comp_save->ring - off.cr.desc,
737                        off.cr.desc + umem->config.comp_size * sizeof(__u64));
738         }
739 
740         close(umem->fd);
741         free(umem);
742 
743         return 0;
744 }
745 
746 void xsk_socket__delete(struct xsk_socket *xsk)
747 {
748         size_t desc_sz = sizeof(struct xdp_desc);
749         struct xdp_mmap_offsets off;
750         struct xsk_umem *umem;
751         struct xsk_ctx *ctx;
752         int err;
753 
754         if (!xsk)
755                 return;
756 
757         ctx = xsk->ctx;
758         umem = ctx->umem;
759 
760         xsk_put_ctx(ctx, true);
761 
762         err = xsk_get_mmap_offsets(xsk->fd, &off);
763         if (!err) {
764                 if (xsk->rx) {
765                         munmap(xsk->rx->ring - off.rx.desc,
766                                off.rx.desc + xsk->config.rx_size * desc_sz);
767                 }
768                 if (xsk->tx) {
769                         munmap(xsk->tx->ring - off.tx.desc,
770                                off.tx.desc + xsk->config.tx_size * desc_sz);
771                 }
772         }
773 
774         umem->refcount--;
775         /* Do not close an fd that also has an associated umem connected
776          * to it.
777          */
778         if (xsk->fd != umem->fd)
779                 close(xsk->fd);
780         free(xsk);
781 }
782 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php