common.c 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
  3. #define _GNU_SOURCE
  4. #include <ctype.h>
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <ftw.h>
  8. #include <libgen.h>
  9. #include <mntent.h>
  10. #include <stdbool.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #include <net/if.h>
  16. #include <sys/mount.h>
  17. #include <sys/resource.h>
  18. #include <sys/stat.h>
  19. #include <sys/vfs.h>
  20. #include <linux/filter.h>
  21. #include <linux/limits.h>
  22. #include <linux/magic.h>
  23. #include <linux/unistd.h>
  24. #include <bpf/bpf.h>
  25. #include <bpf/hashmap.h>
  26. #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
  27. #include <bpf/btf.h>
  28. #include "main.h"
  29. #ifndef BPF_FS_MAGIC
  30. #define BPF_FS_MAGIC 0xcafe4a11
  31. #endif
  32. void p_err(const char *fmt, ...)
  33. {
  34. va_list ap;
  35. va_start(ap, fmt);
  36. if (json_output) {
  37. jsonw_start_object(json_wtr);
  38. jsonw_name(json_wtr, "error");
  39. jsonw_vprintf_enquote(json_wtr, fmt, ap);
  40. jsonw_end_object(json_wtr);
  41. } else {
  42. fprintf(stderr, "Error: ");
  43. vfprintf(stderr, fmt, ap);
  44. fprintf(stderr, "\n");
  45. }
  46. va_end(ap);
  47. }
  48. void p_info(const char *fmt, ...)
  49. {
  50. va_list ap;
  51. if (json_output)
  52. return;
  53. va_start(ap, fmt);
  54. vfprintf(stderr, fmt, ap);
  55. fprintf(stderr, "\n");
  56. va_end(ap);
  57. }
  58. static bool is_bpffs(char *path)
  59. {
  60. struct statfs st_fs;
  61. if (statfs(path, &st_fs) < 0)
  62. return false;
  63. return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
  64. }
  65. /* Probe whether kernel switched from memlock-based (RLIMIT_MEMLOCK) to
  66. * memcg-based memory accounting for BPF maps and programs. This was done in
  67. * commit 97306be45fbe ("Merge branch 'switch to memcg-based memory
  68. * accounting'"), in Linux 5.11.
  69. *
  70. * Libbpf also offers to probe for memcg-based accounting vs rlimit, but does
  71. * so by checking for the availability of a given BPF helper and this has
  72. * failed on some kernels with backports in the past, see commit 6b4384ff1088
  73. * ("Revert "bpftool: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK"").
  74. * Instead, we can probe by lowering the process-based rlimit to 0, trying to
  75. * load a BPF object, and resetting the rlimit. If the load succeeds then
  76. * memcg-based accounting is supported.
  77. *
  78. * This would be too dangerous to do in the library, because multithreaded
  79. * applications might attempt to load items while the rlimit is at 0. Given
  80. * that bpftool is single-threaded, this is fine to do here.
  81. */
  82. static bool known_to_need_rlimit(void)
  83. {
  84. struct rlimit rlim_init, rlim_cur_zero = {};
  85. struct bpf_insn insns[] = {
  86. BPF_MOV64_IMM(BPF_REG_0, 0),
  87. BPF_EXIT_INSN(),
  88. };
  89. size_t insn_cnt = ARRAY_SIZE(insns);
  90. union bpf_attr attr;
  91. int prog_fd, err;
  92. memset(&attr, 0, sizeof(attr));
  93. attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
  94. attr.insns = ptr_to_u64(insns);
  95. attr.insn_cnt = insn_cnt;
  96. attr.license = ptr_to_u64("GPL");
  97. if (getrlimit(RLIMIT_MEMLOCK, &rlim_init))
  98. return false;
  99. /* Drop the soft limit to zero. We maintain the hard limit to its
  100. * current value, because lowering it would be a permanent operation
  101. * for unprivileged users.
  102. */
  103. rlim_cur_zero.rlim_max = rlim_init.rlim_max;
  104. if (setrlimit(RLIMIT_MEMLOCK, &rlim_cur_zero))
  105. return false;
  106. /* Do not use bpf_prog_load() from libbpf here, because it calls
  107. * bump_rlimit_memlock(), interfering with the current probe.
  108. */
  109. prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
  110. err = errno;
  111. /* reset soft rlimit to its initial value */
  112. setrlimit(RLIMIT_MEMLOCK, &rlim_init);
  113. if (prog_fd < 0)
  114. return err == EPERM;
  115. close(prog_fd);
  116. return false;
  117. }
  118. void set_max_rlimit(void)
  119. {
  120. struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
  121. if (known_to_need_rlimit())
  122. setrlimit(RLIMIT_MEMLOCK, &rinf);
  123. }
  124. static int
  125. mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
  126. {
  127. bool bind_done = false;
  128. while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
  129. if (errno != EINVAL || bind_done) {
  130. snprintf(buff, bufflen,
  131. "mount --make-private %s failed: %s",
  132. target, strerror(errno));
  133. return -1;
  134. }
  135. if (mount(target, target, "none", MS_BIND, NULL)) {
  136. snprintf(buff, bufflen,
  137. "mount --bind %s %s failed: %s",
  138. target, target, strerror(errno));
  139. return -1;
  140. }
  141. bind_done = true;
  142. }
  143. if (mount(type, target, type, 0, "mode=0700")) {
  144. snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
  145. type, type, target, strerror(errno));
  146. return -1;
  147. }
  148. return 0;
  149. }
  150. int mount_tracefs(const char *target)
  151. {
  152. char err_str[ERR_MAX_LEN];
  153. int err;
  154. err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
  155. if (err) {
  156. err_str[ERR_MAX_LEN - 1] = '\0';
  157. p_err("can't mount tracefs: %s", err_str);
  158. }
  159. return err;
  160. }
  161. int open_obj_pinned(const char *path, bool quiet)
  162. {
  163. char *pname;
  164. int fd = -1;
  165. pname = strdup(path);
  166. if (!pname) {
  167. if (!quiet)
  168. p_err("mem alloc failed");
  169. goto out_ret;
  170. }
  171. fd = bpf_obj_get(pname);
  172. if (fd < 0) {
  173. if (!quiet)
  174. p_err("bpf obj get (%s): %s", pname,
  175. errno == EACCES && !is_bpffs(dirname(pname)) ?
  176. "directory not in bpf file system (bpffs)" :
  177. strerror(errno));
  178. goto out_free;
  179. }
  180. out_free:
  181. free(pname);
  182. out_ret:
  183. return fd;
  184. }
  185. int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type)
  186. {
  187. enum bpf_obj_type type;
  188. int fd;
  189. fd = open_obj_pinned(path, false);
  190. if (fd < 0)
  191. return -1;
  192. type = get_fd_type(fd);
  193. if (type < 0) {
  194. close(fd);
  195. return type;
  196. }
  197. if (type != exp_type) {
  198. p_err("incorrect object type: %s", get_fd_type_name(type));
  199. close(fd);
  200. return -1;
  201. }
  202. return fd;
  203. }
  204. int mount_bpffs_for_pin(const char *name)
  205. {
  206. char err_str[ERR_MAX_LEN];
  207. char *file;
  208. char *dir;
  209. int err = 0;
  210. file = malloc(strlen(name) + 1);
  211. if (!file) {
  212. p_err("mem alloc failed");
  213. return -1;
  214. }
  215. strcpy(file, name);
  216. dir = dirname(file);
  217. if (is_bpffs(dir))
  218. /* nothing to do if already mounted */
  219. goto out_free;
  220. if (block_mount) {
  221. p_err("no BPF file system found, not mounting it due to --nomount option");
  222. err = -1;
  223. goto out_free;
  224. }
  225. err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
  226. if (err) {
  227. err_str[ERR_MAX_LEN - 1] = '\0';
  228. p_err("can't mount BPF file system to pin the object (%s): %s",
  229. name, err_str);
  230. }
  231. out_free:
  232. free(file);
  233. return err;
  234. }
  235. int do_pin_fd(int fd, const char *name)
  236. {
  237. int err;
  238. err = mount_bpffs_for_pin(name);
  239. if (err)
  240. return err;
  241. err = bpf_obj_pin(fd, name);
  242. if (err)
  243. p_err("can't pin the object (%s): %s", name, strerror(errno));
  244. return err;
  245. }
  246. int do_pin_any(int argc, char **argv, int (*get_fd)(int *, char ***))
  247. {
  248. int err;
  249. int fd;
  250. if (!REQ_ARGS(3))
  251. return -EINVAL;
  252. fd = get_fd(&argc, &argv);
  253. if (fd < 0)
  254. return fd;
  255. err = do_pin_fd(fd, *argv);
  256. close(fd);
  257. return err;
  258. }
  259. const char *get_fd_type_name(enum bpf_obj_type type)
  260. {
  261. static const char * const names[] = {
  262. [BPF_OBJ_UNKNOWN] = "unknown",
  263. [BPF_OBJ_PROG] = "prog",
  264. [BPF_OBJ_MAP] = "map",
  265. [BPF_OBJ_LINK] = "link",
  266. };
  267. if (type < 0 || type >= ARRAY_SIZE(names) || !names[type])
  268. return names[BPF_OBJ_UNKNOWN];
  269. return names[type];
  270. }
  271. void get_prog_full_name(const struct bpf_prog_info *prog_info, int prog_fd,
  272. char *name_buff, size_t buff_len)
  273. {
  274. const char *prog_name = prog_info->name;
  275. const struct btf_type *func_type;
  276. const struct bpf_func_info finfo = {};
  277. struct bpf_prog_info info = {};
  278. __u32 info_len = sizeof(info);
  279. struct btf *prog_btf = NULL;
  280. if (buff_len <= BPF_OBJ_NAME_LEN ||
  281. strlen(prog_info->name) < BPF_OBJ_NAME_LEN - 1)
  282. goto copy_name;
  283. if (!prog_info->btf_id || prog_info->nr_func_info == 0)
  284. goto copy_name;
  285. info.nr_func_info = 1;
  286. info.func_info_rec_size = prog_info->func_info_rec_size;
  287. if (info.func_info_rec_size > sizeof(finfo))
  288. info.func_info_rec_size = sizeof(finfo);
  289. info.func_info = ptr_to_u64(&finfo);
  290. if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len))
  291. goto copy_name;
  292. prog_btf = btf__load_from_kernel_by_id(info.btf_id);
  293. if (!prog_btf)
  294. goto copy_name;
  295. func_type = btf__type_by_id(prog_btf, finfo.type_id);
  296. if (!func_type || !btf_is_func(func_type))
  297. goto copy_name;
  298. prog_name = btf__name_by_offset(prog_btf, func_type->name_off);
  299. copy_name:
  300. snprintf(name_buff, buff_len, "%s", prog_name);
  301. if (prog_btf)
  302. btf__free(prog_btf);
  303. }
  304. int get_fd_type(int fd)
  305. {
  306. char path[PATH_MAX];
  307. char buf[512];
  308. ssize_t n;
  309. snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
  310. n = readlink(path, buf, sizeof(buf));
  311. if (n < 0) {
  312. p_err("can't read link type: %s", strerror(errno));
  313. return -1;
  314. }
  315. if (n == sizeof(path)) {
  316. p_err("can't read link type: path too long!");
  317. return -1;
  318. }
  319. if (strstr(buf, "bpf-map"))
  320. return BPF_OBJ_MAP;
  321. else if (strstr(buf, "bpf-prog"))
  322. return BPF_OBJ_PROG;
  323. else if (strstr(buf, "bpf-link"))
  324. return BPF_OBJ_LINK;
  325. return BPF_OBJ_UNKNOWN;
  326. }
  327. char *get_fdinfo(int fd, const char *key)
  328. {
  329. char path[PATH_MAX];
  330. char *line = NULL;
  331. size_t line_n = 0;
  332. ssize_t n;
  333. FILE *fdi;
  334. snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
  335. fdi = fopen(path, "r");
  336. if (!fdi)
  337. return NULL;
  338. while ((n = getline(&line, &line_n, fdi)) > 0) {
  339. char *value;
  340. int len;
  341. if (!strstr(line, key))
  342. continue;
  343. fclose(fdi);
  344. value = strchr(line, '\t');
  345. if (!value || !value[1]) {
  346. free(line);
  347. return NULL;
  348. }
  349. value++;
  350. len = strlen(value);
  351. memmove(line, value, len);
  352. line[len - 1] = '\0';
  353. return line;
  354. }
  355. free(line);
  356. fclose(fdi);
  357. return NULL;
  358. }
  359. void print_data_json(uint8_t *data, size_t len)
  360. {
  361. unsigned int i;
  362. jsonw_start_array(json_wtr);
  363. for (i = 0; i < len; i++)
  364. jsonw_printf(json_wtr, "%d", data[i]);
  365. jsonw_end_array(json_wtr);
  366. }
  367. void print_hex_data_json(uint8_t *data, size_t len)
  368. {
  369. unsigned int i;
  370. jsonw_start_array(json_wtr);
  371. for (i = 0; i < len; i++)
  372. jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
  373. jsonw_end_array(json_wtr);
  374. }
  375. /* extra params for nftw cb */
  376. static struct hashmap *build_fn_table;
  377. static enum bpf_obj_type build_fn_type;
  378. static int do_build_table_cb(const char *fpath, const struct stat *sb,
  379. int typeflag, struct FTW *ftwbuf)
  380. {
  381. struct bpf_prog_info pinned_info;
  382. __u32 len = sizeof(pinned_info);
  383. enum bpf_obj_type objtype;
  384. int fd, err = 0;
  385. char *path;
  386. if (typeflag != FTW_F)
  387. goto out_ret;
  388. fd = open_obj_pinned(fpath, true);
  389. if (fd < 0)
  390. goto out_ret;
  391. objtype = get_fd_type(fd);
  392. if (objtype != build_fn_type)
  393. goto out_close;
  394. memset(&pinned_info, 0, sizeof(pinned_info));
  395. if (bpf_obj_get_info_by_fd(fd, &pinned_info, &len))
  396. goto out_close;
  397. path = strdup(fpath);
  398. if (!path) {
  399. err = -1;
  400. goto out_close;
  401. }
  402. err = hashmap__append(build_fn_table, u32_as_hash_field(pinned_info.id), path);
  403. if (err) {
  404. p_err("failed to append entry to hashmap for ID %u, path '%s': %s",
  405. pinned_info.id, path, strerror(errno));
  406. free(path);
  407. goto out_close;
  408. }
  409. out_close:
  410. close(fd);
  411. out_ret:
  412. return err;
  413. }
  414. int build_pinned_obj_table(struct hashmap *tab,
  415. enum bpf_obj_type type)
  416. {
  417. struct mntent *mntent = NULL;
  418. FILE *mntfile = NULL;
  419. int flags = FTW_PHYS;
  420. int nopenfd = 16;
  421. int err = 0;
  422. mntfile = setmntent("/proc/mounts", "r");
  423. if (!mntfile)
  424. return -1;
  425. build_fn_table = tab;
  426. build_fn_type = type;
  427. while ((mntent = getmntent(mntfile))) {
  428. char *path = mntent->mnt_dir;
  429. if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
  430. continue;
  431. err = nftw(path, do_build_table_cb, nopenfd, flags);
  432. if (err)
  433. break;
  434. }
  435. fclose(mntfile);
  436. return err;
  437. }
  438. void delete_pinned_obj_table(struct hashmap *map)
  439. {
  440. struct hashmap_entry *entry;
  441. size_t bkt;
  442. if (!map)
  443. return;
  444. hashmap__for_each_entry(map, entry, bkt)
  445. free(entry->value);
  446. hashmap__free(map);
  447. }
  448. unsigned int get_page_size(void)
  449. {
  450. static int result;
  451. if (!result)
  452. result = getpagesize();
  453. return result;
  454. }
  455. unsigned int get_possible_cpus(void)
  456. {
  457. int cpus = libbpf_num_possible_cpus();
  458. if (cpus < 0) {
  459. p_err("Can't get # of possible cpus: %s", strerror(-cpus));
  460. exit(-1);
  461. }
  462. return cpus;
  463. }
  464. static char *
  465. ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
  466. {
  467. struct stat st;
  468. int err;
  469. err = stat("/proc/self/ns/net", &st);
  470. if (err) {
  471. p_err("Can't stat /proc/self: %s", strerror(errno));
  472. return NULL;
  473. }
  474. if (st.st_dev != ns_dev || st.st_ino != ns_ino)
  475. return NULL;
  476. return if_indextoname(ifindex, buf);
  477. }
  478. static int read_sysfs_hex_int(char *path)
  479. {
  480. char vendor_id_buf[8];
  481. int len;
  482. int fd;
  483. fd = open(path, O_RDONLY);
  484. if (fd < 0) {
  485. p_err("Can't open %s: %s", path, strerror(errno));
  486. return -1;
  487. }
  488. len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
  489. close(fd);
  490. if (len < 0) {
  491. p_err("Can't read %s: %s", path, strerror(errno));
  492. return -1;
  493. }
  494. if (len >= (int)sizeof(vendor_id_buf)) {
  495. p_err("Value in %s too long", path);
  496. return -1;
  497. }
  498. vendor_id_buf[len] = 0;
  499. return strtol(vendor_id_buf, NULL, 0);
  500. }
  501. static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
  502. {
  503. char full_path[64];
  504. snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
  505. devname, entry_name);
  506. return read_sysfs_hex_int(full_path);
  507. }
  508. const char *
  509. ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
  510. const char **opt)
  511. {
  512. char devname[IF_NAMESIZE];
  513. int vendor_id;
  514. int device_id;
  515. if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
  516. p_err("Can't get net device name for ifindex %d: %s", ifindex,
  517. strerror(errno));
  518. return NULL;
  519. }
  520. vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
  521. if (vendor_id < 0) {
  522. p_err("Can't get device vendor id for %s", devname);
  523. return NULL;
  524. }
  525. switch (vendor_id) {
  526. case 0x19ee:
  527. device_id = read_sysfs_netdev_hex_int(devname, "device");
  528. if (device_id != 0x4000 &&
  529. device_id != 0x6000 &&
  530. device_id != 0x6003)
  531. p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
  532. *opt = "ctx4";
  533. return "NFP-6xxx";
  534. default:
  535. p_err("Can't get bfd arch name for device vendor id 0x%04x",
  536. vendor_id);
  537. return NULL;
  538. }
  539. }
  540. void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
  541. {
  542. char name[IF_NAMESIZE];
  543. if (!ifindex)
  544. return;
  545. printf(" offloaded_to ");
  546. if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
  547. printf("%s", name);
  548. else
  549. printf("ifindex %u ns_dev %llu ns_ino %llu",
  550. ifindex, ns_dev, ns_inode);
  551. }
  552. void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
  553. {
  554. char name[IF_NAMESIZE];
  555. if (!ifindex)
  556. return;
  557. jsonw_name(json_wtr, "dev");
  558. jsonw_start_object(json_wtr);
  559. jsonw_uint_field(json_wtr, "ifindex", ifindex);
  560. jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
  561. jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
  562. if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
  563. jsonw_string_field(json_wtr, "ifname", name);
  564. jsonw_end_object(json_wtr);
  565. }
  566. int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what)
  567. {
  568. char *endptr;
  569. NEXT_ARGP();
  570. if (*val) {
  571. p_err("%s already specified", what);
  572. return -1;
  573. }
  574. *val = strtoul(**argv, &endptr, 0);
  575. if (*endptr) {
  576. p_err("can't parse %s as %s", **argv, what);
  577. return -1;
  578. }
  579. NEXT_ARGP();
  580. return 0;
  581. }
  582. int __printf(2, 0)
  583. print_all_levels(__maybe_unused enum libbpf_print_level level,
  584. const char *format, va_list args)
  585. {
  586. return vfprintf(stderr, format, args);
  587. }
  588. static int prog_fd_by_nametag(void *nametag, int **fds, bool tag)
  589. {
  590. char prog_name[MAX_PROG_FULL_NAME];
  591. unsigned int id = 0;
  592. int fd, nb_fds = 0;
  593. void *tmp;
  594. int err;
  595. while (true) {
  596. struct bpf_prog_info info = {};
  597. __u32 len = sizeof(info);
  598. err = bpf_prog_get_next_id(id, &id);
  599. if (err) {
  600. if (errno != ENOENT) {
  601. p_err("%s", strerror(errno));
  602. goto err_close_fds;
  603. }
  604. return nb_fds;
  605. }
  606. fd = bpf_prog_get_fd_by_id(id);
  607. if (fd < 0) {
  608. p_err("can't get prog by id (%u): %s",
  609. id, strerror(errno));
  610. goto err_close_fds;
  611. }
  612. err = bpf_obj_get_info_by_fd(fd, &info, &len);
  613. if (err) {
  614. p_err("can't get prog info (%u): %s",
  615. id, strerror(errno));
  616. goto err_close_fd;
  617. }
  618. if (tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) {
  619. close(fd);
  620. continue;
  621. }
  622. if (!tag) {
  623. get_prog_full_name(&info, fd, prog_name,
  624. sizeof(prog_name));
  625. if (strncmp(nametag, prog_name, sizeof(prog_name))) {
  626. close(fd);
  627. continue;
  628. }
  629. }
  630. if (nb_fds > 0) {
  631. tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
  632. if (!tmp) {
  633. p_err("failed to realloc");
  634. goto err_close_fd;
  635. }
  636. *fds = tmp;
  637. }
  638. (*fds)[nb_fds++] = fd;
  639. }
  640. err_close_fd:
  641. close(fd);
  642. err_close_fds:
  643. while (--nb_fds >= 0)
  644. close((*fds)[nb_fds]);
  645. return -1;
  646. }
  647. int prog_parse_fds(int *argc, char ***argv, int **fds)
  648. {
  649. if (is_prefix(**argv, "id")) {
  650. unsigned int id;
  651. char *endptr;
  652. NEXT_ARGP();
  653. id = strtoul(**argv, &endptr, 0);
  654. if (*endptr) {
  655. p_err("can't parse %s as ID", **argv);
  656. return -1;
  657. }
  658. NEXT_ARGP();
  659. (*fds)[0] = bpf_prog_get_fd_by_id(id);
  660. if ((*fds)[0] < 0) {
  661. p_err("get by id (%u): %s", id, strerror(errno));
  662. return -1;
  663. }
  664. return 1;
  665. } else if (is_prefix(**argv, "tag")) {
  666. unsigned char tag[BPF_TAG_SIZE];
  667. NEXT_ARGP();
  668. if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2,
  669. tag + 3, tag + 4, tag + 5, tag + 6, tag + 7)
  670. != BPF_TAG_SIZE) {
  671. p_err("can't parse tag");
  672. return -1;
  673. }
  674. NEXT_ARGP();
  675. return prog_fd_by_nametag(tag, fds, true);
  676. } else if (is_prefix(**argv, "name")) {
  677. char *name;
  678. NEXT_ARGP();
  679. name = **argv;
  680. if (strlen(name) > MAX_PROG_FULL_NAME - 1) {
  681. p_err("can't parse name");
  682. return -1;
  683. }
  684. NEXT_ARGP();
  685. return prog_fd_by_nametag(name, fds, false);
  686. } else if (is_prefix(**argv, "pinned")) {
  687. char *path;
  688. NEXT_ARGP();
  689. path = **argv;
  690. NEXT_ARGP();
  691. (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG);
  692. if ((*fds)[0] < 0)
  693. return -1;
  694. return 1;
  695. }
  696. p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv);
  697. return -1;
  698. }
  699. int prog_parse_fd(int *argc, char ***argv)
  700. {
  701. int *fds = NULL;
  702. int nb_fds, fd;
  703. fds = malloc(sizeof(int));
  704. if (!fds) {
  705. p_err("mem alloc failed");
  706. return -1;
  707. }
  708. nb_fds = prog_parse_fds(argc, argv, &fds);
  709. if (nb_fds != 1) {
  710. if (nb_fds > 1) {
  711. p_err("several programs match this handle");
  712. while (nb_fds--)
  713. close(fds[nb_fds]);
  714. }
  715. fd = -1;
  716. goto exit_free;
  717. }
  718. fd = fds[0];
  719. exit_free:
  720. free(fds);
  721. return fd;
  722. }
  723. static int map_fd_by_name(char *name, int **fds)
  724. {
  725. unsigned int id = 0;
  726. int fd, nb_fds = 0;
  727. void *tmp;
  728. int err;
  729. while (true) {
  730. struct bpf_map_info info = {};
  731. __u32 len = sizeof(info);
  732. err = bpf_map_get_next_id(id, &id);
  733. if (err) {
  734. if (errno != ENOENT) {
  735. p_err("%s", strerror(errno));
  736. goto err_close_fds;
  737. }
  738. return nb_fds;
  739. }
  740. fd = bpf_map_get_fd_by_id(id);
  741. if (fd < 0) {
  742. p_err("can't get map by id (%u): %s",
  743. id, strerror(errno));
  744. goto err_close_fds;
  745. }
  746. err = bpf_obj_get_info_by_fd(fd, &info, &len);
  747. if (err) {
  748. p_err("can't get map info (%u): %s",
  749. id, strerror(errno));
  750. goto err_close_fd;
  751. }
  752. if (strncmp(name, info.name, BPF_OBJ_NAME_LEN)) {
  753. close(fd);
  754. continue;
  755. }
  756. if (nb_fds > 0) {
  757. tmp = realloc(*fds, (nb_fds + 1) * sizeof(int));
  758. if (!tmp) {
  759. p_err("failed to realloc");
  760. goto err_close_fd;
  761. }
  762. *fds = tmp;
  763. }
  764. (*fds)[nb_fds++] = fd;
  765. }
  766. err_close_fd:
  767. close(fd);
  768. err_close_fds:
  769. while (--nb_fds >= 0)
  770. close((*fds)[nb_fds]);
  771. return -1;
  772. }
  773. int map_parse_fds(int *argc, char ***argv, int **fds)
  774. {
  775. if (is_prefix(**argv, "id")) {
  776. unsigned int id;
  777. char *endptr;
  778. NEXT_ARGP();
  779. id = strtoul(**argv, &endptr, 0);
  780. if (*endptr) {
  781. p_err("can't parse %s as ID", **argv);
  782. return -1;
  783. }
  784. NEXT_ARGP();
  785. (*fds)[0] = bpf_map_get_fd_by_id(id);
  786. if ((*fds)[0] < 0) {
  787. p_err("get map by id (%u): %s", id, strerror(errno));
  788. return -1;
  789. }
  790. return 1;
  791. } else if (is_prefix(**argv, "name")) {
  792. char *name;
  793. NEXT_ARGP();
  794. name = **argv;
  795. if (strlen(name) > BPF_OBJ_NAME_LEN - 1) {
  796. p_err("can't parse name");
  797. return -1;
  798. }
  799. NEXT_ARGP();
  800. return map_fd_by_name(name, fds);
  801. } else if (is_prefix(**argv, "pinned")) {
  802. char *path;
  803. NEXT_ARGP();
  804. path = **argv;
  805. NEXT_ARGP();
  806. (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_MAP);
  807. if ((*fds)[0] < 0)
  808. return -1;
  809. return 1;
  810. }
  811. p_err("expected 'id', 'name' or 'pinned', got: '%s'?", **argv);
  812. return -1;
  813. }
  814. int map_parse_fd(int *argc, char ***argv)
  815. {
  816. int *fds = NULL;
  817. int nb_fds, fd;
  818. fds = malloc(sizeof(int));
  819. if (!fds) {
  820. p_err("mem alloc failed");
  821. return -1;
  822. }
  823. nb_fds = map_parse_fds(argc, argv, &fds);
  824. if (nb_fds != 1) {
  825. if (nb_fds > 1) {
  826. p_err("several maps match this handle");
  827. while (nb_fds--)
  828. close(fds[nb_fds]);
  829. }
  830. fd = -1;
  831. goto exit_free;
  832. }
  833. fd = fds[0];
  834. exit_free:
  835. free(fds);
  836. return fd;
  837. }
  838. int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
  839. {
  840. int err;
  841. int fd;
  842. fd = map_parse_fd(argc, argv);
  843. if (fd < 0)
  844. return -1;
  845. err = bpf_obj_get_info_by_fd(fd, info, info_len);
  846. if (err) {
  847. p_err("can't get map info: %s", strerror(errno));
  848. close(fd);
  849. return err;
  850. }
  851. return fd;
  852. }
  853. size_t hash_fn_for_key_as_id(const void *key, void *ctx)
  854. {
  855. return (size_t)key;
  856. }
  857. bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx)
  858. {
  859. return k1 == k2;
  860. }
  861. const char *bpf_attach_type_input_str(enum bpf_attach_type t)
  862. {
  863. switch (t) {
  864. case BPF_CGROUP_INET_INGRESS: return "ingress";
  865. case BPF_CGROUP_INET_EGRESS: return "egress";
  866. case BPF_CGROUP_INET_SOCK_CREATE: return "sock_create";
  867. case BPF_CGROUP_INET_SOCK_RELEASE: return "sock_release";
  868. case BPF_CGROUP_SOCK_OPS: return "sock_ops";
  869. case BPF_CGROUP_DEVICE: return "device";
  870. case BPF_CGROUP_INET4_BIND: return "bind4";
  871. case BPF_CGROUP_INET6_BIND: return "bind6";
  872. case BPF_CGROUP_INET4_CONNECT: return "connect4";
  873. case BPF_CGROUP_INET6_CONNECT: return "connect6";
  874. case BPF_CGROUP_INET4_POST_BIND: return "post_bind4";
  875. case BPF_CGROUP_INET6_POST_BIND: return "post_bind6";
  876. case BPF_CGROUP_INET4_GETPEERNAME: return "getpeername4";
  877. case BPF_CGROUP_INET6_GETPEERNAME: return "getpeername6";
  878. case BPF_CGROUP_INET4_GETSOCKNAME: return "getsockname4";
  879. case BPF_CGROUP_INET6_GETSOCKNAME: return "getsockname6";
  880. case BPF_CGROUP_UDP4_SENDMSG: return "sendmsg4";
  881. case BPF_CGROUP_UDP6_SENDMSG: return "sendmsg6";
  882. case BPF_CGROUP_SYSCTL: return "sysctl";
  883. case BPF_CGROUP_UDP4_RECVMSG: return "recvmsg4";
  884. case BPF_CGROUP_UDP6_RECVMSG: return "recvmsg6";
  885. case BPF_CGROUP_GETSOCKOPT: return "getsockopt";
  886. case BPF_CGROUP_SETSOCKOPT: return "setsockopt";
  887. case BPF_TRACE_RAW_TP: return "raw_tp";
  888. case BPF_TRACE_FENTRY: return "fentry";
  889. case BPF_TRACE_FEXIT: return "fexit";
  890. case BPF_MODIFY_RETURN: return "mod_ret";
  891. case BPF_SK_REUSEPORT_SELECT: return "sk_skb_reuseport_select";
  892. case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE: return "sk_skb_reuseport_select_or_migrate";
  893. default: return libbpf_bpf_attach_type_str(t);
  894. }
  895. }