test_map_in_map_user.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2017 Facebook
  4. */
  5. #include <sys/resource.h>
  6. #include <sys/socket.h>
  7. #include <arpa/inet.h>
  8. #include <stdint.h>
  9. #include <assert.h>
  10. #include <errno.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <bpf/bpf.h>
  14. #include <bpf/libbpf.h>
  15. static int map_fd[7];
  16. #define PORT_A (map_fd[0])
  17. #define PORT_H (map_fd[1])
  18. #define REG_RESULT_H (map_fd[2])
  19. #define INLINE_RESULT_H (map_fd[3])
  20. #define A_OF_PORT_A (map_fd[4]) /* Test case #0 */
  21. #define H_OF_PORT_A (map_fd[5]) /* Test case #1 */
  22. #define H_OF_PORT_H (map_fd[6]) /* Test case #2 */
  23. static const char * const test_names[] = {
  24. "Array of Array",
  25. "Hash of Array",
  26. "Hash of Hash",
  27. };
  28. #define NR_TESTS (sizeof(test_names) / sizeof(*test_names))
  29. static void check_map_id(int inner_map_fd, int map_in_map_fd, uint32_t key)
  30. {
  31. struct bpf_map_info info = {};
  32. uint32_t info_len = sizeof(info);
  33. int ret, id;
  34. ret = bpf_obj_get_info_by_fd(inner_map_fd, &info, &info_len);
  35. assert(!ret);
  36. ret = bpf_map_lookup_elem(map_in_map_fd, &key, &id);
  37. assert(!ret);
  38. assert(id == info.id);
  39. }
  40. static void populate_map(uint32_t port_key, int magic_result)
  41. {
  42. int ret;
  43. ret = bpf_map_update_elem(PORT_A, &port_key, &magic_result, BPF_ANY);
  44. assert(!ret);
  45. ret = bpf_map_update_elem(PORT_H, &port_key, &magic_result,
  46. BPF_NOEXIST);
  47. assert(!ret);
  48. ret = bpf_map_update_elem(A_OF_PORT_A, &port_key, &PORT_A, BPF_ANY);
  49. assert(!ret);
  50. check_map_id(PORT_A, A_OF_PORT_A, port_key);
  51. ret = bpf_map_update_elem(H_OF_PORT_A, &port_key, &PORT_A, BPF_NOEXIST);
  52. assert(!ret);
  53. check_map_id(PORT_A, H_OF_PORT_A, port_key);
  54. ret = bpf_map_update_elem(H_OF_PORT_H, &port_key, &PORT_H, BPF_NOEXIST);
  55. assert(!ret);
  56. check_map_id(PORT_H, H_OF_PORT_H, port_key);
  57. }
  58. static void test_map_in_map(void)
  59. {
  60. struct sockaddr_in6 in6 = { .sin6_family = AF_INET6 };
  61. uint32_t result_key = 0, port_key;
  62. int result, inline_result;
  63. int magic_result = 0xfaceb00c;
  64. int ret;
  65. int i;
  66. port_key = rand() & 0x00FF;
  67. populate_map(port_key, magic_result);
  68. in6.sin6_addr.s6_addr16[0] = 0xdead;
  69. in6.sin6_addr.s6_addr16[1] = 0xbeef;
  70. in6.sin6_port = port_key;
  71. for (i = 0; i < NR_TESTS; i++) {
  72. printf("%s: ", test_names[i]);
  73. in6.sin6_addr.s6_addr16[7] = i;
  74. ret = connect(-1, (struct sockaddr *)&in6, sizeof(in6));
  75. assert(ret == -1 && errno == EBADF);
  76. ret = bpf_map_lookup_elem(REG_RESULT_H, &result_key, &result);
  77. assert(!ret);
  78. ret = bpf_map_lookup_elem(INLINE_RESULT_H, &result_key,
  79. &inline_result);
  80. assert(!ret);
  81. if (result != magic_result || inline_result != magic_result) {
  82. printf("Error. result:%d inline_result:%d\n",
  83. result, inline_result);
  84. exit(1);
  85. }
  86. bpf_map_delete_elem(REG_RESULT_H, &result_key);
  87. bpf_map_delete_elem(INLINE_RESULT_H, &result_key);
  88. printf("Pass\n");
  89. }
  90. }
  91. int main(int argc, char **argv)
  92. {
  93. struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
  94. struct bpf_link *link = NULL;
  95. struct bpf_program *prog;
  96. struct bpf_object *obj;
  97. char filename[256];
  98. if (setrlimit(RLIMIT_MEMLOCK, &r)) {
  99. perror("setrlimit(RLIMIT_MEMLOCK)");
  100. return 1;
  101. }
  102. snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
  103. obj = bpf_object__open_file(filename, NULL);
  104. if (libbpf_get_error(obj)) {
  105. fprintf(stderr, "ERROR: opening BPF object file failed\n");
  106. return 0;
  107. }
  108. prog = bpf_object__find_program_by_name(obj, "trace_sys_connect");
  109. if (!prog) {
  110. printf("finding a prog in obj file failed\n");
  111. goto cleanup;
  112. }
  113. /* load BPF program */
  114. if (bpf_object__load(obj)) {
  115. fprintf(stderr, "ERROR: loading BPF object file failed\n");
  116. goto cleanup;
  117. }
  118. map_fd[0] = bpf_object__find_map_fd_by_name(obj, "port_a");
  119. map_fd[1] = bpf_object__find_map_fd_by_name(obj, "port_h");
  120. map_fd[2] = bpf_object__find_map_fd_by_name(obj, "reg_result_h");
  121. map_fd[3] = bpf_object__find_map_fd_by_name(obj, "inline_result_h");
  122. map_fd[4] = bpf_object__find_map_fd_by_name(obj, "a_of_port_a");
  123. map_fd[5] = bpf_object__find_map_fd_by_name(obj, "h_of_port_a");
  124. map_fd[6] = bpf_object__find_map_fd_by_name(obj, "h_of_port_h");
  125. if (map_fd[0] < 0 || map_fd[1] < 0 || map_fd[2] < 0 ||
  126. map_fd[3] < 0 || map_fd[4] < 0 || map_fd[5] < 0 || map_fd[6] < 0) {
  127. fprintf(stderr, "ERROR: finding a map in obj file failed\n");
  128. goto cleanup;
  129. }
  130. link = bpf_program__attach(prog);
  131. if (libbpf_get_error(link)) {
  132. fprintf(stderr, "ERROR: bpf_program__attach failed\n");
  133. link = NULL;
  134. goto cleanup;
  135. }
  136. test_map_in_map();
  137. cleanup:
  138. bpf_link__destroy(link);
  139. bpf_object__close(obj);
  140. return 0;
  141. }