cregit-Linux how code gets into the kernel

Release 4.15 kernel/bpf/offload.c

Directory: kernel/bpf
/*
 * Copyright (C) 2017 Netronome Systems, Inc.
 *
 * This software is licensed under the GNU General License Version 2,
 * June 1991 as shown in the file COPYING in the top-level directory of this
 * source tree.
 *
 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 */

#include <linux/bpf.h>
#include <linux/bpf_verifier.h>
#include <linux/bug.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
#include <linux/rtnetlink.h>

/* protected by RTNL */
static LIST_HEAD(bpf_prog_offload_devs);


int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr) { struct net *net = current->nsproxy->net_ns; struct bpf_dev_offload *offload; if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS && attr->prog_type != BPF_PROG_TYPE_XDP) return -EINVAL; if (attr->prog_flags) return -EINVAL; offload = kzalloc(sizeof(*offload), GFP_USER); if (!offload) return -ENOMEM; offload->prog = prog; init_waitqueue_head(&offload->verifier_done); rtnl_lock(); offload->netdev = __dev_get_by_index(net, attr->prog_ifindex); if (!offload->netdev) { rtnl_unlock(); kfree(offload); return -EINVAL; } prog->aux->offload = offload; list_add_tail(&offload->offloads, &bpf_prog_offload_devs); rtnl_unlock(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński157100.00%3100.00%
Total157100.00%3100.00%


static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd, struct netdev_bpf *data) { struct net_device *netdev = prog->aux->offload->netdev; ASSERT_RTNL(); if (!netdev) return -ENODEV; if (!netdev->netdev_ops->ndo_bpf) return -EOPNOTSUPP; data->command = cmd; return netdev->netdev_ops->ndo_bpf(netdev, data); }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński76100.00%1100.00%
Total76100.00%1100.00%


int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env) { struct netdev_bpf data = {}; int err; data.verifier.prog = env->prog; rtnl_lock(); err = __bpf_offload_ndo(env->prog, BPF_OFFLOAD_VERIFIER_PREP, &data); if (err) goto exit_unlock; env->dev_ops = data.verifier.ops; env->prog->aux->offload->dev_state = true; env->prog->aux->offload->verifier_running = true; exit_unlock: rtnl_unlock(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński95100.00%1100.00%
Total95100.00%1100.00%


static void __bpf_prog_offload_destroy(struct bpf_prog *prog) { struct bpf_dev_offload *offload = prog->aux->offload; struct netdev_bpf data = {}; /* Caution - if netdev is destroyed before the program, this function * will be called twice. */ data.offload.prog = prog; if (offload->verifier_running) wait_event(offload->verifier_done, !offload->verifier_running); if (offload->dev_state) WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data)); offload->dev_state = false; list_del_init(&offload->offloads); offload->netdev = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński94100.00%2100.00%
Total94100.00%2100.00%


void bpf_prog_offload_destroy(struct bpf_prog *prog) { struct bpf_dev_offload *offload = prog->aux->offload; offload->verifier_running = false; wake_up(&offload->verifier_done); rtnl_lock(); __bpf_prog_offload_destroy(prog); rtnl_unlock(); kfree(offload); }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński51100.00%1100.00%
Total51100.00%1100.00%


static int bpf_prog_offload_translate(struct bpf_prog *prog) { struct bpf_dev_offload *offload = prog->aux->offload; struct netdev_bpf data = {}; int ret; data.offload.prog = prog; offload->verifier_running = false; wake_up(&offload->verifier_done); rtnl_lock(); ret = __bpf_offload_ndo(prog, BPF_OFFLOAD_TRANSLATE, &data); rtnl_unlock(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński74100.00%1100.00%
Total74100.00%1100.00%


static unsigned int bpf_prog_warn_on_exec(const void *ctx, const struct bpf_insn *insn) { WARN(1, "attempt to execute device eBPF program on the host!"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński28100.00%1100.00%
Total28100.00%1100.00%


int bpf_prog_offload_compile(struct bpf_prog *prog) { prog->bpf_func = bpf_prog_warn_on_exec; return bpf_prog_offload_translate(prog); }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński22100.00%1100.00%
Total22100.00%1100.00%

const struct bpf_prog_ops bpf_offload_prog_ops = { };
static int bpf_offload_notification(struct notifier_block *notifier, ulong event, void *ptr) { struct net_device *netdev = netdev_notifier_info_to_dev(ptr); struct bpf_dev_offload *offload, *tmp; ASSERT_RTNL(); switch (event) { case NETDEV_UNREGISTER: /* ignore namespace changes */ if (netdev->reg_state != NETREG_UNREGISTERING) break; list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs, offloads) { if (offload->netdev == netdev) __bpf_prog_offload_destroy(offload->prog); } break; default: break; } return NOTIFY_OK; }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński91100.00%2100.00%
Total91100.00%2100.00%

static struct notifier_block bpf_offload_notifier = { .notifier_call = bpf_offload_notification, };
static int __init bpf_offload_init(void) { register_netdevice_notifier(&bpf_offload_notifier); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński18100.00%1100.00%
Total18100.00%1100.00%

subsys_initcall(bpf_offload_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
Jakub Kiciński759100.00%6100.00%
Total759100.00%6100.00%
Directory: kernel/bpf
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.