Commit bfecc243 authored by Joel's avatar Joel Committed by yonghong-song

clang: loader: Allow user to override kernel version (#1895)

BCC currently requires exactly matching headers. Sometimes this is quite
inconvenient especially if the kernel version is only very slightly
different such as updates in a stable kernel. This patch gives the user
the flexibility to override the the LINUX_VERSION_CODE provided in the
linux kernel headers, so that the eBPF program may load. We also print a
message when this is done, so that the user is warned about the override
happening and that results may be unpredictable.

Also updated the docs.
Signed-off-by: default avatarJoel Fernandes <joel@joelfernandes.org>
parent 492a2bf3
...@@ -90,6 +90,10 @@ This guide is incomplete. If something feels missing, check the bcc and kernel s ...@@ -90,6 +90,10 @@ This guide is incomplete. If something feels missing, check the bcc and kernel s
- [1. Invalid mem access](#1-invalid-mem-access) - [1. Invalid mem access](#1-invalid-mem-access)
- [2. Cannot call GPL only function from proprietary program](#2-cannot-call-gpl-only-function-from-proprietary-program) - [2. Cannot call GPL only function from proprietary program](#2-cannot-call-gpl-only-function-from-proprietary-program)
- [Environment Variables](#envvars)
- [1. kernel source directory](#1-kernel-source-directory)
- [2. kernel version overriding](#2-kernel-version-overriding)
# BPF C # BPF C
This section describes the C part of a bcc program. This section describes the C part of a bcc program.
...@@ -1558,3 +1562,26 @@ bpf: Failed to load program: Invalid argument ...@@ -1558,3 +1562,26 @@ bpf: Failed to load program: Invalid argument
8: (85) call bpf_get_stackid#27 8: (85) call bpf_get_stackid#27
cannot call GPL only function from proprietary program cannot call GPL only function from proprietary program
``` ```
# Environment Variables
## 1. Kernel source directory
eBPF program compilation needs kernel sources or kernel headers with headers
compiled. In case your kernel sources are at a non-standard location where BCC
cannot find then, its possible to provide BCC the absolute path of the location
by setting `BCC_KERNEL_SOURCE` to it.
## 2. Kernel version overriding
By default, BCC stores the `LINUX_VERSION_CODE` in the generated eBPF object
which is then passed along to the kernel when the eBPF program is loaded.
Sometimes this is quite inconvenient especially when the kernel is slightly
updated such as an LTS kernel release. Its extremely unlikely the slight
mismatch would cause any issues with the loaded eBPF program. By setting
`BCC_LINUX_VERSION_CODE` to the version of the kernel that's running, the check
for verifying the kernel version can be bypassed. This is needed for programs
that use kprobes. This needs to be encoded in the format: `(VERSION * 65536) +
(PATCHLEVEL * 256) + SUBLEVEL`. For example, if the running kernel is `4.9.10`,
then can set `export BCC_LINUX_VERSION_CODE=264458` to override the kernel
version check successfully.
...@@ -222,7 +222,11 @@ struct _name##_table_t _name = { .max_entries = (_max_entries) } ...@@ -222,7 +222,11 @@ struct _name##_table_t _name = { .max_entries = (_max_entries) }
#define cursor_advance(_cursor, _len) \ #define cursor_advance(_cursor, _len) \
({ void *_tmp = _cursor; _cursor += _len; _tmp; }) ({ void *_tmp = _cursor; _cursor += _len; _tmp; })
#ifdef LINUX_VERSION_CODE_OVERRIDE
unsigned _version SEC("version") = LINUX_VERSION_CODE_OVERRIDE;
#else
unsigned _version SEC("version") = LINUX_VERSION_CODE; unsigned _version SEC("version") = LINUX_VERSION_CODE;
#endif
/* helper functions called from eBPF programs written in C */ /* helper functions called from eBPF programs written in C */
static void *(*bpf_map_lookup_elem)(void *map, void *key) = static void *(*bpf_map_lookup_elem)(void *map, void *key) =
......
...@@ -114,7 +114,9 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, ...@@ -114,7 +114,9 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
uname(&un); uname(&un);
string kdir, kpath; string kdir, kpath;
const char *kpath_env = ::getenv("BCC_KERNEL_SOURCE"); const char *kpath_env = ::getenv("BCC_KERNEL_SOURCE");
const char *version_override = ::getenv("BCC_LINUX_VERSION_CODE");
bool has_kpath_source = false; bool has_kpath_source = false;
string vmacro;
if (kpath_env) { if (kpath_env) {
kpath = string(kpath_env); kpath = string(kpath_env);
...@@ -175,6 +177,15 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, ...@@ -175,6 +177,15 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
flags_cstr.push_back(it->c_str()); flags_cstr.push_back(it->c_str());
vector<const char *> flags_cstr_rem; vector<const char *> flags_cstr_rem;
if (version_override) {
vmacro = "-DLINUX_VERSION_CODE_OVERRIDE=" + string(version_override);
std::cout << "WARNING: Linux version for eBPF program is being overridden with: " << version_override << "\n";
std::cout << "WARNING: Due to this, the results of the program may be unpredictable\n";
flags_cstr_rem.push_back(vmacro.c_str());
}
flags_cstr_rem.push_back("-include"); flags_cstr_rem.push_back("-include");
flags_cstr_rem.push_back("/virtual/include/bcc/helpers.h"); flags_cstr_rem.push_back("/virtual/include/bcc/helpers.h");
flags_cstr_rem.push_back("-isystem"); flags_cstr_rem.push_back("-isystem");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment