common.c 24 KB

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