netlink_dumper.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0+
  2. // Copyright (C) 2018 Facebook
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <libbpf.h>
  6. #include <linux/rtnetlink.h>
  7. #include <linux/tc_act/tc_bpf.h>
  8. #include <nlattr.h>
  9. #include "main.h"
  10. #include "netlink_dumper.h"
  11. static void xdp_dump_prog_id(struct nlattr **tb, int attr,
  12. const char *mode,
  13. bool new_json_object)
  14. {
  15. if (!tb[attr])
  16. return;
  17. if (new_json_object)
  18. NET_START_OBJECT
  19. NET_DUMP_STR("mode", " %s", mode);
  20. NET_DUMP_UINT("id", " id %u", libbpf_nla_getattr_u32(tb[attr]))
  21. if (new_json_object)
  22. NET_END_OBJECT
  23. }
  24. static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex,
  25. const char *name)
  26. {
  27. struct nlattr *tb[IFLA_XDP_MAX + 1];
  28. unsigned char mode;
  29. if (libbpf_nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0)
  30. return -1;
  31. if (!tb[IFLA_XDP_ATTACHED])
  32. return 0;
  33. mode = libbpf_nla_getattr_u8(tb[IFLA_XDP_ATTACHED]);
  34. if (mode == XDP_ATTACHED_NONE)
  35. return 0;
  36. NET_START_OBJECT;
  37. if (name)
  38. NET_DUMP_STR("devname", "%s", name);
  39. NET_DUMP_UINT("ifindex", "(%d)", ifindex);
  40. if (mode == XDP_ATTACHED_MULTI) {
  41. if (json_output) {
  42. jsonw_name(json_wtr, "multi_attachments");
  43. jsonw_start_array(json_wtr);
  44. }
  45. xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic", true);
  46. xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "driver", true);
  47. xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload", true);
  48. if (json_output)
  49. jsonw_end_array(json_wtr);
  50. } else if (mode == XDP_ATTACHED_DRV) {
  51. xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "driver", false);
  52. } else if (mode == XDP_ATTACHED_SKB) {
  53. xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "generic", false);
  54. } else if (mode == XDP_ATTACHED_HW) {
  55. xdp_dump_prog_id(tb, IFLA_XDP_PROG_ID, "offload", false);
  56. }
  57. NET_END_OBJECT_FINAL;
  58. return 0;
  59. }
  60. int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb)
  61. {
  62. if (!tb[IFLA_XDP])
  63. return 0;
  64. return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index,
  65. libbpf_nla_getattr_str(tb[IFLA_IFNAME]));
  66. }
  67. static int do_bpf_dump_one_act(struct nlattr *attr)
  68. {
  69. struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
  70. if (libbpf_nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0)
  71. return -LIBBPF_ERRNO__NLPARSE;
  72. if (!tb[TCA_ACT_BPF_PARMS])
  73. return -LIBBPF_ERRNO__NLPARSE;
  74. NET_START_OBJECT_NESTED2;
  75. if (tb[TCA_ACT_BPF_NAME])
  76. NET_DUMP_STR("name", "%s",
  77. libbpf_nla_getattr_str(tb[TCA_ACT_BPF_NAME]));
  78. if (tb[TCA_ACT_BPF_ID])
  79. NET_DUMP_UINT("id", " id %u",
  80. libbpf_nla_getattr_u32(tb[TCA_ACT_BPF_ID]));
  81. NET_END_OBJECT_NESTED;
  82. return 0;
  83. }
  84. static int do_dump_one_act(struct nlattr *attr)
  85. {
  86. struct nlattr *tb[TCA_ACT_MAX + 1];
  87. if (!attr)
  88. return 0;
  89. if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0)
  90. return -LIBBPF_ERRNO__NLPARSE;
  91. if (tb[TCA_ACT_KIND] &&
  92. strcmp(libbpf_nla_data(tb[TCA_ACT_KIND]), "bpf") == 0)
  93. return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]);
  94. return 0;
  95. }
  96. static int do_bpf_act_dump(struct nlattr *attr)
  97. {
  98. struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
  99. int act, ret;
  100. if (libbpf_nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0)
  101. return -LIBBPF_ERRNO__NLPARSE;
  102. NET_START_ARRAY("act", " %s [");
  103. for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) {
  104. ret = do_dump_one_act(tb[act]);
  105. if (ret)
  106. break;
  107. }
  108. NET_END_ARRAY("] ");
  109. return ret;
  110. }
  111. static int do_bpf_filter_dump(struct nlattr *attr)
  112. {
  113. struct nlattr *tb[TCA_BPF_MAX + 1];
  114. int ret;
  115. if (libbpf_nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0)
  116. return -LIBBPF_ERRNO__NLPARSE;
  117. if (tb[TCA_BPF_NAME])
  118. NET_DUMP_STR("name", " %s",
  119. libbpf_nla_getattr_str(tb[TCA_BPF_NAME]));
  120. if (tb[TCA_BPF_ID])
  121. NET_DUMP_UINT("id", " id %u",
  122. libbpf_nla_getattr_u32(tb[TCA_BPF_ID]));
  123. if (tb[TCA_BPF_ACT]) {
  124. ret = do_bpf_act_dump(tb[TCA_BPF_ACT]);
  125. if (ret)
  126. return ret;
  127. }
  128. return 0;
  129. }
  130. int do_filter_dump(struct tcmsg *info, struct nlattr **tb, const char *kind,
  131. const char *devname, int ifindex)
  132. {
  133. int ret = 0;
  134. if (tb[TCA_OPTIONS] &&
  135. strcmp(libbpf_nla_data(tb[TCA_KIND]), "bpf") == 0) {
  136. NET_START_OBJECT;
  137. if (devname[0] != '\0')
  138. NET_DUMP_STR("devname", "%s", devname);
  139. NET_DUMP_UINT("ifindex", "(%u)", ifindex);
  140. NET_DUMP_STR("kind", " %s", kind);
  141. ret = do_bpf_filter_dump(tb[TCA_OPTIONS]);
  142. NET_END_OBJECT_FINAL;
  143. }
  144. return ret;
  145. }