^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright(c) 2019 Intel Corporation. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/hash.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/bpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/filter.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) /* The BPF dispatcher is a multiway branch code generator. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * dispatcher is a mechanism to avoid the performance penalty of an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * indirect call, which is expensive when retpolines are enabled. A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * dispatch client registers a BPF program into the dispatcher, and if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * there is available room in the dispatcher a direct call to the BPF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * program will be generated. All calls to the BPF programs called via
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * the dispatcher will then be a direct call, instead of an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * indirect. The dispatcher hijacks a trampoline function it via the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * __fentry__ of the trampoline. The trampoline function has the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * following signature:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * unsigned int trampoline(const void *ctx, const struct bpf_insn *insnsi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * unsigned int (*bpf_func)(const void *,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * const struct bpf_insn *));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static struct bpf_dispatcher_prog *bpf_dispatcher_find_prog(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct bpf_dispatcher *d, struct bpf_prog *prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) for (i = 0; i < BPF_DISPATCHER_MAX; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) if (prog == d->progs[i].prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return &d->progs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static struct bpf_dispatcher_prog *bpf_dispatcher_find_free(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct bpf_dispatcher *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return bpf_dispatcher_find_prog(d, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static bool bpf_dispatcher_add_prog(struct bpf_dispatcher *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct bpf_prog *prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct bpf_dispatcher_prog *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (!prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) entry = bpf_dispatcher_find_prog(d, prog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (entry) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) refcount_inc(&entry->users);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) entry = bpf_dispatcher_find_free(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) bpf_prog_inc(prog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) entry->prog = prog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) refcount_set(&entry->users, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) d->num_progs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static bool bpf_dispatcher_remove_prog(struct bpf_dispatcher *d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct bpf_prog *prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct bpf_dispatcher_prog *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) entry = bpf_dispatcher_find_prog(d, prog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (refcount_dec_and_test(&entry->users)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) entry->prog = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) bpf_prog_put(prog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) d->num_progs--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) int __weak arch_prepare_bpf_dispatcher(void *image, s64 *funcs, int num_funcs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static int bpf_dispatcher_prepare(struct bpf_dispatcher *d, void *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) s64 ips[BPF_DISPATCHER_MAX] = {}, *ipsp = &ips[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) for (i = 0; i < BPF_DISPATCHER_MAX; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (d->progs[i].prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *ipsp++ = (s64)(uintptr_t)d->progs[i].prog->bpf_func;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return arch_prepare_bpf_dispatcher(image, &ips[0], d->num_progs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static void bpf_dispatcher_update(struct bpf_dispatcher *d, int prev_num_progs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) void *old, *new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) u32 noff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (!prev_num_progs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) old = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) noff = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) old = d->image + d->image_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) noff = d->image_off ^ (PAGE_SIZE / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) new = d->num_progs ? d->image + noff : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (new) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (bpf_dispatcher_prepare(d, new))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) err = bpf_arch_text_poke(d->func, BPF_MOD_JUMP, old, new);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (err || !new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) d->image_off = noff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct bpf_prog *to)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) bool changed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int prev_num_progs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (from == to)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) mutex_lock(&d->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (!d->image) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) d->image = bpf_jit_alloc_exec_page();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (!d->image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) bpf_image_ksym_add(d->image, &d->ksym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) prev_num_progs = d->num_progs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) changed |= bpf_dispatcher_remove_prog(d, from);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) changed |= bpf_dispatcher_add_prog(d, to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if (!changed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) bpf_dispatcher_update(d, prev_num_progs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) mutex_unlock(&d->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }