link.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2020 Facebook */
  3. #include <errno.h>
  4. #include <linux/err.h>
  5. #include <net/if.h>
  6. #include <stdio.h>
  7. #include <unistd.h>
  8. #include <bpf/bpf.h>
  9. #include <bpf/hashmap.h>
  10. #include "json_writer.h"
  11. #include "main.h"
  12. static struct hashmap *link_table;
  13. static int link_parse_fd(int *argc, char ***argv)
  14. {
  15. int fd;
  16. if (is_prefix(**argv, "id")) {
  17. unsigned int id;
  18. char *endptr;
  19. NEXT_ARGP();
  20. id = strtoul(**argv, &endptr, 0);
  21. if (*endptr) {
  22. p_err("can't parse %s as ID", **argv);
  23. return -1;
  24. }
  25. NEXT_ARGP();
  26. fd = bpf_link_get_fd_by_id(id);
  27. if (fd < 0)
  28. p_err("failed to get link with ID %d: %s", id, strerror(errno));
  29. return fd;
  30. } else if (is_prefix(**argv, "pinned")) {
  31. char *path;
  32. NEXT_ARGP();
  33. path = **argv;
  34. NEXT_ARGP();
  35. return open_obj_pinned_any(path, BPF_OBJ_LINK);
  36. }
  37. p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
  38. return -1;
  39. }
  40. static void
  41. show_link_header_json(struct bpf_link_info *info, json_writer_t *wtr)
  42. {
  43. const char *link_type_str;
  44. jsonw_uint_field(wtr, "id", info->id);
  45. link_type_str = libbpf_bpf_link_type_str(info->type);
  46. if (link_type_str)
  47. jsonw_string_field(wtr, "type", link_type_str);
  48. else
  49. jsonw_uint_field(wtr, "type", info->type);
  50. jsonw_uint_field(json_wtr, "prog_id", info->prog_id);
  51. }
  52. static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr)
  53. {
  54. const char *attach_type_str;
  55. attach_type_str = libbpf_bpf_attach_type_str(attach_type);
  56. if (attach_type_str)
  57. jsonw_string_field(wtr, "attach_type", attach_type_str);
  58. else
  59. jsonw_uint_field(wtr, "attach_type", attach_type);
  60. }
  61. static bool is_iter_map_target(const char *target_name)
  62. {
  63. return strcmp(target_name, "bpf_map_elem") == 0 ||
  64. strcmp(target_name, "bpf_sk_storage_map") == 0;
  65. }
  66. static bool is_iter_cgroup_target(const char *target_name)
  67. {
  68. return strcmp(target_name, "cgroup") == 0;
  69. }
  70. static const char *cgroup_order_string(__u32 order)
  71. {
  72. switch (order) {
  73. case BPF_CGROUP_ITER_ORDER_UNSPEC:
  74. return "order_unspec";
  75. case BPF_CGROUP_ITER_SELF_ONLY:
  76. return "self_only";
  77. case BPF_CGROUP_ITER_DESCENDANTS_PRE:
  78. return "descendants_pre";
  79. case BPF_CGROUP_ITER_DESCENDANTS_POST:
  80. return "descendants_post";
  81. case BPF_CGROUP_ITER_ANCESTORS_UP:
  82. return "ancestors_up";
  83. default: /* won't happen */
  84. return "unknown";
  85. }
  86. }
  87. static bool is_iter_task_target(const char *target_name)
  88. {
  89. return strcmp(target_name, "task") == 0 ||
  90. strcmp(target_name, "task_file") == 0 ||
  91. strcmp(target_name, "task_vma") == 0;
  92. }
  93. static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr)
  94. {
  95. const char *target_name = u64_to_ptr(info->iter.target_name);
  96. jsonw_string_field(wtr, "target_name", target_name);
  97. if (is_iter_map_target(target_name))
  98. jsonw_uint_field(wtr, "map_id", info->iter.map.map_id);
  99. else if (is_iter_task_target(target_name)) {
  100. if (info->iter.task.tid)
  101. jsonw_uint_field(wtr, "tid", info->iter.task.tid);
  102. else if (info->iter.task.pid)
  103. jsonw_uint_field(wtr, "pid", info->iter.task.pid);
  104. }
  105. if (is_iter_cgroup_target(target_name)) {
  106. jsonw_lluint_field(wtr, "cgroup_id", info->iter.cgroup.cgroup_id);
  107. jsonw_string_field(wtr, "order",
  108. cgroup_order_string(info->iter.cgroup.order));
  109. }
  110. }
  111. static int get_prog_info(int prog_id, struct bpf_prog_info *info)
  112. {
  113. __u32 len = sizeof(*info);
  114. int err, prog_fd;
  115. prog_fd = bpf_prog_get_fd_by_id(prog_id);
  116. if (prog_fd < 0)
  117. return prog_fd;
  118. memset(info, 0, sizeof(*info));
  119. err = bpf_obj_get_info_by_fd(prog_fd, info, &len);
  120. if (err)
  121. p_err("can't get prog info: %s", strerror(errno));
  122. close(prog_fd);
  123. return err;
  124. }
  125. static int show_link_close_json(int fd, struct bpf_link_info *info)
  126. {
  127. struct bpf_prog_info prog_info;
  128. const char *prog_type_str;
  129. int err;
  130. jsonw_start_object(json_wtr);
  131. show_link_header_json(info, json_wtr);
  132. switch (info->type) {
  133. case BPF_LINK_TYPE_RAW_TRACEPOINT:
  134. jsonw_string_field(json_wtr, "tp_name",
  135. u64_to_ptr(info->raw_tracepoint.tp_name));
  136. break;
  137. case BPF_LINK_TYPE_TRACING:
  138. err = get_prog_info(info->prog_id, &prog_info);
  139. if (err)
  140. return err;
  141. prog_type_str = libbpf_bpf_prog_type_str(prog_info.type);
  142. /* libbpf will return NULL for variants unknown to it. */
  143. if (prog_type_str)
  144. jsonw_string_field(json_wtr, "prog_type", prog_type_str);
  145. else
  146. jsonw_uint_field(json_wtr, "prog_type", prog_info.type);
  147. show_link_attach_type_json(info->tracing.attach_type,
  148. json_wtr);
  149. break;
  150. case BPF_LINK_TYPE_CGROUP:
  151. jsonw_lluint_field(json_wtr, "cgroup_id",
  152. info->cgroup.cgroup_id);
  153. show_link_attach_type_json(info->cgroup.attach_type, json_wtr);
  154. break;
  155. case BPF_LINK_TYPE_ITER:
  156. show_iter_json(info, json_wtr);
  157. break;
  158. case BPF_LINK_TYPE_NETNS:
  159. jsonw_uint_field(json_wtr, "netns_ino",
  160. info->netns.netns_ino);
  161. show_link_attach_type_json(info->netns.attach_type, json_wtr);
  162. break;
  163. default:
  164. break;
  165. }
  166. if (!hashmap__empty(link_table)) {
  167. struct hashmap_entry *entry;
  168. jsonw_name(json_wtr, "pinned");
  169. jsonw_start_array(json_wtr);
  170. hashmap__for_each_key_entry(link_table, entry,
  171. u32_as_hash_field(info->id))
  172. jsonw_string(json_wtr, entry->value);
  173. jsonw_end_array(json_wtr);
  174. }
  175. emit_obj_refs_json(refs_table, info->id, json_wtr);
  176. jsonw_end_object(json_wtr);
  177. return 0;
  178. }
  179. static void show_link_header_plain(struct bpf_link_info *info)
  180. {
  181. const char *link_type_str;
  182. printf("%u: ", info->id);
  183. link_type_str = libbpf_bpf_link_type_str(info->type);
  184. if (link_type_str)
  185. printf("%s ", link_type_str);
  186. else
  187. printf("type %u ", info->type);
  188. printf("prog %u ", info->prog_id);
  189. }
  190. static void show_link_attach_type_plain(__u32 attach_type)
  191. {
  192. const char *attach_type_str;
  193. attach_type_str = libbpf_bpf_attach_type_str(attach_type);
  194. if (attach_type_str)
  195. printf("attach_type %s ", attach_type_str);
  196. else
  197. printf("attach_type %u ", attach_type);
  198. }
  199. static void show_iter_plain(struct bpf_link_info *info)
  200. {
  201. const char *target_name = u64_to_ptr(info->iter.target_name);
  202. printf("target_name %s ", target_name);
  203. if (is_iter_map_target(target_name))
  204. printf("map_id %u ", info->iter.map.map_id);
  205. else if (is_iter_task_target(target_name)) {
  206. if (info->iter.task.tid)
  207. printf("tid %u ", info->iter.task.tid);
  208. else if (info->iter.task.pid)
  209. printf("pid %u ", info->iter.task.pid);
  210. }
  211. if (is_iter_cgroup_target(target_name)) {
  212. printf("cgroup_id %llu ", info->iter.cgroup.cgroup_id);
  213. printf("order %s ",
  214. cgroup_order_string(info->iter.cgroup.order));
  215. }
  216. }
  217. static int show_link_close_plain(int fd, struct bpf_link_info *info)
  218. {
  219. struct bpf_prog_info prog_info;
  220. const char *prog_type_str;
  221. int err;
  222. show_link_header_plain(info);
  223. switch (info->type) {
  224. case BPF_LINK_TYPE_RAW_TRACEPOINT:
  225. printf("\n\ttp '%s' ",
  226. (const char *)u64_to_ptr(info->raw_tracepoint.tp_name));
  227. break;
  228. case BPF_LINK_TYPE_TRACING:
  229. err = get_prog_info(info->prog_id, &prog_info);
  230. if (err)
  231. return err;
  232. prog_type_str = libbpf_bpf_prog_type_str(prog_info.type);
  233. /* libbpf will return NULL for variants unknown to it. */
  234. if (prog_type_str)
  235. printf("\n\tprog_type %s ", prog_type_str);
  236. else
  237. printf("\n\tprog_type %u ", prog_info.type);
  238. show_link_attach_type_plain(info->tracing.attach_type);
  239. break;
  240. case BPF_LINK_TYPE_CGROUP:
  241. printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id);
  242. show_link_attach_type_plain(info->cgroup.attach_type);
  243. break;
  244. case BPF_LINK_TYPE_ITER:
  245. show_iter_plain(info);
  246. break;
  247. case BPF_LINK_TYPE_NETNS:
  248. printf("\n\tnetns_ino %u ", info->netns.netns_ino);
  249. show_link_attach_type_plain(info->netns.attach_type);
  250. break;
  251. default:
  252. break;
  253. }
  254. if (!hashmap__empty(link_table)) {
  255. struct hashmap_entry *entry;
  256. hashmap__for_each_key_entry(link_table, entry,
  257. u32_as_hash_field(info->id))
  258. printf("\n\tpinned %s", (char *)entry->value);
  259. }
  260. emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
  261. printf("\n");
  262. return 0;
  263. }
  264. static int do_show_link(int fd)
  265. {
  266. struct bpf_link_info info;
  267. __u32 len = sizeof(info);
  268. char buf[256];
  269. int err;
  270. memset(&info, 0, sizeof(info));
  271. again:
  272. err = bpf_obj_get_info_by_fd(fd, &info, &len);
  273. if (err) {
  274. p_err("can't get link info: %s",
  275. strerror(errno));
  276. close(fd);
  277. return err;
  278. }
  279. if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT &&
  280. !info.raw_tracepoint.tp_name) {
  281. info.raw_tracepoint.tp_name = (unsigned long)&buf;
  282. info.raw_tracepoint.tp_name_len = sizeof(buf);
  283. goto again;
  284. }
  285. if (info.type == BPF_LINK_TYPE_ITER &&
  286. !info.iter.target_name) {
  287. info.iter.target_name = (unsigned long)&buf;
  288. info.iter.target_name_len = sizeof(buf);
  289. goto again;
  290. }
  291. if (json_output)
  292. show_link_close_json(fd, &info);
  293. else
  294. show_link_close_plain(fd, &info);
  295. close(fd);
  296. return 0;
  297. }
  298. static int do_show(int argc, char **argv)
  299. {
  300. __u32 id = 0;
  301. int err, fd;
  302. if (show_pinned) {
  303. link_table = hashmap__new(hash_fn_for_key_as_id,
  304. equal_fn_for_key_as_id, NULL);
  305. if (IS_ERR(link_table)) {
  306. p_err("failed to create hashmap for pinned paths");
  307. return -1;
  308. }
  309. build_pinned_obj_table(link_table, BPF_OBJ_LINK);
  310. }
  311. build_obj_refs_table(&refs_table, BPF_OBJ_LINK);
  312. if (argc == 2) {
  313. fd = link_parse_fd(&argc, &argv);
  314. if (fd < 0)
  315. return fd;
  316. return do_show_link(fd);
  317. }
  318. if (argc)
  319. return BAD_ARG();
  320. if (json_output)
  321. jsonw_start_array(json_wtr);
  322. while (true) {
  323. err = bpf_link_get_next_id(id, &id);
  324. if (err) {
  325. if (errno == ENOENT)
  326. break;
  327. p_err("can't get next link: %s%s", strerror(errno),
  328. errno == EINVAL ? " -- kernel too old?" : "");
  329. break;
  330. }
  331. fd = bpf_link_get_fd_by_id(id);
  332. if (fd < 0) {
  333. if (errno == ENOENT)
  334. continue;
  335. p_err("can't get link by id (%u): %s",
  336. id, strerror(errno));
  337. break;
  338. }
  339. err = do_show_link(fd);
  340. if (err)
  341. break;
  342. }
  343. if (json_output)
  344. jsonw_end_array(json_wtr);
  345. delete_obj_refs_table(refs_table);
  346. if (show_pinned)
  347. delete_pinned_obj_table(link_table);
  348. return errno == ENOENT ? 0 : -1;
  349. }
  350. static int do_pin(int argc, char **argv)
  351. {
  352. int err;
  353. err = do_pin_any(argc, argv, link_parse_fd);
  354. if (!err && json_output)
  355. jsonw_null(json_wtr);
  356. return err;
  357. }
  358. static int do_detach(int argc, char **argv)
  359. {
  360. int err, fd;
  361. if (argc != 2) {
  362. p_err("link specifier is invalid or missing\n");
  363. return 1;
  364. }
  365. fd = link_parse_fd(&argc, &argv);
  366. if (fd < 0)
  367. return 1;
  368. err = bpf_link_detach(fd);
  369. if (err)
  370. err = -errno;
  371. close(fd);
  372. if (err) {
  373. p_err("failed link detach: %s", strerror(-err));
  374. return 1;
  375. }
  376. if (json_output)
  377. jsonw_null(json_wtr);
  378. return 0;
  379. }
  380. static int do_help(int argc, char **argv)
  381. {
  382. if (json_output) {
  383. jsonw_null(json_wtr);
  384. return 0;
  385. }
  386. fprintf(stderr,
  387. "Usage: %1$s %2$s { show | list } [LINK]\n"
  388. " %1$s %2$s pin LINK FILE\n"
  389. " %1$s %2$s detach LINK\n"
  390. " %1$s %2$s help\n"
  391. "\n"
  392. " " HELP_SPEC_LINK "\n"
  393. " " HELP_SPEC_OPTIONS " |\n"
  394. " {-f|--bpffs} | {-n|--nomount} }\n"
  395. "",
  396. bin_name, argv[-2]);
  397. return 0;
  398. }
  399. static const struct cmd cmds[] = {
  400. { "show", do_show },
  401. { "list", do_show },
  402. { "help", do_help },
  403. { "pin", do_pin },
  404. { "detach", do_detach },
  405. { 0 }
  406. };
  407. int do_link(int argc, char **argv)
  408. {
  409. return cmd_select(cmds, argc, argv, do_help);
  410. }