Skip to content

Commit 20afe95

Browse files
Florian WestphalKernel Patches Daemon
authored andcommitted
tools: bpftool: print netfilter link info
Dump protocol family, hook and priority value: $ bpftool link 2: netfilter prog 14 ip input prio -128 pids install(3264) 5: netfilter prog 14 ip6 forward prio 21 pids a.out(3387) 9: netfilter prog 14 ip prerouting prio 123 pids a.out(5700) 10: netfilter prog 14 ip input prio 21 pids test2(5701) v2: Quentin Monnet suggested to also add 'bpftool net' support: $ bpftool net xdp: tc: flow_dissector: netfilter: ip prerouting prio 21 prog_id 14 ip input prio -128 prog_id 14 ip input prio 21 prog_id 14 ip forward prio 21 prog_id 14 ip output prio 21 prog_id 14 ip postrouting prio 21 prog_id 14 'bpftool net' only dumps netfilter link type, links are sorted by protocol family, hook and priority. v4: fix bpf.h copy, 'reserved' member was removed (Alexei) use p_err, not fprintf (Quentin) Suggested-by: Quentin Monnet <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]/ Reviewed-by: Quentin Monnet <[email protected]> Signed-off-by: Florian Westphal <[email protected]>
1 parent 33d6bdb commit 20afe95

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

tools/bpf/bpftool/link.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include <errno.h>
55
#include <linux/err.h>
6+
#include <linux/netfilter.h>
7+
#include <linux/netfilter_arp.h>
68
#include <net/if.h>
79
#include <stdio.h>
810
#include <unistd.h>
@@ -135,6 +137,18 @@ static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr)
135137
}
136138
}
137139

140+
void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr)
141+
{
142+
jsonw_uint_field(json_wtr, "pf",
143+
info->netfilter.pf);
144+
jsonw_uint_field(json_wtr, "hook",
145+
info->netfilter.hooknum);
146+
jsonw_int_field(json_wtr, "prio",
147+
info->netfilter.priority);
148+
jsonw_uint_field(json_wtr, "flags",
149+
info->netfilter.flags);
150+
}
151+
138152
static int get_prog_info(int prog_id, struct bpf_prog_info *info)
139153
{
140154
__u32 len = sizeof(*info);
@@ -195,6 +209,10 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
195209
info->netns.netns_ino);
196210
show_link_attach_type_json(info->netns.attach_type, json_wtr);
197211
break;
212+
case BPF_LINK_TYPE_NETFILTER:
213+
netfilter_dump_json(info, json_wtr);
214+
break;
215+
198216
default:
199217
break;
200218
}
@@ -263,6 +281,68 @@ static void show_iter_plain(struct bpf_link_info *info)
263281
}
264282
}
265283

284+
static const char * const pf2name[] = {
285+
[NFPROTO_INET] = "inet",
286+
[NFPROTO_IPV4] = "ip",
287+
[NFPROTO_ARP] = "arp",
288+
[NFPROTO_NETDEV] = "netdev",
289+
[NFPROTO_BRIDGE] = "bridge",
290+
[NFPROTO_IPV6] = "ip6",
291+
};
292+
293+
static const char * const inethook2name[] = {
294+
[NF_INET_PRE_ROUTING] = "prerouting",
295+
[NF_INET_LOCAL_IN] = "input",
296+
[NF_INET_FORWARD] = "forward",
297+
[NF_INET_LOCAL_OUT] = "output",
298+
[NF_INET_POST_ROUTING] = "postrouting",
299+
};
300+
301+
static const char * const arphook2name[] = {
302+
[NF_ARP_IN] = "input",
303+
[NF_ARP_OUT] = "output",
304+
};
305+
306+
void netfilter_dump_plain(const struct bpf_link_info *info)
307+
{
308+
const char *hookname = NULL, *pfname = NULL;
309+
unsigned int hook = info->netfilter.hooknum;
310+
unsigned int pf = info->netfilter.pf;
311+
312+
if (pf < ARRAY_SIZE(pf2name))
313+
pfname = pf2name[pf];
314+
315+
switch (pf) {
316+
case NFPROTO_BRIDGE: /* bridge shares numbers with enum nf_inet_hooks */
317+
case NFPROTO_IPV4:
318+
case NFPROTO_IPV6:
319+
case NFPROTO_INET:
320+
if (hook < ARRAY_SIZE(inethook2name))
321+
hookname = inethook2name[hook];
322+
break;
323+
case NFPROTO_ARP:
324+
if (hook < ARRAY_SIZE(arphook2name))
325+
hookname = arphook2name[hook];
326+
default:
327+
break;
328+
}
329+
330+
if (pfname)
331+
printf("\n\t%s", pfname);
332+
else
333+
printf("\n\tpf: %d", pf);
334+
335+
if (hookname)
336+
printf(" %s", hookname);
337+
else
338+
printf(", hook %u,", hook);
339+
340+
printf(" prio %d", info->netfilter.priority);
341+
342+
if (info->netfilter.flags)
343+
printf(" flags 0x%x", info->netfilter.flags);
344+
}
345+
266346
static int show_link_close_plain(int fd, struct bpf_link_info *info)
267347
{
268348
struct bpf_prog_info prog_info;
@@ -301,6 +381,9 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
301381
printf("\n\tnetns_ino %u ", info->netns.netns_ino);
302382
show_link_attach_type_plain(info->netns.attach_type);
303383
break;
384+
case BPF_LINK_TYPE_NETFILTER:
385+
netfilter_dump_plain(info);
386+
break;
304387
default:
305388
break;
306389
}

