Add full JSON output support in the dump of 'act_bpf'. Example using eBPF:
# tc actions flush action bpf # tc action add action bpf object bpf/action.o section 'action-ok' # tc -j action list action bpf | jq [ { "total acts": 1 }, { "actions": [ { "order": 0, "kind": "bpf", "bpf_name": "action.o:[action-ok]", "prog": { "id": 33, "tag": "a04f5eef06a7f555", "jited": 1 }, "control_action": { "type": "pipe" }, "index": 1, "ref": 1, "bind": 0 } ] } ] Example using cBPF: # tc actions flush action bpf # a=$(mktemp) # tcpdump -ddd not ether proto 0x888e >$a # tc action add action bpf bytecode-file $a index 42 # rm $a # tc -j action list action bpf | jq [ { "total acts": 1 }, { "actions": [ { "order": 0, "kind": "bpf", "bytecode": { "length": 4, "insns": [ { "code": 40, "jt": 0, "jf": 0, "k": 12 }, { "code": 21, "jt": 0, "jf": 1, "k": 34958 }, { "code": 6, "jt": 0, "jf": 0, "k": 0 }, { "code": 6, "jt": 0, "jf": 0, "k": 262144 } ] }, "control_action": { "type": "pipe" }, "index": 42, "ref": 1, "bind": 0 } ] } ] Tested with: # ./tdc.py -c bpf Cc: Andrea Claudi <acla...@redhat.com> Signed-off-by: Davide Caratti <dcara...@redhat.com> --- include/bpf_util.h | 2 +- lib/bpf.c | 26 ++++++++++++++++++-------- tc/f_bpf.c | 2 +- tc/m_bpf.c | 32 +++++++++++++++++--------------- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/include/bpf_util.h b/include/bpf_util.h index 63837a04e56f..63db07ca49ae 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -272,7 +272,7 @@ const char *bpf_prog_to_default_section(enum bpf_prog_type type); int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv); int bpf_trace_pipe(void); -void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len); +void bpf_print_ops(struct rtattr *bpf_ops, __u16 len); int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, size_t size_insns, const char *license, char *log, diff --git a/lib/bpf.c b/lib/bpf.c index 5e85cfc0bdd5..dfc4f4f522c3 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -339,7 +339,7 @@ out: return ret; } -void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) +void bpf_print_ops(struct rtattr *bpf_ops, __u16 len) { struct sock_filter *ops = RTA_DATA(bpf_ops); int i; @@ -347,14 +347,24 @@ void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) if (len == 0) return; - fprintf(f, "bytecode \'%u,", len); - - for (i = 0; i < len - 1; i++) - fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt, - ops[i].jf, ops[i].k); + open_json_object("bytecode"); + print_uint(PRINT_ANY, "length", "bytecode \'%u,", len); + open_json_array(PRINT_JSON, "insns"); + + for (i = 0; i < len; i++) { + open_json_object(NULL); + print_uint(PRINT_ANY, "code", "%hu ", ops[i].code); + print_uint(PRINT_ANY, "jt", "%hhu ", ops[i].jt); + print_uint(PRINT_ANY, "jf", "%hhu ", ops[i].jf); + if (i == len - 1) + print_uint(PRINT_ANY, "k", "%u\'", ops[i].k); + else + print_uint(PRINT_ANY, "k", "%u,", ops[i].k); + close_json_object(); + } - fprintf(f, "%hu %hhu %hhu %u\'", ops[i].code, ops[i].jt, - ops[i].jf, ops[i].k); + close_json_array(PRINT_JSON, NULL); + close_json_object(); } static void bpf_map_pin_report(const struct bpf_elf_map *pin, diff --git a/tc/f_bpf.c b/tc/f_bpf.c index 5906f8bb969d..948d9051b9a5 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -235,7 +235,7 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f, } if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) - bpf_print_ops(f, tb[TCA_BPF_OPS], + bpf_print_ops(tb[TCA_BPF_OPS], rta_getattr_u16(tb[TCA_BPF_OPS_LEN])); if (tb[TCA_BPF_ID]) diff --git a/tc/m_bpf.c b/tc/m_bpf.c index 7c6f8c298abd..3e8468c68324 100644 --- a/tc/m_bpf.c +++ b/tc/m_bpf.c @@ -157,7 +157,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) { struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; struct tc_act_bpf *parm; - int dump_ok = 0; + int d_ok = 0; if (arg == NULL) return -1; @@ -170,31 +170,33 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg) } parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]); - fprintf(f, "bpf "); + print_string(PRINT_ANY, "kind", "%s ", "bpf"); if (tb[TCA_ACT_BPF_NAME]) - fprintf(f, "%s ", rta_getattr_str(tb[TCA_ACT_BPF_NAME])); - + print_string(PRINT_ANY, "bpf_name", "%s ", + rta_getattr_str(tb[TCA_ACT_BPF_NAME])); if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) { - bpf_print_ops(f, tb[TCA_ACT_BPF_OPS], + bpf_print_ops(tb[TCA_ACT_BPF_OPS], rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN])); - fprintf(f, " "); + print_string(PRINT_FP, NULL, "%s", " "); } if (tb[TCA_ACT_BPF_ID]) - dump_ok = bpf_dump_prog_info(f, rta_getattr_u32(tb[TCA_ACT_BPF_ID])); - if (!dump_ok && tb[TCA_ACT_BPF_TAG]) { + d_ok = bpf_dump_prog_info(f, + rta_getattr_u32(tb[TCA_ACT_BPF_ID])); + if (!d_ok && tb[TCA_ACT_BPF_TAG]) { SPRINT_BUF(b); - fprintf(f, "tag %s ", - hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]), - RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]), - b, sizeof(b))); + print_string(PRINT_ANY, "tag", "tag %s ", + hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]), + RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]), + b, sizeof(b))); } - print_action_control(f, "default-action ", parm->action, "\n"); - fprintf(f, "\tindex %u ref %d bind %d", parm->index, parm->refcnt, - parm->bindcnt); + print_action_control(f, "default-action ", parm->action, _SL_); + print_uint(PRINT_ANY, "index", "\t index %u", parm->index); + print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt); + print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt); if (show_stats) { if (tb[TCA_ACT_BPF_TM]) { -- 2.20.1