mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 13:22:23 +00:00
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:
parent
6086d29def
commit
138d0be35b
@ -98,6 +98,25 @@ static const struct proc_ops proc_net_seq_ops = {
|
||||
.proc_release = seq_release_net,
|
||||
};
|
||||
|
||||
int bpf_iter_init_seq_net(void *priv_data)
|
||||
{
|
||||
#ifdef CONFIG_NET_NS
|
||||
struct seq_net_private *p = priv_data;
|
||||
|
||||
p->net = get_net(current->nsproxy->net_ns);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bpf_iter_fini_seq_net(void *priv_data)
|
||||
{
|
||||
#ifdef CONFIG_NET_NS
|
||||
struct seq_net_private *p = priv_data;
|
||||
|
||||
put_net(p->net);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode,
|
||||
struct proc_dir_entry *parent, const struct seq_operations *ops,
|
||||
unsigned int state_size, void *data)
|
||||
|
@ -105,6 +105,9 @@ struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mo
|
||||
void *data);
|
||||
extern struct pid *tgid_pidfd_to_pid(const struct file *file);
|
||||
|
||||
extern int bpf_iter_init_seq_net(void *priv_data);
|
||||
extern void bpf_iter_fini_seq_net(void *priv_data);
|
||||
|
||||
#ifdef CONFIG_PROC_PID_ARCH_STATUS
|
||||
/*
|
||||
* The architecture which selects CONFIG_PROC_PID_ARCH_STATUS must
|
||||
|
@ -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,
|
||||
|
@ -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(®_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();
|
||||
|
@ -2596,7 +2596,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
return __netlink_seq_next(seq);
|
||||
}
|
||||
|
||||
static void netlink_seq_stop(struct seq_file *seq, void *v)
|
||||
static void netlink_native_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct nl_seq_iter *iter = seq->private;
|
||||
|
||||
@ -2607,7 +2607,7 @@ static void netlink_seq_stop(struct seq_file *seq, void *v)
|
||||
}
|
||||
|
||||
|
||||
static int netlink_seq_show(struct seq_file *seq, void *v)
|
||||
static int netlink_native_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
seq_puts(seq,
|
||||
@ -2634,6 +2634,68 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BPF_SYSCALL
|
||||
struct bpf_iter__netlink {
|
||||
__bpf_md_ptr(struct bpf_iter_meta *, meta);
|
||||
__bpf_md_ptr(struct netlink_sock *, sk);
|
||||
};
|
||||
|
||||
DEFINE_BPF_ITER_FUNC(netlink, struct bpf_iter_meta *meta, struct netlink_sock *sk)
|
||||
|
||||
static int netlink_prog_seq_show(struct bpf_prog *prog,
|
||||
struct bpf_iter_meta *meta,
|
||||
void *v)
|
||||
{
|
||||
struct bpf_iter__netlink ctx;
|
||||
|
||||
meta->seq_num--; /* skip SEQ_START_TOKEN */
|
||||
ctx.meta = meta;
|
||||
ctx.sk = nlk_sk((struct sock *)v);
|
||||
return bpf_iter_run_prog(prog, &ctx);
|
||||
}
|
||||
|
||||
static int netlink_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct bpf_iter_meta meta;
|
||||
struct bpf_prog *prog;
|
||||
|
||||
meta.seq = seq;
|
||||
prog = bpf_iter_get_info(&meta, false);
|
||||
if (!prog)
|
||||
return netlink_native_seq_show(seq, v);
|
||||
|
||||
if (v != SEQ_START_TOKEN)
|
||||
return netlink_prog_seq_show(prog, &meta, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void netlink_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)netlink_prog_seq_show(prog, &meta, v);
|
||||
}
|
||||
|
||||
netlink_native_seq_stop(seq, v);
|
||||
}
|
||||
#else
|
||||
static int netlink_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
return netlink_native_seq_show(seq, v);
|
||||
}
|
||||
|
||||
static void netlink_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
netlink_native_seq_stop(seq, v);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct seq_operations netlink_seq_ops = {
|
||||
.start = netlink_seq_start,
|
||||
.next = netlink_seq_next,
|
||||
@ -2740,6 +2802,21 @@ static const struct rhashtable_params netlink_rhashtable_params = {
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
|
||||
static int __init bpf_iter_register(void)
|
||||
{
|
||||
struct bpf_iter_reg reg_info = {
|
||||
.target = "netlink",
|
||||
.seq_ops = &netlink_seq_ops,
|
||||
.init_seq_private = bpf_iter_init_seq_net,
|
||||
.fini_seq_private = bpf_iter_fini_seq_net,
|
||||
.seq_priv_size = sizeof(struct nl_seq_iter),
|
||||
};
|
||||
|
||||
return bpf_iter_reg_target(®_info);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init netlink_proto_init(void)
|
||||
{
|
||||
int i;
|
||||
@ -2748,6 +2825,12 @@ static int __init netlink_proto_init(void)
|
||||
if (err != 0)
|
||||
goto out;
|
||||
|
||||
#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
|
||||
err = bpf_iter_register();
|
||||
if (err)
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof_field(struct sk_buff, cb));
|
||||
|
||||
nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL);
|
||||
|
Loading…
Reference in New Issue
Block a user