Blame man/man8/tc-bpf.8

Packit d3f73b
.TH "BPF classifier and actions in tc" 8 "18 May 2015" "iproute2" "Linux"
Packit d3f73b
.SH NAME
Packit d3f73b
BPF \- BPF programmable classifier and actions for ingress/egress
Packit d3f73b
queueing disciplines
Packit d3f73b
.SH SYNOPSIS
Packit d3f73b
.SS eBPF classifier (filter) or action:
Packit d3f73b
.B tc filter ... bpf
Packit d3f73b
[
Packit d3f73b
.B object-file
Packit d3f73b
OBJ_FILE ] [
Packit d3f73b
.B section
Packit d3f73b
CLS_NAME ] [
Packit d3f73b
.B export
Packit d3f73b
UDS_FILE ] [
Packit d3f73b
.B verbose
Packit d3f73b
] [
Packit d3f73b
.B direct-action
Packit d3f73b
|
Packit d3f73b
.B da
Packit d3f73b
] [
Packit d3f73b
.B skip_hw
Packit d3f73b
|
Packit d3f73b
.B skip_sw
Packit d3f73b
] [
Packit d3f73b
.B police
Packit d3f73b
POLICE_SPEC ] [
Packit d3f73b
.B action
Packit d3f73b
ACTION_SPEC ] [
Packit d3f73b
.B classid
Packit d3f73b
CLASSID ]
Packit d3f73b
.br
Packit d3f73b
.B tc action ... bpf
Packit d3f73b
[
Packit d3f73b
.B object-file
Packit d3f73b
OBJ_FILE ] [
Packit d3f73b
.B section
Packit d3f73b
CLS_NAME ] [
Packit d3f73b
.B export
Packit d3f73b
UDS_FILE ] [
Packit d3f73b
.B verbose
Packit d3f73b
]
Packit d3f73b
Packit d3f73b
.SS cBPF classifier (filter) or action:
Packit d3f73b
.B tc filter ... bpf
Packit d3f73b
[
Packit d3f73b
.B bytecode-file
Packit d3f73b
BPF_FILE |
Packit d3f73b
.B bytecode
Packit d3f73b
BPF_BYTECODE ] [
Packit d3f73b
.B police
Packit d3f73b
POLICE_SPEC ] [
Packit d3f73b
.B action
Packit d3f73b
ACTION_SPEC ] [
Packit d3f73b
.B classid
Packit d3f73b
CLASSID ]
Packit d3f73b
.br
Packit d3f73b
.B tc action ... bpf
Packit d3f73b
[
Packit d3f73b
.B bytecode-file
Packit d3f73b
BPF_FILE |
Packit d3f73b
.B bytecode
Packit d3f73b
BPF_BYTECODE ]
Packit d3f73b
Packit d3f73b
.SH DESCRIPTION
Packit d3f73b
Packit d3f73b
Extended Berkeley Packet Filter (
Packit d3f73b
.B eBPF
Packit d3f73b
) and classic Berkeley Packet Filter
Packit d3f73b
(originally known as BPF, for better distinction referred to as
Packit d3f73b
.B cBPF
Packit d3f73b
here) are both available as a fully programmable and highly efficient
Packit d3f73b
classifier and actions. They both offer a minimal instruction set for
Packit d3f73b
implementing small programs which can safely be loaded into the kernel
Packit d3f73b
and thus executed in a tiny virtual machine from kernel space. An in-kernel
Packit d3f73b
verifier guarantees that a specified program always terminates and neither
Packit d3f73b
crashes nor leaks data from the kernel.
Packit d3f73b
Packit d3f73b
In Linux, it's generally considered that eBPF is the successor of cBPF.
Packit d3f73b
The kernel internally transforms cBPF expressions into eBPF expressions and
Packit d3f73b
executes the latter. Execution of them can be performed in an interpreter
Packit d3f73b
or at setup time, they can be just-in-time compiled (JIT'ed) to run as
Packit d3f73b
native machine code.
Packit d3f73b
.PP
Packit d3f73b
Currently, the eBPF JIT compiler is available for the following architectures:
Packit d3f73b
.IP * 4
Packit d3f73b
x86_64 (since Linux 3.18)
Packit d3f73b
.PD 0
Packit d3f73b
.IP *
Packit d3f73b
arm64 (since Linux 3.18)
Packit d3f73b
.IP *
Packit d3f73b
s390 (since Linux 4.1)
Packit d3f73b
.IP *
Packit d3f73b
ppc64 (since Linux 4.8)
Packit d3f73b
.IP *
Packit d3f73b
sparc64 (since Linux 4.12)
Packit d3f73b
.IP *
Packit d3f73b
mips64 (since Linux 4.13)
Packit d3f73b
.IP *
Packit d3f73b
arm32 (since Linux 4.14)
Packit d3f73b
.IP *
Packit d3f73b
x86_32 (since Linux 4.18)
Packit d3f73b
.PD
Packit d3f73b
.PP
Packit d3f73b
Whereas the following architectures have cBPF, but did not (yet) switch to eBPF
Packit d3f73b
JIT support:
Packit d3f73b
.IP * 4
Packit d3f73b
ppc32
Packit d3f73b
.PD 0
Packit d3f73b
.IP *
Packit d3f73b
sparc32
Packit d3f73b
.IP *
Packit d3f73b
mips32
Packit d3f73b
.PD
Packit d3f73b
.PP
Packit d3f73b
eBPF's instruction set has similar underlying principles as the cBPF
Packit d3f73b
instruction set, it however is modelled closer to the underlying
Packit d3f73b
architecture to better mimic native instruction sets with the aim to
Packit d3f73b
achieve a better run-time performance. It is designed to be JIT'ed with
Packit d3f73b
a one to one mapping, which can also open up the possibility for compilers
Packit d3f73b
to generate optimized eBPF code through an eBPF backend that performs
Packit d3f73b
almost as fast as natively compiled code. Given that LLVM provides such
Packit d3f73b
an eBPF backend, eBPF programs can therefore easily be programmed in a
Packit d3f73b
subset of the C language. Other than that, eBPF infrastructure also comes
Packit d3f73b
with a construct called "maps". eBPF maps are key/value stores that are
Packit d3f73b
shared between multiple eBPF programs, but also between eBPF programs and
Packit d3f73b
user space applications.
Packit d3f73b
Packit d3f73b
For the traffic control subsystem, classifier and actions that can be
Packit d3f73b
attached to ingress and egress qdiscs can be written in eBPF or cBPF. The
Packit d3f73b
advantage over other classifier and actions is that eBPF/cBPF provides the
Packit d3f73b
generic framework, while users can implement their highly specialized use
Packit d3f73b
cases efficiently. This means that the classifier or action written that
Packit d3f73b
way will not suffer from feature bloat, and can therefore execute its task
Packit d3f73b
highly efficient. It allows for non-linear classification and even merging
Packit d3f73b
the action part into the classification. Combined with efficient eBPF map
Packit d3f73b
data structures, user space can push new policies like classids into the
Packit d3f73b
kernel without reloading a classifier, or it can gather statistics that
Packit d3f73b
are pushed into one map and use another one for dynamically load balancing
Packit d3f73b
traffic based on the determined load, just to provide a few examples.
Packit d3f73b
Packit d3f73b
.SH PARAMETERS
Packit d3f73b
.SS object-file
Packit d3f73b
points to an object file that has an executable and linkable format (ELF)
Packit d3f73b
and contains eBPF opcodes and eBPF map definitions. The LLVM compiler
Packit d3f73b
infrastructure with
Packit d3f73b
.B clang(1)
Packit d3f73b
as a C language front end is one project that supports emitting eBPF object
Packit d3f73b
files that can be passed to the eBPF classifier (more details in the
Packit d3f73b
.B EXAMPLES
Packit d3f73b
section). This option is mandatory when an eBPF classifier or action is
Packit d3f73b
to be loaded.
Packit d3f73b
Packit d3f73b
.SS section
Packit d3f73b
is the name of the ELF section from the object file, where the eBPF
Packit d3f73b
classifier or action resides. By default the section name for the
Packit d3f73b
classifier is called "classifier", and for the action "action". Given
Packit d3f73b
that a single object file can contain multiple classifier and actions,
Packit d3f73b
the corresponding section name needs to be specified, if it differs
Packit d3f73b
from the defaults.
Packit d3f73b
Packit d3f73b
.SS export
Packit d3f73b
points to a Unix domain socket file. In case the eBPF object file also
Packit d3f73b
contains a section named "maps" with eBPF map specifications, then the
Packit d3f73b
map file descriptors can be handed off via the Unix domain socket to
Packit d3f73b
an eBPF "agent" herding all descriptors after tc lifetime. This can be
Packit d3f73b
some third party application implementing the IPC counterpart for the
Packit d3f73b
import, that uses them for calling into
Packit d3f73b
.B bpf(2)
Packit d3f73b
system call to read out or update eBPF map data from user space, for
Packit d3f73b
example, for monitoring purposes or to push down new policies.
Packit d3f73b
Packit d3f73b
.SS verbose
Packit d3f73b
if set, it will dump the eBPF verifier output, even if loading the eBPF
Packit d3f73b
program was successful. By default, only on error, the verifier log is
Packit d3f73b
being emitted to the user.
Packit d3f73b
Packit d3f73b
.SS direct-action | da
Packit d3f73b
instructs eBPF classifier to not invoke external TC actions, instead use the
Packit d3f73b
TC actions return codes (\fBTC_ACT_OK\fR, \fBTC_ACT_SHOT\fR etc.) for
Packit d3f73b
classifiers.
Packit d3f73b
Packit d3f73b
.SS skip_hw | skip_sw
Packit d3f73b
hardware offload control flags. By default TC will try to offload
Packit d3f73b
filters to hardware if possible.
Packit d3f73b
.B skip_hw
Packit d3f73b
explicitly disables the attempt to offload.
Packit d3f73b
.B skip_sw
Packit d3f73b
forces the offload and disables running the eBPF program in the kernel.
Packit d3f73b
If hardware offload is not possible and this flag was set kernel will
Packit d3f73b
report an error and filter will not be installed at all.
Packit d3f73b
Packit d3f73b
.SS police
Packit d3f73b
is an optional parameter for an eBPF/cBPF classifier that specifies a
Packit d3f73b
police in
Packit d3f73b
.B tc(1)
Packit d3f73b
which is attached to the classifier, for example, on an ingress qdisc.
Packit d3f73b
Packit d3f73b
.SS action
Packit d3f73b
is an optional parameter for an eBPF/cBPF classifier that specifies a
Packit d3f73b
subsequent action in
Packit d3f73b
.B tc(1)
Packit d3f73b
which is attached to a classifier.
Packit d3f73b
Packit d3f73b
.SS classid
Packit d3f73b
.SS flowid
Packit d3f73b
provides the default traffic control class identifier for this eBPF/cBPF
Packit d3f73b
classifier. The default class identifier can also be overwritten by the
Packit d3f73b
return code of the eBPF/cBPF program. A default return code of
Packit d3f73b
.B -1
Packit d3f73b
specifies the here provided default class identifier to be used. A return
Packit d3f73b
code of the eBPF/cBPF program of 0 implies that no match took place, and
Packit d3f73b
a return code other than these two will override the default classid. This
Packit d3f73b
allows for efficient, non-linear classification with only a single eBPF/cBPF
Packit d3f73b
program as opposed to having multiple individual programs for various class
Packit d3f73b
identifiers which would need to reparse packet contents.
Packit d3f73b
Packit d3f73b
.SS bytecode
Packit d3f73b
is being used for loading cBPF classifier and actions only. The cBPF bytecode
Packit d3f73b
is directly passed as a text string in the form of
Packit d3f73b
.B \'s,c t f k,c t f k,c t f k,...\'
Packit d3f73b
, where
Packit d3f73b
.B s
Packit d3f73b
denotes the number of subsequent 4-tuples. One such 4-tuple consists of
Packit d3f73b
.B c t f k
Packit d3f73b
decimals, where
Packit d3f73b
.B c
Packit d3f73b
represents the cBPF opcode,
Packit d3f73b
.B t
Packit d3f73b
the jump true offset target,
Packit d3f73b
.B f
Packit d3f73b
the jump false offset target and
Packit d3f73b
.B k
Packit d3f73b
the immediate constant/literal. There are various tools that generate code
Packit d3f73b
in this loadable format, for example,
Packit d3f73b
.B bpf_asm
Packit d3f73b
that ships with the Linux kernel source tree under
Packit d3f73b
.B tools/net/
Packit d3f73b
, so it is certainly not expected to hack this by hand. The
Packit d3f73b
.B bytecode
Packit d3f73b
or
Packit d3f73b
.B bytecode-file
Packit d3f73b
option is mandatory when a cBPF classifier or action is to be loaded.
Packit d3f73b
Packit d3f73b
.SS bytecode-file
Packit d3f73b
also being used to load a cBPF classifier or action. It's effectively the
Packit d3f73b
same as
Packit d3f73b
.B bytecode
Packit d3f73b
only that the cBPF bytecode is not passed directly via command line, but
Packit d3f73b
rather resides in a text file.
Packit d3f73b
Packit d3f73b
.SH EXAMPLES
Packit d3f73b
.SS eBPF TOOLING
Packit d3f73b
A full blown example including eBPF agent code can be found inside the
Packit d3f73b
iproute2 source package under:
Packit d3f73b
.B examples/bpf/
Packit d3f73b
Packit d3f73b
As prerequisites, the kernel needs to have the eBPF system call namely
Packit d3f73b
.B bpf(2)
Packit d3f73b
enabled and ships with
Packit d3f73b
.B cls_bpf
Packit d3f73b
and
Packit d3f73b
.B act_bpf
Packit d3f73b
kernel modules for the traffic control subsystem. To enable eBPF/eBPF JIT
Packit d3f73b
support, depending which of the two the given architecture supports:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B echo 1 > /proc/sys/net/core/bpf_jit_enable
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
A given restricted C file can be compiled via LLVM as:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B clang -O2 -emit-llvm -c bpf.c -o - | llc -march=bpf -filetype=obj -o bpf.o
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
The compiler invocation might still simplify in future, so for now,
Packit d3f73b
it's quite handy to alias this construct in one way or another, for
Packit d3f73b
example:
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
__bcc() {
Packit d3f73b
        clang -O2 -emit-llvm -c $1 -o - | \\
Packit d3f73b
        llc -march=bpf -filetype=obj -o "`basename $1 .c`.o"
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
alias bcc=__bcc
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
A minimal, stand-alone unit, which matches on all traffic with the
Packit d3f73b
default classid (return code of -1) looks like:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
#include <linux/bpf.h>
Packit d3f73b
Packit d3f73b
#ifndef __section
Packit d3f73b
# define __section(x)  __attribute__((section(x), used))
Packit d3f73b
#endif
Packit d3f73b
Packit d3f73b
__section("classifier") int cls_main(struct __sk_buff *skb)
Packit d3f73b
{
Packit d3f73b
        return -1;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
char __license[] __section("license") = "GPL";
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
More examples can be found further below in subsection
Packit d3f73b
.B eBPF PROGRAMMING
Packit d3f73b
as focus here will be on tooling.
Packit d3f73b
Packit d3f73b
There can be various other sections, for example, also for actions.
Packit d3f73b
Thus, an object file in eBPF can contain multiple entrance points.
Packit d3f73b
Always a specific entrance point, however, must be specified when
Packit d3f73b
configuring with tc. A license must be part of the restricted C code
Packit d3f73b
and the license string syntax is the same as with Linux kernel modules.
Packit d3f73b
The kernel reserves its right that some eBPF helper functions can be
Packit d3f73b
restricted to GPL compatible licenses only, and thus may reject a program
Packit d3f73b
from loading into the kernel when such a license mismatch occurs.
Packit d3f73b
Packit d3f73b
The resulting object file from the compilation can be inspected with
Packit d3f73b
the usual set of tools that also operate on normal object files, for
Packit d3f73b
example
Packit d3f73b
.B objdump(1)
Packit d3f73b
for inspecting ELF section headers:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
objdump -h bpf.o
Packit d3f73b
[...]
Packit d3f73b
3 classifier    000007f8  0000000000000000  0000000000000000  00000040  2**3
Packit d3f73b
                CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
Packit d3f73b
4 action-mark   00000088  0000000000000000  0000000000000000  00000838  2**3
Packit d3f73b
                CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
Packit d3f73b
5 action-rand   00000098  0000000000000000  0000000000000000  000008c0  2**3
Packit d3f73b
                CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
Packit d3f73b
6 maps          00000030  0000000000000000  0000000000000000  00000958  2**2
Packit d3f73b
                CONTENTS, ALLOC, LOAD, DATA
Packit d3f73b
7 license       00000004  0000000000000000  0000000000000000  00000988  2**0
Packit d3f73b
                CONTENTS, ALLOC, LOAD, DATA
Packit d3f73b
[...]
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Adding an eBPF classifier from an object file that contains a classifier
Packit d3f73b
in the default ELF section is trivial (note that instead of "object-file"
Packit d3f73b
also shortcuts such as "obj" can be used):
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B bcc bpf.c
Packit d3f73b
.br
Packit d3f73b
.B tc filter add dev em1 parent 1: bpf obj bpf.o flowid 1:1
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
In case the classifier resides in ELF section "mycls", then that same
Packit d3f73b
command needs to be invoked as:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tc filter add dev em1 parent 1: bpf obj bpf.o sec mycls flowid 1:1
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Dumping the classifier configuration will tell the location of the
Packit d3f73b
classifier, in other words that it's from object file "bpf.o" under
Packit d3f73b
section "mycls":
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tc filter show dev em1
Packit d3f73b
.br
Packit d3f73b
.B filter parent 1: protocol all pref 49152 bpf
Packit d3f73b
.br
Packit d3f73b
.B filter parent 1: protocol all pref 49152 bpf handle 0x1 flowid 1:1 bpf.o:[mycls]
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
The same program can also be installed on ingress qdisc side as opposed
Packit d3f73b
to egress ...
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tc qdisc add dev em1 handle ffff: ingress
Packit d3f73b
.br
Packit d3f73b
.B tc filter add dev em1 parent ffff: bpf obj bpf.o sec mycls flowid ffff:1
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
\&... and again dumped from there:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tc filter show dev em1 parent ffff:
Packit d3f73b
.br
Packit d3f73b
.B filter protocol all pref 49152 bpf
Packit d3f73b
.br
Packit d3f73b
.B filter protocol all pref 49152 bpf handle 0x1 flowid ffff:1 bpf.o:[mycls]
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Attaching a classifier and action on ingress has the restriction that
Packit d3f73b
it doesn't have an actual underlying queueing discipline. What ingress
Packit d3f73b
can do is to classify, mangle, redirect or drop packets. When queueing
Packit d3f73b
is required on ingress side, then ingress must redirect packets to the
Packit d3f73b
.B ifb
Packit d3f73b
device, otherwise policing can be used. Moreover, ingress can be used to
Packit d3f73b
have an early drop point of unwanted packets before they hit upper layers
Packit d3f73b
of the networking stack, perform network accounting with eBPF maps that
Packit d3f73b
could be shared with egress, or have an early mangle and/or redirection
Packit d3f73b
point to different networking devices.
Packit d3f73b
Packit d3f73b
Multiple eBPF actions and classifier can be placed into a single
Packit d3f73b
object file within various sections. In that case, non-default section
Packit d3f73b
names must be provided, which is the case for both actions in this
Packit d3f73b
example:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tc filter add dev em1 parent 1: bpf obj bpf.o flowid 1:1 \e
Packit d3f73b
.br
Packit d3f73b
.in +25n
Packit d3f73b
.B                          action bpf obj bpf.o sec action-mark \e
Packit d3f73b
.br
Packit d3f73b
.B                          action bpf obj bpf.o sec action-rand ok
Packit d3f73b
.in -25n
Packit d3f73b
.in -4n
Packit d3f73b
Packit d3f73b
The advantage of this is that the classifier and the two actions can
Packit d3f73b
then share eBPF maps with each other, if implemented in the programs.
Packit d3f73b
Packit d3f73b
In order to access eBPF maps from user space beyond
Packit d3f73b
.B tc(8)
Packit d3f73b
setup lifetime, the ownership can be transferred to an eBPF agent via
Packit d3f73b
Unix domain sockets. There are two possibilities for implementing this:
Packit d3f73b
Packit d3f73b
.B 1)
Packit d3f73b
implementation of an own eBPF agent that takes care of setting up
Packit d3f73b
the Unix domain socket and implementing the protocol that
Packit d3f73b
.B tc(8)
Packit d3f73b
dictates. A code example of this can be found inside the iproute2
Packit d3f73b
source package under:
Packit d3f73b
.B examples/bpf/
Packit d3f73b
Packit d3f73b
.B 2)
Packit d3f73b
use
Packit d3f73b
.B tc exec
Packit d3f73b
for transferring the eBPF map file descriptors through a Unix domain
Packit d3f73b
socket, and spawning an application such as
Packit d3f73b
.B sh(1)
Packit d3f73b
\&. This approach's advantage is that tc will place the file descriptors
Packit d3f73b
into the environment and thus make them available just like stdin, stdout,
Packit d3f73b
stderr file descriptors, meaning, in case user applications run from within
Packit d3f73b
this fd-owner shell, they can terminate and restart without losing eBPF
Packit d3f73b
maps file descriptors. Example invocation with the previous classifier and
Packit d3f73b
action mixture:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tc exec bpf imp /tmp/bpf
Packit d3f73b
.br
Packit d3f73b
.B tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf flowid 1:1 \e
Packit d3f73b
.br
Packit d3f73b
.in +25n
Packit d3f73b
.B                          action bpf obj bpf.o sec action-mark \e
Packit d3f73b
.br
Packit d3f73b
.B                          action bpf obj bpf.o sec action-rand ok
Packit d3f73b
.in -25n
Packit d3f73b
.in -4n
Packit d3f73b
Packit d3f73b
Assuming that eBPF maps are shared with classifier and actions, it's
Packit d3f73b
enough to export them once, for example, from within the classifier
Packit d3f73b
or action command. tc will setup all eBPF map file descriptors at the
Packit d3f73b
time when the object file is first parsed.
Packit d3f73b
Packit d3f73b
When a shell has been spawned, the environment will have a couple of
Packit d3f73b
eBPF related variables. BPF_NUM_MAPS provides the total number of maps
Packit d3f73b
that have been transferred over the Unix domain socket. BPF_MAP<X>'s
Packit d3f73b
value is the file descriptor number that can be accessed in eBPF agent
Packit d3f73b
applications, in other words, it can directly be used as the file
Packit d3f73b
descriptor value for the
Packit d3f73b
.B bpf(2)
Packit d3f73b
system call to retrieve or alter eBPF map values. <X> denotes the
Packit d3f73b
identifier of the eBPF map. It corresponds to the
Packit d3f73b
.B id
Packit d3f73b
member of
Packit d3f73b
.B struct bpf_elf_map
Packit d3f73b
\& from the tc eBPF map specification.
Packit d3f73b
Packit d3f73b
The environment in this example looks as follows:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
sh# env | grep BPF
Packit d3f73b
    BPF_NUM_MAPS=3
Packit d3f73b
    BPF_MAP1=6
Packit d3f73b
    BPF_MAP0=5
Packit d3f73b
    BPF_MAP2=7
Packit d3f73b
sh# ls -la /proc/self/fd
Packit d3f73b
    [...]
Packit d3f73b
    lrwx------. 1 root root 64 Apr 14 16:46 5 -> anon_inode:bpf-map
Packit d3f73b
    lrwx------. 1 root root 64 Apr 14 16:46 6 -> anon_inode:bpf-map
Packit d3f73b
    lrwx------. 1 root root 64 Apr 14 16:46 7 -> anon_inode:bpf-map
Packit d3f73b
sh# my_bpf_agent
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
eBPF agents are very useful in that they can prepopulate eBPF maps from
Packit d3f73b
user space, monitor statistics via maps and based on that feedback, for
Packit d3f73b
example, rewrite classids in eBPF map values during runtime. Given that eBPF
Packit d3f73b
agents are implemented as normal applications, they can also dynamically
Packit d3f73b
receive traffic control policies from external controllers and thus push
Packit d3f73b
them down into eBPF maps to dynamically adapt to network conditions. Moreover,
Packit d3f73b
eBPF maps can also be shared with other eBPF program types (e.g. tracing),
Packit d3f73b
thus very powerful combination can therefore be implemented.
Packit d3f73b
Packit d3f73b
.SS eBPF PROGRAMMING
Packit d3f73b
Packit d3f73b
eBPF classifier and actions are being implemented in restricted C syntax
Packit d3f73b
(in future, there could additionally be new language frontends supported).
Packit d3f73b
Packit d3f73b
The header file
Packit d3f73b
.B linux/bpf.h
Packit d3f73b
provides eBPF helper functions that can be called from an eBPF program.
Packit d3f73b
This man page will only provide two minimal, stand-alone examples, have a
Packit d3f73b
look at
Packit d3f73b
.B examples/bpf
Packit d3f73b
from the iproute2 source package for a fully fledged flow dissector
Packit d3f73b
example to better demonstrate some of the possibilities with eBPF.
Packit d3f73b
Packit d3f73b
Supported 32 bit classifier return codes from the C program and their meanings:
Packit d3f73b
.in +4n
Packit d3f73b
.B 0
Packit d3f73b
, denotes a mismatch
Packit d3f73b
.br
Packit d3f73b
.B -1
Packit d3f73b
, denotes the default classid configured from the command line
Packit d3f73b
.br
Packit d3f73b
.B else
Packit d3f73b
, everything else will override the default classid to provide a facility for
Packit d3f73b
non-linear matching
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Supported 32 bit action return codes from the C program and their meanings (
Packit d3f73b
.B linux/pkt_cls.h
Packit d3f73b
):
Packit d3f73b
.in +4n
Packit d3f73b
.B TC_ACT_OK (0)
Packit d3f73b
, will terminate the packet processing pipeline and allows the packet to
Packit d3f73b
proceed
Packit d3f73b
.br
Packit d3f73b
.B TC_ACT_SHOT (2)
Packit d3f73b
, will terminate the packet processing pipeline and drops the packet
Packit d3f73b
.br
Packit d3f73b
.B TC_ACT_UNSPEC (-1)
Packit d3f73b
, will use the default action configured from tc (similarly as returning
Packit d3f73b
.B -1
Packit d3f73b
from a classifier)
Packit d3f73b
.br
Packit d3f73b
.B TC_ACT_PIPE (3)
Packit d3f73b
, will iterate to the next action, if available
Packit d3f73b
.br
Packit d3f73b
.B TC_ACT_RECLASSIFY (1)
Packit d3f73b
, will terminate the packet processing pipeline and start classification
Packit d3f73b
from the beginning
Packit d3f73b
.br
Packit d3f73b
.B else
Packit d3f73b
, everything else is an unspecified return code
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Both classifier and action return codes are supported in eBPF and cBPF
Packit d3f73b
programs.
Packit d3f73b
Packit d3f73b
To demonstrate restricted C syntax, a minimal toy classifier example is
Packit d3f73b
provided, which assumes that egress packets, for instance originating
Packit d3f73b
from a container, have previously been marked in interval [0, 255]. The
Packit d3f73b
program keeps statistics on different marks for user space and maps the
Packit d3f73b
classid to the root qdisc with the marking itself as the minor handle:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
#include <stdint.h>
Packit d3f73b
#include <asm/types.h>
Packit d3f73b
Packit d3f73b
#include <linux/bpf.h>
Packit d3f73b
#include <linux/pkt_sched.h>
Packit d3f73b
Packit d3f73b
#include "helpers.h"
Packit d3f73b
Packit d3f73b
struct tuple {
Packit d3f73b
        long packets;
Packit d3f73b
        long bytes;
Packit d3f73b
};
Packit d3f73b
Packit d3f73b
#define BPF_MAP_ID_STATS        1 /* agent's map identifier */
Packit d3f73b
#define BPF_MAX_MARK            256
Packit d3f73b
Packit d3f73b
struct bpf_elf_map __section("maps") map_stats = {
Packit d3f73b
        .type           =       BPF_MAP_TYPE_ARRAY,
Packit d3f73b
        .id             =       BPF_MAP_ID_STATS,
Packit d3f73b
        .size_key       =       sizeof(uint32_t),
Packit d3f73b
        .size_value     =       sizeof(struct tuple),
Packit d3f73b
        .max_elem       =       BPF_MAX_MARK,
Packit d3f73b
        .pinning        =       PIN_GLOBAL_NS,
Packit d3f73b
};
Packit d3f73b
Packit d3f73b
static inline void cls_update_stats(const struct __sk_buff *skb,
Packit d3f73b
                                    uint32_t mark)
Packit d3f73b
{
Packit d3f73b
        struct tuple *tu;
Packit d3f73b
Packit d3f73b
        tu = bpf_map_lookup_elem(&map_stats, &mark);
Packit d3f73b
        if (likely(tu)) {
Packit d3f73b
                __sync_fetch_and_add(&tu->packets, 1);
Packit d3f73b
                __sync_fetch_and_add(&tu->bytes, skb->len);
Packit d3f73b
        }
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
__section("cls") int cls_main(struct __sk_buff *skb)
Packit d3f73b
{
Packit d3f73b
        uint32_t mark = skb->mark;
Packit d3f73b
Packit d3f73b
        if (unlikely(mark >= BPF_MAX_MARK))
Packit d3f73b
                return 0;
Packit d3f73b
Packit d3f73b
        cls_update_stats(skb, mark);
Packit d3f73b
Packit d3f73b
        return TC_H_MAKE(TC_H_ROOT, mark);
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
char __license[] __section("license") = "GPL";
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Another small example is a port redirector which demuxes destination port
Packit d3f73b
80 into the interval [8080, 8087] steered by RSS, that can then be attached
Packit d3f73b
to ingress qdisc. The exercise of adding the egress counterpart and IPv6
Packit d3f73b
support is left to the reader:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
#include <asm/types.h>
Packit d3f73b
#include <asm/byteorder.h>
Packit d3f73b
Packit d3f73b
#include <linux/bpf.h>
Packit d3f73b
#include <linux/filter.h>
Packit d3f73b
#include <linux/in.h>
Packit d3f73b
#include <linux/if_ether.h>
Packit d3f73b
#include <linux/ip.h>
Packit d3f73b
#include <linux/tcp.h>
Packit d3f73b
Packit d3f73b
#include "helpers.h"
Packit d3f73b
Packit d3f73b
static inline void set_tcp_dport(struct __sk_buff *skb, int nh_off,
Packit d3f73b
                                 __u16 old_port, __u16 new_port)
Packit d3f73b
{
Packit d3f73b
        bpf_l4_csum_replace(skb, nh_off + offsetof(struct tcphdr, check),
Packit d3f73b
                            old_port, new_port, sizeof(new_port));
Packit d3f73b
        bpf_skb_store_bytes(skb, nh_off + offsetof(struct tcphdr, dest),
Packit d3f73b
                            &new_port, sizeof(new_port), 0);
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
static inline int lb_do_ipv4(struct __sk_buff *skb, int nh_off)
Packit d3f73b
{
Packit d3f73b
        __u16 dport, dport_new = 8080, off;
Packit d3f73b
        __u8 ip_proto, ip_vl;
Packit d3f73b
Packit d3f73b
        ip_proto = load_byte(skb, nh_off +
Packit d3f73b
                             offsetof(struct iphdr, protocol));
Packit d3f73b
        if (ip_proto != IPPROTO_TCP)
Packit d3f73b
                return 0;
Packit d3f73b
Packit d3f73b
        ip_vl = load_byte(skb, nh_off);
Packit d3f73b
        if (likely(ip_vl == 0x45))
Packit d3f73b
                nh_off += sizeof(struct iphdr);
Packit d3f73b
        else
Packit d3f73b
                nh_off += (ip_vl & 0xF) << 2;
Packit d3f73b
Packit d3f73b
        dport = load_half(skb, nh_off + offsetof(struct tcphdr, dest));
Packit d3f73b
        if (dport != 80)
Packit d3f73b
                return 0;
Packit d3f73b
Packit d3f73b
        off = skb->queue_mapping & 7;
Packit d3f73b
        set_tcp_dport(skb, nh_off - BPF_LL_OFF, __constant_htons(80),
Packit d3f73b
                      __cpu_to_be16(dport_new + off));
Packit d3f73b
        return -1;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
__section("lb") int lb_main(struct __sk_buff *skb)
Packit d3f73b
{
Packit d3f73b
        int ret = 0, nh_off = BPF_LL_OFF + ETH_HLEN;
Packit d3f73b
Packit d3f73b
        if (likely(skb->protocol == __constant_htons(ETH_P_IP)))
Packit d3f73b
                ret = lb_do_ipv4(skb, nh_off);
Packit d3f73b
Packit d3f73b
        return ret;
Packit d3f73b
}
Packit d3f73b
Packit d3f73b
char __license[] __section("license") = "GPL";
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
The related helper header file
Packit d3f73b
.B helpers.h
Packit d3f73b
in both examples was:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
/* Misc helper macros. */
Packit d3f73b
#define __section(x) __attribute__((section(x), used))
Packit d3f73b
#define offsetof(x, y) __builtin_offsetof(x, y)
Packit d3f73b
#define likely(x) __builtin_expect(!!(x), 1)
Packit d3f73b
#define unlikely(x) __builtin_expect(!!(x), 0)
Packit d3f73b
Packit d3f73b
/* Object pinning settings */
Packit d3f73b
#define PIN_NONE       0
Packit d3f73b
#define PIN_OBJECT_NS  1
Packit d3f73b
#define PIN_GLOBAL_NS  2
Packit d3f73b
Packit d3f73b
/* ELF map definition */
Packit d3f73b
struct bpf_elf_map {
Packit d3f73b
    __u32 type;
Packit d3f73b
    __u32 size_key;
Packit d3f73b
    __u32 size_value;
Packit d3f73b
    __u32 max_elem;
Packit d3f73b
    __u32 flags;
Packit d3f73b
    __u32 id;
Packit d3f73b
    __u32 pinning;
Packit d3f73b
    __u32 inner_id;
Packit d3f73b
    __u32 inner_idx;
Packit d3f73b
};
Packit d3f73b
Packit d3f73b
/* Some used BPF function calls. */
Packit d3f73b
static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from,
Packit d3f73b
                                  int len, int flags) =
Packit d3f73b
      (void *) BPF_FUNC_skb_store_bytes;
Packit d3f73b
static int (*bpf_l4_csum_replace)(void *ctx, int off, int from,
Packit d3f73b
                                  int to, int flags) =
Packit d3f73b
      (void *) BPF_FUNC_l4_csum_replace;
Packit d3f73b
static void *(*bpf_map_lookup_elem)(void *map, void *key) =
Packit d3f73b
      (void *) BPF_FUNC_map_lookup_elem;
Packit d3f73b
Packit d3f73b
/* Some used BPF intrinsics. */
Packit d3f73b
unsigned long long load_byte(void *skb, unsigned long long off)
Packit d3f73b
    asm ("llvm.bpf.load.byte");
Packit d3f73b
unsigned long long load_half(void *skb, unsigned long long off)
Packit d3f73b
    asm ("llvm.bpf.load.half");
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Best practice, we recommend to only have a single eBPF classifier loaded
Packit d3f73b
in tc and perform
Packit d3f73b
.B all
Packit d3f73b
necessary matching and mangling from there instead of a list of individual
Packit d3f73b
classifier and separate actions. Just a single classifier tailored for a
Packit d3f73b
given use-case will be most efficient to run.
Packit d3f73b
Packit d3f73b
.SS eBPF DEBUGGING
Packit d3f73b
Packit d3f73b
Both tc
Packit d3f73b
.B filter
Packit d3f73b
and
Packit d3f73b
.B action
Packit d3f73b
commands for
Packit d3f73b
.B bpf
Packit d3f73b
support an optional
Packit d3f73b
.B verbose
Packit d3f73b
parameter that can be used to inspect the eBPF verifier log. It is dumped
Packit d3f73b
by default in case of an error.
Packit d3f73b
Packit d3f73b
In case the eBPF/cBPF JIT compiler has been enabled, it can also be
Packit d3f73b
instructed to emit a debug output of the resulting opcode image into
Packit d3f73b
the kernel log, which can be read via
Packit d3f73b
.B dmesg(1)
Packit d3f73b
:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B echo 2 > /proc/sys/net/core/bpf_jit_enable
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
The Linux kernel source tree ships additionally under
Packit d3f73b
.B tools/net/
Packit d3f73b
a small helper called
Packit d3f73b
.B bpf_jit_disasm
Packit d3f73b
that reads out the opcode image dump from the kernel log and dumps the
Packit d3f73b
resulting disassembly:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B bpf_jit_disasm -o
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Other than that, the Linux kernel also contains an extensive eBPF/cBPF
Packit d3f73b
test suite module called
Packit d3f73b
.B test_bpf
Packit d3f73b
\&. Upon ...
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B modprobe test_bpf
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
\&... it performs a diversity of test cases and dumps the results into
Packit d3f73b
the kernel log that can be inspected with
Packit d3f73b
.B dmesg(1)
Packit d3f73b
\&. The results can differ depending on whether the JIT compiler is enabled
Packit d3f73b
or not. In case of failed test cases, the module will fail to load. In
Packit d3f73b
such cases, we urge you to file a bug report to the related JIT authors,
Packit d3f73b
Linux kernel and networking mailing lists.
Packit d3f73b
Packit d3f73b
.SS cBPF
Packit d3f73b
Packit d3f73b
Although we generally recommend switching to implementing
Packit d3f73b
.B eBPF
Packit d3f73b
classifier and actions, for the sake of completeness, a few words on how to
Packit d3f73b
program in cBPF will be lost here.
Packit d3f73b
Packit d3f73b
Likewise, the
Packit d3f73b
.B bpf_jit_enable
Packit d3f73b
switch can be enabled as mentioned already. Tooling such as
Packit d3f73b
.B bpf_jit_disasm
Packit d3f73b
is also independent whether eBPF or cBPF code is being loaded.
Packit d3f73b
Packit d3f73b
Unlike in eBPF, classifier and action are not implemented in restricted C,
Packit d3f73b
but rather in a minimal assembler-like language or with the help of other
Packit d3f73b
tooling.
Packit d3f73b
Packit d3f73b
The raw interface with tc takes opcodes directly. For example, the most
Packit d3f73b
minimal classifier matching on every packet resulting in the default
Packit d3f73b
classid of 1:1 looks like:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tc filter add dev em1 parent 1: bpf bytecode '1,6 0 0 4294967295,' flowid 1:1
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
The first decimal of the bytecode sequence denotes the number of subsequent
Packit d3f73b
4-tuples of cBPF opcodes. As mentioned, such a 4-tuple consists of
Packit d3f73b
.B c t f k
Packit d3f73b
decimals, where
Packit d3f73b
.B c
Packit d3f73b
represents the cBPF opcode,
Packit d3f73b
.B t
Packit d3f73b
the jump true offset target,
Packit d3f73b
.B f
Packit d3f73b
the jump false offset target and
Packit d3f73b
.B k
Packit d3f73b
the immediate constant/literal. Here, this denotes an unconditional return
Packit d3f73b
from the program with immediate value of -1.
Packit d3f73b
Packit d3f73b
Thus, for egress classification, Willem de Bruijn implemented a minimal stand-alone
Packit d3f73b
helper tool under the GNU General Public License version 2 for
Packit d3f73b
.B iptables(8)
Packit d3f73b
BPF extension, which abuses the
Packit d3f73b
.B libpcap
Packit d3f73b
internal classic BPF compiler, his code derived here for usage with
Packit d3f73b
.B tc(8)
Packit d3f73b
:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
#include <pcap.h>
Packit d3f73b
#include <stdio.h>
Packit d3f73b
Packit d3f73b
int main(int argc, char **argv)
Packit d3f73b
{
Packit d3f73b
        struct bpf_program prog;
Packit d3f73b
        struct bpf_insn *ins;
Packit d3f73b
        int i, ret, dlt = DLT_RAW;
Packit d3f73b
Packit d3f73b
        if (argc < 2 || argc > 3)
Packit d3f73b
                return 1;
Packit d3f73b
        if (argc == 3) {
Packit d3f73b
                dlt = pcap_datalink_name_to_val(argv[1]);
Packit d3f73b
                if (dlt == -1)
Packit d3f73b
                        return 1;
Packit d3f73b
        }
Packit d3f73b
Packit d3f73b
        ret = pcap_compile_nopcap(-1, dlt, &prog, argv[argc - 1],
Packit d3f73b
                                  1, PCAP_NETMASK_UNKNOWN);
Packit d3f73b
        if (ret)
Packit d3f73b
                return 1;
Packit d3f73b
Packit d3f73b
        printf("%d,", prog.bf_len);
Packit d3f73b
        ins = prog.bf_insns;
Packit d3f73b
Packit d3f73b
        for (i = 0; i < prog.bf_len - 1; ++ins, ++i)
Packit d3f73b
                printf("%u %u %u %u,", ins->code,
Packit d3f73b
                       ins->jt, ins->jf, ins->k);
Packit d3f73b
        printf("%u %u %u %u",
Packit d3f73b
               ins->code, ins->jt, ins->jf, ins->k);
Packit d3f73b
Packit d3f73b
        pcap_freecode(&prog;;
Packit d3f73b
        return 0;
Packit d3f73b
}
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Given this small helper, any
Packit d3f73b
.B tcpdump(8)
Packit d3f73b
filter expression can be abused as a classifier where a match will
Packit d3f73b
result in the default classid:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B bpftool EN10MB 'tcp[tcpflags] & tcp-syn != 0' > /var/bpf/tcp-syn
Packit d3f73b
.br
Packit d3f73b
.B tc filter add dev em1 parent 1: bpf bytecode-file /var/bpf/tcp-syn flowid 1:1
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Basically, such a minimal generator is equivalent to:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B tcpdump -iem1 -ddd 'tcp[tcpflags] & tcp-syn != 0' | tr '\\\\n' ',' > /var/bpf/tcp-syn
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Since
Packit d3f73b
.B libpcap
Packit d3f73b
does not support all Linux' specific cBPF extensions in its compiler, the
Packit d3f73b
Linux kernel also ships under
Packit d3f73b
.B tools/net/
Packit d3f73b
a minimal BPF assembler called
Packit d3f73b
.B bpf_asm
Packit d3f73b
for providing full control. For detailed syntax and semantics on implementing
Packit d3f73b
such programs by hand, see references under
Packit d3f73b
.B FURTHER READING
Packit d3f73b
\&.
Packit d3f73b
Packit d3f73b
Trivial toy example in
Packit d3f73b
.B bpf_asm
Packit d3f73b
for classifying IPv4/TCP packets, saved in a text file called
Packit d3f73b
.B foobar
Packit d3f73b
:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.nf
Packit d3f73b
.sp
Packit d3f73b
ldh [12]
Packit d3f73b
jne #0x800, drop
Packit d3f73b
ldb [23]
Packit d3f73b
jneq #6, drop
Packit d3f73b
ret #-1
Packit d3f73b
drop: ret #0
Packit d3f73b
.fi
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
Similarly, such a classifier can be loaded as:
Packit d3f73b
Packit d3f73b
.in +4n
Packit d3f73b
.B bpf_asm foobar > /var/bpf/tcp-syn
Packit d3f73b
.br
Packit d3f73b
.B tc filter add dev em1 parent 1: bpf bytecode-file /var/bpf/tcp-syn flowid 1:1
Packit d3f73b
.in
Packit d3f73b
Packit d3f73b
For BPF classifiers, the Linux kernel provides additionally under
Packit d3f73b
.B tools/net/
Packit d3f73b
a small BPF debugger called
Packit d3f73b
.B bpf_dbg
Packit d3f73b
, which can be used to test a classifier against pcap files, single-step
Packit d3f73b
or add various breakpoints into the classifier program and dump register
Packit d3f73b
contents during runtime.
Packit d3f73b
Packit d3f73b
Implementing an action in classic BPF is rather limited in the sense that
Packit d3f73b
packet mangling is not supported. Therefore, it's generally recommended to
Packit d3f73b
make the switch to eBPF, whenever possible.
Packit d3f73b
Packit d3f73b
.SH FURTHER READING
Packit d3f73b
Further and more technical details about the BPF architecture can be found
Packit d3f73b
in the Linux kernel source tree under
Packit d3f73b
.B Documentation/networking/filter.txt
Packit d3f73b
\&.
Packit d3f73b
Packit d3f73b
Further details on eBPF
Packit d3f73b
.B tc(8)
Packit d3f73b
examples can be found in the iproute2 source
Packit d3f73b
tree under
Packit d3f73b
.B examples/bpf/
Packit d3f73b
\&.
Packit d3f73b
Packit d3f73b
.SH SEE ALSO
Packit d3f73b
.BR tc (8),
Packit d3f73b
.BR tc-ematch (8)
Packit d3f73b
.BR bpf (2)
Packit d3f73b
.BR bpf (4)
Packit d3f73b
Packit d3f73b
.SH AUTHORS
Packit d3f73b
Manpage written by Daniel Borkmann.
Packit d3f73b
Packit d3f73b
Please report corrections or improvements to the Linux kernel networking
Packit d3f73b
mailing list:
Packit d3f73b
.B <netdev@vger.kernel.org>