xref: /openbmc/linux/kernel/bpf/offload.c (revision ab3f0063)
1ab3f0063SJakub Kicinski #include <linux/bpf.h>
2ab3f0063SJakub Kicinski #include <linux/bpf_verifier.h>
3ab3f0063SJakub Kicinski #include <linux/bug.h>
4ab3f0063SJakub Kicinski #include <linux/list.h>
5ab3f0063SJakub Kicinski #include <linux/netdevice.h>
6ab3f0063SJakub Kicinski #include <linux/printk.h>
7ab3f0063SJakub Kicinski #include <linux/rtnetlink.h>
8ab3f0063SJakub Kicinski 
9ab3f0063SJakub Kicinski /* protected by RTNL */
10ab3f0063SJakub Kicinski static LIST_HEAD(bpf_prog_offload_devs);
11ab3f0063SJakub Kicinski 
12ab3f0063SJakub Kicinski int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
13ab3f0063SJakub Kicinski {
14ab3f0063SJakub Kicinski 	struct net *net = current->nsproxy->net_ns;
15ab3f0063SJakub Kicinski 	struct bpf_dev_offload *offload;
16ab3f0063SJakub Kicinski 
17ab3f0063SJakub Kicinski 	if (!capable(CAP_SYS_ADMIN))
18ab3f0063SJakub Kicinski 		return -EPERM;
19ab3f0063SJakub Kicinski 
20ab3f0063SJakub Kicinski 	if (attr->prog_flags)
21ab3f0063SJakub Kicinski 		return -EINVAL;
22ab3f0063SJakub Kicinski 
23ab3f0063SJakub Kicinski 	offload = kzalloc(sizeof(*offload), GFP_USER);
24ab3f0063SJakub Kicinski 	if (!offload)
25ab3f0063SJakub Kicinski 		return -ENOMEM;
26ab3f0063SJakub Kicinski 
27ab3f0063SJakub Kicinski 	offload->prog = prog;
28ab3f0063SJakub Kicinski 	init_waitqueue_head(&offload->verifier_done);
29ab3f0063SJakub Kicinski 
30ab3f0063SJakub Kicinski 	rtnl_lock();
31ab3f0063SJakub Kicinski 	offload->netdev = __dev_get_by_index(net, attr->prog_target_ifindex);
32ab3f0063SJakub Kicinski 	if (!offload->netdev) {
33ab3f0063SJakub Kicinski 		rtnl_unlock();
34ab3f0063SJakub Kicinski 		kfree(offload);
35ab3f0063SJakub Kicinski 		return -EINVAL;
36ab3f0063SJakub Kicinski 	}
37ab3f0063SJakub Kicinski 
38ab3f0063SJakub Kicinski 	prog->aux->offload = offload;
39ab3f0063SJakub Kicinski 	list_add_tail(&offload->offloads, &bpf_prog_offload_devs);
40ab3f0063SJakub Kicinski 	rtnl_unlock();
41ab3f0063SJakub Kicinski 
42ab3f0063SJakub Kicinski 	return 0;
43ab3f0063SJakub Kicinski }
44ab3f0063SJakub Kicinski 
45ab3f0063SJakub Kicinski static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd,
46ab3f0063SJakub Kicinski 			     struct netdev_bpf *data)
47ab3f0063SJakub Kicinski {
48ab3f0063SJakub Kicinski 	struct net_device *netdev = prog->aux->offload->netdev;
49ab3f0063SJakub Kicinski 
50ab3f0063SJakub Kicinski 	ASSERT_RTNL();
51ab3f0063SJakub Kicinski 
52ab3f0063SJakub Kicinski 	if (!netdev)
53ab3f0063SJakub Kicinski 		return -ENODEV;
54ab3f0063SJakub Kicinski 	if (!netdev->netdev_ops->ndo_bpf)
55ab3f0063SJakub Kicinski 		return -EOPNOTSUPP;
56ab3f0063SJakub Kicinski 
57ab3f0063SJakub Kicinski 	data->command = cmd;
58ab3f0063SJakub Kicinski 
59ab3f0063SJakub Kicinski 	return netdev->netdev_ops->ndo_bpf(netdev, data);
60ab3f0063SJakub Kicinski }
61ab3f0063SJakub Kicinski 
62ab3f0063SJakub Kicinski int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)
63ab3f0063SJakub Kicinski {
64ab3f0063SJakub Kicinski 	struct netdev_bpf data = {};
65ab3f0063SJakub Kicinski 	int err;
66ab3f0063SJakub Kicinski 
67ab3f0063SJakub Kicinski 	data.verifier.prog = env->prog;
68ab3f0063SJakub Kicinski 
69ab3f0063SJakub Kicinski 	rtnl_lock();
70ab3f0063SJakub Kicinski 	err = __bpf_offload_ndo(env->prog, BPF_OFFLOAD_VERIFIER_PREP, &data);
71ab3f0063SJakub Kicinski 	if (err)
72ab3f0063SJakub Kicinski 		goto exit_unlock;
73ab3f0063SJakub Kicinski 
74ab3f0063SJakub Kicinski 	env->dev_ops = data.verifier.ops;
75ab3f0063SJakub Kicinski 
76ab3f0063SJakub Kicinski 	env->prog->aux->offload->dev_state = true;
77ab3f0063SJakub Kicinski 	env->prog->aux->offload->verifier_running = true;
78ab3f0063SJakub Kicinski exit_unlock:
79ab3f0063SJakub Kicinski 	rtnl_unlock();
80ab3f0063SJakub Kicinski 	return err;
81ab3f0063SJakub Kicinski }
82ab3f0063SJakub Kicinski 
83ab3f0063SJakub Kicinski static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
84ab3f0063SJakub Kicinski {
85ab3f0063SJakub Kicinski 	struct bpf_dev_offload *offload = prog->aux->offload;
86ab3f0063SJakub Kicinski 	struct netdev_bpf data = {};
87ab3f0063SJakub Kicinski 
88ab3f0063SJakub Kicinski 	data.offload.prog = prog;
89ab3f0063SJakub Kicinski 
90ab3f0063SJakub Kicinski 	if (offload->verifier_running)
91ab3f0063SJakub Kicinski 		wait_event(offload->verifier_done, !offload->verifier_running);
92ab3f0063SJakub Kicinski 
93ab3f0063SJakub Kicinski 	if (offload->dev_state)
94ab3f0063SJakub Kicinski 		WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data));
95ab3f0063SJakub Kicinski 
96ab3f0063SJakub Kicinski 	offload->dev_state = false;
97ab3f0063SJakub Kicinski 	list_del_init(&offload->offloads);
98ab3f0063SJakub Kicinski 	offload->netdev = NULL;
99ab3f0063SJakub Kicinski }
100ab3f0063SJakub Kicinski 
101ab3f0063SJakub Kicinski void bpf_prog_offload_destroy(struct bpf_prog *prog)
102ab3f0063SJakub Kicinski {
103ab3f0063SJakub Kicinski 	struct bpf_dev_offload *offload = prog->aux->offload;
104ab3f0063SJakub Kicinski 
105ab3f0063SJakub Kicinski 	offload->verifier_running = false;
106ab3f0063SJakub Kicinski 	wake_up(&offload->verifier_done);
107ab3f0063SJakub Kicinski 
108ab3f0063SJakub Kicinski 	rtnl_lock();
109ab3f0063SJakub Kicinski 	__bpf_prog_offload_destroy(prog);
110ab3f0063SJakub Kicinski 	rtnl_unlock();
111ab3f0063SJakub Kicinski 
112ab3f0063SJakub Kicinski 	kfree(offload);
113ab3f0063SJakub Kicinski }
114ab3f0063SJakub Kicinski 
115ab3f0063SJakub Kicinski static int bpf_prog_offload_translate(struct bpf_prog *prog)
116ab3f0063SJakub Kicinski {
117ab3f0063SJakub Kicinski 	struct bpf_dev_offload *offload = prog->aux->offload;
118ab3f0063SJakub Kicinski 	struct netdev_bpf data = {};
119ab3f0063SJakub Kicinski 	int ret;
120ab3f0063SJakub Kicinski 
121ab3f0063SJakub Kicinski 	data.offload.prog = prog;
122ab3f0063SJakub Kicinski 
123ab3f0063SJakub Kicinski 	offload->verifier_running = false;
124ab3f0063SJakub Kicinski 	wake_up(&offload->verifier_done);
125ab3f0063SJakub Kicinski 
126ab3f0063SJakub Kicinski 	rtnl_lock();
127ab3f0063SJakub Kicinski 	ret = __bpf_offload_ndo(prog, BPF_OFFLOAD_TRANSLATE, &data);
128ab3f0063SJakub Kicinski 	rtnl_unlock();
129ab3f0063SJakub Kicinski 
130ab3f0063SJakub Kicinski 	return ret;
131ab3f0063SJakub Kicinski }
132ab3f0063SJakub Kicinski 
133ab3f0063SJakub Kicinski static unsigned int bpf_prog_warn_on_exec(const void *ctx,
134ab3f0063SJakub Kicinski 					  const struct bpf_insn *insn)
135ab3f0063SJakub Kicinski {
136ab3f0063SJakub Kicinski 	WARN(1, "attempt to execute device eBPF program on the host!");
137ab3f0063SJakub Kicinski 	return 0;
138ab3f0063SJakub Kicinski }
139ab3f0063SJakub Kicinski 
140ab3f0063SJakub Kicinski int bpf_prog_offload_compile(struct bpf_prog *prog)
141ab3f0063SJakub Kicinski {
142ab3f0063SJakub Kicinski 	prog->bpf_func = bpf_prog_warn_on_exec;
143ab3f0063SJakub Kicinski 
144ab3f0063SJakub Kicinski 	return bpf_prog_offload_translate(prog);
145ab3f0063SJakub Kicinski }
146ab3f0063SJakub Kicinski 
147ab3f0063SJakub Kicinski const struct bpf_prog_ops bpf_offload_prog_ops = {
148ab3f0063SJakub Kicinski };
149ab3f0063SJakub Kicinski 
150ab3f0063SJakub Kicinski static int bpf_offload_notification(struct notifier_block *notifier,
151ab3f0063SJakub Kicinski 				    ulong event, void *ptr)
152ab3f0063SJakub Kicinski {
153ab3f0063SJakub Kicinski 	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
154ab3f0063SJakub Kicinski 	struct bpf_dev_offload *offload, *tmp;
155ab3f0063SJakub Kicinski 
156ab3f0063SJakub Kicinski 	ASSERT_RTNL();
157ab3f0063SJakub Kicinski 
158ab3f0063SJakub Kicinski 	switch (event) {
159ab3f0063SJakub Kicinski 	case NETDEV_UNREGISTER:
160ab3f0063SJakub Kicinski 		list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs,
161ab3f0063SJakub Kicinski 					 offloads) {
162ab3f0063SJakub Kicinski 			if (offload->netdev == netdev)
163ab3f0063SJakub Kicinski 				__bpf_prog_offload_destroy(offload->prog);
164ab3f0063SJakub Kicinski 		}
165ab3f0063SJakub Kicinski 		break;
166ab3f0063SJakub Kicinski 	default:
167ab3f0063SJakub Kicinski 		break;
168ab3f0063SJakub Kicinski 	}
169ab3f0063SJakub Kicinski 	return NOTIFY_OK;
170ab3f0063SJakub Kicinski }
171ab3f0063SJakub Kicinski 
172ab3f0063SJakub Kicinski static struct notifier_block bpf_offload_notifier = {
173ab3f0063SJakub Kicinski 	.notifier_call = bpf_offload_notification,
174ab3f0063SJakub Kicinski };
175ab3f0063SJakub Kicinski 
176ab3f0063SJakub Kicinski static int __init bpf_offload_init(void)
177ab3f0063SJakub Kicinski {
178ab3f0063SJakub Kicinski 	register_netdevice_notifier(&bpf_offload_notifier);
179ab3f0063SJakub Kicinski 	return 0;
180ab3f0063SJakub Kicinski }
181ab3f0063SJakub Kicinski 
182ab3f0063SJakub Kicinski subsys_initcall(bpf_offload_init);
183