net.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. // Copyright (C) 2018 Facebook
  3. #ifndef _GNU_SOURCE
  4. #define _GNU_SOURCE
  5. #endif
  6. #include <errno.h>
  7. #include <fcntl.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <time.h>
  11. #include <unistd.h>
  12. #include <bpf/bpf.h>
  13. #include <bpf/libbpf.h>
  14. #include <net/if.h>
  15. #include <linux/rtnetlink.h>
  16. #include <linux/socket.h>
  17. #include <linux/tc_act/tc_bpf.h>
  18. #include <sys/socket.h>
  19. #include <sys/stat.h>
  20. #include <sys/types.h>
  21. #include "bpf/nlattr.h"
  22. #include "main.h"
  23. #include "netlink_dumper.h"
  24. #ifndef SOL_NETLINK
  25. #define SOL_NETLINK 270
  26. #endif
  27. struct ip_devname_ifindex {
  28. char devname[64];
  29. int ifindex;
  30. };
  31. struct bpf_netdev_t {
  32. struct ip_devname_ifindex *devices;
  33. int used_len;
  34. int array_len;
  35. int filter_idx;
  36. };
  37. struct tc_kind_handle {
  38. char kind[64];
  39. int handle;
  40. };
  41. struct bpf_tcinfo_t {
  42. struct tc_kind_handle *handle_array;
  43. int used_len;
  44. int array_len;
  45. bool is_qdisc;
  46. };
  47. struct bpf_filter_t {
  48. const char *kind;
  49. const char *devname;
  50. int ifindex;
  51. };
  52. struct bpf_attach_info {
  53. __u32 flow_dissector_id;
  54. };
  55. enum net_attach_type {
  56. NET_ATTACH_TYPE_XDP,
  57. NET_ATTACH_TYPE_XDP_GENERIC,
  58. NET_ATTACH_TYPE_XDP_DRIVER,
  59. NET_ATTACH_TYPE_XDP_OFFLOAD,
  60. NET_ATTACH_TYPE_TCX_INGRESS,
  61. NET_ATTACH_TYPE_TCX_EGRESS,
  62. };
  63. static const char * const attach_type_strings[] = {
  64. [NET_ATTACH_TYPE_XDP] = "xdp",
  65. [NET_ATTACH_TYPE_XDP_GENERIC] = "xdpgeneric",
  66. [NET_ATTACH_TYPE_XDP_DRIVER] = "xdpdrv",
  67. [NET_ATTACH_TYPE_XDP_OFFLOAD] = "xdpoffload",
  68. [NET_ATTACH_TYPE_TCX_INGRESS] = "tcx_ingress",
  69. [NET_ATTACH_TYPE_TCX_EGRESS] = "tcx_egress",
  70. };
  71. static const char * const attach_loc_strings[] = {
  72. [BPF_TCX_INGRESS] = "tcx/ingress",
  73. [BPF_TCX_EGRESS] = "tcx/egress",
  74. [BPF_NETKIT_PRIMARY] = "netkit/primary",
  75. [BPF_NETKIT_PEER] = "netkit/peer",
  76. };
  77. const size_t net_attach_type_size = ARRAY_SIZE(attach_type_strings);
  78. static enum net_attach_type parse_attach_type(const char *str)
  79. {
  80. enum net_attach_type type;
  81. for (type = 0; type < net_attach_type_size; type++) {
  82. if (attach_type_strings[type] &&
  83. is_prefix(str, attach_type_strings[type]))
  84. return type;
  85. }
  86. return net_attach_type_size;
  87. }
  88. typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
  89. typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t, void *cookie);
  90. static int netlink_open(__u32 *nl_pid)
  91. {
  92. struct sockaddr_nl sa;
  93. socklen_t addrlen;
  94. int one = 1, ret;
  95. int sock;
  96. memset(&sa, 0, sizeof(sa));
  97. sa.nl_family = AF_NETLINK;
  98. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  99. if (sock < 0)
  100. return -errno;
  101. if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
  102. &one, sizeof(one)) < 0) {
  103. p_err("Netlink error reporting not supported");
  104. }
  105. if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  106. ret = -errno;
  107. goto cleanup;
  108. }
  109. addrlen = sizeof(sa);
  110. if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
  111. ret = -errno;
  112. goto cleanup;
  113. }
  114. if (addrlen != sizeof(sa)) {
  115. ret = -LIBBPF_ERRNO__INTERNAL;
  116. goto cleanup;
  117. }
  118. *nl_pid = sa.nl_pid;
  119. return sock;
  120. cleanup:
  121. close(sock);
  122. return ret;
  123. }
  124. static int netlink_recv(int sock, __u32 nl_pid, __u32 seq,
  125. __dump_nlmsg_t _fn, dump_nlmsg_t fn,
  126. void *cookie)
  127. {
  128. bool multipart = true;
  129. struct nlmsgerr *err;
  130. struct nlmsghdr *nh;
  131. char buf[8192];
  132. int len, ret;
  133. while (multipart) {
  134. multipart = false;
  135. len = recv(sock, buf, sizeof(buf), 0);
  136. if (len < 0) {
  137. ret = -errno;
  138. goto done;
  139. }
  140. if (len == 0)
  141. break;
  142. for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, (unsigned int)len);
  143. nh = NLMSG_NEXT(nh, len)) {
  144. if (nh->nlmsg_pid != nl_pid) {
  145. ret = -LIBBPF_ERRNO__WRNGPID;
  146. goto done;
  147. }
  148. if (nh->nlmsg_seq != seq) {
  149. ret = -LIBBPF_ERRNO__INVSEQ;
  150. goto done;
  151. }
  152. if (nh->nlmsg_flags & NLM_F_MULTI)
  153. multipart = true;
  154. switch (nh->nlmsg_type) {
  155. case NLMSG_ERROR:
  156. err = (struct nlmsgerr *)NLMSG_DATA(nh);
  157. if (!err->error)
  158. continue;
  159. ret = err->error;
  160. libbpf_nla_dump_errormsg(nh);
  161. goto done;
  162. case NLMSG_DONE:
  163. return 0;
  164. default:
  165. break;
  166. }
  167. if (_fn) {
  168. ret = _fn(nh, fn, cookie);
  169. if (ret)
  170. return ret;
  171. }
  172. }
  173. if (len)
  174. p_err("Invalid message or trailing data in Netlink response: %d bytes left", len);
  175. }
  176. ret = 0;
  177. done:
  178. return ret;
  179. }
  180. static int __dump_class_nlmsg(struct nlmsghdr *nlh,
  181. dump_nlmsg_t dump_class_nlmsg,
  182. void *cookie)
  183. {
  184. struct nlattr *tb[TCA_MAX + 1], *attr;
  185. struct tcmsg *t = NLMSG_DATA(nlh);
  186. int len;
  187. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  188. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  189. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  190. return -LIBBPF_ERRNO__NLPARSE;
  191. return dump_class_nlmsg(cookie, t, tb);
  192. }
  193. static int netlink_get_class(int sock, unsigned int nl_pid, int ifindex,
  194. dump_nlmsg_t dump_class_nlmsg, void *cookie)
  195. {
  196. struct {
  197. struct nlmsghdr nlh;
  198. struct tcmsg t;
  199. } req = {
  200. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  201. .nlh.nlmsg_type = RTM_GETTCLASS,
  202. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  203. .t.tcm_family = AF_UNSPEC,
  204. .t.tcm_ifindex = ifindex,
  205. };
  206. int seq = time(NULL);
  207. req.nlh.nlmsg_seq = seq;
  208. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  209. return -errno;
  210. return netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg,
  211. dump_class_nlmsg, cookie);
  212. }
  213. static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh,
  214. dump_nlmsg_t dump_qdisc_nlmsg,
  215. void *cookie)
  216. {
  217. struct nlattr *tb[TCA_MAX + 1], *attr;
  218. struct tcmsg *t = NLMSG_DATA(nlh);
  219. int len;
  220. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  221. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  222. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  223. return -LIBBPF_ERRNO__NLPARSE;
  224. return dump_qdisc_nlmsg(cookie, t, tb);
  225. }
  226. static int netlink_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
  227. dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
  228. {
  229. struct {
  230. struct nlmsghdr nlh;
  231. struct tcmsg t;
  232. } req = {
  233. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  234. .nlh.nlmsg_type = RTM_GETQDISC,
  235. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  236. .t.tcm_family = AF_UNSPEC,
  237. .t.tcm_ifindex = ifindex,
  238. };
  239. int seq = time(NULL);
  240. req.nlh.nlmsg_seq = seq;
  241. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  242. return -errno;
  243. return netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg,
  244. dump_qdisc_nlmsg, cookie);
  245. }
  246. static int __dump_filter_nlmsg(struct nlmsghdr *nlh,
  247. dump_nlmsg_t dump_filter_nlmsg,
  248. void *cookie)
  249. {
  250. struct nlattr *tb[TCA_MAX + 1], *attr;
  251. struct tcmsg *t = NLMSG_DATA(nlh);
  252. int len;
  253. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  254. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  255. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  256. return -LIBBPF_ERRNO__NLPARSE;
  257. return dump_filter_nlmsg(cookie, t, tb);
  258. }
  259. static int netlink_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
  260. dump_nlmsg_t dump_filter_nlmsg, void *cookie)
  261. {
  262. struct {
  263. struct nlmsghdr nlh;
  264. struct tcmsg t;
  265. } req = {
  266. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  267. .nlh.nlmsg_type = RTM_GETTFILTER,
  268. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  269. .t.tcm_family = AF_UNSPEC,
  270. .t.tcm_ifindex = ifindex,
  271. .t.tcm_parent = handle,
  272. };
  273. int seq = time(NULL);
  274. req.nlh.nlmsg_seq = seq;
  275. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  276. return -errno;
  277. return netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg,
  278. dump_filter_nlmsg, cookie);
  279. }
  280. static int __dump_link_nlmsg(struct nlmsghdr *nlh,
  281. dump_nlmsg_t dump_link_nlmsg, void *cookie)
  282. {
  283. struct nlattr *tb[IFLA_MAX + 1], *attr;
  284. struct ifinfomsg *ifi = NLMSG_DATA(nlh);
  285. int len;
  286. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
  287. attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
  288. if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
  289. return -LIBBPF_ERRNO__NLPARSE;
  290. return dump_link_nlmsg(cookie, ifi, tb);
  291. }
  292. static int netlink_get_link(int sock, unsigned int nl_pid,
  293. dump_nlmsg_t dump_link_nlmsg, void *cookie)
  294. {
  295. struct {
  296. struct nlmsghdr nlh;
  297. struct ifinfomsg ifm;
  298. } req = {
  299. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  300. .nlh.nlmsg_type = RTM_GETLINK,
  301. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  302. .ifm.ifi_family = AF_PACKET,
  303. };
  304. int seq = time(NULL);
  305. req.nlh.nlmsg_seq = seq;
  306. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  307. return -errno;
  308. return netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
  309. dump_link_nlmsg, cookie);
  310. }
  311. static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  312. {
  313. struct bpf_netdev_t *netinfo = cookie;
  314. struct ifinfomsg *ifinfo = msg;
  315. struct ip_devname_ifindex *tmp;
  316. if (netinfo->filter_idx > 0 && netinfo->filter_idx != ifinfo->ifi_index)
  317. return 0;
  318. if (netinfo->used_len == netinfo->array_len) {
  319. tmp = realloc(netinfo->devices,
  320. (netinfo->array_len + 16) * sizeof(struct ip_devname_ifindex));
  321. if (!tmp)
  322. return -ENOMEM;
  323. netinfo->devices = tmp;
  324. netinfo->array_len += 16;
  325. }
  326. netinfo->devices[netinfo->used_len].ifindex = ifinfo->ifi_index;
  327. snprintf(netinfo->devices[netinfo->used_len].devname,
  328. sizeof(netinfo->devices[netinfo->used_len].devname),
  329. "%s",
  330. tb[IFLA_IFNAME]
  331. ? libbpf_nla_getattr_str(tb[IFLA_IFNAME])
  332. : "");
  333. netinfo->used_len++;
  334. return do_xdp_dump(ifinfo, tb);
  335. }
  336. static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  337. {
  338. struct bpf_tcinfo_t *tcinfo = cookie;
  339. struct tcmsg *info = msg;
  340. struct tc_kind_handle *tmp;
  341. if (tcinfo->is_qdisc) {
  342. /* skip clsact qdisc */
  343. if (tb[TCA_KIND] &&
  344. strcmp(libbpf_nla_data(tb[TCA_KIND]), "clsact") == 0)
  345. return 0;
  346. if (info->tcm_handle == 0)
  347. return 0;
  348. }
  349. if (tcinfo->used_len == tcinfo->array_len) {
  350. tmp = realloc(tcinfo->handle_array,
  351. (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle));
  352. if (!tmp)
  353. return -ENOMEM;
  354. tcinfo->handle_array = tmp;
  355. tcinfo->array_len += 16;
  356. }
  357. tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle;
  358. snprintf(tcinfo->handle_array[tcinfo->used_len].kind,
  359. sizeof(tcinfo->handle_array[tcinfo->used_len].kind),
  360. "%s",
  361. tb[TCA_KIND]
  362. ? libbpf_nla_getattr_str(tb[TCA_KIND])
  363. : "unknown");
  364. tcinfo->used_len++;
  365. return 0;
  366. }
  367. static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  368. {
  369. const struct bpf_filter_t *filter_info = cookie;
  370. return do_filter_dump((struct tcmsg *)msg, tb, filter_info->kind,
  371. filter_info->devname, filter_info->ifindex);
  372. }
  373. static int __show_dev_tc_bpf_name(__u32 id, char *name, size_t len)
  374. {
  375. struct bpf_prog_info info = {};
  376. __u32 ilen = sizeof(info);
  377. int fd, ret;
  378. fd = bpf_prog_get_fd_by_id(id);
  379. if (fd < 0)
  380. return fd;
  381. ret = bpf_obj_get_info_by_fd(fd, &info, &ilen);
  382. if (ret < 0)
  383. goto out;
  384. ret = -ENOENT;
  385. if (info.name[0]) {
  386. get_prog_full_name(&info, fd, name, len);
  387. ret = 0;
  388. }
  389. out:
  390. close(fd);
  391. return ret;
  392. }
  393. static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
  394. const enum bpf_attach_type loc)
  395. {
  396. __u32 prog_flags[64] = {}, link_flags[64] = {}, i, j;
  397. __u32 prog_ids[64] = {}, link_ids[64] = {};
  398. LIBBPF_OPTS(bpf_prog_query_opts, optq);
  399. char prog_name[MAX_PROG_FULL_NAME];
  400. int ret;
  401. optq.prog_ids = prog_ids;
  402. optq.prog_attach_flags = prog_flags;
  403. optq.link_ids = link_ids;
  404. optq.link_attach_flags = link_flags;
  405. optq.count = ARRAY_SIZE(prog_ids);
  406. ret = bpf_prog_query_opts(dev->ifindex, loc, &optq);
  407. if (ret)
  408. return;
  409. for (i = 0; i < optq.count; i++) {
  410. NET_START_OBJECT;
  411. NET_DUMP_STR("devname", "%s", dev->devname);
  412. NET_DUMP_UINT("ifindex", "(%u)", (unsigned int)dev->ifindex);
  413. NET_DUMP_STR("kind", " %s", attach_loc_strings[loc]);
  414. ret = __show_dev_tc_bpf_name(prog_ids[i], prog_name,
  415. sizeof(prog_name));
  416. if (!ret)
  417. NET_DUMP_STR("name", " %s", prog_name);
  418. NET_DUMP_UINT("prog_id", " prog_id %u ", prog_ids[i]);
  419. if (prog_flags[i] || json_output) {
  420. NET_START_ARRAY("prog_flags", "%s ");
  421. for (j = 0; prog_flags[i] && j < 32; j++) {
  422. if (!(prog_flags[i] & (1U << j)))
  423. continue;
  424. NET_DUMP_UINT_ONLY(1U << j);
  425. }
  426. NET_END_ARRAY("");
  427. }
  428. if (link_ids[i] || json_output) {
  429. NET_DUMP_UINT("link_id", "link_id %u ", link_ids[i]);
  430. if (link_flags[i] || json_output) {
  431. NET_START_ARRAY("link_flags", "%s ");
  432. for (j = 0; link_flags[i] && j < 32; j++) {
  433. if (!(link_flags[i] & (1U << j)))
  434. continue;
  435. NET_DUMP_UINT_ONLY(1U << j);
  436. }
  437. NET_END_ARRAY("");
  438. }
  439. }
  440. NET_END_OBJECT_FINAL;
  441. }
  442. }
  443. static void show_dev_tc_bpf(struct ip_devname_ifindex *dev)
  444. {
  445. __show_dev_tc_bpf(dev, BPF_TCX_INGRESS);
  446. __show_dev_tc_bpf(dev, BPF_TCX_EGRESS);
  447. __show_dev_tc_bpf(dev, BPF_NETKIT_PRIMARY);
  448. __show_dev_tc_bpf(dev, BPF_NETKIT_PEER);
  449. }
  450. static int show_dev_tc_bpf_classic(int sock, unsigned int nl_pid,
  451. struct ip_devname_ifindex *dev)
  452. {
  453. struct bpf_filter_t filter_info;
  454. struct bpf_tcinfo_t tcinfo;
  455. int i, handle, ret = 0;
  456. tcinfo.handle_array = NULL;
  457. tcinfo.used_len = 0;
  458. tcinfo.array_len = 0;
  459. tcinfo.is_qdisc = false;
  460. ret = netlink_get_class(sock, nl_pid, dev->ifindex,
  461. dump_class_qdisc_nlmsg, &tcinfo);
  462. if (ret)
  463. goto out;
  464. tcinfo.is_qdisc = true;
  465. ret = netlink_get_qdisc(sock, nl_pid, dev->ifindex,
  466. dump_class_qdisc_nlmsg, &tcinfo);
  467. if (ret)
  468. goto out;
  469. filter_info.devname = dev->devname;
  470. filter_info.ifindex = dev->ifindex;
  471. for (i = 0; i < tcinfo.used_len; i++) {
  472. filter_info.kind = tcinfo.handle_array[i].kind;
  473. ret = netlink_get_filter(sock, nl_pid, dev->ifindex,
  474. tcinfo.handle_array[i].handle,
  475. dump_filter_nlmsg, &filter_info);
  476. if (ret)
  477. goto out;
  478. }
  479. /* root, ingress and egress handle */
  480. handle = TC_H_ROOT;
  481. filter_info.kind = "root";
  482. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  483. dump_filter_nlmsg, &filter_info);
  484. if (ret)
  485. goto out;
  486. handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
  487. filter_info.kind = "clsact/ingress";
  488. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  489. dump_filter_nlmsg, &filter_info);
  490. if (ret)
  491. goto out;
  492. handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS);
  493. filter_info.kind = "clsact/egress";
  494. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  495. dump_filter_nlmsg, &filter_info);
  496. if (ret)
  497. goto out;
  498. out:
  499. free(tcinfo.handle_array);
  500. return 0;
  501. }
  502. static int query_flow_dissector(struct bpf_attach_info *attach_info)
  503. {
  504. __u32 attach_flags;
  505. __u32 prog_ids[1];
  506. __u32 prog_cnt;
  507. int err;
  508. int fd;
  509. fd = open("/proc/self/ns/net", O_RDONLY);
  510. if (fd < 0) {
  511. p_err("can't open /proc/self/ns/net: %s",
  512. strerror(errno));
  513. return -1;
  514. }
  515. prog_cnt = ARRAY_SIZE(prog_ids);
  516. err = bpf_prog_query(fd, BPF_FLOW_DISSECTOR, 0,
  517. &attach_flags, prog_ids, &prog_cnt);
  518. close(fd);
  519. if (err) {
  520. if (errno == EINVAL) {
  521. /* Older kernel's don't support querying
  522. * flow dissector programs.
  523. */
  524. errno = 0;
  525. return 0;
  526. }
  527. p_err("can't query prog: %s", strerror(errno));
  528. return -1;
  529. }
  530. if (prog_cnt == 1)
  531. attach_info->flow_dissector_id = prog_ids[0];
  532. return 0;
  533. }
  534. static int net_parse_dev(int *argc, char ***argv)
  535. {
  536. int ifindex;
  537. if (is_prefix(**argv, "dev")) {
  538. NEXT_ARGP();
  539. ifindex = if_nametoindex(**argv);
  540. if (!ifindex)
  541. p_err("invalid devname %s", **argv);
  542. NEXT_ARGP();
  543. } else {
  544. p_err("expected 'dev', got: '%s'?", **argv);
  545. return -1;
  546. }
  547. return ifindex;
  548. }
  549. static int do_attach_detach_xdp(int progfd, enum net_attach_type attach_type,
  550. int ifindex, bool overwrite)
  551. {
  552. __u32 flags = 0;
  553. if (!overwrite)
  554. flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
  555. if (attach_type == NET_ATTACH_TYPE_XDP_GENERIC)
  556. flags |= XDP_FLAGS_SKB_MODE;
  557. if (attach_type == NET_ATTACH_TYPE_XDP_DRIVER)
  558. flags |= XDP_FLAGS_DRV_MODE;
  559. if (attach_type == NET_ATTACH_TYPE_XDP_OFFLOAD)
  560. flags |= XDP_FLAGS_HW_MODE;
  561. return bpf_xdp_attach(ifindex, progfd, flags, NULL);
  562. }
  563. static int get_tcx_type(enum net_attach_type attach_type)
  564. {
  565. switch (attach_type) {
  566. case NET_ATTACH_TYPE_TCX_INGRESS:
  567. return BPF_TCX_INGRESS;
  568. case NET_ATTACH_TYPE_TCX_EGRESS:
  569. return BPF_TCX_EGRESS;
  570. default:
  571. return -1;
  572. }
  573. }
  574. static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex, bool prepend)
  575. {
  576. int type = get_tcx_type(attach_type);
  577. if (prepend) {
  578. LIBBPF_OPTS(bpf_prog_attach_opts, opts,
  579. .flags = BPF_F_BEFORE
  580. );
  581. return bpf_prog_attach_opts(progfd, ifindex, type, &opts);
  582. }
  583. return bpf_prog_attach(progfd, ifindex, type, 0);
  584. }
  585. static int do_detach_tcx(int targetfd, enum net_attach_type attach_type)
  586. {
  587. int type = get_tcx_type(attach_type);
  588. return bpf_prog_detach(targetfd, type);
  589. }
  590. static int do_attach(int argc, char **argv)
  591. {
  592. enum net_attach_type attach_type;
  593. int progfd, ifindex, err = 0;
  594. bool overwrite = false;
  595. bool prepend = false;
  596. /* parse attach args */
  597. if (!REQ_ARGS(5))
  598. return -EINVAL;
  599. attach_type = parse_attach_type(*argv);
  600. if (attach_type == net_attach_type_size) {
  601. p_err("invalid net attach/detach type: %s", *argv);
  602. return -EINVAL;
  603. }
  604. NEXT_ARG();
  605. progfd = prog_parse_fd(&argc, &argv);
  606. if (progfd < 0)
  607. return -EINVAL;
  608. ifindex = net_parse_dev(&argc, &argv);
  609. if (ifindex < 1) {
  610. err = -EINVAL;
  611. goto cleanup;
  612. }
  613. if (argc) {
  614. if (is_prefix(*argv, "overwrite")) {
  615. if (attach_type != NET_ATTACH_TYPE_XDP &&
  616. attach_type != NET_ATTACH_TYPE_XDP_GENERIC &&
  617. attach_type != NET_ATTACH_TYPE_XDP_DRIVER &&
  618. attach_type != NET_ATTACH_TYPE_XDP_OFFLOAD) {
  619. p_err("'overwrite' is only supported for xdp types");
  620. err = -EINVAL;
  621. goto cleanup;
  622. }
  623. overwrite = true;
  624. } else if (is_prefix(*argv, "prepend")) {
  625. if (attach_type != NET_ATTACH_TYPE_TCX_INGRESS &&
  626. attach_type != NET_ATTACH_TYPE_TCX_EGRESS) {
  627. p_err("'prepend' is only supported for tcx_ingress/tcx_egress");
  628. err = -EINVAL;
  629. goto cleanup;
  630. }
  631. prepend = true;
  632. } else {
  633. p_err("expected 'overwrite' or 'prepend', got: '%s'?", *argv);
  634. err = -EINVAL;
  635. goto cleanup;
  636. }
  637. }
  638. switch (attach_type) {
  639. /* attach xdp prog */
  640. case NET_ATTACH_TYPE_XDP:
  641. case NET_ATTACH_TYPE_XDP_GENERIC:
  642. case NET_ATTACH_TYPE_XDP_DRIVER:
  643. case NET_ATTACH_TYPE_XDP_OFFLOAD:
  644. err = do_attach_detach_xdp(progfd, attach_type, ifindex, overwrite);
  645. break;
  646. /* attach tcx prog */
  647. case NET_ATTACH_TYPE_TCX_INGRESS:
  648. case NET_ATTACH_TYPE_TCX_EGRESS:
  649. err = do_attach_tcx(progfd, attach_type, ifindex, prepend);
  650. break;
  651. default:
  652. break;
  653. }
  654. if (err) {
  655. p_err("interface %s attach failed: %s",
  656. attach_type_strings[attach_type], strerror(-err));
  657. goto cleanup;
  658. }
  659. if (json_output)
  660. jsonw_null(json_wtr);
  661. cleanup:
  662. close(progfd);
  663. return err;
  664. }
  665. static int do_detach(int argc, char **argv)
  666. {
  667. enum net_attach_type attach_type;
  668. int progfd, ifindex, err = 0;
  669. /* parse detach args */
  670. if (!REQ_ARGS(3))
  671. return -EINVAL;
  672. attach_type = parse_attach_type(*argv);
  673. if (attach_type == net_attach_type_size) {
  674. p_err("invalid net attach/detach type: %s", *argv);
  675. return -EINVAL;
  676. }
  677. NEXT_ARG();
  678. ifindex = net_parse_dev(&argc, &argv);
  679. if (ifindex < 1)
  680. return -EINVAL;
  681. switch (attach_type) {
  682. /* detach xdp prog */
  683. case NET_ATTACH_TYPE_XDP:
  684. case NET_ATTACH_TYPE_XDP_GENERIC:
  685. case NET_ATTACH_TYPE_XDP_DRIVER:
  686. case NET_ATTACH_TYPE_XDP_OFFLOAD:
  687. progfd = -1;
  688. err = do_attach_detach_xdp(progfd, attach_type, ifindex, NULL);
  689. break;
  690. /* detach tcx prog */
  691. case NET_ATTACH_TYPE_TCX_INGRESS:
  692. case NET_ATTACH_TYPE_TCX_EGRESS:
  693. err = do_detach_tcx(ifindex, attach_type);
  694. break;
  695. default:
  696. break;
  697. }
  698. if (err < 0) {
  699. p_err("interface %s detach failed: %s",
  700. attach_type_strings[attach_type], strerror(-err));
  701. return err;
  702. }
  703. if (json_output)
  704. jsonw_null(json_wtr);
  705. return 0;
  706. }
  707. static int netfilter_link_compar(const void *a, const void *b)
  708. {
  709. const struct bpf_link_info *nfa = a;
  710. const struct bpf_link_info *nfb = b;
  711. int delta;
  712. delta = nfa->netfilter.pf - nfb->netfilter.pf;
  713. if (delta)
  714. return delta;
  715. delta = nfa->netfilter.hooknum - nfb->netfilter.hooknum;
  716. if (delta)
  717. return delta;
  718. if (nfa->netfilter.priority < nfb->netfilter.priority)
  719. return -1;
  720. if (nfa->netfilter.priority > nfb->netfilter.priority)
  721. return 1;
  722. return nfa->netfilter.flags - nfb->netfilter.flags;
  723. }
  724. static void show_link_netfilter(void)
  725. {
  726. unsigned int nf_link_len = 0, nf_link_count = 0;
  727. struct bpf_link_info *nf_link_info = NULL;
  728. __u32 id = 0;
  729. while (true) {
  730. struct bpf_link_info info;
  731. int fd, err;
  732. __u32 len;
  733. err = bpf_link_get_next_id(id, &id);
  734. if (err) {
  735. if (errno == ENOENT)
  736. break;
  737. p_err("can't get next link: %s (id %u)", strerror(errno), id);
  738. break;
  739. }
  740. fd = bpf_link_get_fd_by_id(id);
  741. if (fd < 0) {
  742. p_err("can't get link by id (%u): %s", id, strerror(errno));
  743. continue;
  744. }
  745. memset(&info, 0, sizeof(info));
  746. len = sizeof(info);
  747. err = bpf_link_get_info_by_fd(fd, &info, &len);
  748. close(fd);
  749. if (err) {
  750. p_err("can't get link info for fd %d: %s", fd, strerror(errno));
  751. continue;
  752. }
  753. if (info.type != BPF_LINK_TYPE_NETFILTER)
  754. continue;
  755. if (nf_link_count >= nf_link_len) {
  756. static const unsigned int max_link_count = INT_MAX / sizeof(info);
  757. struct bpf_link_info *expand;
  758. if (nf_link_count > max_link_count) {
  759. p_err("cannot handle more than %u links\n", max_link_count);
  760. break;
  761. }
  762. nf_link_len += 16;
  763. expand = realloc(nf_link_info, nf_link_len * sizeof(info));
  764. if (!expand) {
  765. p_err("realloc: %s", strerror(errno));
  766. break;
  767. }
  768. nf_link_info = expand;
  769. }
  770. nf_link_info[nf_link_count] = info;
  771. nf_link_count++;
  772. }
  773. if (!nf_link_info)
  774. return;
  775. qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar);
  776. for (id = 0; id < nf_link_count; id++) {
  777. NET_START_OBJECT;
  778. if (json_output)
  779. netfilter_dump_json(&nf_link_info[id], json_wtr);
  780. else
  781. netfilter_dump_plain(&nf_link_info[id]);
  782. NET_DUMP_UINT("id", " prog_id %u", nf_link_info[id].prog_id);
  783. NET_END_OBJECT;
  784. }
  785. free(nf_link_info);
  786. }
  787. static int do_show(int argc, char **argv)
  788. {
  789. struct bpf_attach_info attach_info = {};
  790. int i, sock, ret, filter_idx = -1;
  791. struct bpf_netdev_t dev_array;
  792. unsigned int nl_pid = 0;
  793. char err_buf[256];
  794. if (argc == 2) {
  795. filter_idx = net_parse_dev(&argc, &argv);
  796. if (filter_idx < 1)
  797. return -1;
  798. } else if (argc != 0) {
  799. usage();
  800. }
  801. ret = query_flow_dissector(&attach_info);
  802. if (ret)
  803. return -1;
  804. sock = netlink_open(&nl_pid);
  805. if (sock < 0) {
  806. fprintf(stderr, "failed to open netlink sock\n");
  807. return -1;
  808. }
  809. dev_array.devices = NULL;
  810. dev_array.used_len = 0;
  811. dev_array.array_len = 0;
  812. dev_array.filter_idx = filter_idx;
  813. if (json_output)
  814. jsonw_start_array(json_wtr);
  815. NET_START_OBJECT;
  816. NET_START_ARRAY("xdp", "%s:\n");
  817. ret = netlink_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array);
  818. NET_END_ARRAY("\n");
  819. if (!ret) {
  820. NET_START_ARRAY("tc", "%s:\n");
  821. for (i = 0; i < dev_array.used_len; i++) {
  822. show_dev_tc_bpf(&dev_array.devices[i]);
  823. ret = show_dev_tc_bpf_classic(sock, nl_pid,
  824. &dev_array.devices[i]);
  825. if (ret)
  826. break;
  827. }
  828. NET_END_ARRAY("\n");
  829. }
  830. NET_START_ARRAY("flow_dissector", "%s:\n");
  831. if (attach_info.flow_dissector_id > 0)
  832. NET_DUMP_UINT("id", "id %u", attach_info.flow_dissector_id);
  833. NET_END_ARRAY("\n");
  834. NET_START_ARRAY("netfilter", "%s:\n");
  835. show_link_netfilter();
  836. NET_END_ARRAY("\n");
  837. NET_END_OBJECT;
  838. if (json_output)
  839. jsonw_end_array(json_wtr);
  840. if (ret) {
  841. if (json_output)
  842. jsonw_null(json_wtr);
  843. libbpf_strerror(ret, err_buf, sizeof(err_buf));
  844. fprintf(stderr, "Error: %s\n", err_buf);
  845. }
  846. free(dev_array.devices);
  847. close(sock);
  848. return ret;
  849. }
  850. static int do_help(int argc, char **argv)
  851. {
  852. if (json_output) {
  853. jsonw_null(json_wtr);
  854. return 0;
  855. }
  856. fprintf(stderr,
  857. "Usage: %1$s %2$s { show | list } [dev <devname>]\n"
  858. " %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite | prepend ]\n"
  859. " %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
  860. " %1$s %2$s help\n"
  861. "\n"
  862. " " HELP_SPEC_PROGRAM "\n"
  863. " ATTACH_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload | tcx_ingress\n"
  864. " | tcx_egress }\n"
  865. " " HELP_SPEC_OPTIONS " }\n"
  866. "\n"
  867. "Note: Only xdp, tcx, tc, netkit, flow_dissector and netfilter attachments\n"
  868. " are currently supported.\n"
  869. " For progs attached to cgroups, use \"bpftool cgroup\"\n"
  870. " to dump program attachments. For program types\n"
  871. " sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
  872. " consult iproute2.\n"
  873. "",
  874. bin_name, argv[-2]);
  875. return 0;
  876. }
  877. static const struct cmd cmds[] = {
  878. { "show", do_show },
  879. { "list", do_show },
  880. { "attach", do_attach },
  881. { "detach", do_detach },
  882. { "help", do_help },
  883. { 0 }
  884. };
  885. int do_net(int argc, char **argv)
  886. {
  887. return cmd_select(cmds, argc, argv, do_help);
  888. }