cgroup.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. // SPDX-License-Identifier: GPL-2.0+
  2. // Copyright (C) 2017 Facebook
  3. // Author: Roman Gushchin <guro@fb.com>
  4. #include <fcntl.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/stat.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include <bpf.h>
  11. #include "main.h"
  12. #define HELP_SPEC_ATTACH_FLAGS \
  13. "ATTACH_FLAGS := { multi | override }"
  14. #define HELP_SPEC_ATTACH_TYPES \
  15. " ATTACH_TYPE := { ingress | egress | sock_create |\n" \
  16. " sock_ops | device | bind4 | bind6 |\n" \
  17. " post_bind4 | post_bind6 | connect4 |\n" \
  18. " connect6 | sendmsg4 | sendmsg6 }"
  19. static const char * const attach_type_strings[] = {
  20. [BPF_CGROUP_INET_INGRESS] = "ingress",
  21. [BPF_CGROUP_INET_EGRESS] = "egress",
  22. [BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
  23. [BPF_CGROUP_SOCK_OPS] = "sock_ops",
  24. [BPF_CGROUP_DEVICE] = "device",
  25. [BPF_CGROUP_INET4_BIND] = "bind4",
  26. [BPF_CGROUP_INET6_BIND] = "bind6",
  27. [BPF_CGROUP_INET4_CONNECT] = "connect4",
  28. [BPF_CGROUP_INET6_CONNECT] = "connect6",
  29. [BPF_CGROUP_INET4_POST_BIND] = "post_bind4",
  30. [BPF_CGROUP_INET6_POST_BIND] = "post_bind6",
  31. [BPF_CGROUP_UDP4_SENDMSG] = "sendmsg4",
  32. [BPF_CGROUP_UDP6_SENDMSG] = "sendmsg6",
  33. [__MAX_BPF_ATTACH_TYPE] = NULL,
  34. };
  35. static enum bpf_attach_type parse_attach_type(const char *str)
  36. {
  37. enum bpf_attach_type type;
  38. for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
  39. if (attach_type_strings[type] &&
  40. is_prefix(str, attach_type_strings[type]))
  41. return type;
  42. }
  43. return __MAX_BPF_ATTACH_TYPE;
  44. }
  45. static int show_bpf_prog(int id, const char *attach_type_str,
  46. const char *attach_flags_str)
  47. {
  48. struct bpf_prog_info info = {};
  49. __u32 info_len = sizeof(info);
  50. int prog_fd;
  51. prog_fd = bpf_prog_get_fd_by_id(id);
  52. if (prog_fd < 0)
  53. return -1;
  54. if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
  55. close(prog_fd);
  56. return -1;
  57. }
  58. if (json_output) {
  59. jsonw_start_object(json_wtr);
  60. jsonw_uint_field(json_wtr, "id", info.id);
  61. jsonw_string_field(json_wtr, "attach_type",
  62. attach_type_str);
  63. jsonw_string_field(json_wtr, "attach_flags",
  64. attach_flags_str);
  65. jsonw_string_field(json_wtr, "name", info.name);
  66. jsonw_end_object(json_wtr);
  67. } else {
  68. printf("%-8u %-15s %-15s %-15s\n", info.id,
  69. attach_type_str,
  70. attach_flags_str,
  71. info.name);
  72. }
  73. close(prog_fd);
  74. return 0;
  75. }
  76. static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
  77. {
  78. __u32 prog_ids[1024] = {0};
  79. char *attach_flags_str;
  80. __u32 prog_cnt, iter;
  81. __u32 attach_flags;
  82. char buf[32];
  83. int ret;
  84. prog_cnt = ARRAY_SIZE(prog_ids);
  85. ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids,
  86. &prog_cnt);
  87. if (ret)
  88. return ret;
  89. if (prog_cnt == 0)
  90. return 0;
  91. switch (attach_flags) {
  92. case BPF_F_ALLOW_MULTI:
  93. attach_flags_str = "multi";
  94. break;
  95. case BPF_F_ALLOW_OVERRIDE:
  96. attach_flags_str = "override";
  97. break;
  98. case 0:
  99. attach_flags_str = "";
  100. break;
  101. default:
  102. snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
  103. attach_flags_str = buf;
  104. }
  105. for (iter = 0; iter < prog_cnt; iter++)
  106. show_bpf_prog(prog_ids[iter], attach_type_strings[type],
  107. attach_flags_str);
  108. return 0;
  109. }
  110. static int do_show(int argc, char **argv)
  111. {
  112. enum bpf_attach_type type;
  113. int cgroup_fd;
  114. int ret = -1;
  115. if (argc < 1) {
  116. p_err("too few parameters for cgroup show");
  117. goto exit;
  118. } else if (argc > 1) {
  119. p_err("too many parameters for cgroup show");
  120. goto exit;
  121. }
  122. cgroup_fd = open(argv[0], O_RDONLY);
  123. if (cgroup_fd < 0) {
  124. p_err("can't open cgroup %s", argv[1]);
  125. goto exit;
  126. }
  127. if (json_output)
  128. jsonw_start_array(json_wtr);
  129. else
  130. printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
  131. "AttachFlags", "Name");
  132. for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
  133. /*
  134. * Not all attach types may be supported, so it's expected,
  135. * that some requests will fail.
  136. * If we were able to get the show for at least one
  137. * attach type, let's return 0.
  138. */
  139. if (show_attached_bpf_progs(cgroup_fd, type) == 0)
  140. ret = 0;
  141. }
  142. if (json_output)
  143. jsonw_end_array(json_wtr);
  144. close(cgroup_fd);
  145. exit:
  146. return ret;
  147. }
  148. static int do_attach(int argc, char **argv)
  149. {
  150. enum bpf_attach_type attach_type;
  151. int cgroup_fd, prog_fd;
  152. int attach_flags = 0;
  153. int ret = -1;
  154. int i;
  155. if (argc < 4) {
  156. p_err("too few parameters for cgroup attach");
  157. goto exit;
  158. }
  159. cgroup_fd = open(argv[0], O_RDONLY);
  160. if (cgroup_fd < 0) {
  161. p_err("can't open cgroup %s", argv[1]);
  162. goto exit;
  163. }
  164. attach_type = parse_attach_type(argv[1]);
  165. if (attach_type == __MAX_BPF_ATTACH_TYPE) {
  166. p_err("invalid attach type");
  167. goto exit_cgroup;
  168. }
  169. argc -= 2;
  170. argv = &argv[2];
  171. prog_fd = prog_parse_fd(&argc, &argv);
  172. if (prog_fd < 0)
  173. goto exit_cgroup;
  174. for (i = 0; i < argc; i++) {
  175. if (is_prefix(argv[i], "multi")) {
  176. attach_flags |= BPF_F_ALLOW_MULTI;
  177. } else if (is_prefix(argv[i], "override")) {
  178. attach_flags |= BPF_F_ALLOW_OVERRIDE;
  179. } else {
  180. p_err("unknown option: %s", argv[i]);
  181. goto exit_cgroup;
  182. }
  183. }
  184. if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) {
  185. p_err("failed to attach program");
  186. goto exit_prog;
  187. }
  188. if (json_output)
  189. jsonw_null(json_wtr);
  190. ret = 0;
  191. exit_prog:
  192. close(prog_fd);
  193. exit_cgroup:
  194. close(cgroup_fd);
  195. exit:
  196. return ret;
  197. }
  198. static int do_detach(int argc, char **argv)
  199. {
  200. enum bpf_attach_type attach_type;
  201. int prog_fd, cgroup_fd;
  202. int ret = -1;
  203. if (argc < 4) {
  204. p_err("too few parameters for cgroup detach");
  205. goto exit;
  206. }
  207. cgroup_fd = open(argv[0], O_RDONLY);
  208. if (cgroup_fd < 0) {
  209. p_err("can't open cgroup %s", argv[1]);
  210. goto exit;
  211. }
  212. attach_type = parse_attach_type(argv[1]);
  213. if (attach_type == __MAX_BPF_ATTACH_TYPE) {
  214. p_err("invalid attach type");
  215. goto exit_cgroup;
  216. }
  217. argc -= 2;
  218. argv = &argv[2];
  219. prog_fd = prog_parse_fd(&argc, &argv);
  220. if (prog_fd < 0)
  221. goto exit_cgroup;
  222. if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
  223. p_err("failed to detach program");
  224. goto exit_prog;
  225. }
  226. if (json_output)
  227. jsonw_null(json_wtr);
  228. ret = 0;
  229. exit_prog:
  230. close(prog_fd);
  231. exit_cgroup:
  232. close(cgroup_fd);
  233. exit:
  234. return ret;
  235. }
  236. static int do_help(int argc, char **argv)
  237. {
  238. if (json_output) {
  239. jsonw_null(json_wtr);
  240. return 0;
  241. }
  242. fprintf(stderr,
  243. "Usage: %s %s { show | list } CGROUP\n"
  244. " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
  245. " %s %s detach CGROUP ATTACH_TYPE PROG\n"
  246. " %s %s help\n"
  247. "\n"
  248. HELP_SPEC_ATTACH_TYPES "\n"
  249. " " HELP_SPEC_ATTACH_FLAGS "\n"
  250. " " HELP_SPEC_PROGRAM "\n"
  251. " " HELP_SPEC_OPTIONS "\n"
  252. "",
  253. bin_name, argv[-2], bin_name, argv[-2],
  254. bin_name, argv[-2], bin_name, argv[-2]);
  255. return 0;
  256. }
  257. static const struct cmd cmds[] = {
  258. { "show", do_show },
  259. { "list", do_show },
  260. { "attach", do_attach },
  261. { "detach", do_detach },
  262. { "help", do_help },
  263. { 0 }
  264. };
  265. int do_cgroup(int argc, char **argv)
  266. {
  267. return cmd_select(cmds, argc, argv, do_help);
  268. }