net.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  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[4096];
  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. }
  174. ret = 0;
  175. done:
  176. return ret;
  177. }
  178. static int __dump_class_nlmsg(struct nlmsghdr *nlh,
  179. dump_nlmsg_t dump_class_nlmsg,
  180. void *cookie)
  181. {
  182. struct nlattr *tb[TCA_MAX + 1], *attr;
  183. struct tcmsg *t = NLMSG_DATA(nlh);
  184. int len;
  185. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  186. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  187. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  188. return -LIBBPF_ERRNO__NLPARSE;
  189. return dump_class_nlmsg(cookie, t, tb);
  190. }
  191. static int netlink_get_class(int sock, unsigned int nl_pid, int ifindex,
  192. dump_nlmsg_t dump_class_nlmsg, void *cookie)
  193. {
  194. struct {
  195. struct nlmsghdr nlh;
  196. struct tcmsg t;
  197. } req = {
  198. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  199. .nlh.nlmsg_type = RTM_GETTCLASS,
  200. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  201. .t.tcm_family = AF_UNSPEC,
  202. .t.tcm_ifindex = ifindex,
  203. };
  204. int seq = time(NULL);
  205. req.nlh.nlmsg_seq = seq;
  206. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  207. return -errno;
  208. return netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg,
  209. dump_class_nlmsg, cookie);
  210. }
  211. static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh,
  212. dump_nlmsg_t dump_qdisc_nlmsg,
  213. void *cookie)
  214. {
  215. struct nlattr *tb[TCA_MAX + 1], *attr;
  216. struct tcmsg *t = NLMSG_DATA(nlh);
  217. int len;
  218. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  219. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  220. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  221. return -LIBBPF_ERRNO__NLPARSE;
  222. return dump_qdisc_nlmsg(cookie, t, tb);
  223. }
  224. static int netlink_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
  225. dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
  226. {
  227. struct {
  228. struct nlmsghdr nlh;
  229. struct tcmsg t;
  230. } req = {
  231. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  232. .nlh.nlmsg_type = RTM_GETQDISC,
  233. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  234. .t.tcm_family = AF_UNSPEC,
  235. .t.tcm_ifindex = ifindex,
  236. };
  237. int seq = time(NULL);
  238. req.nlh.nlmsg_seq = seq;
  239. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  240. return -errno;
  241. return netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg,
  242. dump_qdisc_nlmsg, cookie);
  243. }
  244. static int __dump_filter_nlmsg(struct nlmsghdr *nlh,
  245. dump_nlmsg_t dump_filter_nlmsg,
  246. void *cookie)
  247. {
  248. struct nlattr *tb[TCA_MAX + 1], *attr;
  249. struct tcmsg *t = NLMSG_DATA(nlh);
  250. int len;
  251. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  252. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  253. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  254. return -LIBBPF_ERRNO__NLPARSE;
  255. return dump_filter_nlmsg(cookie, t, tb);
  256. }
  257. static int netlink_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
  258. dump_nlmsg_t dump_filter_nlmsg, void *cookie)
  259. {
  260. struct {
  261. struct nlmsghdr nlh;
  262. struct tcmsg t;
  263. } req = {
  264. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  265. .nlh.nlmsg_type = RTM_GETTFILTER,
  266. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  267. .t.tcm_family = AF_UNSPEC,
  268. .t.tcm_ifindex = ifindex,
  269. .t.tcm_parent = handle,
  270. };
  271. int seq = time(NULL);
  272. req.nlh.nlmsg_seq = seq;
  273. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  274. return -errno;
  275. return netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg,
  276. dump_filter_nlmsg, cookie);
  277. }
  278. static int __dump_link_nlmsg(struct nlmsghdr *nlh,
  279. dump_nlmsg_t dump_link_nlmsg, void *cookie)
  280. {
  281. struct nlattr *tb[IFLA_MAX + 1], *attr;
  282. struct ifinfomsg *ifi = NLMSG_DATA(nlh);
  283. int len;
  284. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
  285. attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
  286. if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
  287. return -LIBBPF_ERRNO__NLPARSE;
  288. return dump_link_nlmsg(cookie, ifi, tb);
  289. }
  290. static int netlink_get_link(int sock, unsigned int nl_pid,
  291. dump_nlmsg_t dump_link_nlmsg, void *cookie)
  292. {
  293. struct {
  294. struct nlmsghdr nlh;
  295. struct ifinfomsg ifm;
  296. } req = {
  297. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  298. .nlh.nlmsg_type = RTM_GETLINK,
  299. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  300. .ifm.ifi_family = AF_PACKET,
  301. };
  302. int seq = time(NULL);
  303. req.nlh.nlmsg_seq = seq;
  304. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  305. return -errno;
  306. return netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
  307. dump_link_nlmsg, cookie);
  308. }
  309. static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  310. {
  311. struct bpf_netdev_t *netinfo = cookie;
  312. struct ifinfomsg *ifinfo = msg;
  313. struct ip_devname_ifindex *tmp;
  314. if (netinfo->filter_idx > 0 && netinfo->filter_idx != ifinfo->ifi_index)
  315. return 0;
  316. if (netinfo->used_len == netinfo->array_len) {
  317. tmp = realloc(netinfo->devices,
  318. (netinfo->array_len + 16) * sizeof(struct ip_devname_ifindex));
  319. if (!tmp)
  320. return -ENOMEM;
  321. netinfo->devices = tmp;
  322. netinfo->array_len += 16;
  323. }
  324. netinfo->devices[netinfo->used_len].ifindex = ifinfo->ifi_index;
  325. snprintf(netinfo->devices[netinfo->used_len].devname,
  326. sizeof(netinfo->devices[netinfo->used_len].devname),
  327. "%s",
  328. tb[IFLA_IFNAME]
  329. ? libbpf_nla_getattr_str(tb[IFLA_IFNAME])
  330. : "");
  331. netinfo->used_len++;
  332. return do_xdp_dump(ifinfo, tb);
  333. }
  334. static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  335. {
  336. struct bpf_tcinfo_t *tcinfo = cookie;
  337. struct tcmsg *info = msg;
  338. struct tc_kind_handle *tmp;
  339. if (tcinfo->is_qdisc) {
  340. /* skip clsact qdisc */
  341. if (tb[TCA_KIND] &&
  342. strcmp(libbpf_nla_data(tb[TCA_KIND]), "clsact") == 0)
  343. return 0;
  344. if (info->tcm_handle == 0)
  345. return 0;
  346. }
  347. if (tcinfo->used_len == tcinfo->array_len) {
  348. tmp = realloc(tcinfo->handle_array,
  349. (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle));
  350. if (!tmp)
  351. return -ENOMEM;
  352. tcinfo->handle_array = tmp;
  353. tcinfo->array_len += 16;
  354. }
  355. tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle;
  356. snprintf(tcinfo->handle_array[tcinfo->used_len].kind,
  357. sizeof(tcinfo->handle_array[tcinfo->used_len].kind),
  358. "%s",
  359. tb[TCA_KIND]
  360. ? libbpf_nla_getattr_str(tb[TCA_KIND])
  361. : "unknown");
  362. tcinfo->used_len++;
  363. return 0;
  364. }
  365. static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  366. {
  367. const struct bpf_filter_t *filter_info = cookie;
  368. return do_filter_dump((struct tcmsg *)msg, tb, filter_info->kind,
  369. filter_info->devname, filter_info->ifindex);
  370. }
  371. static int __show_dev_tc_bpf_name(__u32 id, char *name, size_t len)
  372. {
  373. struct bpf_prog_info info = {};
  374. __u32 ilen = sizeof(info);
  375. int fd, ret;
  376. fd = bpf_prog_get_fd_by_id(id);
  377. if (fd < 0)
  378. return fd;
  379. ret = bpf_obj_get_info_by_fd(fd, &info, &ilen);
  380. if (ret < 0)
  381. goto out;
  382. ret = -ENOENT;
  383. if (info.name[0]) {
  384. get_prog_full_name(&info, fd, name, len);
  385. ret = 0;
  386. }
  387. out:
  388. close(fd);
  389. return ret;
  390. }
  391. static void __show_dev_tc_bpf(const struct ip_devname_ifindex *dev,
  392. const enum bpf_attach_type loc)
  393. {
  394. __u32 prog_flags[64] = {}, link_flags[64] = {}, i, j;
  395. __u32 prog_ids[64] = {}, link_ids[64] = {};
  396. LIBBPF_OPTS(bpf_prog_query_opts, optq);
  397. char prog_name[MAX_PROG_FULL_NAME];
  398. int ret;
  399. optq.prog_ids = prog_ids;
  400. optq.prog_attach_flags = prog_flags;
  401. optq.link_ids = link_ids;
  402. optq.link_attach_flags = link_flags;
  403. optq.count = ARRAY_SIZE(prog_ids);
  404. ret = bpf_prog_query_opts(dev->ifindex, loc, &optq);
  405. if (ret)
  406. return;
  407. for (i = 0; i < optq.count; i++) {
  408. NET_START_OBJECT;
  409. NET_DUMP_STR("devname", "%s", dev->devname);
  410. NET_DUMP_UINT("ifindex", "(%u)", dev->ifindex);
  411. NET_DUMP_STR("kind", " %s", attach_loc_strings[loc]);
  412. ret = __show_dev_tc_bpf_name(prog_ids[i], prog_name,
  413. sizeof(prog_name));
  414. if (!ret)
  415. NET_DUMP_STR("name", " %s", prog_name);
  416. NET_DUMP_UINT("prog_id", " prog_id %u ", prog_ids[i]);
  417. if (prog_flags[i] || json_output) {
  418. NET_START_ARRAY("prog_flags", "%s ");
  419. for (j = 0; prog_flags[i] && j < 32; j++) {
  420. if (!(prog_flags[i] & (1U << j)))
  421. continue;
  422. NET_DUMP_UINT_ONLY(1U << j);
  423. }
  424. NET_END_ARRAY("");
  425. }
  426. if (link_ids[i] || json_output) {
  427. NET_DUMP_UINT("link_id", "link_id %u ", link_ids[i]);
  428. if (link_flags[i] || json_output) {
  429. NET_START_ARRAY("link_flags", "%s ");
  430. for (j = 0; link_flags[i] && j < 32; j++) {
  431. if (!(link_flags[i] & (1U << j)))
  432. continue;
  433. NET_DUMP_UINT_ONLY(1U << j);
  434. }
  435. NET_END_ARRAY("");
  436. }
  437. }
  438. NET_END_OBJECT_FINAL;
  439. }
  440. }
  441. static void show_dev_tc_bpf(struct ip_devname_ifindex *dev)
  442. {
  443. __show_dev_tc_bpf(dev, BPF_TCX_INGRESS);
  444. __show_dev_tc_bpf(dev, BPF_TCX_EGRESS);
  445. __show_dev_tc_bpf(dev, BPF_NETKIT_PRIMARY);
  446. __show_dev_tc_bpf(dev, BPF_NETKIT_PEER);
  447. }
  448. static int show_dev_tc_bpf_classic(int sock, unsigned int nl_pid,
  449. struct ip_devname_ifindex *dev)
  450. {
  451. struct bpf_filter_t filter_info;
  452. struct bpf_tcinfo_t tcinfo;
  453. int i, handle, ret = 0;
  454. tcinfo.handle_array = NULL;
  455. tcinfo.used_len = 0;
  456. tcinfo.array_len = 0;
  457. tcinfo.is_qdisc = false;
  458. ret = netlink_get_class(sock, nl_pid, dev->ifindex,
  459. dump_class_qdisc_nlmsg, &tcinfo);
  460. if (ret)
  461. goto out;
  462. tcinfo.is_qdisc = true;
  463. ret = netlink_get_qdisc(sock, nl_pid, dev->ifindex,
  464. dump_class_qdisc_nlmsg, &tcinfo);
  465. if (ret)
  466. goto out;
  467. filter_info.devname = dev->devname;
  468. filter_info.ifindex = dev->ifindex;
  469. for (i = 0; i < tcinfo.used_len; i++) {
  470. filter_info.kind = tcinfo.handle_array[i].kind;
  471. ret = netlink_get_filter(sock, nl_pid, dev->ifindex,
  472. tcinfo.handle_array[i].handle,
  473. dump_filter_nlmsg, &filter_info);
  474. if (ret)
  475. goto out;
  476. }
  477. /* root, ingress and egress handle */
  478. handle = TC_H_ROOT;
  479. filter_info.kind = "root";
  480. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  481. dump_filter_nlmsg, &filter_info);
  482. if (ret)
  483. goto out;
  484. handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
  485. filter_info.kind = "clsact/ingress";
  486. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  487. dump_filter_nlmsg, &filter_info);
  488. if (ret)
  489. goto out;
  490. handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS);
  491. filter_info.kind = "clsact/egress";
  492. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  493. dump_filter_nlmsg, &filter_info);
  494. if (ret)
  495. goto out;
  496. out:
  497. free(tcinfo.handle_array);
  498. return 0;
  499. }
  500. static int query_flow_dissector(struct bpf_attach_info *attach_info)
  501. {
  502. __u32 attach_flags;
  503. __u32 prog_ids[1];
  504. __u32 prog_cnt;
  505. int err;
  506. int fd;
  507. fd = open("/proc/self/ns/net", O_RDONLY);
  508. if (fd < 0) {
  509. p_err("can't open /proc/self/ns/net: %s",
  510. strerror(errno));
  511. return -1;
  512. }
  513. prog_cnt = ARRAY_SIZE(prog_ids);
  514. err = bpf_prog_query(fd, BPF_FLOW_DISSECTOR, 0,
  515. &attach_flags, prog_ids, &prog_cnt);
  516. close(fd);
  517. if (err) {
  518. if (errno == EINVAL) {
  519. /* Older kernel's don't support querying
  520. * flow dissector programs.
  521. */
  522. errno = 0;
  523. return 0;
  524. }
  525. p_err("can't query prog: %s", strerror(errno));
  526. return -1;
  527. }
  528. if (prog_cnt == 1)
  529. attach_info->flow_dissector_id = prog_ids[0];
  530. return 0;
  531. }
  532. static int net_parse_dev(int *argc, char ***argv)
  533. {
  534. int ifindex;
  535. if (is_prefix(**argv, "dev")) {
  536. NEXT_ARGP();
  537. ifindex = if_nametoindex(**argv);
  538. if (!ifindex)
  539. p_err("invalid devname %s", **argv);
  540. NEXT_ARGP();
  541. } else {
  542. p_err("expected 'dev', got: '%s'?", **argv);
  543. return -1;
  544. }
  545. return ifindex;
  546. }
  547. static int do_attach_detach_xdp(int progfd, enum net_attach_type attach_type,
  548. int ifindex, bool overwrite)
  549. {
  550. __u32 flags = 0;
  551. if (!overwrite)
  552. flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
  553. if (attach_type == NET_ATTACH_TYPE_XDP_GENERIC)
  554. flags |= XDP_FLAGS_SKB_MODE;
  555. if (attach_type == NET_ATTACH_TYPE_XDP_DRIVER)
  556. flags |= XDP_FLAGS_DRV_MODE;
  557. if (attach_type == NET_ATTACH_TYPE_XDP_OFFLOAD)
  558. flags |= XDP_FLAGS_HW_MODE;
  559. return bpf_xdp_attach(ifindex, progfd, flags, NULL);
  560. }
  561. static int get_tcx_type(enum net_attach_type attach_type)
  562. {
  563. switch (attach_type) {
  564. case NET_ATTACH_TYPE_TCX_INGRESS:
  565. return BPF_TCX_INGRESS;
  566. case NET_ATTACH_TYPE_TCX_EGRESS:
  567. return BPF_TCX_EGRESS;
  568. default:
  569. return -1;
  570. }
  571. }
  572. static int do_attach_tcx(int progfd, enum net_attach_type attach_type, int ifindex)
  573. {
  574. int type = get_tcx_type(attach_type);
  575. return bpf_prog_attach(progfd, ifindex, type, 0);
  576. }
  577. static int do_detach_tcx(int targetfd, enum net_attach_type attach_type)
  578. {
  579. int type = get_tcx_type(attach_type);
  580. return bpf_prog_detach(targetfd, type);
  581. }
  582. static int do_attach(int argc, char **argv)
  583. {
  584. enum net_attach_type attach_type;
  585. int progfd, ifindex, err = 0;
  586. bool overwrite = false;
  587. /* parse attach args */
  588. if (!REQ_ARGS(5))
  589. return -EINVAL;
  590. attach_type = parse_attach_type(*argv);
  591. if (attach_type == net_attach_type_size) {
  592. p_err("invalid net attach/detach type: %s", *argv);
  593. return -EINVAL;
  594. }
  595. NEXT_ARG();
  596. progfd = prog_parse_fd(&argc, &argv);
  597. if (progfd < 0)
  598. return -EINVAL;
  599. ifindex = net_parse_dev(&argc, &argv);
  600. if (ifindex < 1) {
  601. err = -EINVAL;
  602. goto cleanup;
  603. }
  604. if (argc) {
  605. if (is_prefix(*argv, "overwrite")) {
  606. overwrite = true;
  607. } else {
  608. p_err("expected 'overwrite', got: '%s'?", *argv);
  609. err = -EINVAL;
  610. goto cleanup;
  611. }
  612. }
  613. switch (attach_type) {
  614. /* attach xdp prog */
  615. case NET_ATTACH_TYPE_XDP:
  616. case NET_ATTACH_TYPE_XDP_GENERIC:
  617. case NET_ATTACH_TYPE_XDP_DRIVER:
  618. case NET_ATTACH_TYPE_XDP_OFFLOAD:
  619. err = do_attach_detach_xdp(progfd, attach_type, ifindex, overwrite);
  620. break;
  621. /* attach tcx prog */
  622. case NET_ATTACH_TYPE_TCX_INGRESS:
  623. case NET_ATTACH_TYPE_TCX_EGRESS:
  624. err = do_attach_tcx(progfd, attach_type, ifindex);
  625. break;
  626. default:
  627. break;
  628. }
  629. if (err) {
  630. p_err("interface %s attach failed: %s",
  631. attach_type_strings[attach_type], strerror(-err));
  632. goto cleanup;
  633. }
  634. if (json_output)
  635. jsonw_null(json_wtr);
  636. cleanup:
  637. close(progfd);
  638. return err;
  639. }
  640. static int do_detach(int argc, char **argv)
  641. {
  642. enum net_attach_type attach_type;
  643. int progfd, ifindex, err = 0;
  644. /* parse detach args */
  645. if (!REQ_ARGS(3))
  646. return -EINVAL;
  647. attach_type = parse_attach_type(*argv);
  648. if (attach_type == net_attach_type_size) {
  649. p_err("invalid net attach/detach type: %s", *argv);
  650. return -EINVAL;
  651. }
  652. NEXT_ARG();
  653. ifindex = net_parse_dev(&argc, &argv);
  654. if (ifindex < 1)
  655. return -EINVAL;
  656. switch (attach_type) {
  657. /* detach xdp prog */
  658. case NET_ATTACH_TYPE_XDP:
  659. case NET_ATTACH_TYPE_XDP_GENERIC:
  660. case NET_ATTACH_TYPE_XDP_DRIVER:
  661. case NET_ATTACH_TYPE_XDP_OFFLOAD:
  662. progfd = -1;
  663. err = do_attach_detach_xdp(progfd, attach_type, ifindex, NULL);
  664. break;
  665. /* detach tcx prog */
  666. case NET_ATTACH_TYPE_TCX_INGRESS:
  667. case NET_ATTACH_TYPE_TCX_EGRESS:
  668. err = do_detach_tcx(ifindex, attach_type);
  669. break;
  670. default:
  671. break;
  672. }
  673. if (err < 0) {
  674. p_err("interface %s detach failed: %s",
  675. attach_type_strings[attach_type], strerror(-err));
  676. return err;
  677. }
  678. if (json_output)
  679. jsonw_null(json_wtr);
  680. return 0;
  681. }
  682. static int netfilter_link_compar(const void *a, const void *b)
  683. {
  684. const struct bpf_link_info *nfa = a;
  685. const struct bpf_link_info *nfb = b;
  686. int delta;
  687. delta = nfa->netfilter.pf - nfb->netfilter.pf;
  688. if (delta)
  689. return delta;
  690. delta = nfa->netfilter.hooknum - nfb->netfilter.hooknum;
  691. if (delta)
  692. return delta;
  693. if (nfa->netfilter.priority < nfb->netfilter.priority)
  694. return -1;
  695. if (nfa->netfilter.priority > nfb->netfilter.priority)
  696. return 1;
  697. return nfa->netfilter.flags - nfb->netfilter.flags;
  698. }
  699. static void show_link_netfilter(void)
  700. {
  701. unsigned int nf_link_len = 0, nf_link_count = 0;
  702. struct bpf_link_info *nf_link_info = NULL;
  703. __u32 id = 0;
  704. while (true) {
  705. struct bpf_link_info info;
  706. int fd, err;
  707. __u32 len;
  708. err = bpf_link_get_next_id(id, &id);
  709. if (err) {
  710. if (errno == ENOENT)
  711. break;
  712. p_err("can't get next link: %s (id %d)", strerror(errno), id);
  713. break;
  714. }
  715. fd = bpf_link_get_fd_by_id(id);
  716. if (fd < 0) {
  717. p_err("can't get link by id (%u): %s", id, strerror(errno));
  718. continue;
  719. }
  720. memset(&info, 0, sizeof(info));
  721. len = sizeof(info);
  722. err = bpf_link_get_info_by_fd(fd, &info, &len);
  723. close(fd);
  724. if (err) {
  725. p_err("can't get link info for fd %d: %s", fd, strerror(errno));
  726. continue;
  727. }
  728. if (info.type != BPF_LINK_TYPE_NETFILTER)
  729. continue;
  730. if (nf_link_count >= nf_link_len) {
  731. static const unsigned int max_link_count = INT_MAX / sizeof(info);
  732. struct bpf_link_info *expand;
  733. if (nf_link_count > max_link_count) {
  734. p_err("cannot handle more than %u links\n", max_link_count);
  735. break;
  736. }
  737. nf_link_len += 16;
  738. expand = realloc(nf_link_info, nf_link_len * sizeof(info));
  739. if (!expand) {
  740. p_err("realloc: %s", strerror(errno));
  741. break;
  742. }
  743. nf_link_info = expand;
  744. }
  745. nf_link_info[nf_link_count] = info;
  746. nf_link_count++;
  747. }
  748. if (!nf_link_info)
  749. return;
  750. qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar);
  751. for (id = 0; id < nf_link_count; id++) {
  752. NET_START_OBJECT;
  753. if (json_output)
  754. netfilter_dump_json(&nf_link_info[id], json_wtr);
  755. else
  756. netfilter_dump_plain(&nf_link_info[id]);
  757. NET_DUMP_UINT("id", " prog_id %u", nf_link_info[id].prog_id);
  758. NET_END_OBJECT;
  759. }
  760. free(nf_link_info);
  761. }
  762. static int do_show(int argc, char **argv)
  763. {
  764. struct bpf_attach_info attach_info = {};
  765. int i, sock, ret, filter_idx = -1;
  766. struct bpf_netdev_t dev_array;
  767. unsigned int nl_pid = 0;
  768. char err_buf[256];
  769. if (argc == 2) {
  770. filter_idx = net_parse_dev(&argc, &argv);
  771. if (filter_idx < 1)
  772. return -1;
  773. } else if (argc != 0) {
  774. usage();
  775. }
  776. ret = query_flow_dissector(&attach_info);
  777. if (ret)
  778. return -1;
  779. sock = netlink_open(&nl_pid);
  780. if (sock < 0) {
  781. fprintf(stderr, "failed to open netlink sock\n");
  782. return -1;
  783. }
  784. dev_array.devices = NULL;
  785. dev_array.used_len = 0;
  786. dev_array.array_len = 0;
  787. dev_array.filter_idx = filter_idx;
  788. if (json_output)
  789. jsonw_start_array(json_wtr);
  790. NET_START_OBJECT;
  791. NET_START_ARRAY("xdp", "%s:\n");
  792. ret = netlink_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array);
  793. NET_END_ARRAY("\n");
  794. if (!ret) {
  795. NET_START_ARRAY("tc", "%s:\n");
  796. for (i = 0; i < dev_array.used_len; i++) {
  797. show_dev_tc_bpf(&dev_array.devices[i]);
  798. ret = show_dev_tc_bpf_classic(sock, nl_pid,
  799. &dev_array.devices[i]);
  800. if (ret)
  801. break;
  802. }
  803. NET_END_ARRAY("\n");
  804. }
  805. NET_START_ARRAY("flow_dissector", "%s:\n");
  806. if (attach_info.flow_dissector_id > 0)
  807. NET_DUMP_UINT("id", "id %u", attach_info.flow_dissector_id);
  808. NET_END_ARRAY("\n");
  809. NET_START_ARRAY("netfilter", "%s:\n");
  810. show_link_netfilter();
  811. NET_END_ARRAY("\n");
  812. NET_END_OBJECT;
  813. if (json_output)
  814. jsonw_end_array(json_wtr);
  815. if (ret) {
  816. if (json_output)
  817. jsonw_null(json_wtr);
  818. libbpf_strerror(ret, err_buf, sizeof(err_buf));
  819. fprintf(stderr, "Error: %s\n", err_buf);
  820. }
  821. free(dev_array.devices);
  822. close(sock);
  823. return ret;
  824. }
  825. static int do_help(int argc, char **argv)
  826. {
  827. if (json_output) {
  828. jsonw_null(json_wtr);
  829. return 0;
  830. }
  831. fprintf(stderr,
  832. "Usage: %1$s %2$s { show | list } [dev <devname>]\n"
  833. " %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
  834. " %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
  835. " %1$s %2$s help\n"
  836. "\n"
  837. " " HELP_SPEC_PROGRAM "\n"
  838. " ATTACH_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload | tcx_ingress\n"
  839. " | tcx_egress }\n"
  840. " " HELP_SPEC_OPTIONS " }\n"
  841. "\n"
  842. "Note: Only xdp, tcx, tc, netkit, flow_dissector and netfilter attachments\n"
  843. " are currently supported.\n"
  844. " For progs attached to cgroups, use \"bpftool cgroup\"\n"
  845. " to dump program attachments. For program types\n"
  846. " sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
  847. " consult iproute2.\n"
  848. "",
  849. bin_name, argv[-2]);
  850. return 0;
  851. }
  852. static const struct cmd cmds[] = {
  853. { "show", do_show },
  854. { "list", do_show },
  855. { "attach", do_attach },
  856. { "detach", do_detach },
  857. { "help", do_help },
  858. { 0 }
  859. };
  860. int do_net(int argc, char **argv)
  861. {
  862. return cmd_select(cmds, argc, argv, do_help);
  863. }