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