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 147bd601b6aSJakub Kicinski u32 bpf_prog_offload_ifindex(struct bpf_prog *prog) 148bd601b6aSJakub Kicinski { 149bd601b6aSJakub Kicinski struct bpf_dev_offload *offload = prog->aux->offload; 150bd601b6aSJakub Kicinski u32 ifindex; 151bd601b6aSJakub Kicinski 152bd601b6aSJakub Kicinski rtnl_lock(); 153bd601b6aSJakub Kicinski ifindex = offload->netdev ? offload->netdev->ifindex : 0; 154bd601b6aSJakub Kicinski rtnl_unlock(); 155bd601b6aSJakub Kicinski 156bd601b6aSJakub Kicinski return ifindex; 157bd601b6aSJakub Kicinski } 158bd601b6aSJakub Kicinski 159ab3f0063SJakub Kicinski const struct bpf_prog_ops bpf_offload_prog_ops = { 160ab3f0063SJakub Kicinski }; 161ab3f0063SJakub Kicinski 162ab3f0063SJakub Kicinski static int bpf_offload_notification(struct notifier_block *notifier, 163ab3f0063SJakub Kicinski ulong event, void *ptr) 164ab3f0063SJakub Kicinski { 165ab3f0063SJakub Kicinski struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 166ab3f0063SJakub Kicinski struct bpf_dev_offload *offload, *tmp; 167ab3f0063SJakub Kicinski 168ab3f0063SJakub Kicinski ASSERT_RTNL(); 169ab3f0063SJakub Kicinski 170ab3f0063SJakub Kicinski switch (event) { 171ab3f0063SJakub Kicinski case NETDEV_UNREGISTER: 172ab3f0063SJakub Kicinski list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs, 173ab3f0063SJakub Kicinski offloads) { 174ab3f0063SJakub Kicinski if (offload->netdev == netdev) 175ab3f0063SJakub Kicinski __bpf_prog_offload_destroy(offload->prog); 176ab3f0063SJakub Kicinski } 177ab3f0063SJakub Kicinski break; 178ab3f0063SJakub Kicinski default: 179ab3f0063SJakub Kicinski break; 180ab3f0063SJakub Kicinski } 181ab3f0063SJakub Kicinski return NOTIFY_OK; 182ab3f0063SJakub Kicinski } 183ab3f0063SJakub Kicinski 184ab3f0063SJakub Kicinski static struct notifier_block bpf_offload_notifier = { 185ab3f0063SJakub Kicinski .notifier_call = bpf_offload_notification, 186ab3f0063SJakub Kicinski }; 187ab3f0063SJakub Kicinski 188ab3f0063SJakub Kicinski static int __init bpf_offload_init(void) 189ab3f0063SJakub Kicinski { 190ab3f0063SJakub Kicinski register_netdevice_notifier(&bpf_offload_notifier); 191ab3f0063SJakub Kicinski return 0; 192ab3f0063SJakub Kicinski } 193ab3f0063SJakub Kicinski 194ab3f0063SJakub Kicinski subsys_initcall(bpf_offload_init); 195