aboutsummaryrefslogtreecommitdiffstats
path: root/tools/bpf/bpftool/net.c
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2018-09-17 19:13:00 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-09-18 11:42:31 -0400
commit7900efc19214e326913dc0f0e8ded24adc0018f2 (patch)
tree9dcb527a1ec501454909874b3c4c410c76f61c54 /tools/bpf/bpftool/net.c
parent70e88c758a6b8544b5e0d982e55d1e36f9aa0b85 (diff)
tools/bpf: bpftool: improve output format for bpftool net
This is a followup patch for Commit f6f3bac08ff9 ("tools/bpf: bpftool: add net support"). Some improvements are made for the bpftool net output. Specially, plain output is more concise such that per attachment should nicely fit in one line. Compared to previous output, the prog tag is removed since it can be easily obtained with program id. Similar to xdp attachments, the device name is added to tc attachments. The bpf program attached through shared block mechanism is supported as well. $ ip link add dev v1 type veth peer name v2 $ tc qdisc add dev v1 ingress_block 10 egress_block 20 clsact $ tc qdisc add dev v2 ingress_block 10 egress_block 20 clsact $ tc filter add block 10 protocol ip prio 25 bpf obj bpf_shared.o sec ingress flowid 1:1 $ tc filter add block 20 protocol ip prio 30 bpf obj bpf_cyclic.o sec classifier flowid 1:1 $ bpftool net xdp: tc: v2(7) clsact/ingress bpf_shared.o:[ingress] id 23 v2(7) clsact/egress bpf_cyclic.o:[classifier] id 24 v1(8) clsact/ingress bpf_shared.o:[ingress] id 23 v1(8) clsact/egress bpf_cyclic.o:[classifier] id 24 The documentation and "bpftool net help" are updated to make it clear that current implementation only supports xdp and tc attachments. For programs attached to cgroups, "bpftool cgroup" can be used to dump attachments. For other programs e.g. sk_{filter,skb,msg,reuseport} and lwt/seg6, iproute2 tools should be used. The new output: $ bpftool net xdp: eth0(2) driver id 198 tc: eth0(2) clsact/ingress fbflow_icmp id 335 act [{icmp_action id 336}] eth0(2) clsact/egress fbflow_egress id 334 $ bpftool -jp net [{ "xdp": [{ "devname": "eth0", "ifindex": 2, "mode": "driver", "id": 198 } ], "tc": [{ "devname": "eth0", "ifindex": 2, "kind": "clsact/ingress", "name": "fbflow_icmp", "id": 335, "act": [{ "name": "icmp_action", "id": 336 } ] },{ "devname": "eth0", "ifindex": 2, "kind": "clsact/egress", "name": "fbflow_egress", "id": 334 } ] } ] Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools/bpf/bpftool/net.c')
-rw-r--r--tools/bpf/bpftool/net.c103
1 files changed, 71 insertions, 32 deletions
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 77dd73dd9ade..ed205ee57655 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -2,6 +2,7 @@
2// Copyright (C) 2018 Facebook 2// Copyright (C) 2018 Facebook
3 3
4#define _GNU_SOURCE 4#define _GNU_SOURCE
5#include <errno.h>
5#include <stdlib.h> 6#include <stdlib.h>
6#include <string.h> 7#include <string.h>
7#include <unistd.h> 8#include <unistd.h>
@@ -17,8 +18,13 @@
17#include "main.h" 18#include "main.h"
18#include "netlink_dumper.h" 19#include "netlink_dumper.h"
19 20
21struct ip_devname_ifindex {
22 char devname[64];
23 int ifindex;
24};
25
20struct bpf_netdev_t { 26struct bpf_netdev_t {
21 int *ifindex_array; 27 struct ip_devname_ifindex *devices;
22 int used_len; 28 int used_len;
23 int array_len; 29 int array_len;
24 int filter_idx; 30 int filter_idx;
@@ -36,6 +42,12 @@ struct bpf_tcinfo_t {
36 bool is_qdisc; 42 bool is_qdisc;
37}; 43};
38 44
45struct bpf_filter_t {
46 const char *kind;
47 const char *devname;
48 int ifindex;
49};
50
39static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb) 51static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
40{ 52{
41 struct bpf_netdev_t *netinfo = cookie; 53 struct bpf_netdev_t *netinfo = cookie;
@@ -45,11 +57,20 @@ static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
45 return 0; 57 return 0;
46 58
47 if (netinfo->used_len == netinfo->array_len) { 59 if (netinfo->used_len == netinfo->array_len) {
48 netinfo->ifindex_array = realloc(netinfo->ifindex_array, 60 netinfo->devices = realloc(netinfo->devices,
49 (netinfo->array_len + 16) * sizeof(int)); 61 (netinfo->array_len + 16) *
62 sizeof(struct ip_devname_ifindex));
63 if (!netinfo->devices)
64 return -ENOMEM;
65
50 netinfo->array_len += 16; 66 netinfo->array_len += 16;
51 } 67 }
52 netinfo->ifindex_array[netinfo->used_len++] = ifinfo->ifi_index; 68 netinfo->devices[netinfo->used_len].ifindex = ifinfo->ifi_index;
69 snprintf(netinfo->devices[netinfo->used_len].devname,
70 sizeof(netinfo->devices[netinfo->used_len].devname),
71 "%s",
72 tb[IFLA_IFNAME] ? nla_getattr_str(tb[IFLA_IFNAME]) : "");
73 netinfo->used_len++;
53 74
54 return do_xdp_dump(ifinfo, tb); 75 return do_xdp_dump(ifinfo, tb);
55} 76}
@@ -71,13 +92,15 @@ static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb)
71 if (tcinfo->used_len == tcinfo->array_len) { 92 if (tcinfo->used_len == tcinfo->array_len) {
72 tcinfo->handle_array = realloc(tcinfo->handle_array, 93 tcinfo->handle_array = realloc(tcinfo->handle_array,
73 (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle)); 94 (tcinfo->array_len + 16) * sizeof(struct tc_kind_handle));
95 if (!tcinfo->handle_array)
96 return -ENOMEM;
97
74 tcinfo->array_len += 16; 98 tcinfo->array_len += 16;
75 } 99 }
76 tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle; 100 tcinfo->handle_array[tcinfo->used_len].handle = info->tcm_handle;
77 snprintf(tcinfo->handle_array[tcinfo->used_len].kind, 101 snprintf(tcinfo->handle_array[tcinfo->used_len].kind,
78 sizeof(tcinfo->handle_array[tcinfo->used_len].kind), 102 sizeof(tcinfo->handle_array[tcinfo->used_len].kind),
79 "%s_%s", 103 "%s",
80 tcinfo->is_qdisc ? "qdisc" : "class",
81 tb[TCA_KIND] ? nla_getattr_str(tb[TCA_KIND]) : "unknown"); 104 tb[TCA_KIND] ? nla_getattr_str(tb[TCA_KIND]) : "unknown");
82 tcinfo->used_len++; 105 tcinfo->used_len++;
83 106
@@ -86,60 +109,71 @@ static int dump_class_qdisc_nlmsg(void *cookie, void *msg, struct nlattr **tb)
86 109
87static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb) 110static int dump_filter_nlmsg(void *cookie, void *msg, struct nlattr **tb)
88{ 111{
89 const char *kind = cookie; 112 const struct bpf_filter_t *filter_info = cookie;
90 113
91 return do_filter_dump((struct tcmsg *)msg, tb, kind); 114 return do_filter_dump((struct tcmsg *)msg, tb, filter_info->kind,
115 filter_info->devname, filter_info->ifindex);
92} 116}
93 117
94static int show_dev_tc_bpf(int sock, unsigned int nl_pid, int ifindex) 118static int show_dev_tc_bpf(int sock, unsigned int nl_pid,
119 struct ip_devname_ifindex *dev)
95{ 120{
121 struct bpf_filter_t filter_info;
96 struct bpf_tcinfo_t tcinfo; 122 struct bpf_tcinfo_t tcinfo;
97 int i, handle, ret; 123 int i, handle, ret = 0;
98 124
99 tcinfo.handle_array = NULL; 125 tcinfo.handle_array = NULL;
100 tcinfo.used_len = 0; 126 tcinfo.used_len = 0;
101 tcinfo.array_len = 0; 127 tcinfo.array_len = 0;
102 128
103 tcinfo.is_qdisc = false; 129 tcinfo.is_qdisc = false;
104 ret = nl_get_class(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg, 130 ret = nl_get_class(sock, nl_pid, dev->ifindex, dump_class_qdisc_nlmsg,
105 &tcinfo); 131 &tcinfo);
106 if (ret) 132 if (ret)
107 return ret; 133 goto out;
108 134
109 tcinfo.is_qdisc = true; 135 tcinfo.is_qdisc = true;
110 ret = nl_get_qdisc(sock, nl_pid, ifindex, dump_class_qdisc_nlmsg, 136 ret = nl_get_qdisc(sock, nl_pid, dev->ifindex, dump_class_qdisc_nlmsg,
111 &tcinfo); 137 &tcinfo);
112 if (ret) 138 if (ret)
113 return ret; 139 goto out;
114 140
141 filter_info.devname = dev->devname;
142 filter_info.ifindex = dev->ifindex;
115 for (i = 0; i < tcinfo.used_len; i++) { 143 for (i = 0; i < tcinfo.used_len; i++) {
116 ret = nl_get_filter(sock, nl_pid, ifindex, 144 filter_info.kind = tcinfo.handle_array[i].kind;
145 ret = nl_get_filter(sock, nl_pid, dev->ifindex,
117 tcinfo.handle_array[i].handle, 146 tcinfo.handle_array[i].handle,
118 dump_filter_nlmsg, 147 dump_filter_nlmsg,
119 tcinfo.handle_array[i].kind); 148 &filter_info);
120 if (ret) 149 if (ret)
121 return ret; 150 goto out;
122 } 151 }
123 152
124 /* root, ingress and egress handle */ 153 /* root, ingress and egress handle */
125 handle = TC_H_ROOT; 154 handle = TC_H_ROOT;
126 ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, 155 filter_info.kind = "root";
127 "root"); 156 ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle,
157 dump_filter_nlmsg, &filter_info);
128 if (ret) 158 if (ret)
129 return ret; 159 goto out;
130 160
131 handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS); 161 handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_INGRESS);
132 ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, 162 filter_info.kind = "clsact/ingress";
133 "qdisc_clsact_ingress"); 163 ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle,
164 dump_filter_nlmsg, &filter_info);
134 if (ret) 165 if (ret)
135 return ret; 166 goto out;
136 167
137 handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS); 168 handle = TC_H_MAKE(TC_H_CLSACT, TC_H_MIN_EGRESS);
138 ret = nl_get_filter(sock, nl_pid, ifindex, handle, dump_filter_nlmsg, 169 filter_info.kind = "clsact/egress";
139 "qdisc_clsact_egress"); 170 ret = nl_get_filter(sock, nl_pid, dev->ifindex, handle,
171 dump_filter_nlmsg, &filter_info);
140 if (ret) 172 if (ret)
141 return ret; 173 goto out;
142 174
175out:
176 free(tcinfo.handle_array);
143 return 0; 177 return 0;
144} 178}
145 179
@@ -168,7 +202,7 @@ static int do_show(int argc, char **argv)
168 return -1; 202 return -1;
169 } 203 }
170 204
171 dev_array.ifindex_array = NULL; 205 dev_array.devices = NULL;
172 dev_array.used_len = 0; 206 dev_array.used_len = 0;
173 dev_array.array_len = 0; 207 dev_array.array_len = 0;
174 dev_array.filter_idx = filter_idx; 208 dev_array.filter_idx = filter_idx;
@@ -176,15 +210,15 @@ static int do_show(int argc, char **argv)
176 if (json_output) 210 if (json_output)
177 jsonw_start_array(json_wtr); 211 jsonw_start_array(json_wtr);
178 NET_START_OBJECT; 212 NET_START_OBJECT;
179 NET_START_ARRAY("xdp", "\n"); 213 NET_START_ARRAY("xdp", "%s:\n");
180 ret = nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array); 214 ret = nl_get_link(sock, nl_pid, dump_link_nlmsg, &dev_array);
181 NET_END_ARRAY("\n"); 215 NET_END_ARRAY("\n");
182 216
183 if (!ret) { 217 if (!ret) {
184 NET_START_ARRAY("tc_filters", "\n"); 218 NET_START_ARRAY("tc", "%s:\n");
185 for (i = 0; i < dev_array.used_len; i++) { 219 for (i = 0; i < dev_array.used_len; i++) {
186 ret = show_dev_tc_bpf(sock, nl_pid, 220 ret = show_dev_tc_bpf(sock, nl_pid,
187 dev_array.ifindex_array[i]); 221 &dev_array.devices[i]);
188 if (ret) 222 if (ret)
189 break; 223 break;
190 } 224 }
@@ -200,7 +234,7 @@ static int do_show(int argc, char **argv)
200 libbpf_strerror(ret, err_buf, sizeof(err_buf)); 234 libbpf_strerror(ret, err_buf, sizeof(err_buf));
201 fprintf(stderr, "Error: %s\n", err_buf); 235 fprintf(stderr, "Error: %s\n", err_buf);
202 } 236 }
203 free(dev_array.ifindex_array); 237 free(dev_array.devices);
204 close(sock); 238 close(sock);
205 return ret; 239 return ret;
206} 240}
@@ -214,7 +248,12 @@ static int do_help(int argc, char **argv)
214 248
215 fprintf(stderr, 249 fprintf(stderr,
216 "Usage: %s %s { show | list } [dev <devname>]\n" 250 "Usage: %s %s { show | list } [dev <devname>]\n"
217 " %s %s help\n", 251 " %s %s help\n"
252 "Note: Only xdp and tc attachments are supported now.\n"
253 " For progs attached to cgroups, use \"bpftool cgroup\"\n"
254 " to dump program attachments. For program types\n"
255 " sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
256 " consult iproute2.\n",
218 bin_name, argv[-2], bin_name, argv[-2]); 257 bin_name, argv[-2], bin_name, argv[-2]);
219 258
220 return 0; 259 return 0;