tools/bpf/bpftool/main.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,4 +264,7 @@ static inline bool hashmap__empty(struct hashmap *map)
264264
return map ? hashmap__size(map) == 0 : true;
265265
}
266266

267+
/* print netfilter bpf_link info */
268+
void netfilter_dump_plain(const struct bpf_link_info *info);
269+
void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr);
267270
#endif

tools/bpf/bpftool/net.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,108 @@ static int do_detach(int argc, char **argv)
647647
return 0;
648648
}
649649

650+
static int netfilter_link_compar(const void *a, const void *b)
651+
{
652+
const struct bpf_link_info *nfa = a;
653+
const struct bpf_link_info *nfb = b;
654+
int delta;
655+
656+
delta = nfa->netfilter.pf - nfb->netfilter.pf;
657+
if (delta)
658+
return delta;
659+
660+
delta = nfa->netfilter.hooknum - nfb->netfilter.hooknum;
661+
if (delta)
662+
return delta;
663+
664+
if (nfa->netfilter.priority < nfb->netfilter.priority)
665+
return -1;
666+
if (nfa->netfilter.priority > nfb->netfilter.priority)
667+
return 1;
668+
669+
return nfa->netfilter.flags - nfb->netfilter.flags;
670+
}
671+
672+
static void show_link_netfilter(void)
673+
{
674+
unsigned int nf_link_len = 0, nf_link_count = 0;
675+
struct bpf_link_info *nf_link_info = NULL;
676+
__u32 id = 0;
677+
678+
while (true) {
679+
struct bpf_link_info info;
680+
int fd, err;
681+
__u32 len;
682+
683+
err = bpf_link_get_next_id(id, &id);
684+
if (err) {
685+
if (errno == ENOENT)
686+
break;
687+
p_err("can't get next link: %s (id %d)", strerror(errno), id);
688+
break;
689+
}
690+
691+
fd = bpf_link_get_fd_by_id(id);
692+
if (fd < 0) {
693+
p_err("can't get link by id (%u): %s", id, strerror(errno));
694+
continue;
695+
}
696+
697+
memset(&info, 0, sizeof(info));
698+
len = sizeof(info);
699+
700+
err = bpf_link_get_info_by_fd(fd, &info, &len);
701+
702+
close(fd);
703+
704+
if (err) {
705+
p_err("can't get link info for fd %d: %s", fd, strerror(errno));
706+
continue;
707+
}
708+
709+
if (info.type != BPF_LINK_TYPE_NETFILTER)
710+
continue;
711+
712+
if (nf_link_count >= nf_link_len) {
713+
static const unsigned int max_link_count = INT_MAX / sizeof(info);
714+
struct bpf_link_info *expand;
715+
716+
if (nf_link_count > max_link_count) {
717+
p_err("cannot handle more than %u links\n", max_link_count);
718+
break;
719+
}
720+
721+
nf_link_len += 16;
722+
723+
expand = realloc(nf_link_info, nf_link_len * sizeof(info));
724+
if (!expand) {
725+
p_err("realloc: %s", strerror(errno));
726+
break;
727+
}
728+
729+
nf_link_info = expand;
730+
}
731+
732+
nf_link_info[nf_link_count] = info;
733+
nf_link_count++;
734+
}
735+
736+
qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar);
737+
738+
for (id = 0; id < nf_link_count; id++) {
739+
NET_START_OBJECT;
740+
if (json_output)
741+
netfilter_dump_json(&nf_link_info[id], json_wtr);
742+
else
743+
netfilter_dump_plain(&nf_link_info[id]);
744+
745+
NET_DUMP_UINT("id", " prog_id %u", nf_link_info[id].prog_id);
746+
NET_END_OBJECT;
747+
}
748+
749+
free(nf_link_info);
750+
}
751+
650752
static int do_show(int argc, char **argv)
651753
{
652754
struct bpf_attach_info attach_info = {};
@@ -701,6 +803,10 @@ static int do_show(int argc, char **argv)
701803
NET_DUMP_UINT("id", "id %u", attach_info.flow_dissector_id);
702804
NET_END_ARRAY("\n");
703805

806+
NET_START_ARRAY("netfilter", "%s:\n");
807+
show_link_netfilter();
808+
NET_END_ARRAY("\n");
809+
704810
NET_END_OBJECT;
705811
if (json_output)
706812
jsonw_end_array(json_wtr);

tools/include/uapi/linux/bpf.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,7 @@ enum bpf_prog_type {
986986
BPF_PROG_TYPE_LSM,
987987
BPF_PROG_TYPE_SK_LOOKUP,
988988
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
989+
BPF_PROG_TYPE_NETFILTER,
989990
};
990991

991992
enum bpf_attach_type {
@@ -1050,6 +1051,7 @@ enum bpf_link_type {
10501051
BPF_LINK_TYPE_PERF_EVENT = 7,
10511052
BPF_LINK_TYPE_KPROBE_MULTI = 8,
10521053
BPF_LINK_TYPE_STRUCT_OPS = 9,
1054+
BPF_LINK_TYPE_NETFILTER = 10,
10531055

10541056
MAX_BPF_LINK_TYPE,
10551057
};
@@ -1560,6 +1562,12 @@ union bpf_attr {
15601562
*/
15611563
__u64 cookie;
15621564
} tracing;
1565+
struct {
1566+
__u32 pf;
1567+
__u32 hooknum;
1568+
__s32 priority;
1569+
__u32 flags;
1570+
} netfilter;
15631571
};
15641572
} link_create;
15651573

