Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Implement link_query for bpf iterators

The link query for bpf iterators is implemented.
Besides being shown to the user what bpf iterator
the link represents, the target_name is also used
to filter out what additional information should be
printed out, e.g., whether map_id should be shown or not.
The following is an example of bpf_iter link dump,
plain output or pretty output.

$ bpftool link show
11: iter prog 59 target_name task
pids test_progs(1749)
34: iter prog 173 target_name bpf_map_elem map_id 127
pids test_progs_1(1753)
$ bpftool -p link show
[{
"id": 11,
"type": "iter",
"prog_id": 59,
"target_name": "task",
"pids": [{
"pid": 1749,
"comm": "test_progs"
}
]
},{
"id": 34,
"type": "iter",
"prog_id": 173,
"target_name": "bpf_map_elem",
"map_id": 127,
"pids": [{
"pid": 1753,
"comm": "test_progs_1"
}
]
}
]

Signed-off-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/20200821184420.574430-1-yhs@fb.com

authored by

Yonghong Song and committed by
Alexei Starovoitov
e60495ea b76f2226

+41 -3
+41 -3
tools/bpf/bpftool/link.c
··· 77 77 jsonw_uint_field(wtr, "attach_type", attach_type); 78 78 } 79 79 80 + static bool is_iter_map_target(const char *target_name) 81 + { 82 + return strcmp(target_name, "bpf_map_elem") == 0 || 83 + strcmp(target_name, "bpf_sk_storage_map") == 0; 84 + } 85 + 86 + static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr) 87 + { 88 + const char *target_name = u64_to_ptr(info->iter.target_name); 89 + 90 + jsonw_string_field(wtr, "target_name", target_name); 91 + 92 + if (is_iter_map_target(target_name)) 93 + jsonw_uint_field(wtr, "map_id", info->iter.map.map_id); 94 + } 95 + 80 96 static int get_prog_info(int prog_id, struct bpf_prog_info *info) 81 97 { 82 98 __u32 len = sizeof(*info); ··· 144 128 info->cgroup.cgroup_id); 145 129 show_link_attach_type_json(info->cgroup.attach_type, json_wtr); 146 130 break; 131 + case BPF_LINK_TYPE_ITER: 132 + show_iter_json(info, json_wtr); 133 + break; 147 134 case BPF_LINK_TYPE_NETNS: 148 135 jsonw_uint_field(json_wtr, "netns_ino", 149 136 info->netns.netns_ino); ··· 194 175 printf("attach_type %u ", attach_type); 195 176 } 196 177 178 + static void show_iter_plain(struct bpf_link_info *info) 179 + { 180 + const char *target_name = u64_to_ptr(info->iter.target_name); 181 + 182 + printf("target_name %s ", target_name); 183 + 184 + if (is_iter_map_target(target_name)) 185 + printf("map_id %u ", info->iter.map.map_id); 186 + } 187 + 197 188 static int show_link_close_plain(int fd, struct bpf_link_info *info) 198 189 { 199 190 struct bpf_prog_info prog_info; ··· 233 204 printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id); 234 205 show_link_attach_type_plain(info->cgroup.attach_type); 235 206 break; 207 + case BPF_LINK_TYPE_ITER: 208 + show_iter_plain(info); 209 + break; 236 210 case BPF_LINK_TYPE_NETNS: 237 211 printf("\n\tnetns_ino %u ", info->netns.netns_ino); 238 212 show_link_attach_type_plain(info->netns.attach_type); ··· 263 231 { 264 232 struct bpf_link_info info; 265 233 __u32 len = sizeof(info); 266 - char raw_tp_name[256]; 234 + char buf[256]; 267 235 int err; 268 236 269 237 memset(&info, 0, sizeof(info)); ··· 277 245 } 278 246 if (info.type == BPF_LINK_TYPE_RAW_TRACEPOINT && 279 247 !info.raw_tracepoint.tp_name) { 280 - info.raw_tracepoint.tp_name = (unsigned long)&raw_tp_name; 281 - info.raw_tracepoint.tp_name_len = sizeof(raw_tp_name); 248 + info.raw_tracepoint.tp_name = (unsigned long)&buf; 249 + info.raw_tracepoint.tp_name_len = sizeof(buf); 250 + goto again; 251 + } 252 + if (info.type == BPF_LINK_TYPE_ITER && 253 + !info.iter.target_name) { 254 + info.iter.target_name = (unsigned long)&buf; 255 + info.iter.target_name_len = sizeof(buf); 282 256 goto again; 283 257 } 284 258