Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2020 Facebook */
0003 
0004 #include <errno.h>
0005 #include <linux/err.h>
0006 #include <net/if.h>
0007 #include <stdio.h>
0008 #include <unistd.h>
0009 
0010 #include <bpf/bpf.h>
0011 #include <bpf/hashmap.h>
0012 
0013 #include "json_writer.h"
0014 #include "main.h"
0015 
0016 static struct hashmap *link_table;
0017 
0018 static int link_parse_fd(int *argc, char ***argv)
0019 {
0020     int fd;
0021 
0022     if (is_prefix(**argv, "id")) {
0023         unsigned int id;
0024         char *endptr;
0025 
0026         NEXT_ARGP();
0027 
0028         id = strtoul(**argv, &endptr, 0);
0029         if (*endptr) {
0030             p_err("can't parse %s as ID", **argv);
0031             return -1;
0032         }
0033         NEXT_ARGP();
0034 
0035         fd = bpf_link_get_fd_by_id(id);
0036         if (fd < 0)
0037             p_err("failed to get link with ID %d: %s", id, strerror(errno));
0038         return fd;
0039     } else if (is_prefix(**argv, "pinned")) {
0040         char *path;
0041 
0042         NEXT_ARGP();
0043 
0044         path = **argv;
0045         NEXT_ARGP();
0046 
0047         return open_obj_pinned_any(path, BPF_OBJ_LINK);
0048     }
0049 
0050     p_err("expected 'id' or 'pinned', got: '%s'?", **argv);
0051     return -1;
0052 }
0053 
0054 static void
0055 show_link_header_json(struct bpf_link_info *info, json_writer_t *wtr)
0056 {
0057     const char *link_type_str;
0058 
0059     jsonw_uint_field(wtr, "id", info->id);
0060     link_type_str = libbpf_bpf_link_type_str(info->type);
0061     if (link_type_str)
0062         jsonw_string_field(wtr, "type", link_type_str);
0063     else
0064         jsonw_uint_field(wtr, "type", info->type);
0065 
0066     jsonw_uint_field(json_wtr, "prog_id", info->prog_id);
0067 }
0068 
0069 static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr)
0070 {
0071     const char *attach_type_str;
0072 
0073     attach_type_str = libbpf_bpf_attach_type_str(attach_type);
0074     if (attach_type_str)
0075         jsonw_string_field(wtr, "attach_type", attach_type_str);
0076     else
0077         jsonw_uint_field(wtr, "attach_type", attach_type);
0078 }
0079 
0080 static bool is_iter_map_target(const char *target_name)
0081 {
0082     return strcmp(target_name, "bpf_map_elem") == 0 ||
0083            strcmp(target_name, "bpf_sk_storage_map") == 0;
0084 }
0085 
0086 static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr)
0087 {
0088     const char *target_name = u64_to_ptr(info->iter.target_name);
0089 
0090     jsonw_string_field(wtr, "target_name", target_name);
0091 
0092     if (is_iter_map_target(target_name))
0093         jsonw_uint_field(wtr, "map_id", info->iter.map.map_id);
0094 }
0095 
0096 static int get_prog_info(int prog_id, struct bpf_prog_info *info)
0097 {
0098     __u32 len = sizeof(*info);
0099     int err, prog_fd;
0100 
0101     prog_fd = bpf_prog_get_fd_by_id(prog_id);
0102     if (prog_fd < 0)
0103         return prog_fd;
0104 
0105     memset(info, 0, sizeof(*info));
0106     err = bpf_obj_get_info_by_fd(prog_fd, info, &len);
0107     if (err)
0108         p_err("can't get prog info: %s", strerror(errno));
0109     close(prog_fd);
0110     return err;
0111 }
0112 
0113 static int show_link_close_json(int fd, struct bpf_link_info *info)
0114 {
0115     struct bpf_prog_info prog_info;
0116     const char *prog_type_str;
0117     int err;
0118 
0119     jsonw_start_object(json_wtr);
0120 
0121     show_link_header_json(info, json_wtr);
0122 
0123     switch (info->type) {
0124     case BPF_LINK_TYPE_RAW_TRACEPOINT:
0125         jsonw_string_field(json_wtr, "tp_name",
0126                    u64_to_ptr(info->raw_tracepoint.tp_name));
0127         break;
0128     case BPF_LINK_TYPE_TRACING:
0129         err = get_prog_info(info->prog_id, &prog_info);
0130         if (err)
0131             return err;
0132 
0133         prog_type_str = libbpf_bpf_prog_type_str(prog_info.type);
0134         /* libbpf will return NULL for variants unknown to it. */
0135         if (prog_type_str)
0136             jsonw_string_field(json_wtr, "prog_type", prog_type_str);
0137         else
0138             jsonw_uint_field(json_wtr, "prog_type", prog_info.type);
0139 
0140         show_link_attach_type_json(info->tracing.attach_type,
0141                        json_wtr);
0142         break;
0143     case BPF_LINK_TYPE_CGROUP:
0144         jsonw_lluint_field(json_wtr, "cgroup_id",
0145                    info->cgroup.cgroup_id);
0146         show_link_attach_type_json(info->cgroup.attach_type, json_wtr);
0147         break;
0148     case BPF_LINK_TYPE_ITER:
0149         show_iter_json(info, json_wtr);
0150         break;
0151     case BPF_LINK_TYPE_NETNS:
0152         jsonw_uint_field(json_wtr, "netns_ino",
0153                  info->netns.netns_ino);
0154         show_link_attach_type_json(info->netns.attach_type, json_wtr);
0155         break;
0156     default:
0157         break;
0158     }
0159 
0160     if (!hashmap__empty(link_table)) {
0161         struct hashmap_entry *entry;
0162 
0163         jsonw_name(json_wtr, "pinned");
0164         jsonw_start_array(json_wtr);
0165         hashmap__for_each_key_entry(link_table, entry,
0166                         u32_as_hash_field(info->id))
0167             jsonw_string(json_wtr, entry->value);
0168         jsonw_end_array(json_wtr);
0169     }
0170 
0171     emit_obj_refs_json(refs_table, info->id, json_wtr);
0172 
0173     jsonw_end_object(json_wtr);
0174 
0175     return 0;
0176 }
0177 
0178 static void show_link_header_plain(struct bpf_link_info *info)
0179 {
0180     const char *link_type_str;
0181 
0182     printf("%u: ", info->id);
0183     link_type_str = libbpf_bpf_link_type_str(info->type);
0184     if (link_type_str)
0185         printf("%s  ", link_type_str);
0186     else
0187         printf("type %u  ", info->type);
0188 
0189     printf("prog %u  ", info->prog_id);
0190 }
0191 
0192 static void show_link_attach_type_plain(__u32 attach_type)
0193 {
0194     const char *attach_type_str;
0195 
0196     attach_type_str = libbpf_bpf_attach_type_str(attach_type);
0197     if (attach_type_str)
0198         printf("attach_type %s  ", attach_type_str);
0199     else
0200         printf("attach_type %u  ", attach_type);
0201 }
0202 
0203 static void show_iter_plain(struct bpf_link_info *info)
0204 {
0205     const char *target_name = u64_to_ptr(info->iter.target_name);
0206 
0207     printf("target_name %s  ", target_name);
0208 
0209     if (is_iter_map_target(target_name))
0210         printf("map_id %u  ", info->iter.map.map_id);
0211 }
0212 
0213 static int show_link_close_plain(int fd, struct bpf_link_info *info)
0214 {
0215     struct bpf_prog_info prog_info;
0216     const char *prog_type_str;
0217     int err;
0218 
0219     show_link_header_plain(info);
0220 
0221     switch (info->type) {
0222     case BPF_LINK_TYPE_RAW_TRACEPOINT:
0223         printf("\n\ttp '%s'  ",
0224                (const char *)u64_to_ptr(info->raw_tracepoint.tp_name));
0225         break;
0226     case BPF_LINK_TYPE_TRACING:
0227         err = get_prog_info(info->prog_id, &prog_info);
0228         if (err)
0229             return err;
0230 
0231         prog_type_str = libbpf_bpf_prog_type_str(prog_info.type);
0232         /* libbpf will return NULL for variants unknown to it. */
0233         if (prog_type_str)
0234             printf("\n\tprog_type %s  ", prog_type_str);
0235         else
0236             printf("\n\tprog_type %u  ", prog_info.type);
0237 
0238         show_link_attach_type_plain(info->tracing.attach_type);
0239         break;
0240     case BPF_LINK_TYPE_CGROUP:
0241         printf("\n\tcgroup_id %zu  ", (size_t)info->cgroup.cgroup_id);
0242         show_link_attach_type_plain(info->cgroup.attach_type);
0243         break;
0244     case BPF_LINK_TYPE_ITER:
0245         show_iter_plain(info);
0246         break;
0247     case BPF_LINK_TYPE_NETNS:
0248         printf("\n\tnetns_ino %u  ", info->netns.netns_ino);
0249         show_link_attach_type_plain(info->netns.attach_type);
0250         break;
0251     default:
0252         break;
0253     }
0254 
0255     if (!hashmap__empty(link_table)) {
0256         struct hashmap_entry *entry;
0257 
0258         hashmap__for_each_key_entry(link_table, entry,
0259                         u32_as_hash_field(info->id))
0260             printf("\n\tpinned %s", (char *)entry->value);
0261     }
0262     emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
0263 
0264     printf("\n");
0265 
0266     return 0;
0267 }
0268 
0269 static int do_show_link(int fd)
0270 {
0271     struct bpf_link_info info;
0272     __u32 len = sizeof(info);
0273     char buf[256];
0274     int err;
0275 
0276     memset(&info, 0, sizeof(info));
0277 again:
0278     err = bpf_obj_get_info_by_fd(fd, &info, &len);
0279     if (err) {
0280         p_err("can't get link info: %s",
0281               strerror(errno));
0282         close(fd);
0283         return err;
0284     }
0285     if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT &&
0286         !info.raw_tracepoint.tp_name) {
0287         info.raw_tracepoint.tp_name = (unsigned long)&buf;
0288         info.raw_tracepoint.tp_name_len = sizeof(buf);
0289         goto again;
0290     }
0291     if (info.type == BPF_LINK_TYPE_ITER &&
0292         !info.iter.target_name) {
0293         info.iter.target_name = (unsigned long)&buf;
0294         info.iter.target_name_len = sizeof(buf);
0295         goto again;
0296     }
0297 
0298     if (json_output)
0299         show_link_close_json(fd, &info);
0300     else
0301         show_link_close_plain(fd, &info);
0302 
0303     close(fd);
0304     return 0;
0305 }
0306 
0307 static int do_show(int argc, char **argv)
0308 {
0309     __u32 id = 0;
0310     int err, fd;
0311 
0312     if (show_pinned) {
0313         link_table = hashmap__new(hash_fn_for_key_as_id,
0314                       equal_fn_for_key_as_id, NULL);
0315         if (IS_ERR(link_table)) {
0316             p_err("failed to create hashmap for pinned paths");
0317             return -1;
0318         }
0319         build_pinned_obj_table(link_table, BPF_OBJ_LINK);
0320     }
0321     build_obj_refs_table(&refs_table, BPF_OBJ_LINK);
0322 
0323     if (argc == 2) {
0324         fd = link_parse_fd(&argc, &argv);
0325         if (fd < 0)
0326             return fd;
0327         return do_show_link(fd);
0328     }
0329 
0330     if (argc)
0331         return BAD_ARG();
0332 
0333     if (json_output)
0334         jsonw_start_array(json_wtr);
0335     while (true) {
0336         err = bpf_link_get_next_id(id, &id);
0337         if (err) {
0338             if (errno == ENOENT)
0339                 break;
0340             p_err("can't get next link: %s%s", strerror(errno),
0341                   errno == EINVAL ? " -- kernel too old?" : "");
0342             break;
0343         }
0344 
0345         fd = bpf_link_get_fd_by_id(id);
0346         if (fd < 0) {
0347             if (errno == ENOENT)
0348                 continue;
0349             p_err("can't get link by id (%u): %s",
0350                   id, strerror(errno));
0351             break;
0352         }
0353 
0354         err = do_show_link(fd);
0355         if (err)
0356             break;
0357     }
0358     if (json_output)
0359         jsonw_end_array(json_wtr);
0360 
0361     delete_obj_refs_table(refs_table);
0362 
0363     if (show_pinned)
0364         delete_pinned_obj_table(link_table);
0365 
0366     return errno == ENOENT ? 0 : -1;
0367 }
0368 
0369 static int do_pin(int argc, char **argv)
0370 {
0371     int err;
0372 
0373     err = do_pin_any(argc, argv, link_parse_fd);
0374     if (!err && json_output)
0375         jsonw_null(json_wtr);
0376     return err;
0377 }
0378 
0379 static int do_detach(int argc, char **argv)
0380 {
0381     int err, fd;
0382 
0383     if (argc != 2) {
0384         p_err("link specifier is invalid or missing\n");
0385         return 1;
0386     }
0387 
0388     fd = link_parse_fd(&argc, &argv);
0389     if (fd < 0)
0390         return 1;
0391 
0392     err = bpf_link_detach(fd);
0393     if (err)
0394         err = -errno;
0395     close(fd);
0396     if (err) {
0397         p_err("failed link detach: %s", strerror(-err));
0398         return 1;
0399     }
0400 
0401     if (json_output)
0402         jsonw_null(json_wtr);
0403 
0404     return 0;
0405 }
0406 
0407 static int do_help(int argc, char **argv)
0408 {
0409     if (json_output) {
0410         jsonw_null(json_wtr);
0411         return 0;
0412     }
0413 
0414     fprintf(stderr,
0415         "Usage: %1$s %2$s { show | list }   [LINK]\n"
0416         "       %1$s %2$s pin        LINK  FILE\n"
0417         "       %1$s %2$s detach     LINK\n"
0418         "       %1$s %2$s help\n"
0419         "\n"
0420         "       " HELP_SPEC_LINK "\n"
0421         "       " HELP_SPEC_OPTIONS " |\n"
0422         "                    {-f|--bpffs} | {-n|--nomount} }\n"
0423         "",
0424         bin_name, argv[-2]);
0425 
0426     return 0;
0427 }
0428 
0429 static const struct cmd cmds[] = {
0430     { "show",   do_show },
0431     { "list",   do_show },
0432     { "help",   do_help },
0433     { "pin",    do_pin },
0434     { "detach", do_detach },
0435     { 0 }
0436 };
0437 
0438 int do_link(int argc, char **argv)
0439 {
0440     return cmd_select(cmds, argc, argv, do_help);
0441 }