xdp_redirect_map_user.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2017 Covalent IO, Inc. http://covalent.io
  3. */
  4. #include <linux/bpf.h>
  5. #include <linux/if_link.h>
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <signal.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <stdbool.h>
  12. #include <string.h>
  13. #include <net/if.h>
  14. #include <unistd.h>
  15. #include <libgen.h>
  16. #include <sys/resource.h>
  17. #include "bpf_util.h"
  18. #include <bpf/bpf.h>
  19. #include <bpf/libbpf.h>
  20. static int ifindex_in;
  21. static int ifindex_out;
  22. static bool ifindex_out_xdp_dummy_attached = true;
  23. static __u32 prog_id;
  24. static __u32 dummy_prog_id;
  25. static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
  26. static int rxcnt_map_fd;
  27. static void int_exit(int sig)
  28. {
  29. __u32 curr_prog_id = 0;
  30. if (bpf_get_link_xdp_id(ifindex_in, &curr_prog_id, xdp_flags)) {
  31. printf("bpf_get_link_xdp_id failed\n");
  32. exit(1);
  33. }
  34. if (prog_id == curr_prog_id)
  35. bpf_set_link_xdp_fd(ifindex_in, -1, xdp_flags);
  36. else if (!curr_prog_id)
  37. printf("couldn't find a prog id on iface IN\n");
  38. else
  39. printf("program on iface IN changed, not removing\n");
  40. if (ifindex_out_xdp_dummy_attached) {
  41. curr_prog_id = 0;
  42. if (bpf_get_link_xdp_id(ifindex_out, &curr_prog_id,
  43. xdp_flags)) {
  44. printf("bpf_get_link_xdp_id failed\n");
  45. exit(1);
  46. }
  47. if (dummy_prog_id == curr_prog_id)
  48. bpf_set_link_xdp_fd(ifindex_out, -1, xdp_flags);
  49. else if (!curr_prog_id)
  50. printf("couldn't find a prog id on iface OUT\n");
  51. else
  52. printf("program on iface OUT changed, not removing\n");
  53. }
  54. exit(0);
  55. }
  56. static void poll_stats(int interval, int ifindex)
  57. {
  58. unsigned int nr_cpus = bpf_num_possible_cpus();
  59. __u64 values[nr_cpus], prev[nr_cpus];
  60. memset(prev, 0, sizeof(prev));
  61. while (1) {
  62. __u64 sum = 0;
  63. __u32 key = 0;
  64. int i;
  65. sleep(interval);
  66. assert(bpf_map_lookup_elem(rxcnt_map_fd, &key, values) == 0);
  67. for (i = 0; i < nr_cpus; i++)
  68. sum += (values[i] - prev[i]);
  69. if (sum)
  70. printf("ifindex %i: %10llu pkt/s\n",
  71. ifindex, sum / interval);
  72. memcpy(prev, values, sizeof(values));
  73. }
  74. }
  75. static void usage(const char *prog)
  76. {
  77. fprintf(stderr,
  78. "usage: %s [OPTS] <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n\n"
  79. "OPTS:\n"
  80. " -S use skb-mode\n"
  81. " -N enforce native mode\n"
  82. " -F force loading prog\n",
  83. prog);
  84. }
  85. int main(int argc, char **argv)
  86. {
  87. struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
  88. struct bpf_prog_load_attr prog_load_attr = {
  89. .prog_type = BPF_PROG_TYPE_XDP,
  90. };
  91. struct bpf_program *prog, *dummy_prog;
  92. struct bpf_prog_info info = {};
  93. __u32 info_len = sizeof(info);
  94. int prog_fd, dummy_prog_fd;
  95. const char *optstr = "FSN";
  96. struct bpf_object *obj;
  97. int ret, opt, key = 0;
  98. char filename[256];
  99. int tx_port_map_fd;
  100. while ((opt = getopt(argc, argv, optstr)) != -1) {
  101. switch (opt) {
  102. case 'S':
  103. xdp_flags |= XDP_FLAGS_SKB_MODE;
  104. break;
  105. case 'N':
  106. /* default, set below */
  107. break;
  108. case 'F':
  109. xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
  110. break;
  111. default:
  112. usage(basename(argv[0]));
  113. return 1;
  114. }
  115. }
  116. if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
  117. xdp_flags |= XDP_FLAGS_DRV_MODE;
  118. if (optind == argc) {
  119. printf("usage: %s <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n", argv[0]);
  120. return 1;
  121. }
  122. if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  123. perror("setrlimit(RLIMIT_MEMLOCK)");
  124. return 1;
  125. }
  126. ifindex_in = if_nametoindex(argv[optind]);
  127. if (!ifindex_in)
  128. ifindex_in = strtoul(argv[optind], NULL, 0);
  129. ifindex_out = if_nametoindex(argv[optind + 1]);
  130. if (!ifindex_out)
  131. ifindex_out = strtoul(argv[optind + 1], NULL, 0);
  132. printf("input: %d output: %d\n", ifindex_in, ifindex_out);
  133. snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
  134. prog_load_attr.file = filename;
  135. if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
  136. return 1;
  137. prog = bpf_program__next(NULL, obj);
  138. dummy_prog = bpf_program__next(prog, obj);
  139. if (!prog || !dummy_prog) {
  140. printf("finding a prog in obj file failed\n");
  141. return 1;
  142. }
  143. /* bpf_prog_load_xattr gives us the pointer to first prog's fd,
  144. * so we're missing only the fd for dummy prog
  145. */
  146. dummy_prog_fd = bpf_program__fd(dummy_prog);
  147. if (prog_fd < 0 || dummy_prog_fd < 0) {
  148. printf("bpf_prog_load_xattr: %s\n", strerror(errno));
  149. return 1;
  150. }
  151. tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port");
  152. rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
  153. if (tx_port_map_fd < 0 || rxcnt_map_fd < 0) {
  154. printf("bpf_object__find_map_fd_by_name failed\n");
  155. return 1;
  156. }
  157. if (bpf_set_link_xdp_fd(ifindex_in, prog_fd, xdp_flags) < 0) {
  158. printf("ERROR: link set xdp fd failed on %d\n", ifindex_in);
  159. return 1;
  160. }
  161. ret = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
  162. if (ret) {
  163. printf("can't get prog info - %s\n", strerror(errno));
  164. return ret;
  165. }
  166. prog_id = info.id;
  167. /* Loading dummy XDP prog on out-device */
  168. if (bpf_set_link_xdp_fd(ifindex_out, dummy_prog_fd,
  169. (xdp_flags | XDP_FLAGS_UPDATE_IF_NOEXIST)) < 0) {
  170. printf("WARN: link set xdp fd failed on %d\n", ifindex_out);
  171. ifindex_out_xdp_dummy_attached = false;
  172. }
  173. memset(&info, 0, sizeof(info));
  174. ret = bpf_obj_get_info_by_fd(dummy_prog_fd, &info, &info_len);
  175. if (ret) {
  176. printf("can't get prog info - %s\n", strerror(errno));
  177. return ret;
  178. }
  179. dummy_prog_id = info.id;
  180. signal(SIGINT, int_exit);
  181. signal(SIGTERM, int_exit);
  182. /* populate virtual to physical port map */
  183. ret = bpf_map_update_elem(tx_port_map_fd, &key, &ifindex_out, 0);
  184. if (ret) {
  185. perror("bpf_update_elem");
  186. goto out;
  187. }
  188. poll_stats(2, ifindex_out);
  189. out:
  190. return 0;
  191. }