Skip to content

Commit

Permalink
net: bpf: Implement bpf iterator for udp
Browse files Browse the repository at this point in the history
The bpf iterator for udp is implemented. Both udp4 and udp6
sockets will be traversed. It is up to bpf program to
filter for udp4 or udp6 only, or both families of sockets.

Signed-off-by: Yonghong Song <[email protected]>
Signed-off-by: Alexei Starovoitov <[email protected]>
Acked-by: Martin KaFai Lau <[email protected]>
Link: https://lore.kernel.org/bpf/[email protected]
  • Loading branch information
yonghong-song authored and Alexei Starovoitov committed Jun 25, 2020
1 parent 9e8ca27 commit 5788b3a
Showing 1 changed file with 116 additions and 0 deletions.
116 changes: 116 additions & 0 deletions net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2968,6 +2968,67 @@ int udp4_seq_show(struct seq_file *seq, void *v)
return 0;
}

#ifdef CONFIG_BPF_SYSCALL
struct bpf_iter__udp {
__bpf_md_ptr(struct bpf_iter_meta *, meta);
__bpf_md_ptr(struct udp_sock *, udp_sk);
uid_t uid __aligned(8);
int bucket __aligned(8);
};

static int udp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
struct udp_sock *udp_sk, uid_t uid, int bucket)
{
struct bpf_iter__udp ctx;

meta->seq_num--; /* skip SEQ_START_TOKEN */
ctx.meta = meta;
ctx.udp_sk = udp_sk;
ctx.uid = uid;
ctx.bucket = bucket;
return bpf_iter_run_prog(prog, &ctx);
}

static int bpf_iter_udp_seq_show(struct seq_file *seq, void *v)
{
struct udp_iter_state *state = seq->private;
struct bpf_iter_meta meta;
struct bpf_prog *prog;
struct sock *sk = v;
uid_t uid;

if (v == SEQ_START_TOKEN)
return 0;

uid = from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk));
meta.seq = seq;
prog = bpf_iter_get_info(&meta, false);
return udp_prog_seq_show(prog, &meta, v, uid, state->bucket);
}

static void bpf_iter_udp_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)udp_prog_seq_show(prog, &meta, v, 0, 0);
}

udp_seq_stop(seq, v);
}

static const struct seq_operations bpf_iter_udp_seq_ops = {
.start = udp_seq_start,
.next = udp_seq_next,
.stop = bpf_iter_udp_seq_stop,
.show = bpf_iter_udp_seq_show,
};
#endif

const struct seq_operations udp_seq_ops = {
.start = udp_seq_start,
.next = udp_seq_next,
Expand Down Expand Up @@ -3085,6 +3146,57 @@ static struct pernet_operations __net_initdata udp_sysctl_ops = {
.init = udp_sysctl_init,
};

#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
DEFINE_BPF_ITER_FUNC(udp, struct bpf_iter_meta *meta,
struct udp_sock *udp_sk, uid_t uid, int bucket)

static int bpf_iter_init_udp(void *priv_data)
{
struct udp_iter_state *st = priv_data;
struct udp_seq_afinfo *afinfo;
int ret;

afinfo = kmalloc(sizeof(*afinfo), GFP_USER | __GFP_NOWARN);
if (!afinfo)
return -ENOMEM;

afinfo->family = AF_UNSPEC;
afinfo->udp_table = &udp_table;
st->bpf_seq_afinfo = afinfo;
ret = bpf_iter_init_seq_net(priv_data);
if (ret)
kfree(afinfo);
return ret;
}

static void bpf_iter_fini_udp(void *priv_data)
{
struct udp_iter_state *st = priv_data;

kfree(st->bpf_seq_afinfo);
bpf_iter_fini_seq_net(priv_data);
}

static const struct bpf_iter_reg udp_reg_info = {
.target = "udp",
.seq_ops = &bpf_iter_udp_seq_ops,
.init_seq_private = bpf_iter_init_udp,
.fini_seq_private = bpf_iter_fini_udp,
.seq_priv_size = sizeof(struct udp_iter_state),
.ctx_arg_info_size = 1,
.ctx_arg_info = {
{ offsetof(struct bpf_iter__udp, udp_sk),
PTR_TO_BTF_ID_OR_NULL },
},
};

static void __init bpf_iter_register(void)
{
if (bpf_iter_reg_target(&udp_reg_info))
pr_warn("Warning: could not register bpf iterator udp\n");
}
#endif

void __init udp_init(void)
{
unsigned long limit;
Expand All @@ -3110,4 +3222,8 @@ void __init udp_init(void)

if (register_pernet_subsys(&udp_sysctl_ops))
panic("UDP: failed to init sysctl parameters.\n");

#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
bpf_iter_register();
#endif
}

0 comments on commit 5788b3a

Please sign in to comment.