xdp1_user.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /* Copyright (c) 2016 PLUMgrid
  2. *
  3. * This program is free software; you can redistribute it and/or
  4. * modify it under the terms of version 2 of the GNU General Public
  5. * License as published by the Free Software Foundation.
  6. */
  7. #include <linux/bpf.h>
  8. #include <linux/netlink.h>
  9. #include <linux/rtnetlink.h>
  10. #include <assert.h>
  11. #include <errno.h>
  12. #include <signal.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/socket.h>
  17. #include <unistd.h>
  18. #include "bpf_load.h"
  19. #include "libbpf.h"
  20. static int set_link_xdp_fd(int ifindex, int fd)
  21. {
  22. struct sockaddr_nl sa;
  23. int sock, seq = 0, len, ret = -1;
  24. char buf[4096];
  25. struct nlattr *nla, *nla_xdp;
  26. struct {
  27. struct nlmsghdr nh;
  28. struct ifinfomsg ifinfo;
  29. char attrbuf[64];
  30. } req;
  31. struct nlmsghdr *nh;
  32. struct nlmsgerr *err;
  33. memset(&sa, 0, sizeof(sa));
  34. sa.nl_family = AF_NETLINK;
  35. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  36. if (sock < 0) {
  37. printf("open netlink socket: %s\n", strerror(errno));
  38. return -1;
  39. }
  40. if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  41. printf("bind to netlink: %s\n", strerror(errno));
  42. goto cleanup;
  43. }
  44. memset(&req, 0, sizeof(req));
  45. req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  46. req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
  47. req.nh.nlmsg_type = RTM_SETLINK;
  48. req.nh.nlmsg_pid = 0;
  49. req.nh.nlmsg_seq = ++seq;
  50. req.ifinfo.ifi_family = AF_UNSPEC;
  51. req.ifinfo.ifi_index = ifindex;
  52. nla = (struct nlattr *)(((char *)&req)
  53. + NLMSG_ALIGN(req.nh.nlmsg_len));
  54. nla->nla_type = NLA_F_NESTED | 43/*IFLA_XDP*/;
  55. nla_xdp = (struct nlattr *)((char *)nla + NLA_HDRLEN);
  56. nla_xdp->nla_type = 1/*IFLA_XDP_FD*/;
  57. nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
  58. memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
  59. nla->nla_len = NLA_HDRLEN + nla_xdp->nla_len;
  60. req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
  61. if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
  62. printf("send to netlink: %s\n", strerror(errno));
  63. goto cleanup;
  64. }
  65. len = recv(sock, buf, sizeof(buf), 0);
  66. if (len < 0) {
  67. printf("recv from netlink: %s\n", strerror(errno));
  68. goto cleanup;
  69. }
  70. for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
  71. nh = NLMSG_NEXT(nh, len)) {
  72. if (nh->nlmsg_pid != getpid()) {
  73. printf("Wrong pid %d, expected %d\n",
  74. nh->nlmsg_pid, getpid());
  75. goto cleanup;
  76. }
  77. if (nh->nlmsg_seq != seq) {
  78. printf("Wrong seq %d, expected %d\n",
  79. nh->nlmsg_seq, seq);
  80. goto cleanup;
  81. }
  82. switch (nh->nlmsg_type) {
  83. case NLMSG_ERROR:
  84. err = (struct nlmsgerr *)NLMSG_DATA(nh);
  85. if (!err->error)
  86. continue;
  87. printf("nlmsg error %s\n", strerror(-err->error));
  88. goto cleanup;
  89. case NLMSG_DONE:
  90. break;
  91. }
  92. }
  93. ret = 0;
  94. cleanup:
  95. close(sock);
  96. return ret;
  97. }
  98. static int ifindex;
  99. static void int_exit(int sig)
  100. {
  101. set_link_xdp_fd(ifindex, -1);
  102. exit(0);
  103. }
  104. /* simple per-protocol drop counter
  105. */
  106. static void poll_stats(int interval)
  107. {
  108. unsigned int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
  109. const unsigned int nr_keys = 256;
  110. __u64 values[nr_cpus], prev[nr_keys][nr_cpus];
  111. __u32 key;
  112. int i;
  113. memset(prev, 0, sizeof(prev));
  114. while (1) {
  115. sleep(interval);
  116. for (key = 0; key < nr_keys; key++) {
  117. __u64 sum = 0;
  118. assert(bpf_lookup_elem(map_fd[0], &key, values) == 0);
  119. for (i = 0; i < nr_cpus; i++)
  120. sum += (values[i] - prev[key][i]);
  121. if (sum)
  122. printf("proto %u: %10llu pkt/s\n",
  123. key, sum / interval);
  124. memcpy(prev[key], values, sizeof(values));
  125. }
  126. }
  127. }
  128. int main(int ac, char **argv)
  129. {
  130. char filename[256];
  131. snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
  132. if (ac != 2) {
  133. printf("usage: %s IFINDEX\n", argv[0]);
  134. return 1;
  135. }
  136. ifindex = strtoul(argv[1], NULL, 0);
  137. if (load_bpf_file(filename)) {
  138. printf("%s", bpf_log_buf);
  139. return 1;
  140. }
  141. if (!prog_fd[0]) {
  142. printf("load_bpf_file: %s\n", strerror(errno));
  143. return 1;
  144. }
  145. signal(SIGINT, int_exit);
  146. if (set_link_xdp_fd(ifindex, prog_fd[0]) < 0) {
  147. printf("link set xdp fd failed\n");
  148. return 1;
  149. }
  150. poll_stats(2);
  151. return 0;
  152. }