common.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
  3. #include <ctype.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <fts.h>
  7. #include <libgen.h>
  8. #include <mntent.h>
  9. #include <stdbool.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include <linux/limits.h>
  15. #include <linux/magic.h>
  16. #include <net/if.h>
  17. #include <sys/mount.h>
  18. #include <sys/resource.h>
  19. #include <sys/stat.h>
  20. #include <sys/vfs.h>
  21. #include <bpf.h>
  22. #include <libbpf.h> /* libbpf_num_possible_cpus */
  23. #include "main.h"
  24. #ifndef BPF_FS_MAGIC
  25. #define BPF_FS_MAGIC 0xcafe4a11
  26. #endif
  27. void p_err(const char *fmt, ...)
  28. {
  29. va_list ap;
  30. va_start(ap, fmt);
  31. if (json_output) {
  32. jsonw_start_object(json_wtr);
  33. jsonw_name(json_wtr, "error");
  34. jsonw_vprintf_enquote(json_wtr, fmt, ap);
  35. jsonw_end_object(json_wtr);
  36. } else {
  37. fprintf(stderr, "Error: ");
  38. vfprintf(stderr, fmt, ap);
  39. fprintf(stderr, "\n");
  40. }
  41. va_end(ap);
  42. }
  43. void p_info(const char *fmt, ...)
  44. {
  45. va_list ap;
  46. if (json_output)
  47. return;
  48. va_start(ap, fmt);
  49. vfprintf(stderr, fmt, ap);
  50. fprintf(stderr, "\n");
  51. va_end(ap);
  52. }
  53. static bool is_bpffs(char *path)
  54. {
  55. struct statfs st_fs;
  56. if (statfs(path, &st_fs) < 0)
  57. return false;
  58. return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
  59. }
  60. void set_max_rlimit(void)
  61. {
  62. struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
  63. setrlimit(RLIMIT_MEMLOCK, &rinf);
  64. }
  65. static int
  66. mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
  67. {
  68. bool bind_done = false;
  69. while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
  70. if (errno != EINVAL || bind_done) {
  71. snprintf(buff, bufflen,
  72. "mount --make-private %s failed: %s",
  73. target, strerror(errno));
  74. return -1;
  75. }
  76. if (mount(target, target, "none", MS_BIND, NULL)) {
  77. snprintf(buff, bufflen,
  78. "mount --bind %s %s failed: %s",
  79. target, target, strerror(errno));
  80. return -1;
  81. }
  82. bind_done = true;
  83. }
  84. if (mount(type, target, type, 0, "mode=0700")) {
  85. snprintf(buff, bufflen, "mount -t %s %s %s failed: %s",
  86. type, type, target, strerror(errno));
  87. return -1;
  88. }
  89. return 0;
  90. }
  91. int mount_tracefs(const char *target)
  92. {
  93. char err_str[ERR_MAX_LEN];
  94. int err;
  95. err = mnt_fs(target, "tracefs", err_str, ERR_MAX_LEN);
  96. if (err) {
  97. err_str[ERR_MAX_LEN - 1] = '\0';
  98. p_err("can't mount tracefs: %s", err_str);
  99. }
  100. return err;
  101. }
  102. int open_obj_pinned(char *path, bool quiet)
  103. {
  104. int fd;
  105. fd = bpf_obj_get(path);
  106. if (fd < 0) {
  107. if (!quiet)
  108. p_err("bpf obj get (%s): %s", path,
  109. errno == EACCES && !is_bpffs(dirname(path)) ?
  110. "directory not in bpf file system (bpffs)" :
  111. strerror(errno));
  112. return -1;
  113. }
  114. return fd;
  115. }
  116. int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
  117. {
  118. enum bpf_obj_type type;
  119. int fd;
  120. fd = open_obj_pinned(path, false);
  121. if (fd < 0)
  122. return -1;
  123. type = get_fd_type(fd);
  124. if (type < 0) {
  125. close(fd);
  126. return type;
  127. }
  128. if (type != exp_type) {
  129. p_err("incorrect object type: %s", get_fd_type_name(type));
  130. close(fd);
  131. return -1;
  132. }
  133. return fd;
  134. }
  135. int mount_bpffs_for_pin(const char *name)
  136. {
  137. char err_str[ERR_MAX_LEN];
  138. char *file;
  139. char *dir;
  140. int err = 0;
  141. file = malloc(strlen(name) + 1);
  142. if (!file) {
  143. p_err("mem alloc failed");
  144. return -1;
  145. }
  146. strcpy(file, name);
  147. dir = dirname(file);
  148. if (is_bpffs(dir))
  149. /* nothing to do if already mounted */
  150. goto out_free;
  151. if (block_mount) {
  152. p_err("no BPF file system found, not mounting it due to --nomount option");
  153. err = -1;
  154. goto out_free;
  155. }
  156. err = mnt_fs(dir, "bpf", err_str, ERR_MAX_LEN);
  157. if (err) {
  158. err_str[ERR_MAX_LEN - 1] = '\0';
  159. p_err("can't mount BPF file system to pin the object (%s): %s",
  160. name, err_str);
  161. }
  162. out_free:
  163. free(file);
  164. return err;
  165. }
  166. int do_pin_fd(int fd, const char *name)
  167. {
  168. int err;
  169. err = mount_bpffs_for_pin(name);
  170. if (err)
  171. return err;
  172. err = bpf_obj_pin(fd, name);
  173. if (err)
  174. p_err("can't pin the object (%s): %s", name, strerror(errno));
  175. return err;
  176. }
  177. int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
  178. {
  179. unsigned int id;
  180. char *endptr;
  181. int err;
  182. int fd;
  183. if (argc < 3) {
  184. p_err("too few arguments, id ID and FILE path is required");
  185. return -1;
  186. } else if (argc > 3) {
  187. p_err("too many arguments");
  188. return -1;
  189. }
  190. if (!is_prefix(*argv, "id")) {
  191. p_err("expected 'id' got %s", *argv);
  192. return -1;
  193. }
  194. NEXT_ARG();
  195. id = strtoul(*argv, &endptr, 0);
  196. if (*endptr) {
  197. p_err("can't parse %s as ID", *argv);
  198. return -1;
  199. }
  200. NEXT_ARG();
  201. fd = get_fd_by_id(id);
  202. if (fd < 0) {
  203. p_err("can't open object by id (%u): %s", id, strerror(errno));
  204. return -1;
  205. }
  206. err = do_pin_fd(fd, *argv);
  207. close(fd);
  208. return err;
  209. }
  210. const char *get_fd_type_name(enum bpf_obj_type type)
  211. {
  212. static const char * const names[] = {
  213. [BPF_OBJ_UNKNOWN] = "unknown",
  214. [BPF_OBJ_PROG] = "prog",
  215. [BPF_OBJ_MAP] = "map",
  216. };
  217. if (type < 0 || type >= ARRAY_SIZE(names) || !names[type])
  218. return names[BPF_OBJ_UNKNOWN];
  219. return names[type];
  220. }
  221. int get_fd_type(int fd)
  222. {
  223. char path[PATH_MAX];
  224. char buf[512];
  225. ssize_t n;
  226. snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
  227. n = readlink(path, buf, sizeof(buf));
  228. if (n < 0) {
  229. p_err("can't read link type: %s", strerror(errno));
  230. return -1;
  231. }
  232. if (n == sizeof(path)) {
  233. p_err("can't read link type: path too long!");
  234. return -1;
  235. }
  236. if (strstr(buf, "bpf-map"))
  237. return BPF_OBJ_MAP;
  238. else if (strstr(buf, "bpf-prog"))
  239. return BPF_OBJ_PROG;
  240. return BPF_OBJ_UNKNOWN;
  241. }
  242. char *get_fdinfo(int fd, const char *key)
  243. {
  244. char path[PATH_MAX];
  245. char *line = NULL;
  246. size_t line_n = 0;
  247. ssize_t n;
  248. FILE *fdi;
  249. snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
  250. fdi = fopen(path, "r");
  251. if (!fdi)
  252. return NULL;
  253. while ((n = getline(&line, &line_n, fdi)) > 0) {
  254. char *value;
  255. int len;
  256. if (!strstr(line, key))
  257. continue;
  258. fclose(fdi);
  259. value = strchr(line, '\t');
  260. if (!value || !value[1]) {
  261. free(line);
  262. return NULL;
  263. }
  264. value++;
  265. len = strlen(value);
  266. memmove(line, value, len);
  267. line[len - 1] = '\0';
  268. return line;
  269. }
  270. free(line);
  271. fclose(fdi);
  272. return NULL;
  273. }
  274. void print_data_json(uint8_t *data, size_t len)
  275. {
  276. unsigned int i;
  277. jsonw_start_array(json_wtr);
  278. for (i = 0; i < len; i++)
  279. jsonw_printf(json_wtr, "%d", data[i]);
  280. jsonw_end_array(json_wtr);
  281. }
  282. void print_hex_data_json(uint8_t *data, size_t len)
  283. {
  284. unsigned int i;
  285. jsonw_start_array(json_wtr);
  286. for (i = 0; i < len; i++)
  287. jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]);
  288. jsonw_end_array(json_wtr);
  289. }
  290. int build_pinned_obj_table(struct pinned_obj_table *tab,
  291. enum bpf_obj_type type)
  292. {
  293. struct bpf_prog_info pinned_info = {};
  294. struct pinned_obj *obj_node = NULL;
  295. __u32 len = sizeof(pinned_info);
  296. struct mntent *mntent = NULL;
  297. enum bpf_obj_type objtype;
  298. FILE *mntfile = NULL;
  299. FTSENT *ftse = NULL;
  300. FTS *fts = NULL;
  301. int fd, err;
  302. mntfile = setmntent("/proc/mounts", "r");
  303. if (!mntfile)
  304. return -1;
  305. while ((mntent = getmntent(mntfile))) {
  306. char *path[] = { mntent->mnt_dir, NULL };
  307. if (strncmp(mntent->mnt_type, "bpf", 3) != 0)
  308. continue;
  309. fts = fts_open(path, 0, NULL);
  310. if (!fts)
  311. continue;
  312. while ((ftse = fts_read(fts))) {
  313. if (!(ftse->fts_info & FTS_F))
  314. continue;
  315. fd = open_obj_pinned(ftse->fts_path, true);
  316. if (fd < 0)
  317. continue;
  318. objtype = get_fd_type(fd);
  319. if (objtype != type) {
  320. close(fd);
  321. continue;
  322. }
  323. memset(&pinned_info, 0, sizeof(pinned_info));
  324. err = bpf_obj_get_info_by_fd(fd, &pinned_info, &len);
  325. if (err) {
  326. close(fd);
  327. continue;
  328. }
  329. obj_node = malloc(sizeof(*obj_node));
  330. if (!obj_node) {
  331. close(fd);
  332. fts_close(fts);
  333. fclose(mntfile);
  334. return -1;
  335. }
  336. memset(obj_node, 0, sizeof(*obj_node));
  337. obj_node->id = pinned_info.id;
  338. obj_node->path = strdup(ftse->fts_path);
  339. hash_add(tab->table, &obj_node->hash, obj_node->id);
  340. close(fd);
  341. }
  342. fts_close(fts);
  343. }
  344. fclose(mntfile);
  345. return 0;
  346. }
  347. void delete_pinned_obj_table(struct pinned_obj_table *tab)
  348. {
  349. struct pinned_obj *obj;
  350. struct hlist_node *tmp;
  351. unsigned int bkt;
  352. hash_for_each_safe(tab->table, bkt, tmp, obj, hash) {
  353. hash_del(&obj->hash);
  354. free(obj->path);
  355. free(obj);
  356. }
  357. }
  358. unsigned int get_page_size(void)
  359. {
  360. static int result;
  361. if (!result)
  362. result = getpagesize();
  363. return result;
  364. }
  365. unsigned int get_possible_cpus(void)
  366. {
  367. int cpus = libbpf_num_possible_cpus();
  368. if (cpus < 0) {
  369. p_err("Can't get # of possible cpus: %s", strerror(-cpus));
  370. exit(-1);
  371. }
  372. return cpus;
  373. }
  374. static char *
  375. ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
  376. {
  377. struct stat st;
  378. int err;
  379. err = stat("/proc/self/ns/net", &st);
  380. if (err) {
  381. p_err("Can't stat /proc/self: %s", strerror(errno));
  382. return NULL;
  383. }
  384. if (st.st_dev != ns_dev || st.st_ino != ns_ino)
  385. return NULL;
  386. return if_indextoname(ifindex, buf);
  387. }
  388. static int read_sysfs_hex_int(char *path)
  389. {
  390. char vendor_id_buf[8];
  391. int len;
  392. int fd;
  393. fd = open(path, O_RDONLY);
  394. if (fd < 0) {
  395. p_err("Can't open %s: %s", path, strerror(errno));
  396. return -1;
  397. }
  398. len = read(fd, vendor_id_buf, sizeof(vendor_id_buf));
  399. close(fd);
  400. if (len < 0) {
  401. p_err("Can't read %s: %s", path, strerror(errno));
  402. return -1;
  403. }
  404. if (len >= (int)sizeof(vendor_id_buf)) {
  405. p_err("Value in %s too long", path);
  406. return -1;
  407. }
  408. vendor_id_buf[len] = 0;
  409. return strtol(vendor_id_buf, NULL, 0);
  410. }
  411. static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name)
  412. {
  413. char full_path[64];
  414. snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s",
  415. devname, entry_name);
  416. return read_sysfs_hex_int(full_path);
  417. }
  418. const char *
  419. ifindex_to_bfd_params(__u32 ifindex, __u64 ns_dev, __u64 ns_ino,
  420. const char **opt)
  421. {
  422. char devname[IF_NAMESIZE];
  423. int vendor_id;
  424. int device_id;
  425. if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) {
  426. p_err("Can't get net device name for ifindex %d: %s", ifindex,
  427. strerror(errno));
  428. return NULL;
  429. }
  430. vendor_id = read_sysfs_netdev_hex_int(devname, "vendor");
  431. if (vendor_id < 0) {
  432. p_err("Can't get device vendor id for %s", devname);
  433. return NULL;
  434. }
  435. switch (vendor_id) {
  436. case 0x19ee:
  437. device_id = read_sysfs_netdev_hex_int(devname, "device");
  438. if (device_id != 0x4000 &&
  439. device_id != 0x6000 &&
  440. device_id != 0x6003)
  441. p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch");
  442. *opt = "ctx4";
  443. return "NFP-6xxx";
  444. default:
  445. p_err("Can't get bfd arch name for device vendor id 0x%04x",
  446. vendor_id);
  447. return NULL;
  448. }
  449. }
  450. void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
  451. {
  452. char name[IF_NAMESIZE];
  453. if (!ifindex)
  454. return;
  455. printf(" offloaded_to ");
  456. if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
  457. printf("%s", name);
  458. else
  459. printf("ifindex %u ns_dev %llu ns_ino %llu",
  460. ifindex, ns_dev, ns_inode);
  461. }
  462. void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
  463. {
  464. char name[IF_NAMESIZE];
  465. if (!ifindex)
  466. return;
  467. jsonw_name(json_wtr, "dev");
  468. jsonw_start_object(json_wtr);
  469. jsonw_uint_field(json_wtr, "ifindex", ifindex);
  470. jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
  471. jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
  472. if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
  473. jsonw_string_field(json_wtr, "ifname", name);
  474. jsonw_end_object(json_wtr);
  475. }
  476. int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what)
  477. {
  478. char *endptr;
  479. NEXT_ARGP();
  480. if (*val) {
  481. p_err("%s already specified", what);
  482. return -1;
  483. }
  484. *val = strtoul(**argv, &endptr, 0);
  485. if (*endptr) {
  486. p_err("can't parse %s as %s", **argv, what);
  487. return -1;
  488. }
  489. NEXT_ARGP();
  490. return 0;
  491. }