From: Yonghong Song <yhs@fb.com>
To: <ast@fb.com>, <daniel@iogearbox.net>, <netdev@vger.kernel.org>
Cc: <kernel-team@fb.com>
Subject: [RFC PATCH bpf-next 4/4] tools/bpf: bpftool: add net support
Date: Mon, 3 Sep 2018 11:26:47 -0700 [thread overview]
Message-ID: <20180903182647.1244630-5-yhs@fb.com> (raw)
In-Reply-To: <20180903182647.1244630-1-yhs@fb.com>
Add "bpftool net" support. Networking devices are enumerated
to dump all xdp information. Also, for each networking device,
tc classes and qdiscs are enumerated in order to check bpf filters
with these classes and qdiscs. In addition, root handle and
clsact ingress/egress are also checked for bpf filters.
For example,
$ bpftool net
xdp [
]
netdev_filters [
ifindex 2 name handle_icmp flags direct-action flags_gen [not_in_hw ]
prog_id 3194 tag 846d29c14d0d7d26 act []
ifindex 2 name handle_egress flags direct-action flags_gen [not_in_hw ]
prog_id 3193 tag 387d281be9fe77aa
]
$ bpftool -jp net
[{
"xdp": [],
"netdev_filters": [{
"ifindex": 2,
"name": "handle_icmp",
"flags": "direct-action",
"flags_gen": ["not_in_hw"
],
"prog_id": 3194,
"tag": "846d29c14d0d7d26",
"act": []
},{
"ifindex": 2,
"name": "handle_egress",
"flags": "direct-action",
"flags_gen": ["not_in_hw"
],
"prog_id": 3193,
"tag": "387d281be9fe77aa"
}
]
}
]
Signed-off-by: Yonghong Song <yhs@fb.com>
---
tools/bpf/bpftool/main.c | 3 +-
tools/bpf/bpftool/main.h | 7 +
tools/bpf/bpftool/net.c | 219 ++++++++++++++++++++++++
tools/bpf/bpftool/netlink_dumper.c | 261 +++++++++++++++++++++++++++++
tools/bpf/bpftool/netlink_dumper.h | 103 ++++++++++++
5 files changed, 592 insertions(+), 1 deletion(-)
create mode 100644 tools/bpf/bpftool/net.c
create mode 100644 tools/bpf/bpftool/netlink_dumper.c
create mode 100644 tools/bpf/bpftool/netlink_dumper.h
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
index d15a62be6cf0..79dc3f193547 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -85,7 +85,7 @@ static int do_help(int argc, char **argv)
" %s batch file FILE\n"
" %s version\n"
"\n"
- " OBJECT := { prog | map | cgroup | perf }\n"
+ " OBJECT := { prog | map | cgroup | perf | net }\n"
" " HELP_SPEC_OPTIONS "\n"
"",
bin_name, bin_name, bin_name);
@@ -215,6 +215,7 @@ static const struct cmd cmds[] = {
{ "map", do_map },
{ "cgroup", do_cgroup },
{ "perf", do_perf },
+ { "net", do_net },
{ "version", do_version },
{ 0 }
};
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 238e734d75b3..f82aeb08a043 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -136,6 +136,7 @@ int do_map(int argc, char **arg);
int do_event_pipe(int argc, char **argv);
int do_cgroup(int argc, char **arg);
int do_perf(int argc, char **arg);
+int do_net(int argc, char **arg);
int prog_parse_fd(int *argc, char ***argv);
int map_parse_fd(int *argc, char ***argv);
@@ -165,4 +166,10 @@ struct btf_dumper {
*/
int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
const void *data);
+
+struct nlattr;
+struct ifinfomsg;
+struct tcmsg;
+int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb);
+int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb);
#endif
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
new file mode 100644
index 000000000000..0ced41d9fee9
--- /dev/null
+++ b/tools/bpf/bpftool/net.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2018 Facebook
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libbpf.h>
+#include <net/if.h>
+#include <linux/if.h>
+#include <linux/rtnetlink.h>
+#include <linux/tc_act/tc_bpf.h>
+#include <sys/socket.h>
+
+#include <bpf.h>
+#include <nlattr.h>
+#include "main.h"
+#include "netlink_dumper.h"
+
+struct bpf_netdev_t {
+ int *ifindex_array;
+ int used_len;
+ int array_len;
+ int filter_idx;
+};
+
+struct bpf_tcinfo_t {
+ int *handle_array;
+ int used_len;
+ int array_len;
+ bool is_qdisc;
+};
+
+static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
+{
+ struct bpf_netdev_t *netinfo = cookie;
+ struct ifinfomsg *ifinfo = msg;
+
+ if (netinfo->filter_idx > 0 && netinfo->filter_idx != ifinfo->ifi_index)
+ return 0;
+
+ if (netinfo->used_len == netinfo->array_len) {
+ netinfo->ifindex_array = realloc(netinfo->ifindex_array,
+ netinfo->array_len * sizeof(int) + 64);
+ netinfo->array_len += 64/sizeof(int);
+ }
+ netinfo->ifindex_array[netinfo->used_len++] = ifinfo->ifi_index;
+
+ return do_xdp_dump(ifinfo, tb);
+}
+
+static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb)
+{
+ struct bpf_tcinfo_t *tcinfo = cookie;
+ struct tcmsg *info = msg;
+
+ if (tcinfo->is_qdisc) {
+ /* skip clsact qdisc */
+ if (tb[TCA_KIND] &&
+ strcmp(nla_data(tb[TCA_KIND]), "clsact") == 0)
+ return 0;
+ if (info->tcm_handle == 0)
+ return 0;
+ }
+
+ if (tcinfo->used_len == tcinfo->array_len) {
+ tcinfo->handle_array = realloc(tcinfo->handle_array,
+ tcinfo->array_len * sizeof(int) + 64);
+ tcinfo->array_len += 64/sizeof(int);
+ }
+ tcinfo->handle_array[tcinfo->used_len++] = info->tcm_handle;
+
+ return 0;
+}
+
+static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb)
+{
+ return do_filter_dump((struct tcmsg *)msg, tb);
+}
+
+static int show_dev_tc_bpf(int sock, unsigned int nl_pid, int ifindex)
+{
+ struct bpf_tcinfo_t tcinfo;
+ int i, handle, ret;
+
+ tcinfo.handle_array = NULL;
+ tcinfo.used_len = 0;
+ tcinfo.array_len = 0;
+
+ tcinfo.is_qdisc = false;
+ ret = nl_get_class(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg,
+ &tcinfo);
+ if (ret)
+ return ret;
+
+ tcinfo.is_qdisc = true;
+ ret = nl_get_qdisc(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg,
+ &tcinfo);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < tcinfo.used_len; i++) {
+ ret = nl_get_filter(sock, nl_pid, ifindex,
+ tcinfo.handle_array[i],
+ dump_filter_nlmsg, NULL);
+ if (ret)
+ return ret;
+ }
+
+ /* root, ingress and egress handle */
+ handle = TC_H_ROOT;
+ ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg,
+ NULL);
+ if (ret)
+ return ret;
+
+ handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
+ ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg,
+ NULL);
+ if (ret)
+ return ret;
+
+ handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS);
+ ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg,
+ NULL);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int do_show(int argc, char **argv)
+{
+ int i, sock, ret, filter_idx = -1;
+ struct bpf_netdev_t dev_array;
+ unsigned int nl_pid;
+ char err_buf[256];
+
+ if (argc == 2) {
+ if (strcmp(argv[0], "dev") != 0)
+ usage();
+ filter_idx = if_nametoindex(argv[1]);
+ if (filter_idx == 0) {
+ fprintf(stderr, "invalid dev name %s\n", argv[1]);
+ return -1;
+ }
+ } else if (argc != 0) {
+ usage();
+ }
+
+ sock = bpf_netlink_open(&nl_pid);
+ if (sock < 0) {
+ fprintf(stderr, "failed to open netlink sock\n");
+ return -1;
+ }
+
+ dev_array.ifindex_array = NULL;
+ dev_array.used_len = 0;
+ dev_array.array_len = 0;
+ dev_array.filter_idx = filter_idx;
+
+ if (json_output)
+ jsonw_start_array(json_wtr);
+ NET_START_OBJECT;
+ NET_START_ARRAY("xdp", "\n");
+ ret = nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array);
+ NET_END_ARRAY("\n");
+
+ if (!ret) {
+ NET_START_ARRAY("netdev_filters", "\n");
+ for (i = 0; i < dev_array.used_len; i++) {
+ ret = show_dev_tc_bpf(sock, nl_pid,
+ dev_array.ifindex_array[i]);
+ if (ret)
+ break;
+ }
+ NET_END_ARRAY("\n");
+ }
+ NET_END_OBJECT;
+ if (json_output)
+ jsonw_end_array(json_wtr);
+
+ if (ret) {
+ if (json_output)
+ jsonw_null(json_wtr);
+ libbpf_strerror(ret, err_buf, sizeof(err_buf));
+ fprintf(stderr, "Error: %s\n", err_buf);
+ }
+ free(dev_array.ifindex_array);
+ close(sock);
+ return ret;
+}
+
+static int do_help(int argc, char **argv)
+{
+ if (json_output) {
+ jsonw_null(json_wtr);
+ return 0;
+ }
+
+ fprintf(stderr,
+ "Usage: %s %s { show | list } [dev <devname>]\n"
+ " %s %s help\n",
+ bin_name, argv[-2], bin_name, argv[-2]);
+
+ return 0;
+}
+
+static const struct cmd cmds[] = {
+ { "show", do_show },
+ { "list", do_show },
+ { "help", do_help },
+ { 0 }
+};
+
+int do_net(int argc, char **argv)
+{
+ return cmd_select(cmds, argc, argv, do_help);
+}
diff --git a/tools/bpf/bpftool/netlink_dumper.c b/tools/bpf/bpftool/netlink_dumper.c
new file mode 100644
index 000000000000..69529be1c37c
--- /dev/null
+++ b/tools/bpf/bpftool/netlink_dumper.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2018 Facebook
+
+#include <stdlib.h>
+#include <string.h>
+#include <libbpf.h>
+#include <linux/rtnetlink.h>
+#include <linux/tc_act/tc_bpf.h>
+
+#include <nlattr.h>
+#include "main.h"
+#include "netlink_dumper.h"
+
+static void xdp_dump_prog_id(struct nlattr **tb, int attr,
+ const char *type)
+{
+ if (!tb[attr])
+ return;
+
+ NET_DUMP_UINT(type, nla_getattr_u32(tb[attr]))
+}
+
+static int do_xdp_dump_one(struct nlattr *attr, unsigned int ifindex,
+ const char *name)
+{
+ struct nlattr *tb[IFLA_XDP_MAX + 1];
+ unsigned char mode;
+
+ if (nla_parse_nested(tb, IFLA_XDP_MAX, attr, NULL) < 0)
+ return -1;
+
+ if (!tb[IFLA_XDP_ATTACHED])
+ return 0;
+
+ mode = nla_getattr_u8(tb[IFLA_XDP_ATTACHED]);
+ if (mode == XDP_ATTACHED_NONE)
+ return 0;
+
+ NET_START_OBJECT;
+ NET_DUMP_UINT("ifindex", ifindex);
+
+ if (name)
+ NET_DUMP_STR("devname", name);
+
+ if (tb[IFLA_XDP_PROG_ID])
+ NET_DUMP_UINT("prog_id", nla_getattr_u32(tb[IFLA_XDP_PROG_ID]));
+
+ if (mode == XDP_ATTACHED_MULTI) {
+ xdp_dump_prog_id(tb, IFLA_XDP_SKB_PROG_ID, "generic_prog_id");
+ xdp_dump_prog_id(tb, IFLA_XDP_DRV_PROG_ID, "drv_prog_id");
+ xdp_dump_prog_id(tb, IFLA_XDP_HW_PROG_ID, "offload_prog_id");
+ }
+
+ NET_END_OBJECT_FINAL;
+ return 0;
+}
+
+int do_xdp_dump(struct ifinfomsg *ifinfo, struct nlattr **tb)
+{
+ if (!tb[IFLA_XDP])
+ return 0;
+
+ return do_xdp_dump_one(tb[IFLA_XDP], ifinfo->ifi_index,
+ nla_getattr_str(tb[IFLA_IFNAME]));
+}
+
+static char *hexstring_n2a(const unsigned char *str, int len,
+ char *buf, int blen)
+{
+ char *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (blen < 3)
+ break;
+ sprintf(ptr, "%02x", str[i]);
+ ptr += 2;
+ blen -= 2;
+ }
+ return buf;
+}
+
+static int do_bpf_dump_one_act(struct nlattr *attr)
+{
+ struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
+ struct tc_act_bpf *parm;
+ char buf[256];
+
+ if (nla_parse_nested(tb, TCA_ACT_BPF_MAX, attr, NULL) < 0)
+ return -LIBBPF_ERRNO__NLPARSE;
+
+ if (!tb[TCA_ACT_BPF_PARMS])
+ return -LIBBPF_ERRNO__NLPARSE;
+
+ NET_START_OBJECT_NESTED2;
+ parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
+ if (tb[TCA_ACT_BPF_NAME])
+ NET_DUMP_STR("name", nla_getattr_str(tb[TCA_ACT_BPF_NAME]));
+ if (tb[TCA_ACT_BPF_ID])
+ NET_DUMP_UINT("bpf_id", nla_getattr_u32(tb[TCA_ACT_BPF_ID]));
+ if (tb[TCA_ACT_BPF_TAG])
+ NET_DUMP_STR("tag", hexstring_n2a(nla_data(tb[TCA_ACT_BPF_TAG]),
+ nla_len(tb[TCA_ACT_BPF_TAG]),
+ buf, sizeof(buf)));
+ NET_DUMP_UINT("default_action", parm->action);
+ NET_DUMP_UINT("index", parm->index);
+ NET_DUMP_UINT("refcnt", parm->refcnt);
+ NET_DUMP_UINT("bindcnt", parm->bindcnt);
+ if (tb[TCA_ACT_BPF_TM]) {
+ struct tcf_t *tm = nla_data(tb[TCA_ACT_BPF_TM]);
+
+ NET_DUMP_LLUINT("tm_install", tm->install);
+ NET_DUMP_LLUINT("tm_lastuse", tm->lastuse);
+ NET_DUMP_LLUINT("tm_expires", tm->expires);
+ NET_DUMP_LLUINT("tm_firstuse", tm->firstuse);
+ }
+ NET_END_OBJECT_NESTED;
+ return 0;
+}
+
+static int do_dump_one_act(struct nlattr *attr)
+{
+ struct nlattr *tb[TCA_ACT_MAX + 1];
+
+ if (!attr)
+ return 0;
+
+ if (nla_parse_nested(tb, TCA_ACT_MAX, attr, NULL) < 0)
+ return -LIBBPF_ERRNO__NLPARSE;
+
+ if (tb[TCA_ACT_KIND] && strcmp(nla_data(tb[TCA_ACT_KIND]), "bpf") == 0)
+ return do_bpf_dump_one_act(tb[TCA_ACT_OPTIONS]);
+
+ return 0;
+}
+
+static int do_bpf_police_dump(struct nlattr *attr)
+{
+ struct nlattr *tb[TCA_POLICE_MAX + 1];
+ struct tc_police *p;
+
+ if (nla_parse_nested(tb, TCA_POLICE_MAX, attr, NULL) < 0)
+ return -LIBBPF_ERRNO__NLPARSE;
+
+ if (!tb[TCA_POLICE_TBF])
+ return 0;
+
+ p = nla_data(tb[TCA_POLICE_TBF]);
+
+ NET_START_OBJECT_NESTED("police");
+ NET_DUMP_UINT("index", p->index);
+ NET_DUMP_UINT("rate", p->rate.rate);
+ NET_DUMP_UINT("burst", p->burst);
+ NET_DUMP_UINT("mtu", p->mtu);
+ NET_DUMP_UINT("peakrate", p->peakrate.rate);
+ if (tb[TCA_POLICE_AVRATE])
+ NET_DUMP_UINT("avrate", nla_getattr_u32(tb[TCA_POLICE_AVRATE]));
+ NET_DUMP_UINT("action", p->action);
+ if (tb[TCA_POLICE_RESULT])
+ NET_DUMP_UINT("result", nla_getattr_u32(tb[TCA_POLICE_RESULT]));
+ NET_DUMP_UINT("overhead", p->rate.overhead);
+ NET_DUMP_UINT("ref", p->refcnt);
+ NET_DUMP_UINT("bind", p->bindcnt);
+ if (tb[TCA_POLICE_TM]) {
+ struct tcf_t *tm = nla_data(tb[TCA_ACT_BPF_TM]);
+
+ NET_DUMP_LLUINT("tm_install", tm->install);
+ NET_DUMP_LLUINT("tm_lastuse", tm->lastuse);
+ NET_DUMP_LLUINT("tm_expires", tm->expires);
+ NET_DUMP_LLUINT("tm_firstuse", tm->firstuse);
+ }
+ NET_END_OBJECT_NESTED;
+
+ return 0;
+}
+
+static int do_bpf_act_dump(struct nlattr *attr)
+{
+ struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
+ int act, ret;
+
+ if (nla_parse_nested(tb, TCA_ACT_MAX_PRIO, attr, NULL) < 0)
+ return -LIBBPF_ERRNO__NLPARSE;
+
+ NET_START_ARRAY("act", "");
+ for (act = 0; act <= TCA_ACT_MAX_PRIO; act++) {
+ ret = do_dump_one_act(tb[act]);
+ if (ret)
+ break;
+ }
+ NET_END_ARRAY(" ");
+
+ return ret;
+}
+
+static int do_bpf_filter_dump(struct nlattr *attr)
+{
+ struct nlattr *tb[TCA_BPF_MAX + 1];
+ char buf[256];
+ int ret;
+
+ if (nla_parse_nested(tb, TCA_BPF_MAX, attr, NULL) < 0)
+ return -LIBBPF_ERRNO__NLPARSE;
+
+ if (tb[TCA_BPF_CLASSID])
+ NET_DUMP_UINT("classid", nla_getattr_u32(tb[TCA_BPF_CLASSID]));
+ if (tb[TCA_BPF_NAME])
+ NET_DUMP_STR("name", nla_getattr_str(tb[TCA_BPF_NAME]));
+ if (tb[TCA_BPF_FLAGS]) {
+ unsigned int flags = nla_getattr_u32(tb[TCA_BPF_FLAGS]);
+
+ if (flags & TCA_BPF_FLAG_ACT_DIRECT)
+ NET_DUMP_STR("flags", "direct-action");
+ }
+ if (tb[TCA_BPF_FLAGS_GEN]) {
+ unsigned int flags = nla_getattr_u32(tb[TCA_BPF_FLAGS_GEN]);
+
+ NET_START_ARRAY("flags_gen", "");
+ if (flags & TCA_CLS_FLAGS_SKIP_HW)
+ NET_DUMP_STR_ONLY("skip_hw");
+ if (flags & TCA_CLS_FLAGS_SKIP_SW)
+ NET_DUMP_STR_ONLY("skip_sw");
+ if (flags & TCA_CLS_FLAGS_IN_HW)
+ NET_DUMP_STR_ONLY("in_hw")
+ else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
+ NET_DUMP_STR_ONLY("not_in_hw")
+ NET_END_ARRAY(" ");
+ }
+ if (tb[TCA_BPF_ID])
+ NET_DUMP_UINT("prog_id", nla_getattr_u32(tb[TCA_BPF_ID]));
+ if (tb[TCA_BPF_TAG])
+ NET_DUMP_STR("tag", hexstring_n2a(nla_data(tb[TCA_BPF_TAG]),
+ nla_len(tb[TCA_BPF_TAG]),
+ buf, sizeof(buf)));
+ if (tb[TCA_BPF_POLICE]) {
+ ret = do_bpf_police_dump(tb[TCA_BPF_POLICE]);
+ if (ret)
+ return ret;
+ }
+ if (tb[TCA_BPF_ACT]) {
+ ret = do_bpf_act_dump(tb[TCA_BPF_ACT]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int do_filter_dump(struct tcmsg *info, struct nlattr **tb)
+{
+ int ret = 0;
+
+ if (tb[TCA_OPTIONS] && strcmp(nla_data(tb[TCA_KIND]), "bpf") == 0) {
+ NET_START_OBJECT;
+ NET_DUMP_UINT("ifindex", info->tcm_ifindex);
+ ret = do_bpf_filter_dump(tb[TCA_OPTIONS]);
+ NET_END_OBJECT_FINAL;
+ }
+
+ return ret;
+}
diff --git a/tools/bpf/bpftool/netlink_dumper.h b/tools/bpf/bpftool/netlink_dumper.h
new file mode 100644
index 000000000000..552d8851ac06
--- /dev/null
+++ b/tools/bpf/bpftool/netlink_dumper.h
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2018 Facebook
+
+#ifndef _NETLINK_DUMPER_H_
+#define _NETLINK_DUMPER_H_
+
+#define NET_START_OBJECT \
+{ \
+ if (json_output) \
+ jsonw_start_object(json_wtr); \
+}
+
+#define NET_START_OBJECT_NESTED(name) \
+{ \
+ if (json_output) { \
+ jsonw_name(json_wtr, name); \
+ jsonw_start_object(json_wtr); \
+ } else { \
+ fprintf(stderr, "%s {", name); \
+ } \
+}
+
+#define NET_START_OBJECT_NESTED2 \
+{ \
+ if (json_output) \
+ jsonw_start_object(json_wtr); \
+ else \
+ fprintf(stderr, "{"); \
+}
+
+#define NET_END_OBJECT_NESTED \
+{ \
+ if (json_output) \
+ jsonw_end_object(json_wtr); \
+ else \
+ fprintf(stderr, "}"); \
+}
+
+#define NET_END_OBJECT \
+{ \
+ if (json_output) \
+ jsonw_end_object(json_wtr); \
+}
+
+#define NET_END_OBJECT_FINAL \
+{ \
+ if (json_output) \
+ jsonw_end_object(json_wtr); \
+ else \
+ fprintf(stderr, "\n"); \
+}
+
+#define NET_START_ARRAY(name, newline) \
+{ \
+ if (json_output) { \
+ jsonw_name(json_wtr, name); \
+ jsonw_start_array(json_wtr); \
+ } else { \
+ fprintf(stderr, "%s [%s", name, newline);\
+ } \
+}
+
+#define NET_END_ARRAY(endstr) \
+{ \
+ if (json_output) \
+ jsonw_end_array(json_wtr); \
+ else \
+ fprintf(stderr, "]%s", endstr); \
+}
+
+#define NET_DUMP_UINT(name, val) \
+{ \
+ if (json_output) \
+ jsonw_uint_field(json_wtr, name, val); \
+ else \
+ fprintf(stderr, "%s %d ", name, val); \
+}
+
+#define NET_DUMP_LLUINT(name, val) \
+{ \
+ if (json_output) \
+ jsonw_lluint_field(json_wtr, name, val);\
+ else \
+ fprintf(stderr, "%s %lld ", name, val); \
+}
+
+#define NET_DUMP_STR(name, str) \
+{ \
+ if (json_output) \
+ jsonw_string_field(json_wtr, name, str);\
+ else \
+ fprintf(stderr, "%s %s ", name, str); \
+}
+
+#define NET_DUMP_STR_ONLY(str) \
+{ \
+ if (json_output) \
+ jsonw_string(json_wtr, str); \
+ else \
+ fprintf(stderr, "%s ", str); \
+}
+
+#endif
--
2.17.1
next prev parent reply other threads:[~2018-09-03 22:48 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-03 18:26 [RFC PATCH bpf-next 0/4] tools/bpf: bpftool: add net support Yonghong Song
2018-09-03 18:26 ` [RFC PATCH bpf-next 1/4] tools/bpf: sync kernel uapi header if_link.h to tools Yonghong Song
2018-09-03 18:26 ` [RFC PATCH bpf-next 2/4] tools/bpf: move bpf/lib netlink related functions into a new file Yonghong Song
2018-09-03 18:26 ` [RFC PATCH bpf-next 3/4] tools/bpf: add more netlink functionalities in lib/bpf Yonghong Song
2018-09-03 18:26 ` Yonghong Song [this message]
2018-09-05 17:51 ` [RFC PATCH bpf-next 0/4] tools/bpf: bpftool: add net support Jakub Kicinski
2018-09-05 19:17 ` Yonghong Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180903182647.1244630-5-yhs@fb.com \
--to=yhs@fb.com \
--cc=ast@fb.com \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).