mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
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. v5: fix bpf ci failure: libbpf needs small update to prog_type_name[] and probe_prog_load helper. v4: don't fail with -EOPNOTSUPP in libbpf probe_prog_load, update prog_type_name[] with "netfilter" entry (bpf ci) v3: fix bpf.h copy, 'reserved' member was removed (Alexei) use p_err, not fprintf (Quentin) Suggested-by: Quentin Monnet <quentin@isovalent.com> Link: https://lore.kernel.org/bpf/eeeaac99-9053-90c2-aa33-cc1ecb1ae9ca@isovalent.com/ Reviewed-by: Quentin Monnet <quentin@isovalent.com> Signed-off-by: Florian Westphal <fw@strlen.de> Link: https://lore.kernel.org/r/20230421170300.24115-6-fw@strlen.de Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
0bdc6da88f
commit
d0fe92fb5e
6 changed files with 210 additions and 0 deletions
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include <linux/netfilter_arp.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -135,6 +137,18 @@ static void show_iter_json(struct bpf_link_info *info, json_writer_t *wtr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr)
|
||||||
|
{
|
||||||
|
jsonw_uint_field(json_wtr, "pf",
|
||||||
|
info->netfilter.pf);
|
||||||
|
jsonw_uint_field(json_wtr, "hook",
|
||||||
|
info->netfilter.hooknum);
|
||||||
|
jsonw_int_field(json_wtr, "prio",
|
||||||
|
info->netfilter.priority);
|
||||||
|
jsonw_uint_field(json_wtr, "flags",
|
||||||
|
info->netfilter.flags);
|
||||||
|
}
|
||||||
|
|
||||||
static int get_prog_info(int prog_id, struct bpf_prog_info *info)
|
static int get_prog_info(int prog_id, struct bpf_prog_info *info)
|
||||||
{
|
{
|
||||||
__u32 len = sizeof(*info);
|
__u32 len = sizeof(*info);
|
||||||
|
@ -195,6 +209,10 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
|
||||||
info->netns.netns_ino);
|
info->netns.netns_ino);
|
||||||
show_link_attach_type_json(info->netns.attach_type, json_wtr);
|
show_link_attach_type_json(info->netns.attach_type, json_wtr);
|
||||||
break;
|
break;
|
||||||
|
case BPF_LINK_TYPE_NETFILTER:
|
||||||
|
netfilter_dump_json(info, json_wtr);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -263,6 +281,68 @@ static void show_iter_plain(struct bpf_link_info *info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char * const pf2name[] = {
|
||||||
|
[NFPROTO_INET] = "inet",
|
||||||
|
[NFPROTO_IPV4] = "ip",
|
||||||
|
[NFPROTO_ARP] = "arp",
|
||||||
|
[NFPROTO_NETDEV] = "netdev",
|
||||||
|
[NFPROTO_BRIDGE] = "bridge",
|
||||||
|
[NFPROTO_IPV6] = "ip6",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const inethook2name[] = {
|
||||||
|
[NF_INET_PRE_ROUTING] = "prerouting",
|
||||||
|
[NF_INET_LOCAL_IN] = "input",
|
||||||
|
[NF_INET_FORWARD] = "forward",
|
||||||
|
[NF_INET_LOCAL_OUT] = "output",
|
||||||
|
[NF_INET_POST_ROUTING] = "postrouting",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const arphook2name[] = {
|
||||||
|
[NF_ARP_IN] = "input",
|
||||||
|
[NF_ARP_OUT] = "output",
|
||||||
|
};
|
||||||
|
|
||||||
|
void netfilter_dump_plain(const struct bpf_link_info *info)
|
||||||
|
{
|
||||||
|
const char *hookname = NULL, *pfname = NULL;
|
||||||
|
unsigned int hook = info->netfilter.hooknum;
|
||||||
|
unsigned int pf = info->netfilter.pf;
|
||||||
|
|
||||||
|
if (pf < ARRAY_SIZE(pf2name))
|
||||||
|
pfname = pf2name[pf];
|
||||||
|
|
||||||
|
switch (pf) {
|
||||||
|
case NFPROTO_BRIDGE: /* bridge shares numbers with enum nf_inet_hooks */
|
||||||
|
case NFPROTO_IPV4:
|
||||||
|
case NFPROTO_IPV6:
|
||||||
|
case NFPROTO_INET:
|
||||||
|
if (hook < ARRAY_SIZE(inethook2name))
|
||||||
|
hookname = inethook2name[hook];
|
||||||
|
break;
|
||||||
|
case NFPROTO_ARP:
|
||||||
|
if (hook < ARRAY_SIZE(arphook2name))
|
||||||
|
hookname = arphook2name[hook];
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfname)
|
||||||
|
printf("\n\t%s", pfname);
|
||||||
|
else
|
||||||
|
printf("\n\tpf: %d", pf);
|
||||||
|
|
||||||
|
if (hookname)
|
||||||
|
printf(" %s", hookname);
|
||||||
|
else
|
||||||
|
printf(", hook %u,", hook);
|
||||||
|
|
||||||
|
printf(" prio %d", info->netfilter.priority);
|
||||||
|
|
||||||
|
if (info->netfilter.flags)
|
||||||
|
printf(" flags 0x%x", info->netfilter.flags);
|
||||||
|
}
|
||||||
|
|
||||||
static int show_link_close_plain(int fd, struct bpf_link_info *info)
|
static int show_link_close_plain(int fd, struct bpf_link_info *info)
|
||||||
{
|
{
|
||||||
struct bpf_prog_info prog_info;
|
struct bpf_prog_info prog_info;
|
||||||
|
@ -301,6 +381,9 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
|
||||||
printf("\n\tnetns_ino %u ", info->netns.netns_ino);
|
printf("\n\tnetns_ino %u ", info->netns.netns_ino);
|
||||||
show_link_attach_type_plain(info->netns.attach_type);
|
show_link_attach_type_plain(info->netns.attach_type);
|
||||||
break;
|
break;
|
||||||
|
case BPF_LINK_TYPE_NETFILTER:
|
||||||
|
netfilter_dump_plain(info);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,4 +267,7 @@ static inline bool hashmap__empty(struct hashmap *map)
|
||||||
int pathname_concat(char *buf, int buf_sz, const char *path,
|
int pathname_concat(char *buf, int buf_sz, const char *path,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
|
/* print netfilter bpf_link info */
|
||||||
|
void netfilter_dump_plain(const struct bpf_link_info *info);
|
||||||
|
void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -647,6 +647,108 @@ static int do_detach(int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int netfilter_link_compar(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct bpf_link_info *nfa = a;
|
||||||
|
const struct bpf_link_info *nfb = b;
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
delta = nfa->netfilter.pf - nfb->netfilter.pf;
|
||||||
|
if (delta)
|
||||||
|
return delta;
|
||||||
|
|
||||||
|
delta = nfa->netfilter.hooknum - nfb->netfilter.hooknum;
|
||||||
|
if (delta)
|
||||||
|
return delta;
|
||||||
|
|
||||||
|
if (nfa->netfilter.priority < nfb->netfilter.priority)
|
||||||
|
return -1;
|
||||||
|
if (nfa->netfilter.priority > nfb->netfilter.priority)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return nfa->netfilter.flags - nfb->netfilter.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_link_netfilter(void)
|
||||||
|
{
|
||||||
|
unsigned int nf_link_len = 0, nf_link_count = 0;
|
||||||
|
struct bpf_link_info *nf_link_info = NULL;
|
||||||
|
__u32 id = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
struct bpf_link_info info;
|
||||||
|
int fd, err;
|
||||||
|
__u32 len;
|
||||||
|
|
||||||
|
err = bpf_link_get_next_id(id, &id);
|
||||||
|
if (err) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
break;
|
||||||
|
p_err("can't get next link: %s (id %d)", strerror(errno), id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = bpf_link_get_fd_by_id(id);
|
||||||
|
if (fd < 0) {
|
||||||
|
p_err("can't get link by id (%u): %s", id, strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
len = sizeof(info);
|
||||||
|
|
||||||
|
err = bpf_link_get_info_by_fd(fd, &info, &len);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
p_err("can't get link info for fd %d: %s", fd, strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.type != BPF_LINK_TYPE_NETFILTER)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nf_link_count >= nf_link_len) {
|
||||||
|
static const unsigned int max_link_count = INT_MAX / sizeof(info);
|
||||||
|
struct bpf_link_info *expand;
|
||||||
|
|
||||||
|
if (nf_link_count > max_link_count) {
|
||||||
|
p_err("cannot handle more than %u links\n", max_link_count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nf_link_len += 16;
|
||||||
|
|
||||||
|
expand = realloc(nf_link_info, nf_link_len * sizeof(info));
|
||||||
|
if (!expand) {
|
||||||
|
p_err("realloc: %s", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nf_link_info = expand;
|
||||||
|
}
|
||||||
|
|
||||||
|
nf_link_info[nf_link_count] = info;
|
||||||
|
nf_link_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(nf_link_info, nf_link_count, sizeof(*nf_link_info), netfilter_link_compar);
|
||||||
|
|
||||||
|
for (id = 0; id < nf_link_count; id++) {
|
||||||
|
NET_START_OBJECT;
|
||||||
|
if (json_output)
|
||||||
|
netfilter_dump_json(&nf_link_info[id], json_wtr);
|
||||||
|
else
|
||||||
|
netfilter_dump_plain(&nf_link_info[id]);
|
||||||
|
|
||||||
|
NET_DUMP_UINT("id", " prog_id %u", nf_link_info[id].prog_id);
|
||||||
|
NET_END_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(nf_link_info);
|
||||||
|
}
|
||||||
|
|
||||||
static int do_show(int argc, char **argv)
|
static int do_show(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct bpf_attach_info attach_info = {};
|
struct bpf_attach_info attach_info = {};
|
||||||
|
@ -701,6 +803,10 @@ static int do_show(int argc, char **argv)
|
||||||
NET_DUMP_UINT("id", "id %u", attach_info.flow_dissector_id);
|
NET_DUMP_UINT("id", "id %u", attach_info.flow_dissector_id);
|
||||||
NET_END_ARRAY("\n");
|
NET_END_ARRAY("\n");
|
||||||
|
|
||||||
|
NET_START_ARRAY("netfilter", "%s:\n");
|
||||||
|
show_link_netfilter();
|
||||||
|
NET_END_ARRAY("\n");
|
||||||
|
|
||||||
NET_END_OBJECT;
|
NET_END_OBJECT;
|
||||||
if (json_output)
|
if (json_output)
|
||||||
jsonw_end_array(json_wtr);
|
jsonw_end_array(json_wtr);
|
||||||
|
|
|
@ -986,6 +986,7 @@ enum bpf_prog_type {
|
||||||
BPF_PROG_TYPE_LSM,
|
BPF_PROG_TYPE_LSM,
|
||||||
BPF_PROG_TYPE_SK_LOOKUP,
|
BPF_PROG_TYPE_SK_LOOKUP,
|
||||||
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
||||||
|
BPF_PROG_TYPE_NETFILTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_attach_type {
|
enum bpf_attach_type {
|
||||||
|
@ -1050,6 +1051,7 @@ enum bpf_link_type {
|
||||||
BPF_LINK_TYPE_PERF_EVENT = 7,
|
BPF_LINK_TYPE_PERF_EVENT = 7,
|
||||||
BPF_LINK_TYPE_KPROBE_MULTI = 8,
|
BPF_LINK_TYPE_KPROBE_MULTI = 8,
|
||||||
BPF_LINK_TYPE_STRUCT_OPS = 9,
|
BPF_LINK_TYPE_STRUCT_OPS = 9,
|
||||||
|
BPF_LINK_TYPE_NETFILTER = 10,
|
||||||
|
|
||||||
MAX_BPF_LINK_TYPE,
|
MAX_BPF_LINK_TYPE,
|
||||||
};
|
};
|
||||||
|
@ -1560,6 +1562,12 @@ union bpf_attr {
|
||||||
*/
|
*/
|
||||||
__u64 cookie;
|
__u64 cookie;
|
||||||
} tracing;
|
} tracing;
|
||||||
|
struct {
|
||||||
|
__u32 pf;
|
||||||
|
__u32 hooknum;
|
||||||
|
__s32 priority;
|
||||||
|
__u32 flags;
|
||||||
|
} netfilter;
|
||||||
};
|
};
|
||||||
} link_create;
|
} link_create;
|
||||||
|
|
||||||
|
@ -6410,6 +6418,12 @@ struct bpf_link_info {
|
||||||
struct {
|
struct {
|
||||||
__u32 map_id;
|
__u32 map_id;
|
||||||
} struct_ops;
|
} struct_ops;
|
||||||
|
struct {
|
||||||
|
__u32 pf;
|
||||||
|
__u32 hooknum;
|
||||||
|
__s32 priority;
|
||||||
|
__u32 flags;
|
||||||
|
} netfilter;
|
||||||
};
|
};
|
||||||
} __attribute__((aligned(8)));
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ static const char * const link_type_name[] = {
|
||||||
[BPF_LINK_TYPE_PERF_EVENT] = "perf_event",
|
[BPF_LINK_TYPE_PERF_EVENT] = "perf_event",
|
||||||
[BPF_LINK_TYPE_KPROBE_MULTI] = "kprobe_multi",
|
[BPF_LINK_TYPE_KPROBE_MULTI] = "kprobe_multi",
|
||||||
[BPF_LINK_TYPE_STRUCT_OPS] = "struct_ops",
|
[BPF_LINK_TYPE_STRUCT_OPS] = "struct_ops",
|
||||||
|
[BPF_LINK_TYPE_NETFILTER] = "netfilter",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const map_type_name[] = {
|
static const char * const map_type_name[] = {
|
||||||
|
@ -201,6 +202,7 @@ static const char * const prog_type_name[] = {
|
||||||
[BPF_PROG_TYPE_LSM] = "lsm",
|
[BPF_PROG_TYPE_LSM] = "lsm",
|
||||||
[BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup",
|
[BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup",
|
||||||
[BPF_PROG_TYPE_SYSCALL] = "syscall",
|
[BPF_PROG_TYPE_SYSCALL] = "syscall",
|
||||||
|
[BPF_PROG_TYPE_NETFILTER] = "netfilter",
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __base_pr(enum libbpf_print_level level, const char *format,
|
static int __base_pr(enum libbpf_print_level level, const char *format,
|
||||||
|
@ -8710,6 +8712,7 @@ static const struct bpf_sec_def section_defs[] = {
|
||||||
SEC_DEF("struct_ops+", STRUCT_OPS, 0, SEC_NONE),
|
SEC_DEF("struct_ops+", STRUCT_OPS, 0, SEC_NONE),
|
||||||
SEC_DEF("struct_ops.s+", STRUCT_OPS, 0, SEC_SLEEPABLE),
|
SEC_DEF("struct_ops.s+", STRUCT_OPS, 0, SEC_SLEEPABLE),
|
||||||
SEC_DEF("sk_lookup", SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
|
SEC_DEF("sk_lookup", SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
|
||||||
|
SEC_DEF("netfilter", NETFILTER, 0, SEC_NONE),
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t custom_sec_def_cnt;
|
static size_t custom_sec_def_cnt;
|
||||||
|
|
|
@ -180,6 +180,7 @@ static int probe_prog_load(enum bpf_prog_type prog_type,
|
||||||
case BPF_PROG_TYPE_SK_REUSEPORT:
|
case BPF_PROG_TYPE_SK_REUSEPORT:
|
||||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||||
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
case BPF_PROG_TYPE_CGROUP_SYSCTL:
|
||||||
|
case BPF_PROG_TYPE_NETFILTER:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue