diff options
Diffstat (limited to 'tools/bpf/bpftool/common.c')
-rw-r--r-- | tools/bpf/bpftool/common.c | 195 |
1 files changed, 164 insertions, 31 deletions
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index 2bd3b280e6dd..0b482c0070e0 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c | |||
@@ -34,6 +34,7 @@ | |||
34 | /* Author: Jakub Kicinski <kubakici@wp.pl> */ | 34 | /* Author: Jakub Kicinski <kubakici@wp.pl> */ |
35 | 35 | ||
36 | #include <errno.h> | 36 | #include <errno.h> |
37 | #include <fcntl.h> | ||
37 | #include <fts.h> | 38 | #include <fts.h> |
38 | #include <libgen.h> | 39 | #include <libgen.h> |
39 | #include <mntent.h> | 40 | #include <mntent.h> |
@@ -44,7 +45,9 @@ | |||
44 | #include <unistd.h> | 45 | #include <unistd.h> |
45 | #include <linux/limits.h> | 46 | #include <linux/limits.h> |
46 | #include <linux/magic.h> | 47 | #include <linux/magic.h> |
48 | #include <net/if.h> | ||
47 | #include <sys/mount.h> | 49 | #include <sys/mount.h> |
50 | #include <sys/stat.h> | ||
48 | #include <sys/types.h> | 51 | #include <sys/types.h> |
49 | #include <sys/vfs.h> | 52 | #include <sys/vfs.h> |
50 | 53 | ||
@@ -163,13 +166,49 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) | |||
163 | return fd; | 166 | return fd; |
164 | } | 167 | } |
165 | 168 | ||
166 | int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) | 169 | int do_pin_fd(int fd, const char *name) |
167 | { | 170 | { |
168 | char err_str[ERR_MAX_LEN]; | 171 | char err_str[ERR_MAX_LEN]; |
169 | unsigned int id; | ||
170 | char *endptr; | ||
171 | char *file; | 172 | char *file; |
172 | char *dir; | 173 | char *dir; |
174 | int err = 0; | ||
175 | |||
176 | err = bpf_obj_pin(fd, name); | ||
177 | if (!err) | ||
178 | goto out; | ||
179 | |||
180 | file = malloc(strlen(name) + 1); | ||
181 | strcpy(file, name); | ||
182 | dir = dirname(file); | ||
183 | |||
184 | if (errno != EPERM || is_bpffs(dir)) { | ||
185 | p_err("can't pin the object (%s): %s", name, strerror(errno)); | ||
186 | goto out_free; | ||
187 | } | ||
188 | |||
189 | /* Attempt to mount bpffs, then retry pinning. */ | ||
190 | err = mnt_bpffs(dir, err_str, ERR_MAX_LEN); | ||
191 | if (!err) { | ||
192 | err = bpf_obj_pin(fd, name); | ||
193 | if (err) | ||
194 | p_err("can't pin the object (%s): %s", name, | ||
195 | strerror(errno)); | ||
196 | } else { | ||
197 | err_str[ERR_MAX_LEN - 1] = '\0'; | ||
198 | p_err("can't mount BPF file system to pin the object (%s): %s", | ||
199 | name, err_str); | ||
200 | } | ||
201 | |||
202 | out_free: | ||
203 | free(file); | ||
204 | out: | ||
205 | return err; | ||
206 | } | ||
207 | |||
208 | int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) | ||
209 | { | ||
210 | unsigned int id; | ||
211 | char *endptr; | ||
173 | int err; | 212 | int err; |
174 | int fd; | 213 | int fd; |
175 | 214 | ||
@@ -195,35 +234,8 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) | |||
195 | return -1; | 234 | return -1; |
196 | } | 235 | } |
197 | 236 | ||
198 | err = bpf_obj_pin(fd, *argv); | 237 | err = do_pin_fd(fd, *argv); |
199 | if (!err) | ||
200 | goto out_close; | ||
201 | |||
202 | file = malloc(strlen(*argv) + 1); | ||
203 | strcpy(file, *argv); | ||
204 | dir = dirname(file); | ||
205 | |||
206 | if (errno != EPERM || is_bpffs(dir)) { | ||
207 | p_err("can't pin the object (%s): %s", *argv, strerror(errno)); | ||
208 | goto out_free; | ||
209 | } | ||
210 | |||
211 | /* Attempt to mount bpffs, then retry pinning. */ | ||
212 | err = mnt_bpffs(dir, err_str, ERR_MAX_LEN); | ||
213 | if (!err) { | ||
214 | err = bpf_obj_pin(fd, *argv); | ||
215 | if (err) | ||
216 | p_err("can't pin the object (%s): %s", *argv, | ||
217 | strerror(errno)); | ||
218 | } else { | ||
219 | err_str[ERR_MAX_LEN - 1] = '\0'; | ||
220 | p_err("can't mount BPF file system to pin the object (%s): %s", | ||
221 | *argv, err_str); | ||
222 | } | ||
223 | 238 | ||
224 | out_free: | ||
225 | free(file); | ||
226 | out_close: | ||
227 | close(fd); | 239 | close(fd); |
228 | return err; | 240 | return err; |
229 | } | 241 | } |
@@ -403,3 +415,124 @@ void delete_pinned_obj_table(struct pinned_obj_table *tab) | |||
403 | free(obj); | 415 | free(obj); |
404 | } | 416 | } |
405 | } | 417 | } |
418 | |||
419 | static char * | ||
420 | ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf) | ||
421 | { | ||
422 | struct stat st; | ||
423 | int err; | ||
424 | |||
425 | err = stat("/proc/self/ns/net", &st); | ||
426 | if (err) { | ||
427 | p_err("Can't stat /proc/self: %s", strerror(errno)); | ||
428 | return NULL; | ||
429 | } | ||
430 | |||
431 | if (st.st_dev != ns_dev || st.st_ino != ns_ino) | ||
432 | return NULL; | ||
433 | |||
434 | return if_indextoname(ifindex, buf); | ||
435 | } | ||
436 | |||
437 | static int read_sysfs_hex_int(char *path) | ||
438 | { | ||
439 | char vendor_id_buf[8]; | ||
440 | int len; | ||
441 | int fd; | ||
442 | |||
443 | fd = open(path, O_RDONLY); | ||
444 | if (fd < 0) { | ||
445 | p_err("Can't open %s: %s", path, strerror(errno)); | ||
446 | return -1; | ||
447 | } | ||
448 | |||
449 | len = read(fd, vendor_id_buf, sizeof(vendor_id_buf)); | ||
450 | close(fd); | ||
451 | if (len < 0) { | ||
452 | p_err("Can't read %s: %s", path, strerror(errno)); | ||
453 | return -1; | ||
454 | } | ||
455 | if (len >= (int)sizeof(vendor_id_buf)) { | ||
456 | p_err("Value in %s too long", path); | ||
457 | return -1; | ||
458 | } | ||
459 | |||
460 | vendor_id_buf[len] = 0; | ||
461 | |||
462 | return strtol(vendor_id_buf, NULL, 0); | ||
463 | } | ||
464 | |||
465 | static int read_sysfs_netdev_hex_int(char *devname, const char *entry_name) | ||
466 | { | ||
467 | char full_path[64]; | ||
468 | |||
469 | snprintf(full_path, sizeof(full_path), "/sys/class/net/%s/device/%s", | ||
470 | devname, entry_name); | ||
471 | |||
472 | return read_sysfs_hex_int(full_path); | ||
473 | } | ||
474 | |||
475 | const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino) | ||
476 | { | ||
477 | char devname[IF_NAMESIZE]; | ||
478 | int vendor_id; | ||
479 | int device_id; | ||
480 | |||
481 | if (!ifindex_to_name_ns(ifindex, ns_dev, ns_ino, devname)) { | ||
482 | p_err("Can't get net device name for ifindex %d: %s", ifindex, | ||
483 | strerror(errno)); | ||
484 | return NULL; | ||
485 | } | ||
486 | |||
487 | vendor_id = read_sysfs_netdev_hex_int(devname, "vendor"); | ||
488 | if (vendor_id < 0) { | ||
489 | p_err("Can't get device vendor id for %s", devname); | ||
490 | return NULL; | ||
491 | } | ||
492 | |||
493 | switch (vendor_id) { | ||
494 | case 0x19ee: | ||
495 | device_id = read_sysfs_netdev_hex_int(devname, "device"); | ||
496 | if (device_id != 0x4000 && | ||
497 | device_id != 0x6000 && | ||
498 | device_id != 0x6003) | ||
499 | p_info("Unknown NFP device ID, assuming it is NFP-6xxx arch"); | ||
500 | return "NFP-6xxx"; | ||
501 | default: | ||
502 | p_err("Can't get bfd arch name for device vendor id 0x%04x", | ||
503 | vendor_id); | ||
504 | return NULL; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode) | ||
509 | { | ||
510 | char name[IF_NAMESIZE]; | ||
511 | |||
512 | if (!ifindex) | ||
513 | return; | ||
514 | |||
515 | printf(" dev "); | ||
516 | if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name)) | ||
517 | printf("%s", name); | ||
518 | else | ||
519 | printf("ifindex %u ns_dev %llu ns_ino %llu", | ||
520 | ifindex, ns_dev, ns_inode); | ||
521 | } | ||
522 | |||
523 | void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode) | ||
524 | { | ||
525 | char name[IF_NAMESIZE]; | ||
526 | |||
527 | if (!ifindex) | ||
528 | return; | ||
529 | |||
530 | jsonw_name(json_wtr, "dev"); | ||
531 | jsonw_start_object(json_wtr); | ||
532 | jsonw_uint_field(json_wtr, "ifindex", ifindex); | ||
533 | jsonw_uint_field(json_wtr, "ns_dev", ns_dev); | ||
534 | jsonw_uint_field(json_wtr, "ns_inode", ns_inode); | ||
535 | if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name)) | ||
536 | jsonw_string_field(json_wtr, "ifname", name); | ||
537 | jsonw_end_object(json_wtr); | ||
538 | } | ||