@@ -6410,6 +6418,12 @@ struct bpf_link_info {
64106418
struct {
64116419
__u32 map_id;
64126420
} struct_ops;
6421+
struct {
6422+
__u32 pf;
6423+
__u32 hooknum;
6424+
__s32 priority;
6425+
__u32 flags;
6426+
} netfilter;
64136427
};
64146428
} __attribute__((aligned(8)));
64156429

tools/lib/bpf/libbpf.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ static const char * const link_type_name[] = {
130130
[BPF_LINK_TYPE_PERF_EVENT] = "perf_event",
131131
[BPF_LINK_TYPE_KPROBE_MULTI] = "kprobe_multi",
132132
[BPF_LINK_TYPE_STRUCT_OPS] = "struct_ops",
133+
[BPF_LINK_TYPE_NETFILTER] = "netfilter",
133134
};
134135

135136
static const char * const map_type_name[] = {
@@ -8710,6 +8711,7 @@ static const struct bpf_sec_def section_defs[] = {
87108711
SEC_DEF("struct_ops+", STRUCT_OPS, 0, SEC_NONE),
87118712
SEC_DEF("struct_ops.s+", STRUCT_OPS, 0, SEC_SLEEPABLE),
87128713
SEC_DEF("sk_lookup", SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
8714+
SEC_DEF("netfilter", NETFILTER, 0, SEC_NONE),
87138715
};
87148716

87158717
static size_t custom_sec_def_cnt;

0 commit comments

Comments
 (0)