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