test_cgroup_storage.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <assert.h>
  3. #include <bpf/bpf.h>
  4. #include <linux/filter.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <sys/sysinfo.h>
  8. #include "bpf_rlimit.h"
  9. #include "cgroup_helpers.h"
  10. char bpf_log_buf[BPF_LOG_BUF_SIZE];
  11. #define TEST_CGROUP "/test-bpf-cgroup-storage-buf/"
  12. int main(int argc, char **argv)
  13. {
  14. struct bpf_insn prog[] = {
  15. BPF_LD_MAP_FD(BPF_REG_1, 0), /* percpu map fd */
  16. BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
  17. BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
  18. BPF_FUNC_get_local_storage),
  19. BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
  20. BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1),
  21. BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0),
  22. BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */
  23. BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
  24. BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
  25. BPF_FUNC_get_local_storage),
  26. BPF_MOV64_IMM(BPF_REG_1, 1),
  27. BPF_STX_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0),
  28. BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
  29. BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x1),
  30. BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
  31. BPF_EXIT_INSN(),
  32. };
  33. size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
  34. int error = EXIT_FAILURE;
  35. int map_fd, percpu_map_fd, prog_fd, cgroup_fd;
  36. struct bpf_cgroup_storage_key key;
  37. unsigned long long value;
  38. unsigned long long *percpu_value;
  39. int cpu, nproc;
  40. nproc = get_nprocs_conf();
  41. percpu_value = malloc(sizeof(*percpu_value) * nproc);
  42. if (!percpu_value) {
  43. printf("Not enough memory for per-cpu area (%d cpus)\n", nproc);
  44. goto err;
  45. }
  46. map_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(key),
  47. sizeof(value), 0, 0);
  48. if (map_fd < 0) {
  49. printf("Failed to create map: %s\n", strerror(errno));
  50. goto out;
  51. }
  52. percpu_map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
  53. sizeof(key), sizeof(value), 0, 0);
  54. if (percpu_map_fd < 0) {
  55. printf("Failed to create map: %s\n", strerror(errno));
  56. goto out;
  57. }
  58. prog[0].imm = percpu_map_fd;
  59. prog[7].imm = map_fd;
  60. prog_fd = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
  61. prog, insns_cnt, "GPL", 0,
  62. bpf_log_buf, BPF_LOG_BUF_SIZE);
  63. if (prog_fd < 0) {
  64. printf("Failed to load bpf program: %s\n", bpf_log_buf);
  65. goto out;
  66. }
  67. if (setup_cgroup_environment()) {
  68. printf("Failed to setup cgroup environment\n");
  69. goto err;
  70. }
  71. /* Create a cgroup, get fd, and join it */
  72. cgroup_fd = create_and_get_cgroup(TEST_CGROUP);
  73. if (!cgroup_fd) {
  74. printf("Failed to create test cgroup\n");
  75. goto err;
  76. }
  77. if (join_cgroup(TEST_CGROUP)) {
  78. printf("Failed to join cgroup\n");
  79. goto err;
  80. }
  81. /* Attach the bpf program */
  82. if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) {
  83. printf("Failed to attach bpf program\n");
  84. goto err;
  85. }
  86. if (bpf_map_get_next_key(map_fd, NULL, &key)) {
  87. printf("Failed to get the first key in cgroup storage\n");
  88. goto err;
  89. }
  90. if (bpf_map_lookup_elem(map_fd, &key, &value)) {
  91. printf("Failed to lookup cgroup storage 0\n");
  92. goto err;
  93. }
  94. for (cpu = 0; cpu < nproc; cpu++)
  95. percpu_value[cpu] = 1000;
  96. if (bpf_map_update_elem(percpu_map_fd, &key, percpu_value, 0)) {
  97. printf("Failed to update the data in the cgroup storage\n");
  98. goto err;
  99. }
  100. /* Every second packet should be dropped */
  101. assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
  102. assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
  103. assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
  104. /* Check the counter in the cgroup local storage */
  105. if (bpf_map_lookup_elem(map_fd, &key, &value)) {
  106. printf("Failed to lookup cgroup storage\n");
  107. goto err;
  108. }
  109. if (value != 3) {
  110. printf("Unexpected data in the cgroup storage: %llu\n", value);
  111. goto err;
  112. }
  113. /* Bump the counter in the cgroup local storage */
  114. value++;
  115. if (bpf_map_update_elem(map_fd, &key, &value, 0)) {
  116. printf("Failed to update the data in the cgroup storage\n");
  117. goto err;
  118. }
  119. /* Every second packet should be dropped */
  120. assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
  121. assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
  122. assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
  123. /* Check the final value of the counter in the cgroup local storage */
  124. if (bpf_map_lookup_elem(map_fd, &key, &value)) {
  125. printf("Failed to lookup the cgroup storage\n");
  126. goto err;
  127. }
  128. if (value != 7) {
  129. printf("Unexpected data in the cgroup storage: %llu\n", value);
  130. goto err;
  131. }
  132. /* Check the final value of the counter in the percpu local storage */
  133. for (cpu = 0; cpu < nproc; cpu++)
  134. percpu_value[cpu] = 0;
  135. if (bpf_map_lookup_elem(percpu_map_fd, &key, percpu_value)) {
  136. printf("Failed to lookup the per-cpu cgroup storage\n");
  137. goto err;
  138. }
  139. value = 0;
  140. for (cpu = 0; cpu < nproc; cpu++)
  141. value += percpu_value[cpu];
  142. if (value != nproc * 1000 + 6) {
  143. printf("Unexpected data in the per-cpu cgroup storage\n");
  144. goto err;
  145. }
  146. error = 0;
  147. printf("test_cgroup_storage:PASS\n");
  148. err:
  149. cleanup_cgroup_environment();
  150. free(percpu_value);
  151. out:
  152. return error;
  153. }