net: bpf: Add netlink and ipv6_route bpf_iter targets

This patch added netlink and ipv6_route targets, using
the same seq_ops (except show() and minor changes for stop())
for /proc/net/{netlink,ipv6_route}.

The net namespace for these targets are the current net
namespace at file open stage, similar to
/proc/net/{netlink,ipv6_route} reference counting
the net namespace at seq_file open stage.

Since module is not supported for now, ipv6_route is
supported only if the IPV6 is built-in, i.e., not compiled
as a module. The restriction can be lifted once module
is properly supported for bpf_iter.

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/20200509175910.2476329-1-yhs@fb.com
This commit is contained in:
Yonghong Song
2020-05-09 10:59:10 -07:00
committed by Alexei Starovoitov
parent 6086d29def
commit 138d0be35b
5 changed files with 207 additions and 4 deletions

View File

@@ -2467,7 +2467,7 @@ void fib6_gc_cleanup(void)
}
#ifdef CONFIG_PROC_FS
static int ipv6_route_seq_show(struct seq_file *seq, void *v)
static int ipv6_route_native_seq_show(struct seq_file *seq, void *v)
{
struct fib6_info *rt = v;
struct ipv6_route_iter *iter = seq->private;
@@ -2625,7 +2625,7 @@ static bool ipv6_route_iter_active(struct ipv6_route_iter *iter)
return w->node && !(w->state == FWS_U && w->node == w->root);
}
static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
static void ipv6_route_native_seq_stop(struct seq_file *seq, void *v)
__releases(RCU_BH)
{
struct net *net = seq_file_net(seq);
@@ -2637,6 +2637,67 @@ static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
rcu_read_unlock_bh();
}
#if IS_BUILTIN(CONFIG_IPV6) && defined(CONFIG_BPF_SYSCALL)
struct bpf_iter__ipv6_route {
__bpf_md_ptr(struct bpf_iter_meta *, meta);
__bpf_md_ptr(struct fib6_info *, rt);
};
static int ipv6_route_prog_seq_show(struct bpf_prog *prog,
struct bpf_iter_meta *meta,
void *v)
{
struct bpf_iter__ipv6_route ctx;
ctx.meta = meta;
ctx.rt = v;
return bpf_iter_run_prog(prog, &ctx);
}
static int ipv6_route_seq_show(struct seq_file *seq, void *v)
{
struct ipv6_route_iter *iter = seq->private;
struct bpf_iter_meta meta;
struct bpf_prog *prog;
int ret;
meta.seq = seq;
prog = bpf_iter_get_info(&meta, false);
if (!prog)
return ipv6_route_native_seq_show(seq, v);
ret = ipv6_route_prog_seq_show(prog, &meta, v);
iter->w.leaf = NULL;
return ret;
}
static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
{
struct bpf_iter_meta meta;
struct bpf_prog *prog;
if (!v) {
meta.seq = seq;
prog = bpf_iter_get_info(&meta, true);
if (prog)
(void)ipv6_route_prog_seq_show(prog, &meta, v);
}
ipv6_route_native_seq_stop(seq, v);
}
#else
static int ipv6_route_seq_show(struct seq_file *seq, void *v)
{
return ipv6_route_native_seq_show(seq, v);
}
static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
{
ipv6_route_native_seq_stop(seq, v);
}
#endif
const struct seq_operations ipv6_route_seq_ops = {
.start = ipv6_route_seq_start,
.next = ipv6_route_seq_next,

View File

@@ -6393,6 +6393,30 @@ void __init ip6_route_init_special_entries(void)
#endif
}
#if IS_BUILTIN(CONFIG_IPV6)
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
DEFINE_BPF_ITER_FUNC(ipv6_route, struct bpf_iter_meta *meta, struct fib6_info *rt)
static int __init bpf_iter_register(void)
{
struct bpf_iter_reg reg_info = {
.target = "ipv6_route",
.seq_ops = &ipv6_route_seq_ops,
.init_seq_private = bpf_iter_init_seq_net,
.fini_seq_private = bpf_iter_fini_seq_net,
.seq_priv_size = sizeof(struct ipv6_route_iter),
};
return bpf_iter_reg_target(&reg_info);
}
static void bpf_iter_unregister(void)
{
bpf_iter_unreg_target("ipv6_route");
}
#endif
#endif
int __init ip6_route_init(void)
{
int ret;
@@ -6455,6 +6479,14 @@ int __init ip6_route_init(void)
if (ret)
goto out_register_late_subsys;
#if IS_BUILTIN(CONFIG_IPV6)
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
ret = bpf_iter_register();
if (ret)
goto out_register_late_subsys;
#endif
#endif
for_each_possible_cpu(cpu) {
struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu);
@@ -6487,6 +6519,11 @@ out_kmem_cache:
void ip6_route_cleanup(void)
{
#if IS_BUILTIN(CONFIG_IPV6)
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
bpf_iter_unregister();
#endif
#endif
unregister_netdevice_notifier(&ip6_route_dev_notifier);
unregister_pernet_subsys(&ip6_route_net_late_ops);
fib6_rules_cleanup();