forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bpf: add bpf_link support for BPF_NETFILTER programs
Add bpf_link support skeleton. To keep this reviewable, no bpf program can be invoked yet, if a program is attached only a c-stub is called and not the actual bpf program. Defaults to 'y' if both netfilter and bpf syscall are enabled in kconfig. Uapi example usage: union bpf_attr attr = { }; attr.link_create.prog_fd = progfd; attr.link_create.attach_type = 0; /* unused */ attr.link_create.netfilter.pf = PF_INET; attr.link_create.netfilter.hooknum = NF_INET_LOCAL_IN; attr.link_create.netfilter.priority = -128; err = bpf(BPF_LINK_CREATE, &attr, sizeof(attr)); ... this would attach progfd to ipv4:input hook. Such hook gets removed automatically if the calling program exits. BPF_NETFILTER program invocation is added in followup change. NF_HOOK_OP_BPF enum will eventually be read from nfnetlink_hook, it allows to tell userspace which program is attached at the given hook when user runs 'nft hook list' command rather than just the priority and not-very-helpful 'this hook runs a bpf prog but I can't tell which one'. Will also be used to disallow registration of two bpf programs with same priority in a followup patch. Signed-off-by: Florian Westphal <fw@strlen.de>
- Loading branch information
1 parent
d099f59
commit f373efb
Showing
7 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
int bpf_nf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
#include <linux/bpf.h> | ||
#include <linux/netfilter.h> | ||
|
||
#include <net/netfilter/nf_bpf_link.h> | ||
|
||
static unsigned int nf_hook_run_bpf(void *bpf_prog, struct sk_buff *skb, const struct nf_hook_state *s) | ||
{ | ||
return NF_ACCEPT; | ||
} | ||
|
||
struct bpf_nf_link { | ||
struct bpf_link link; | ||
struct nf_hook_ops hook_ops; | ||
struct net *net; | ||
}; | ||
|
||
static void bpf_nf_link_release(struct bpf_link *link) | ||
{ | ||
struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link); | ||
|
||
nf_unregister_net_hook(nf_link->net, &nf_link->hook_ops); | ||
} | ||
|
||
static void bpf_nf_link_dealloc(struct bpf_link *link) | ||
{ | ||
struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link); | ||
|
||
kfree(nf_link); | ||
} | ||
|
||
static int bpf_nf_link_detach(struct bpf_link *link) | ||
{ | ||
bpf_nf_link_release(link); | ||
return 0; | ||
} | ||
|
||
static void bpf_nf_link_show_info(const struct bpf_link *link, | ||
struct seq_file *seq) | ||
{ | ||
struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link); | ||
|
||
seq_printf(seq, "pf:\t%u\thooknum:\t%u\tprio:\t%d\n", | ||
nf_link->hook_ops.pf, nf_link->hook_ops.hooknum, | ||
nf_link->hook_ops.priority); | ||
} | ||
|
||
static int bpf_nf_link_fill_link_info(const struct bpf_link *link, | ||
struct bpf_link_info *info) | ||
{ | ||
struct bpf_nf_link *nf_link = container_of(link, struct bpf_nf_link, link); | ||
|
||
info->netfilter.pf = nf_link->hook_ops.pf; | ||
info->netfilter.hooknum = nf_link->hook_ops.hooknum; | ||
info->netfilter.priority = nf_link->hook_ops.priority; | ||
info->netfilter.flags = 0; | ||
|
||
return 0; | ||
} | ||
|
||
static int bpf_nf_link_update(struct bpf_link *link, struct bpf_prog *new_prog, | ||
struct bpf_prog *old_prog) | ||
{ | ||
return -EOPNOTSUPP; | ||
} | ||
|
||
static const struct bpf_link_ops bpf_nf_link_lops = { | ||
.release = bpf_nf_link_release, | ||
.dealloc = bpf_nf_link_dealloc, | ||
.detach = bpf_nf_link_detach, | ||
.show_fdinfo = bpf_nf_link_show_info, | ||
.fill_link_info = bpf_nf_link_fill_link_info, | ||
.update_prog = bpf_nf_link_update, | ||
}; | ||
|
||
int bpf_nf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) | ||
{ | ||
struct net *net = current->nsproxy->net_ns; | ||
struct bpf_link_primer link_primer; | ||
struct bpf_nf_link *link; | ||
int err; | ||
|
||
if (attr->link_create.flags) | ||
return -EINVAL; | ||
|
||
if (attr->link_create.netfilter.flags) | ||
return -EOPNOTSUPP; | ||
|
||
if (attr->link_create.netfilter.reserved[0] | attr->link_create.netfilter.reserved[1]) | ||
return -EINVAL; | ||
|
||
link = kzalloc(sizeof(*link), GFP_USER); | ||
if (!link) | ||
return -ENOMEM; | ||
|
||
bpf_link_init(&link->link, BPF_LINK_TYPE_NETFILTER, &bpf_nf_link_lops, prog); | ||
|
||
link->hook_ops.hook = nf_hook_run_bpf; | ||
link->hook_ops.hook_ops_type = NF_HOOK_OP_BPF; | ||
link->hook_ops.priv = prog; | ||
|
||
link->hook_ops.pf = attr->link_create.netfilter.pf; | ||
link->hook_ops.priority = attr->link_create.netfilter.prio; | ||
link->hook_ops.hooknum = attr->link_create.netfilter.hooknum; | ||
|
||
link->net = net; | ||
|
||
err = bpf_link_prime(&link->link, &link_primer); | ||
if (err) { | ||
kfree(link); | ||
return err; | ||
} | ||
|
||
err = nf_register_net_hook(net, &link->hook_ops); | ||
if (err) { | ||
bpf_link_cleanup(&link_primer); | ||
return err; | ||
} | ||
|
||
return bpf_link_settle(&link_primer); | ||
} |