-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimpl.tex
60 lines (54 loc) · 3.07 KB
/
impl.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
\section{Implementation}
\label{sec:impl}
%We now discuss how of \projname{} is implemented.
The implementation of \projname{} consists of three parts, the \projname{}
kernel crate, the kernel support, and the compiler support.
\subsection{\projname{} kernel crate}
\label{impl:kernel-crate}
The kernel crate uses a mixture of safe and unsafe Rust to implement the safe
interface for \projname{} programs to interact with the kernel.
This interface contains the helper function interface, the kernel data type
bindings, and the wrapper type for program argument.
% \milo{Missing portion?}
\para{Helper function interface:}
\projname{} implements its helper interface on top of the kernel helpers, with
wrapping code that allows programs to invoke helpers with safe Rust types.
Doing so comes at a cost of losing the load time optimization (e.g. inlining) on
certain helpers by the eBPF verfier, which we further evaluate in
\S\ref{eval:inline}.
\para{Kernel data type bindings} are generated for the program to access kernel
data types defined in C.
\projname{} uses \emph{rust-bindgen}~\cite{bindgen} to automatically generate
kernel bindings and integrates it into the build process of the program.
\para{Wrapping of program argument:}
eBPF hides irrelevant data fields of the kernel internal struct that serves as
the program argument.
This done by providing the program a "user" struct with only needed fields and
rewrite accessing instructions at verification time to the kernel struct.
\projname{} implements this by encapsulating the generated binding of the
kernel internal struct in a Rust struct, in which each field accessible by
the extension program has an associated getter method.
\subsection{Kernel support}
\label{impl:kernel}
\projname{} implements its program load code and the runtime environment in the
kernel.
To load the extension program, \projname{} extends the \texttt{bpf} system
call to able to handle a \projname{} program.
The system call parses the ELF executable and locate all the \texttt{LOAD}
segments in the executable.
It then allocates new pages and maps the \texttt{LOAD} segments into the kernel
address space based on the size and permissions of the segments.
The system is also responsible for fixups on the program code to resolve
referenced kernel helpers and eBPF maps.
The \projname{} runtime environment in the kernel consists of the stack
unwinding mechanisms (\S\ref{principle:eh}), the support for dedicated
kernel stack (\S\ref{principle:stack}), and the support for program
termination (\S\ref{principle:termination}).
\subsection{Compiler support}
\label{impl:compiler}
\projname{} employs a compiler pass to handle the \projname{}-specific
compile time instrumentations on the stack (\S\ref{principle:stack}).
We take advantage of Rust's use of LLVM~\cite{llvm} as its default code
generation backend and implement the needed pass in LLVM.
A \projname{}-specific compiler switch is also added to the Rust compiler
frontend (\emph{rustc}~\cite{rustc}) to gate the \projname{} compiler pass.