mirror of
https://github.com/xdp-project/bpf-examples.git
synced 2024-05-06 15:54:53 +00:00
It's way too difficult to read packet data in XDP because LLVM will mostly generate code that doesn't pass the verifier. Thankfully, Cilium has a nice workaround for this in the form of hand-written BPF assembly to perform the reads in a way that the verifier will understand. Let's import these helpers so they can be used by the examples in this repository, along with some of the other BPF helpers that it relies on. This commit imports these files wholesale from Cilium: - include/bpf/builtins.h - include/bpf/compiler.h - include/bpf/errno.h And also adds include/xdp/context_helpers.h which only contains the xdp_load_bytes() and xdp_store_bytes() helpers from Cilium's include/bpf/ctx/xdp.h (as the other functions in that file are specific to how the Cilium code is structured). We also extend the maximum size supported by the efficient memcpy() implementation in builtins.h to 280 bytes, and the mask size applied to packet data copies up to 0x3ff. Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
74 lines
2.0 KiB
C
74 lines
2.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Copyright (C) 2020 Authors of Cilium */
|
|
/* For now, only import the xdp_load_bytes() and xdp_store_bytes() helpers
|
|
* from Cilium.
|
|
*/
|
|
|
|
#ifndef __XDP_CONTEXT_HELPERS_H
|
|
#define __XDP_CONTEXT_HELPERS_H
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/bpf.h>
|
|
|
|
#include "../bpf/builtins.h"
|
|
#include "../bpf/errno.h"
|
|
|
|
/* This must be a mask and all offsets guaranteed to be less than that. */
|
|
#define __CTX_OFF_MAX 0x3fff
|
|
|
|
static __always_inline __maybe_unused int
|
|
xdp_load_bytes(const struct xdp_md *ctx, __u64 off, void *to, const __u64 len)
|
|
{
|
|
void *from;
|
|
int ret;
|
|
/* LLVM tends to generate code that verifier doesn't understand,
|
|
* so force it the way we want it in order to open up a range
|
|
* on the reg.
|
|
*/
|
|
asm volatile("r1 = *(u32 *)(%[ctx] +0)\n\t"
|
|
"r2 = *(u32 *)(%[ctx] +4)\n\t"
|
|
"%[off] &= %[offmax]\n\t"
|
|
"r1 += %[off]\n\t"
|
|
"%[from] = r1\n\t"
|
|
"r1 += %[len]\n\t"
|
|
"if r1 > r2 goto +2\n\t"
|
|
"%[ret] = 0\n\t"
|
|
"goto +1\n\t"
|
|
"%[ret] = %[errno]\n\t"
|
|
: [ret]"=r"(ret), [from]"=r"(from)
|
|
: [ctx]"r"(ctx), [off]"r"(off), [len]"ri"(len),
|
|
[offmax]"i"(__CTX_OFF_MAX), [errno]"i"(-EINVAL)
|
|
: "r1", "r2");
|
|
if (!ret)
|
|
memcpy(to, from, len);
|
|
return ret;
|
|
}
|
|
|
|
static __always_inline __maybe_unused int
|
|
xdp_store_bytes(const struct xdp_md *ctx, __u64 off, const void *from,
|
|
const __u64 len, __u64 flags __maybe_unused)
|
|
{
|
|
void *to;
|
|
int ret;
|
|
/* See xdp_load_bytes(). */
|
|
asm volatile("r1 = *(u32 *)(%[ctx] +0)\n\t"
|
|
"r2 = *(u32 *)(%[ctx] +4)\n\t"
|
|
"%[off] &= %[offmax]\n\t"
|
|
"r1 += %[off]\n\t"
|
|
"%[to] = r1\n\t"
|
|
"r1 += %[len]\n\t"
|
|
"if r1 > r2 goto +2\n\t"
|
|
"%[ret] = 0\n\t"
|
|
"goto +1\n\t"
|
|
"%[ret] = %[errno]\n\t"
|
|
: [ret]"=r"(ret), [to]"=r"(to)
|
|
: [ctx]"r"(ctx), [off]"r"(off), [len]"ri"(len),
|
|
[offmax]"i"(__CTX_OFF_MAX), [errno]"i"(-EINVAL)
|
|
: "r1", "r2");
|
|
if (!ret)
|
|
memcpy(to, from, len);
|
|
return ret;
|
|
}
|
|
|
|
#endif
|