xsk.c 17 KB

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