net.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. // Copyright (C) 2018 Facebook
  3. #define _GNU_SOURCE
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <time.h>
  9. #include <unistd.h>
  10. #include <bpf/bpf.h>
  11. #include <bpf/libbpf.h>
  12. #include <net/if.h>
  13. #include <linux/rtnetlink.h>
  14. #include <linux/socket.h>
  15. #include <linux/tc_act/tc_bpf.h>
  16. #include <sys/socket.h>
  17. #include <sys/stat.h>
  18. #include <sys/types.h>
  19. #include "bpf/nlattr.h"
  20. #include "main.h"
  21. #include "netlink_dumper.h"
  22. #ifndef SOL_NETLINK
  23. #define SOL_NETLINK 270
  24. #endif
  25. struct ip_devname_ifindex {
  26. char devname[64];
  27. int ifindex;
  28. };
  29. struct bpf_netdev_t {
  30. struct ip_devname_ifindex *devices;
  31. int used_len;
  32. int array_len;
  33. int filter_idx;
  34. };
  35. struct tc_kind_handle {
  36. char kind[64];
  37. int handle;
  38. };
  39. struct bpf_tcinfo_t {
  40. struct tc_kind_handle *handle_array;
  41. int used_len;
  42. int array_len;
  43. bool is_qdisc;
  44. };
  45. struct bpf_filter_t {
  46. const char *kind;
  47. const char *devname;
  48. int ifindex;
  49. };
  50. struct bpf_attach_info {
  51. __u32 flow_dissector_id;
  52. };
  53. enum net_attach_type {
  54. NET_ATTACH_TYPE_XDP,
  55. NET_ATTACH_TYPE_XDP_GENERIC,
  56. NET_ATTACH_TYPE_XDP_DRIVER,
  57. NET_ATTACH_TYPE_XDP_OFFLOAD,
  58. };
  59. static const char * const attach_type_strings[] = {
  60. [NET_ATTACH_TYPE_XDP] = "xdp",
  61. [NET_ATTACH_TYPE_XDP_GENERIC] = "xdpgeneric",
  62. [NET_ATTACH_TYPE_XDP_DRIVER] = "xdpdrv",
  63. [NET_ATTACH_TYPE_XDP_OFFLOAD] = "xdpoffload",
  64. };
  65. const size_t net_attach_type_size = ARRAY_SIZE(attach_type_strings);
  66. static enum net_attach_type parse_attach_type(const char *str)
  67. {
  68. enum net_attach_type type;
  69. for (type = 0; type < net_attach_type_size; type++) {
  70. if (attach_type_strings[type] &&
  71. is_prefix(str, attach_type_strings[type]))
  72. return type;
  73. }
  74. return net_attach_type_size;
  75. }
  76. typedef int (*dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
  77. typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, dump_nlmsg_t, void *cookie);
  78. static int netlink_open(__u32 *nl_pid)
  79. {
  80. struct sockaddr_nl sa;
  81. socklen_t addrlen;
  82. int one = 1, ret;
  83. int sock;
  84. memset(&sa, 0, sizeof(sa));
  85. sa.nl_family = AF_NETLINK;
  86. sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  87. if (sock < 0)
  88. return -errno;
  89. if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
  90. &one, sizeof(one)) < 0) {
  91. p_err("Netlink error reporting not supported");
  92. }
  93. if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
  94. ret = -errno;
  95. goto cleanup;
  96. }
  97. addrlen = sizeof(sa);
  98. if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
  99. ret = -errno;
  100. goto cleanup;
  101. }
  102. if (addrlen != sizeof(sa)) {
  103. ret = -LIBBPF_ERRNO__INTERNAL;
  104. goto cleanup;
  105. }
  106. *nl_pid = sa.nl_pid;
  107. return sock;
  108. cleanup:
  109. close(sock);
  110. return ret;
  111. }
  112. static int netlink_recv(int sock, __u32 nl_pid, __u32 seq,
  113. __dump_nlmsg_t _fn, dump_nlmsg_t fn,
  114. void *cookie)
  115. {
  116. bool multipart = true;
  117. struct nlmsgerr *err;
  118. struct nlmsghdr *nh;
  119. char buf[4096];
  120. int len, ret;
  121. while (multipart) {
  122. multipart = false;
  123. len = recv(sock, buf, sizeof(buf), 0);
  124. if (len < 0) {
  125. ret = -errno;
  126. goto done;
  127. }
  128. if (len == 0)
  129. break;
  130. for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, (unsigned int)len);
  131. nh = NLMSG_NEXT(nh, len)) {
  132. if (nh->nlmsg_pid != nl_pid) {
  133. ret = -LIBBPF_ERRNO__WRNGPID;
  134. goto done;
  135. }
  136. if (nh->nlmsg_seq != seq) {
  137. ret = -LIBBPF_ERRNO__INVSEQ;
  138. goto done;
  139. }
  140. if (nh->nlmsg_flags & NLM_F_MULTI)
  141. multipart = true;
  142. switch (nh->nlmsg_type) {
  143. case NLMSG_ERROR:
  144. err = (struct nlmsgerr *)NLMSG_DATA(nh);
  145. if (!err->error)
  146. continue;
  147. ret = err->error;
  148. libbpf_nla_dump_errormsg(nh);
  149. goto done;
  150. case NLMSG_DONE:
  151. return 0;
  152. default:
  153. break;
  154. }
  155. if (_fn) {
  156. ret = _fn(nh, fn, cookie);
  157. if (ret)
  158. return ret;
  159. }
  160. }
  161. }
  162. ret = 0;
  163. done:
  164. return ret;
  165. }
  166. static int __dump_class_nlmsg(struct nlmsghdr *nlh,
  167. dump_nlmsg_t dump_class_nlmsg,
  168. void *cookie)
  169. {
  170. struct nlattr *tb[TCA_MAX + 1], *attr;
  171. struct tcmsg *t = NLMSG_DATA(nlh);
  172. int len;
  173. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  174. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  175. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  176. return -LIBBPF_ERRNO__NLPARSE;
  177. return dump_class_nlmsg(cookie, t, tb);
  178. }
  179. static int netlink_get_class(int sock, unsigned int nl_pid, int ifindex,
  180. dump_nlmsg_t dump_class_nlmsg, void *cookie)
  181. {
  182. struct {
  183. struct nlmsghdr nlh;
  184. struct tcmsg t;
  185. } req = {
  186. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  187. .nlh.nlmsg_type = RTM_GETTCLASS,
  188. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  189. .t.tcm_family = AF_UNSPEC,
  190. .t.tcm_ifindex = ifindex,
  191. };
  192. int seq = time(NULL);
  193. req.nlh.nlmsg_seq = seq;
  194. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  195. return -errno;
  196. return netlink_recv(sock, nl_pid, seq, __dump_class_nlmsg,
  197. dump_class_nlmsg, cookie);
  198. }
  199. static int __dump_qdisc_nlmsg(struct nlmsghdr *nlh,
  200. dump_nlmsg_t dump_qdisc_nlmsg,
  201. void *cookie)
  202. {
  203. struct nlattr *tb[TCA_MAX + 1], *attr;
  204. struct tcmsg *t = NLMSG_DATA(nlh);
  205. int len;
  206. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  207. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  208. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  209. return -LIBBPF_ERRNO__NLPARSE;
  210. return dump_qdisc_nlmsg(cookie, t, tb);
  211. }
  212. static int netlink_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
  213. dump_nlmsg_t dump_qdisc_nlmsg, void *cookie)
  214. {
  215. struct {
  216. struct nlmsghdr nlh;
  217. struct tcmsg t;
  218. } req = {
  219. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  220. .nlh.nlmsg_type = RTM_GETQDISC,
  221. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  222. .t.tcm_family = AF_UNSPEC,
  223. .t.tcm_ifindex = ifindex,
  224. };
  225. int seq = time(NULL);
  226. req.nlh.nlmsg_seq = seq;
  227. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  228. return -errno;
  229. return netlink_recv(sock, nl_pid, seq, __dump_qdisc_nlmsg,
  230. dump_qdisc_nlmsg, cookie);
  231. }
  232. static int __dump_filter_nlmsg(struct nlmsghdr *nlh,
  233. dump_nlmsg_t dump_filter_nlmsg,
  234. void *cookie)
  235. {
  236. struct nlattr *tb[TCA_MAX + 1], *attr;
  237. struct tcmsg *t = NLMSG_DATA(nlh);
  238. int len;
  239. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*t));
  240. attr = (struct nlattr *) ((void *) t + NLMSG_ALIGN(sizeof(*t)));
  241. if (libbpf_nla_parse(tb, TCA_MAX, attr, len, NULL) != 0)
  242. return -LIBBPF_ERRNO__NLPARSE;
  243. return dump_filter_nlmsg(cookie, t, tb);
  244. }
  245. static int netlink_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
  246. dump_nlmsg_t dump_filter_nlmsg, void *cookie)
  247. {
  248. struct {
  249. struct nlmsghdr nlh;
  250. struct tcmsg t;
  251. } req = {
  252. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
  253. .nlh.nlmsg_type = RTM_GETTFILTER,
  254. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  255. .t.tcm_family = AF_UNSPEC,
  256. .t.tcm_ifindex = ifindex,
  257. .t.tcm_parent = handle,
  258. };
  259. int seq = time(NULL);
  260. req.nlh.nlmsg_seq = seq;
  261. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  262. return -errno;
  263. return netlink_recv(sock, nl_pid, seq, __dump_filter_nlmsg,
  264. dump_filter_nlmsg, cookie);
  265. }
  266. static int __dump_link_nlmsg(struct nlmsghdr *nlh,
  267. dump_nlmsg_t dump_link_nlmsg, void *cookie)
  268. {
  269. struct nlattr *tb[IFLA_MAX + 1], *attr;
  270. struct ifinfomsg *ifi = NLMSG_DATA(nlh);
  271. int len;
  272. len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
  273. attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
  274. if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
  275. return -LIBBPF_ERRNO__NLPARSE;
  276. return dump_link_nlmsg(cookie, ifi, tb);
  277. }
  278. static int netlink_get_link(int sock, unsigned int nl_pid,
  279. dump_nlmsg_t dump_link_nlmsg, void *cookie)
  280. {
  281. struct {
  282. struct nlmsghdr nlh;
  283. struct ifinfomsg ifm;
  284. } req = {
  285. .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
  286. .nlh.nlmsg_type = RTM_GETLINK,
  287. .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
  288. .ifm.ifi_family = AF_PACKET,
  289. };
  290. int seq = time(NULL);
  291. req.nlh.nlmsg_seq = seq;
  292. if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
  293. return -errno;
  294. return netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
  295. dump_link_nlmsg, cookie);
  296. }
  297. static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  298. {
  299. struct bpf_netdev_t *netinfo = cookie;
  300. struct ifinfomsg *ifinfo = msg;
  301. if (netinfo->filter_idx > 0 && netinfo->filter_idx != ifinfo->ifi_index)
  302. return 0;
  303. if (netinfo->used_len == netinfo->array_len) {
  304. netinfo->devices = realloc(netinfo->devices,
  305. (netinfo->array_len + 16) *
  306. sizeof(struct ip_devname_ifindex));
  307. if (!netinfo->devices)
  308. return -ENOMEM;
  309. netinfo->array_len += 16;
  310. }
  311. netinfo->devices[netinfo->used_len].ifindex = ifinfo->ifi_index;
  312. snprintf(netinfo->devices[netinfo->used_len].devname,
  313. sizeof(netinfo->devices[netinfo->used_len].devname),
  314. "%s",
  315. tb[IFLA_IFNAME]
  316. ? libbpf_nla_getattr_str(tb[IFLA_IFNAME])
  317. : "");
  318. netinfo->used_len++;
  319. return do_xdp_dump(ifinfo, tb);
  320. }
  321. static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  322. {
  323. struct bpf_tcinfo_t *tcinfo = cookie;
  324. struct tcmsg *info = msg;
  325. if (tcinfo->is_qdisc) {
  326. /* skip clsact qdisc */
  327. if (tb[TCA_KIND] &&
  328. strcmp(libbpf_nla_data(tb[TCA_KIND]), "clsact") == 0)
  329. return 0;
  330. if (info->tcm_handle == 0)
  331. return 0;
  332. }
  333. if (tcinfo->used_len == tcinfo->array_len) {
  334. tcinfo->handle_array = realloc(tcinfo->handle_array,
  335. (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle));
  336. if (!tcinfo->handle_array)
  337. return -ENOMEM;
  338. tcinfo->array_len += 16;
  339. }
  340. tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle;
  341. snprintf(tcinfo->handle_array[tcinfo->used_len].kind,
  342. sizeof(tcinfo->handle_array[tcinfo->used_len].kind),
  343. "%s",
  344. tb[TCA_KIND]
  345. ? libbpf_nla_getattr_str(tb[TCA_KIND])
  346. : "unknown");
  347. tcinfo->used_len++;
  348. return 0;
  349. }
  350. static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb)
  351. {
  352. const struct bpf_filter_t *filter_info = cookie;
  353. return do_filter_dump((struct tcmsg *)msg, tb, filter_info->kind,
  354. filter_info->devname, filter_info->ifindex);
  355. }
  356. static int show_dev_tc_bpf(int sock, unsigned int nl_pid,
  357. struct ip_devname_ifindex *dev)
  358. {
  359. struct bpf_filter_t filter_info;
  360. struct bpf_tcinfo_t tcinfo;
  361. int i, handle, ret = 0;
  362. tcinfo.handle_array = NULL;
  363. tcinfo.used_len = 0;
  364. tcinfo.array_len = 0;
  365. tcinfo.is_qdisc = false;
  366. ret = netlink_get_class(sock, nl_pid, dev->ifindex,
  367. dump_class_qdisc_nlmsg, &tcinfo);
  368. if (ret)
  369. goto out;
  370. tcinfo.is_qdisc = true;
  371. ret = netlink_get_qdisc(sock, nl_pid, dev->ifindex,
  372. dump_class_qdisc_nlmsg, &tcinfo);
  373. if (ret)
  374. goto out;
  375. filter_info.devname = dev->devname;
  376. filter_info.ifindex = dev->ifindex;
  377. for (i = 0; i < tcinfo.used_len; i++) {
  378. filter_info.kind = tcinfo.handle_array[i].kind;
  379. ret = netlink_get_filter(sock, nl_pid, dev->ifindex,
  380. tcinfo.handle_array[i].handle,
  381. dump_filter_nlmsg, &filter_info);
  382. if (ret)
  383. goto out;
  384. }
  385. /* root, ingress and egress handle */
  386. handle = TC_H_ROOT;
  387. filter_info.kind = "root";
  388. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  389. dump_filter_nlmsg, &filter_info);
  390. if (ret)
  391. goto out;
  392. handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
  393. filter_info.kind = "clsact/ingress";
  394. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  395. dump_filter_nlmsg, &filter_info);
  396. if (ret)
  397. goto out;
  398. handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS);
  399. filter_info.kind = "clsact/egress";
  400. ret = netlink_get_filter(sock, nl_pid, dev->ifindex, handle,
  401. dump_filter_nlmsg, &filter_info);
  402. if (ret)
  403. goto out;
  404. out:
  405. free(tcinfo.handle_array);
  406. return 0;
  407. }
  408. static int query_flow_dissector(struct bpf_attach_info *attach_info)
  409. {
  410. __u32 attach_flags;
  411. __u32 prog_ids[1];
  412. __u32 prog_cnt;
  413. int err;
  414. int fd;
  415. fd = open("/proc/self/ns/net", O_RDONLY);
  416. if (fd < 0) {
  417. p_err("can't open /proc/self/ns/net: %s",
  418. strerror(errno));
  419. return -1;
  420. }
  421. prog_cnt = ARRAY_SIZE(prog_ids);
  422. err = bpf_prog_query(fd, BPF_FLOW_DISSECTOR, 0,
  423. &attach_flags, prog_ids, &prog_cnt);
  424. close(fd);
  425. if (err) {
  426. if (errno == EINVAL) {
  427. /* Older kernel's don't support querying
  428. * flow dissector programs.
  429. */
  430. errno = 0;
  431. return 0;
  432. }
  433. p_err("can't query prog: %s", strerror(errno));
  434. return -1;
  435. }
  436. if (prog_cnt == 1)
  437. attach_info->flow_dissector_id = prog_ids[0];
  438. return 0;
  439. }
  440. static int net_parse_dev(int *argc, char ***argv)
  441. {
  442. int ifindex;
  443. if (is_prefix(**argv, "dev")) {
  444. NEXT_ARGP();
  445. ifindex = if_nametoindex(**argv);
  446. if (!ifindex)
  447. p_err("invalid devname %s", **argv);
  448. NEXT_ARGP();
  449. } else {
  450. p_err("expected 'dev', got: '%s'?", **argv);
  451. return -1;
  452. }
  453. return ifindex;
  454. }
  455. static int do_attach_detach_xdp(int progfd, enum net_attach_type attach_type,
  456. int ifindex, bool overwrite)
  457. {
  458. __u32 flags = 0;
  459. if (!overwrite)
  460. flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
  461. if (attach_type == NET_ATTACH_TYPE_XDP_GENERIC)
  462. flags |= XDP_FLAGS_SKB_MODE;
  463. if (attach_type == NET_ATTACH_TYPE_XDP_DRIVER)
  464. flags |= XDP_FLAGS_DRV_MODE;
  465. if (attach_type == NET_ATTACH_TYPE_XDP_OFFLOAD)
  466. flags |= XDP_FLAGS_HW_MODE;
  467. return bpf_xdp_attach(ifindex, progfd, flags, NULL);
  468. }
  469. static int do_attach(int argc, char **argv)
  470. {
  471. enum net_attach_type attach_type;
  472. int progfd, ifindex, err = 0;
  473. bool overwrite = false;
  474. /* parse attach args */
  475. if (!REQ_ARGS(5))
  476. return -EINVAL;
  477. attach_type = parse_attach_type(*argv);
  478. if (attach_type == net_attach_type_size) {
  479. p_err("invalid net attach/detach type: %s", *argv);
  480. return -EINVAL;
  481. }
  482. NEXT_ARG();
  483. progfd = prog_parse_fd(&argc, &argv);
  484. if (progfd < 0)
  485. return -EINVAL;
  486. ifindex = net_parse_dev(&argc, &argv);
  487. if (ifindex < 1) {
  488. err = -EINVAL;
  489. goto cleanup;
  490. }
  491. if (argc) {
  492. if (is_prefix(*argv, "overwrite")) {
  493. overwrite = true;
  494. } else {
  495. p_err("expected 'overwrite', got: '%s'?", *argv);
  496. err = -EINVAL;
  497. goto cleanup;
  498. }
  499. }
  500. /* attach xdp prog */
  501. if (is_prefix("xdp", attach_type_strings[attach_type]))
  502. err = do_attach_detach_xdp(progfd, attach_type, ifindex,
  503. overwrite);
  504. if (err) {
  505. p_err("interface %s attach failed: %s",
  506. attach_type_strings[attach_type], strerror(-err));
  507. goto cleanup;
  508. }
  509. if (json_output)
  510. jsonw_null(json_wtr);
  511. cleanup:
  512. close(progfd);
  513. return err;
  514. }
  515. static int do_detach(int argc, char **argv)
  516. {
  517. enum net_attach_type attach_type;
  518. int progfd, ifindex, err = 0;
  519. /* parse detach args */
  520. if (!REQ_ARGS(3))
  521. return -EINVAL;
  522. attach_type = parse_attach_type(*argv);
  523. if (attach_type == net_attach_type_size) {
  524. p_err("invalid net attach/detach type: %s", *argv);
  525. return -EINVAL;
  526. }
  527. NEXT_ARG();
  528. ifindex = net_parse_dev(&argc, &argv);
  529. if (ifindex < 1)
  530. return -EINVAL;
  531. /* detach xdp prog */
  532. progfd = -1;
  533. if (is_prefix("xdp", attach_type_strings[attach_type]))
  534. err = do_attach_detach_xdp(progfd, attach_type, ifindex, NULL);
  535. if (err < 0) {
  536. p_err("interface %s detach failed: %s",
  537. attach_type_strings[attach_type], strerror(-err));
  538. return err;
  539. }
  540. if (json_output)
  541. jsonw_null(json_wtr);
  542. return 0;
  543. }
  544. static int do_show(int argc, char **argv)
  545. {
  546. struct bpf_attach_info attach_info = {};
  547. int i, sock, ret, filter_idx = -1;
  548. struct bpf_netdev_t dev_array;
  549. unsigned int nl_pid = 0;
  550. char err_buf[256];
  551. if (argc == 2) {
  552. filter_idx = net_parse_dev(&argc, &argv);
  553. if (filter_idx < 1)
  554. return -1;
  555. } else if (argc != 0) {
  556. usage();
  557. }
  558. ret = query_flow_dissector(&attach_info);
  559. if (ret)
  560. return -1;
  561. sock = netlink_open(&nl_pid);
  562. if (sock < 0) {
  563. fprintf(stderr, "failed to open netlink sock\n");
  564. return -1;
  565. }
  566. dev_array.devices = NULL;
  567. dev_array.used_len = 0;
  568. dev_array.array_len = 0;
  569. dev_array.filter_idx = filter_idx;
  570. if (json_output)
  571. jsonw_start_array(json_wtr);
  572. NET_START_OBJECT;
  573. NET_START_ARRAY("xdp", "%s:\n");
  574. ret = netlink_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array);
  575. NET_END_ARRAY("\n");
  576. if (!ret) {
  577. NET_START_ARRAY("tc", "%s:\n");
  578. for (i = 0; i < dev_array.used_len; i++) {
  579. ret = show_dev_tc_bpf(sock, nl_pid,
  580. &dev_array.devices[i]);
  581. if (ret)
  582. break;
  583. }
  584. NET_END_ARRAY("\n");
  585. }
  586. NET_START_ARRAY("flow_dissector", "%s:\n");
  587. if (attach_info.flow_dissector_id > 0)
  588. NET_DUMP_UINT("id", "id %u", attach_info.flow_dissector_id);
  589. NET_END_ARRAY("\n");
  590. NET_END_OBJECT;
  591. if (json_output)
  592. jsonw_end_array(json_wtr);
  593. if (ret) {
  594. if (json_output)
  595. jsonw_null(json_wtr);
  596. libbpf_strerror(ret, err_buf, sizeof(err_buf));
  597. fprintf(stderr, "Error: %s\n", err_buf);
  598. }
  599. free(dev_array.devices);
  600. close(sock);
  601. return ret;
  602. }
  603. static int do_help(int argc, char **argv)
  604. {
  605. if (json_output) {
  606. jsonw_null(json_wtr);
  607. return 0;
  608. }
  609. fprintf(stderr,
  610. "Usage: %1$s %2$s { show | list } [dev <devname>]\n"
  611. " %1$s %2$s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
  612. " %1$s %2$s detach ATTACH_TYPE dev <devname>\n"
  613. " %1$s %2$s help\n"
  614. "\n"
  615. " " HELP_SPEC_PROGRAM "\n"
  616. " ATTACH_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload }\n"
  617. " " HELP_SPEC_OPTIONS " }\n"
  618. "\n"
  619. "Note: Only xdp and tc attachments are supported now.\n"
  620. " For progs attached to cgroups, use \"bpftool cgroup\"\n"
  621. " to dump program attachments. For program types\n"
  622. " sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
  623. " consult iproute2.\n"
  624. "",
  625. bin_name, argv[-2]);
  626. return 0;
  627. }
  628. static const struct cmd cmds[] = {
  629. { "show", do_show },
  630. { "list", do_show },
  631. { "attach", do_attach },
  632. { "detach", do_detach },
  633. { "help", do_help },
  634. { 0 }
  635. };
  636. int do_net(int argc, char **argv)
  637. {
  638. return cmd_select(cmds, argc, argv, do_help);
  639. }