static void dump_raw_db(FILE *fp, int to_hist) { json_writer_t *jw = json_output ? jsonw_new(fp) : NULL; struct ifstat_ent *n, *h; h = hist_db; if (jw) { jsonw_start_object(jw); jsonw_pretty(jw, pretty); jsonw_name(jw, info_source); jsonw_start_object(jw); } else fprintf(fp, "#%s\n", info_source); for (n = kern_db; n; n = n->next) { int i; unsigned long long *vals = n->val; double *rates = n->rate; if (!match(n->name)) { struct ifstat_ent *h1; if (!to_hist) continue; for (h1 = h; h1; h1 = h1->next) { if (h1->ifindex == n->ifindex) { vals = h1->val; rates = h1->rate; h = h1->next; break; } } } if (jw) { jsonw_name(jw, n->name); jsonw_start_object(jw); for (i = 0; i < MAXS && stats[i]; i++) jsonw_uint_field(jw, stats[i], vals[i]); jsonw_end_object(jw); } else { fprintf(fp, "%d %s ", n->ifindex, n->name); for (i = 0; i < MAXS; i++) fprintf(fp, "%llu %u ", vals[i], (unsigned int)rates[i]); fprintf(fp, "\n"); } } if (jw) { jsonw_end_object(jw); jsonw_end_object(jw); jsonw_destroy(&jw); } }
static enum bpf_perf_event_ret print_bpf_output(void *event, void *priv) { struct event_ring_info *ring = priv; struct perf_event_sample *e = event; struct { struct perf_event_header header; __u64 id; __u64 lost; } *lost = event; if (json_output) { jsonw_start_object(json_wtr); jsonw_name(json_wtr, "type"); jsonw_uint(json_wtr, e->header.type); jsonw_name(json_wtr, "cpu"); jsonw_uint(json_wtr, ring->cpu); jsonw_name(json_wtr, "index"); jsonw_uint(json_wtr, ring->key); if (e->header.type == PERF_RECORD_SAMPLE) { jsonw_name(json_wtr, "timestamp"); jsonw_uint(json_wtr, e->time); jsonw_name(json_wtr, "data"); print_data_json(e->data, e->size); } else if (e->header.type == PERF_RECORD_LOST) { jsonw_name(json_wtr, "lost"); jsonw_start_object(json_wtr); jsonw_name(json_wtr, "id"); jsonw_uint(json_wtr, lost->id); jsonw_name(json_wtr, "count"); jsonw_uint(json_wtr, lost->lost); jsonw_end_object(json_wtr); } jsonw_end_object(json_wtr); } else { if (e->header.type == PERF_RECORD_SAMPLE) { printf("== @%lld.%09lld CPU: %d index: %d =====\n", e->time / 1000000000ULL, e->time % 1000000000ULL, ring->cpu, ring->key); fprint_hex(stdout, e->data, e->size, " "); printf("\n"); } else if (e->header.type == PERF_RECORD_LOST) { printf("lost %lld events\n", lost->lost); } else { printf("unknown event type=%d size=%d\n", e->header.type, e->header.size); } } return LIBBPF_PERF_EVENT_CONT; }
static int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback) { uint32_t flags = NLM_F_REQUEST | NLM_F_ACK; uint32_t seq; int ret; if (command != RDMA_NLDEV_CMD_RES_GET) flags |= NLM_F_DUMP; rd_prepare_msg(rd, command, &seq, flags); mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); if (rd->port_idx) mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx); ret = rd_send_msg(rd); if (ret) return ret; if (rd->json_output) jsonw_start_object(rd->jw); ret = rd_recv_msg(rd, callback, rd, seq); if (rd->json_output) jsonw_end_object(rd->jw); return ret; }
static int dump_btf_raw(const struct btf *btf, __u32 *root_type_ids, int root_type_cnt) { const struct btf_type *t; int i; if (json_output) { jsonw_start_object(json_wtr); jsonw_name(json_wtr, "types"); jsonw_start_array(json_wtr); } if (root_type_cnt) { for (i = 0; i < root_type_cnt; i++) { t = btf__type_by_id(btf, root_type_ids[i]); dump_btf_type(btf, root_type_ids[i], t); } } else { int cnt = btf__get_nr_types(btf); for (i = 1; i <= cnt; i++) { t = btf__type_by_id(btf, i); dump_btf_type(btf, i, t); } } if (json_output) { jsonw_end_array(json_wtr); jsonw_end_object(json_wtr); } return 0; }
static int do_dump_btf(const struct btf_dumper *d, struct bpf_map_info *map_info, void *key, void *value) { int ret; /* start of key-value pair */ jsonw_start_object(d->jw); if (map_info->btf_key_type_id) { jsonw_name(d->jw, "key"); ret = btf_dumper_type(d, map_info->btf_key_type_id, key); if (ret) goto err_end_obj; } if (!map_is_per_cpu(map_info->type)) { jsonw_name(d->jw, "value"); ret = btf_dumper_type(d, map_info->btf_value_type_id, value); } else { unsigned int i, n, step; jsonw_name(d->jw, "values"); jsonw_start_array(d->jw); n = get_possible_cpus(); step = round_up(map_info->value_size, 8); for (i = 0; i < n; i++) { jsonw_start_object(d->jw); jsonw_int_field(d->jw, "cpu", i); jsonw_name(d->jw, "value"); ret = btf_dumper_type(d, map_info->btf_value_type_id, value + i * step); jsonw_end_object(d->jw); if (ret) break; } jsonw_end_array(d->jw); } err_end_obj: /* end of key-value pair */ jsonw_end_object(d->jw); return ret; }
static int vlan_show(int argc, char **argv) { char *filter_dev = NULL; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); if (filter_dev) duparg("dev", *argv); filter_dev = *argv; } else if (strcmp(*argv, "vid") == 0) { NEXT_ARG(); if (filter_vlan) duparg("vid", *argv); filter_vlan = atoi(*argv); } argc--; argv++; } if (filter_dev) { if ((filter_index = if_nametoindex(filter_dev)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev); return -1; } } if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK, (compress_vlans ? RTEXT_FILTER_BRVLAN_COMPRESSED : RTEXT_FILTER_BRVLAN)) < 0) { perror("Cannont send dump request"); exit(1); } if (json_output) { jw_global = jsonw_new(stdout); if (!jw_global) { fprintf(stderr, "Error allocation json object\n"); exit(1); } jsonw_start_object(jw_global); } else { printf("port\tvlan ids\n"); } if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) { fprintf(stderr, "Dump ternminated\n"); exit(1); } if (jw_global) { jsonw_end_object(jw_global); jsonw_destroy(&jw_global); } return 0; }
int main(int argc, char **argv) { json_writer_t *wr = jsonw_new(stdout); jsonw_start_object(wr); jsonw_pretty(wr, true); jsonw_name(wr, "Vyatta"); jsonw_start_object(wr); jsonw_string_field(wr, "url", "http://vyatta.com"); jsonw_uint_field(wr, "downloads", 2000000ul); jsonw_float_field(wr, "stock", 8.16); jsonw_name(wr, "ARGV"); jsonw_start_array(wr); while (--argc) jsonw_string(wr, *++argv); jsonw_end_array(wr); jsonw_name(wr, "empty"); jsonw_start_array(wr); jsonw_end_array(wr); jsonw_name(wr, "NIL"); jsonw_start_object(wr); jsonw_end_object(wr); jsonw_null_field(wr, "my_null"); jsonw_name(wr, "special chars"); jsonw_start_array(wr); jsonw_string_field(wr, "slash", "/"); jsonw_string_field(wr, "newline", "\n"); jsonw_string_field(wr, "tab", "\t"); jsonw_string_field(wr, "ff", "\f"); jsonw_string_field(wr, "quote", "\""); jsonw_string_field(wr, "tick", "\'"); jsonw_string_field(wr, "backslash", "\\"); jsonw_end_array(wr); jsonw_end_object(wr); jsonw_end_object(wr); jsonw_destroy(&wr); return 0; }
static void dump_incr_db(FILE *fp) { struct ifstat_ent *n, *h; json_writer_t *jw = json_output ? jsonw_new(fp) : NULL; h = hist_db; if (jw) { jsonw_start_object(jw); jsonw_pretty(jw, pretty); jsonw_name(jw, info_source); jsonw_start_object(jw); } else print_head(fp); for (n = kern_db; n; n = n->next) { int i; unsigned long long vals[MAXS]; struct ifstat_ent *h1; memcpy(vals, n->val, sizeof(vals)); for (h1 = h; h1; h1 = h1->next) { if (h1->ifindex == n->ifindex) { for (i = 0; i < MAXS; i++) vals[i] -= h1->val[i]; h = h1->next; break; } } if (!match(n->name)) continue; if (jw) print_one_json(jw, n, n->val); else print_one_if(fp, n, vals); } if (jw) { jsonw_end_object(jw); jsonw_end_object(jw); jsonw_destroy(&jw); } }
static int do_version(int argc, char **argv) { if (json_output) { jsonw_start_object(json_wtr); jsonw_name(json_wtr, "version"); jsonw_printf(json_wtr, "\"%s\"", BPFTOOL_VERSION); jsonw_end_object(json_wtr); } else { printf("%s v%s\n", bin_name, BPFTOOL_VERSION); } return 0; }
static void print_one_json(json_writer_t *jw, const struct ifstat_ent *n, const unsigned long long *vals) { int i, m = show_errors ? 20 : 10; jsonw_name(jw, n->name); jsonw_start_object(jw); for (i = 0; i < m && stats[i]; i++) jsonw_uint_field(jw, stats[i], vals[i]); jsonw_end_object(jw); }
static int show_bpf_prog(int id, const char *attach_type_str, const char *attach_flags_str, int level) { struct bpf_prog_info info = {}; __u32 info_len = sizeof(info); int prog_fd; prog_fd = bpf_prog_get_fd_by_id(id); if (prog_fd < 0) return -1; if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) { close(prog_fd); return -1; } if (json_output) { jsonw_start_object(json_wtr); jsonw_uint_field(json_wtr, "id", info.id); jsonw_string_field(json_wtr, "attach_type", attach_type_str); jsonw_string_field(json_wtr, "attach_flags", attach_flags_str); jsonw_string_field(json_wtr, "name", info.name); jsonw_end_object(json_wtr); } else { printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "", info.id, attach_type_str, attach_flags_str, info.name); } close(prog_fd); return 0; }
static int do_show_tree_fn(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftw) { enum bpf_attach_type type; bool skip = true; int cgroup_fd; if (typeflag != FTW_D) return 0; cgroup_fd = open(fpath, O_RDONLY); if (cgroup_fd < 0) { p_err("can't open cgroup %s: %s", fpath, strerror(errno)); return SHOW_TREE_FN_ERR; } for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { int count = count_attached_bpf_progs(cgroup_fd, type); if (count < 0 && errno != EINVAL) { p_err("can't query bpf programs attached to %s: %s", fpath, strerror(errno)); close(cgroup_fd); return SHOW_TREE_FN_ERR; } if (count > 0) { skip = false; break; } } if (skip) { close(cgroup_fd); return 0; } if (json_output) { jsonw_start_object(json_wtr); jsonw_string_field(json_wtr, "cgroup", fpath); jsonw_name(json_wtr, "programs"); jsonw_start_array(json_wtr); } else { printf("%s\n", fpath); } for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) show_attached_bpf_progs(cgroup_fd, type, ftw->level); if (errno == EINVAL) /* Last attach type does not support query. * Do not report an error for this, especially because batch * mode would stop processing commands. */ errno = 0; if (json_output) { jsonw_end_array(json_wtr); jsonw_end_object(json_wtr); } close(cgroup_fd); return 0; }
static int do_batch(int argc, char **argv) { char buf[BATCH_LINE_LEN_MAX], contline[BATCH_LINE_LEN_MAX]; char *n_argv[BATCH_ARG_NB_MAX]; unsigned int lines = 0; int n_argc; FILE *fp; char *cp; int err; int i; if (argc < 2) { p_err("too few parameters for batch"); return -1; } else if (!is_prefix(*argv, "file")) { p_err("expected 'file', got: %s", *argv); return -1; } else if (argc > 2) { p_err("too many parameters for batch"); return -1; } NEXT_ARG(); if (!strcmp(*argv, "-")) fp = stdin; else fp = fopen(*argv, "r"); if (!fp) { p_err("Can't open file (%s): %s", *argv, strerror(errno)); return -1; } if (json_output) jsonw_start_array(json_wtr); while (fgets(buf, sizeof(buf), fp)) { cp = strchr(buf, '#'); if (cp) *cp = '\0'; if (strlen(buf) == sizeof(buf) - 1) { errno = E2BIG; break; } /* Append continuation lines if any (coming after a line ending * with '\' in the batch file). */ while ((cp = strstr(buf, "\\\n")) != NULL) { if (!fgets(contline, sizeof(contline), fp) || strlen(contline) == 0) { p_err("missing continuation line on command %d", lines); err = -1; goto err_close; } cp = strchr(contline, '#'); if (cp) *cp = '\0'; if (strlen(buf) + strlen(contline) + 1 > sizeof(buf)) { p_err("command %d is too long", lines); err = -1; goto err_close; } buf[strlen(buf) - 2] = '\0'; strcat(buf, contline); } n_argc = make_args(buf, n_argv, BATCH_ARG_NB_MAX, lines); if (!n_argc) continue; if (n_argc < 0) goto err_close; if (json_output) { jsonw_start_object(json_wtr); jsonw_name(json_wtr, "command"); jsonw_start_array(json_wtr); for (i = 0; i < n_argc; i++) jsonw_string(json_wtr, n_argv[i]); jsonw_end_array(json_wtr); jsonw_name(json_wtr, "output"); } err = cmd_select(cmds, n_argc, n_argv, do_help); if (json_output) jsonw_end_object(json_wtr); if (err) goto err_close; lines++; } if (errno && errno != ENOENT) { p_err("reading batch file failed: %s", strerror(errno)); err = -1; } else { if (!json_output) printf("processed %d commands\n", lines); err = 0; } err_close: if (fp != stdin) fclose(fp); if (json_output) jsonw_end_array(json_wtr); return err; }
void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, bool opcodes, bool linum) { const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; const struct bpf_insn_cbs cbs = { .cb_print = print_insn_json, .cb_call = print_call, .cb_imm = print_imm, .private_data = dd, }; struct bpf_func_info *record; struct bpf_insn *insn = buf; struct btf *btf = dd->btf; bool double_insn = false; unsigned int nr_skip = 0; char func_sig[1024]; unsigned int i; jsonw_start_array(json_wtr); record = dd->func_info; for (i = 0; i < len / sizeof(*insn); i++) { if (double_insn) { double_insn = false; continue; } double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); jsonw_start_object(json_wtr); if (btf && record) { if (record->insn_off == i) { btf_dumper_type_only(btf, record->type_id, func_sig, sizeof(func_sig)); if (func_sig[0] != '\0') { jsonw_name(json_wtr, "proto"); jsonw_string(json_wtr, func_sig); } record = (void *)record + dd->finfo_rec_size; } } if (prog_linfo) { const struct bpf_line_info *linfo; linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); if (linfo) { btf_dump_linfo_json(btf, linfo, linum); nr_skip++; } } jsonw_name(json_wtr, "disasm"); print_bpf_insn(&cbs, insn + i, true); if (opcodes) { jsonw_name(json_wtr, "opcodes"); jsonw_start_object(json_wtr); jsonw_name(json_wtr, "code"); jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); jsonw_name(json_wtr, "src_reg"); jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); jsonw_name(json_wtr, "dst_reg"); jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); jsonw_name(json_wtr, "off"); print_hex_data_json((uint8_t *)(&insn[i].off), 2); jsonw_name(json_wtr, "imm"); if (double_insn && i < len - 1) print_hex_data_json((uint8_t *)(&insn[i].imm), 12); else print_hex_data_json((uint8_t *)(&insn[i].imm), 4); jsonw_end_object(json_wtr); } jsonw_end_object(json_wtr); } jsonw_end_array(json_wtr); }
static int dump_btf_type(const struct btf *btf, __u32 id, const struct btf_type *t) { json_writer_t *w = json_wtr; int kind, safe_kind; kind = BTF_INFO_KIND(t->info); safe_kind = kind <= BTF_KIND_MAX ? kind : BTF_KIND_UNKN; if (json_output) { jsonw_start_object(w); jsonw_uint_field(w, "id", id); jsonw_string_field(w, "kind", btf_kind_str[safe_kind]); jsonw_string_field(w, "name", btf_str(btf, t->name_off)); } else { printf("[%u] %s '%s'", id, btf_kind_str[safe_kind], btf_str(btf, t->name_off)); } switch (BTF_INFO_KIND(t->info)) { case BTF_KIND_INT: { __u32 v = *(__u32 *)(t + 1); const char *enc; enc = btf_int_enc_str(BTF_INT_ENCODING(v)); if (json_output) { jsonw_uint_field(w, "size", t->size); jsonw_uint_field(w, "bits_offset", BTF_INT_OFFSET(v)); jsonw_uint_field(w, "nr_bits", BTF_INT_BITS(v)); jsonw_string_field(w, "encoding", enc); } else { printf(" size=%u bits_offset=%u nr_bits=%u encoding=%s", t->size, BTF_INT_OFFSET(v), BTF_INT_BITS(v), enc); } break; } case BTF_KIND_PTR: case BTF_KIND_CONST: case BTF_KIND_VOLATILE: case BTF_KIND_RESTRICT: case BTF_KIND_TYPEDEF: if (json_output) jsonw_uint_field(w, "type_id", t->type); else printf(" type_id=%u", t->type); break; case BTF_KIND_ARRAY: { const struct btf_array *arr = (const void *)(t + 1); if (json_output) { jsonw_uint_field(w, "type_id", arr->type); jsonw_uint_field(w, "index_type_id", arr->index_type); jsonw_uint_field(w, "nr_elems", arr->nelems); } else { printf(" type_id=%u index_type_id=%u nr_elems=%u", arr->type, arr->index_type, arr->nelems); } break; } case BTF_KIND_STRUCT: case BTF_KIND_UNION: { const struct btf_member *m = (const void *)(t + 1); __u16 vlen = BTF_INFO_VLEN(t->info); int i; if (json_output) { jsonw_uint_field(w, "size", t->size); jsonw_uint_field(w, "vlen", vlen); jsonw_name(w, "members"); jsonw_start_array(w); } else { printf(" size=%u vlen=%u", t->size, vlen); } for (i = 0; i < vlen; i++, m++) { const char *name = btf_str(btf, m->name_off); __u32 bit_off, bit_sz; if (BTF_INFO_KFLAG(t->info)) { bit_off = BTF_MEMBER_BIT_OFFSET(m->offset); bit_sz = BTF_MEMBER_BITFIELD_SIZE(m->offset); } else { bit_off = m->offset; bit_sz = 0; } if (json_output) { jsonw_start_object(w); jsonw_string_field(w, "name", name); jsonw_uint_field(w, "type_id", m->type); jsonw_uint_field(w, "bits_offset", bit_off); if (bit_sz) { jsonw_uint_field(w, "bitfield_size", bit_sz); } jsonw_end_object(w); } else { printf("\n\t'%s' type_id=%u bits_offset=%u", name, m->type, bit_off); if (bit_sz) printf(" bitfield_size=%u", bit_sz); } } if (json_output) jsonw_end_array(w); break; } case BTF_KIND_ENUM: { const struct btf_enum *v = (const void *)(t + 1); __u16 vlen = BTF_INFO_VLEN(t->info); int i; if (json_output) { jsonw_uint_field(w, "size", t->size); jsonw_uint_field(w, "vlen", vlen); jsonw_name(w, "values"); jsonw_start_array(w); } else { printf(" size=%u vlen=%u", t->size, vlen); } for (i = 0; i < vlen; i++, v++) { const char *name = btf_str(btf, v->name_off); if (json_output) { jsonw_start_object(w); jsonw_string_field(w, "name", name); jsonw_uint_field(w, "val", v->val); jsonw_end_object(w); } else { printf("\n\t'%s' val=%u", name, v->val); } } if (json_output) jsonw_end_array(w); break; } case BTF_KIND_FWD: { const char *fwd_kind = BTF_INFO_KFLAG(t->info) ? "union" : "struct"; if (json_output) jsonw_string_field(w, "fwd_kind", fwd_kind); else printf(" fwd_kind=%s", fwd_kind); break; } case BTF_KIND_FUNC: if (json_output) jsonw_uint_field(w, "type_id", t->type); else printf(" type_id=%u", t->type); break; case BTF_KIND_FUNC_PROTO: { const struct btf_param *p = (const void *)(t + 1); __u16 vlen = BTF_INFO_VLEN(t->info); int i; if (json_output) { jsonw_uint_field(w, "ret_type_id", t->type); jsonw_uint_field(w, "vlen", vlen); jsonw_name(w, "params"); jsonw_start_array(w); } else { printf(" ret_type_id=%u vlen=%u", t->type, vlen); } for (i = 0; i < vlen; i++, p++) { const char *name = btf_str(btf, p->name_off); if (json_output) { jsonw_start_object(w); jsonw_string_field(w, "name", name); jsonw_uint_field(w, "type_id", p->type); jsonw_end_object(w); } else { printf("\n\t'%s' type_id=%u", name, p->type); } } if (json_output) jsonw_end_array(w); break; } case BTF_KIND_VAR: { const struct btf_var *v = (const void *)(t + 1); const char *linkage; linkage = btf_var_linkage_str(v->linkage); if (json_output) { jsonw_uint_field(w, "type_id", t->type); jsonw_string_field(w, "linkage", linkage); } else { printf(" type_id=%u, linkage=%s", t->type, linkage); } break; } case BTF_KIND_DATASEC: { const struct btf_var_secinfo *v = (const void *)(t+1); __u16 vlen = BTF_INFO_VLEN(t->info); int i; if (json_output) { jsonw_uint_field(w, "size", t->size); jsonw_uint_field(w, "vlen", vlen); jsonw_name(w, "vars"); jsonw_start_array(w); } else { printf(" size=%u vlen=%u", t->size, vlen); } for (i = 0; i < vlen; i++, v++) { if (json_output) { jsonw_start_object(w); jsonw_uint_field(w, "type_id", v->type); jsonw_uint_field(w, "offset", v->offset); jsonw_uint_field(w, "size", v->size); jsonw_end_object(w); } else { printf("\n\ttype_id=%u offset=%u size=%u", v->type, v->offset, v->size); } } if (json_output) jsonw_end_array(w); break; } default: break; } if (json_output) jsonw_end_object(json_wtr); else printf("\n"); return 0; }
void close_json_object(void) { if (_IS_JSON_CONTEXT(PRINT_JSON)) jsonw_end_object(_jw); }
static int vlan_modify(int cmd, int argc, char **argv) { struct { struct nlmsghdr n; struct ifinfomsg ifm; char buf[1024]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), .n.nlmsg_flags = NLM_F_REQUEST, .n.nlmsg_type = cmd, .ifm.ifi_family = PF_BRIDGE, }; char *d = NULL; short vid = -1; short vid_end = -1; struct rtattr *afspec; struct bridge_vlan_info vinfo = {}; unsigned short flags = 0; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "vid") == 0) { char *p; NEXT_ARG(); p = strchr(*argv, '-'); if (p) { *p = '\0'; p++; vid = atoi(*argv); vid_end = atoi(p); vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; } else { vid = atoi(*argv); } } else if (strcmp(*argv, "self") == 0) { flags |= BRIDGE_FLAGS_SELF; } else if (strcmp(*argv, "master") == 0) { flags |= BRIDGE_FLAGS_MASTER; } else if (strcmp(*argv, "pvid") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_PVID; } else if (strcmp(*argv, "untagged") == 0) { vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; } else { if (matches(*argv, "help") == 0) { NEXT_ARG(); } } argc--; argv++; } if (d == NULL || vid == -1) { fprintf(stderr, "Device and VLAN ID are required arguments.\n"); return -1; } req.ifm.ifi_index = ll_name_to_index(d); if (req.ifm.ifi_index == 0) { fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); return -1; } if (vid >= 4096) { fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid); return -1; } if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) { fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n", vid, vid_end); return -1; } if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) { fprintf(stderr, "pvid cannot be configured for a vlan range\n"); return -1; } } afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); if (flags) addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); vinfo.vid = vid; if (vid_end != -1) { /* send vlan range start */ addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; /* Now send the vlan range end */ vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END; vinfo.vid = vid_end; addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); } else { addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo, sizeof(vinfo)); } addattr_nest_end(&req.n, afspec); if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) return -1; return 0; } /* In order to use this function for both filtering and non-filtering cases * we need to make it a tristate: * return -1 - if filtering we've gone over so don't continue * return 0 - skip entry and continue (applies to range start or to entries * which are less than filter_vlan) * return 1 - print the entry and continue */ static int filter_vlan_check(struct bridge_vlan_info *vinfo) { /* if we're filtering we should stop on the first greater entry */ if (filter_vlan && vinfo->vid > filter_vlan && !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) return -1; if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) || vinfo->vid < filter_vlan) return 0; return 1; } static void print_vlan_port(FILE *fp, int ifi_index) { if (jw_global) { jsonw_pretty(jw_global, 1); jsonw_name(jw_global, ll_index_to_name(ifi_index)); jsonw_start_array(jw_global); } else { fprintf(fp, "%s", ll_index_to_name(ifi_index)); } } static void start_json_vlan_flags_array(bool *vlan_flags) { if (*vlan_flags) return; jsonw_name(jw_global, "flags"); jsonw_start_array(jw_global); *vlan_flags = true; } static int print_vlan(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = arg; struct ifinfomsg *ifm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[IFLA_MAX+1]; bool vlan_flags; if (n->nlmsg_type != RTM_NEWLINK) { fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*ifm)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (ifm->ifi_family != AF_BRIDGE) return 0; if (filter_index && filter_index != ifm->ifi_index) return 0; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len); /* if AF_SPEC isn't there, vlan table is not preset for this port */ if (!tb[IFLA_AF_SPEC]) { if (!filter_vlan) fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index)); return 0; } else { struct rtattr *i, *list = tb[IFLA_AF_SPEC]; int rem = RTA_PAYLOAD(list); __u16 last_vid_start = 0; if (!filter_vlan) print_vlan_port(fp, ifm->ifi_index); for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { struct bridge_vlan_info *vinfo; int vcheck_ret; if (i->rta_type != IFLA_BRIDGE_VLAN_INFO) continue; vinfo = RTA_DATA(i); if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)) last_vid_start = vinfo->vid; vcheck_ret = filter_vlan_check(vinfo); if (vcheck_ret == -1) break; else if (vcheck_ret == 0) continue; if (filter_vlan) print_vlan_port(fp, ifm->ifi_index); if (jw_global) { jsonw_start_object(jw_global); jsonw_uint_field(jw_global, "vlan", last_vid_start); if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) continue; } else { fprintf(fp, "\t %hu", last_vid_start); } if (last_vid_start != vinfo->vid) { if (jw_global) jsonw_uint_field(jw_global, "vlanEnd", vinfo->vid); else fprintf(fp, "-%hu", vinfo->vid); } if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) { if (jw_global) { start_json_vlan_flags_array(&vlan_flags); jsonw_string(jw_global, "PVID"); } else { fprintf(fp, " PVID"); } } if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) { if (jw_global) { start_json_vlan_flags_array(&vlan_flags); jsonw_string(jw_global, "Egress Untagged"); } else { fprintf(fp, " Egress Untagged"); } } if (vlan_flags) { jsonw_end_array(jw_global); vlan_flags = false; } if (jw_global) jsonw_end_object(jw_global); else fprintf(fp, "\n"); } } if (!filter_vlan) { if (jw_global) jsonw_end_array(jw_global); else fprintf(fp, "\n"); } fflush(fp); return 0; }