# tc-bpf

## NAME



           BPF - BPF programmable classifier and actions for ingress/egress
           queueing disciplines
    


## SYNOPSIS



       **eBPF classifier (filter) or action:**
           **tc filter ... bpf**[ **object-file** OBJ_FILE ] [ **section** CLS_NAME ] [
           **export** UDS_FILE ] [ **verbose**] [ **direct-action** | **da**] [ **skip_hw** |
           **skip_sw**] [ **police** POLICE_SPEC ] [ **action** ACTION_SPEC ] [ **classid**
           CLASSID ]
           **tc action ... bpf**[ **object-file** OBJ_FILE ] [ **section** CLS_NAME ] [
           **export** UDS_FILE ] [ **verbose**]
    
       **cBPF classifier (filter) or action:**
           **tc filter ... bpf**[ **bytecode-file** BPF_FILE | **bytecode** BPF_BYTECODE
           ] [ **police** POLICE_SPEC ] [ **action** ACTION_SPEC ] [ **classid** CLASSID
           ]
           **tc action ... bpf**[ **bytecode-file** BPF_FILE | **bytecode** BPF_BYTECODE
           ]
    


## DESCRIPTION



           Extended Berkeley Packet Filter ( **eBPF**) and classic Berkeley
           Packet Filter (originally known as BPF, for better distinction
           referred to as **cBPF** here) are both available as a fully
           programmable and highly efficient classifier and actions. They
           both offer a minimal instruction set for implementing small
           programs which can safely be loaded into the kernel and thus
           executed in a tiny virtual machine from kernel space. An in-kernel
           verifier guarantees that a specified program always terminates and
           neither crashes nor leaks data from the kernel.
    
           In Linux, it's generally considered that eBPF is the successor of
           cBPF.  The kernel internally transforms cBPF expressions into eBPF
           expressions and executes the latter. Execution of them can be
           performed in an interpreter or at setup time, they can be just-in-
           time compiled (JIT'ed) to run as native machine code.
    
           Currently, the eBPF JIT compiler is available for the following
           architectures:
    
           *   x86_64 (since Linux 3.18)
           *   arm64 (since Linux 3.18)
           *   s390 (since Linux 4.1)
           *   ppc64 (since Linux 4.8)
           *   sparc64 (since Linux 4.12)
           *   mips64 (since Linux 4.13)
           *   arm32 (since Linux 4.14)
           *   x86_32 (since Linux 4.18)
    
           Whereas the following architectures have cBPF, but did not (yet)
           switch to eBPF JIT support:
    
           *   ppc32
           *   sparc32
           *   mips32
    
           eBPF's instruction set has similar underlying principles as the
           cBPF instruction set, it however is modelled closer to the
           underlying architecture to better mimic native instruction sets
           with the aim to achieve a better run-time performance. It is
           designed to be JIT'ed with a one to one mapping, which can also
           open up the possibility for compilers to generate optimized eBPF
           code through an eBPF backend that performs almost as fast as
           natively compiled code. Given that LLVM provides such an eBPF
           backend, eBPF programs can therefore easily be programmed in a
           subset of the C language. Other than that, eBPF infrastructure
           also comes with a construct called "maps". eBPF maps are key/value
           stores that are shared between multiple eBPF programs, but also
           between eBPF programs and user space applications.
    
           For the traffic control subsystem, classifier and actions that can
           be attached to ingress and egress qdiscs can be written in eBPF or
           cBPF. The advantage over other classifier and actions is that
           eBPF/cBPF provides the generic framework, while users can
           implement their highly specialized use cases efficiently. This
           means that the classifier or action written that way will not
           suffer from feature bloat, and can therefore execute its task
           highly efficient. It allows for non-linear classification and even
           merging the action part into the classification. Combined with
           efficient eBPF map data structures, user space can push new
           policies like classids into the kernel without reloading a
           classifier, or it can gather statistics that are pushed into one
           map and use another one for dynamically load balancing traffic
           based on the determined load, just to provide a few examples.
    


## PARAMETERS



       **object-file**
           points to an object file that has an executable and linkable
           format (ELF) and contains eBPF opcodes and eBPF map definitions.
           The LLVM compiler infrastructure with **clang**(1) as a C language
           front end is one project that supports emitting eBPF object files
           that can be passed to the eBPF classifier (more details in the
           **EXAMPLES** section). This option is mandatory when an eBPF
           classifier or action is to be loaded.
    
       **section**
           is the name of the ELF section from the object file, where the
           eBPF classifier or action resides. By default the section name for
           the classifier is called "classifier", and for the action
           "action". Given that a single object file can contain multiple
           classifier and actions, the corresponding section name needs to be
           specified, if it differs from the defaults.
    
       **export**
           points to a Unix domain socket file. In case the eBPF object file
           also contains a section named "maps" with eBPF map specifications,
           then the map file descriptors can be handed off via the Unix
           domain socket to an eBPF "agent" herding all descriptors after tc
           lifetime. This can be some third party application implementing
           the IPC counterpart for the import, that uses them for calling
           into bpf(2) system call to read out or update eBPF map data from
           user space, for example, for monitoring purposes or to push down
           new policies.
    
       **verbose**
           if set, it will dump the eBPF verifier output, even if loading the
           eBPF program was successful. By default, only on error, the
           verifier log is being emitted to the user.
    
       **direct-action | da**
           instructs eBPF classifier to not invoke external TC actions,
           instead use the TC actions return codes (**TC_ACT_OK** , **TC_ACT_SHOT**
           etc.) for classifiers.
    
       **skip_hw | skip_sw**
           hardware offload control flags. By default TC will try to offload
           filters to hardware if possible.  **skip_hw** explicitly disables the
           attempt to offload.  **skip_sw** forces the offload and disables
           running the eBPF program in the kernel.  If hardware offload is
           not possible and this flag was set kernel will report an error and
           filter will not be installed at all.
    
       **police**
           is an optional parameter for an eBPF/cBPF classifier that
           specifies a police in **tc**(1) which is attached to the classifier,
           for example, on an ingress qdisc.
    
       **action**
           is an optional parameter for an eBPF/cBPF classifier that
           specifies a subsequent action in **tc**(1) which is attached to a
           classifier.
    
       **classid**
       **flowid**
           provides the default traffic control class identifier for this
           eBPF/cBPF classifier. The default class identifier can also be
           overwritten by the return code of the eBPF/cBPF program. A default
           return code of **-1** specifies the here provided default class
           identifier to be used. A return code of the eBPF/cBPF program of 0
           implies that no match took place, and a return code other than
           these two will override the default classid. This allows for
           efficient, non-linear classification with only a single eBPF/cBPF
           program as opposed to having multiple individual programs for
           various class identifiers which would need to reparse packet
           contents.
    
       **bytecode**
           is being used for loading cBPF classifier and actions only. The
           cBPF bytecode is directly passed as a text string in the form of
           **'s,c t f k,c t f k,c t f k,...'** , where **s** denotes the number of
           subsequent 4-tuples. One such 4-tuple consists of **c t f k**
           decimals, where **c** represents the cBPF opcode, **t** the jump true
           offset target, **f** the jump false offset target and **k** the immediate
           constant/literal. There are various tools that generate code in
           this loadable format, for example, **bpf_asm** that ships with the
           Linux kernel source tree under **tools/net/** , so it is certainly not
           expected to hack this by hand. The **bytecode** or **bytecode-file**
           option is mandatory when a cBPF classifier or action is to be
           loaded.
    
       **bytecode-file**
           also being used to load a cBPF classifier or action. It's
           effectively the same as **bytecode** only that the cBPF bytecode is
           not passed directly via command line, but rather resides in a text
           file.
    


## EXAMPLES



       **eBPF TOOLING**
           A full blown example including eBPF agent code can be found inside
           the iproute2 source package under: **examples/bpf/**
    
           As prerequisites, the kernel needs to have the eBPF system call
           namely bpf(2) enabled and ships with **cls_bpf** and **act_bpf** kernel
           modules for the traffic control subsystem. To enable eBPF/eBPF JIT
           support, depending which of the two the given architecture
           supports:
    
               **echo 1 > /proc/sys/net/core/bpf_jit_enable**
    
           A given restricted C file can be compiled via LLVM as:
    
               **clang -O2 -emit-llvm -c bpf.c -o - | llc -march=bpf**
               **-filetype=obj -o bpf.o**
    
           The compiler invocation might still simplify in future, so for
           now, it's quite handy to alias this construct in one way or
           another, for example:
    
               __bcc() {
                       clang -O2 -emit-llvm -c $1 -o - | \
                       llc -march=bpf -filetype=obj -o "`basename $1 .c`.o"
               }
    
               alias bcc=__bcc
    
           A minimal, stand-alone unit, which matches on all traffic with the
           default classid (return code of -1) looks like:
    
               #include <linux/bpf.h>
    
               #ifndef __section
               # define __section(x)  __attribute__((section(x), used))
               #endif
    
               __section("classifier") int cls_main(struct __sk_buff *skb)
               {
                       return -1;
               }
    
               char __license[] __section("license") = "GPL";
    
           More examples can be found further below in subsection **eBPF**
           **PROGRAMMING** as focus here will be on tooling.
    
           There can be various other sections, for example, also for
           actions.  Thus, an object file in eBPF can contain multiple
           entrance points.  Always a specific entrance point, however, must
           be specified when configuring with tc. A license must be part of
           the restricted C code and the license string syntax is the same as
           with Linux kernel modules.  The kernel reserves its right that
           some eBPF helper functions can be restricted to GPL compatible
           licenses only, and thus may reject a program from loading into the
           kernel when such a license mismatch occurs.
    
           The resulting object file from the compilation can be inspected
           with the usual set of tools that also operate on normal object
           files, for example objdump(1) for inspecting ELF section headers:
    
               objdump -h bpf.o
               [...]
               3 classifier    000007f8  0000000000000000  0000000000000000  00000040  2**3
                               CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
               4 action-mark   00000088  0000000000000000  0000000000000000  00000838  2**3
                               CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
               5 action-rand   00000098  0000000000000000  0000000000000000  000008c0  2**3
                               CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
               6 maps          00000030  0000000000000000  0000000000000000  00000958  2**2
                               CONTENTS, ALLOC, LOAD, DATA
               7 license       00000004  0000000000000000  0000000000000000  00000988  2**0
                               CONTENTS, ALLOC, LOAD, DATA
               [...]
    
           Adding an eBPF classifier from an object file that contains a
           classifier in the default ELF section is trivial (note that
           instead of "object-file" also shortcuts such as "obj" can be
           used):
    
               **bcc bpf.c**
               **tc filter add dev em1 parent 1: bpf obj bpf.o flowid 1:1**
    
           In case the classifier resides in ELF section "mycls", then that
           same command needs to be invoked as:
    
               **tc filter add dev em1 parent 1: bpf obj bpf.o sec mycls flowid**
               **1:1**
    
           Dumping the classifier configuration will tell the location of the
           classifier, in other words that it's from object file "bpf.o"
           under section "mycls":
    
               **tc filter show dev em1**
               **filter parent 1: protocol all pref 49152 bpf**
               **filter parent 1: protocol all pref 49152 bpf handle 0x1 flowid**
               **1:1 bpf.o:[mycls]**
    
           The same program can also be installed on ingress qdisc side as
           opposed to egress ...
    
               **tc qdisc add dev em1 handle ffff: ingress**
               **tc filter add dev em1 parent ffff: bpf obj bpf.o sec mycls**
               **flowid ffff:1**
    
           ... and again dumped from there:
    
               **tc filter show dev em1 parent ffff:**
               **filter protocol all pref 49152 bpf**
               **filter protocol all pref 49152 bpf handle 0x1 flowid ffff:1**
               **bpf.o:[mycls]**
    
           Attaching a classifier and action on ingress has the restriction
           that it doesn't have an actual underlying queueing discipline.
           What ingress can do is to classify, mangle, redirect or drop
           packets. When queueing is required on ingress side, then ingress
           must redirect packets to the **ifb** device, otherwise policing can be
           used. Moreover, ingress can be used to have an early drop point of
           unwanted packets before they hit upper layers of the networking
           stack, perform network accounting with eBPF maps that could be
           shared with egress, or have an early mangle and/or redirection
           point to different networking devices.
    
           Multiple eBPF actions and classifier can be placed into a single
           object file within various sections. In that case, non-default
           section names must be provided, which is the case for both actions
           in this example:
    
               **tc filter add dev em1 parent 1: bpf obj bpf.o flowid 1:1 \**
                                        **action bpf obj bpf.o sec action-mark**
                                        **\**
                                        **action bpf obj bpf.o sec action-rand**
                                        **ok**
    
           The advantage of this is that the classifier and the two actions
           can then share eBPF maps with each other, if implemented in the
           programs.
    
           In order to access eBPF maps from user space beyond tc(8) setup
           lifetime, the ownership can be transferred to an eBPF agent via
           Unix domain sockets. There are two possibilities for implementing
           this:
    
           **1)** implementation of an own eBPF agent that takes care of setting
           up the Unix domain socket and implementing the protocol that tc(8)
           dictates. A code example of this can be found inside the iproute2
           source package under: **examples/bpf/**
    
           **2)** use **tc exec** for transferring the eBPF map file descriptors
           through a Unix domain socket, and spawning an application such as
           **sh**(1) . This approach's advantage is that tc will place the file
           descriptors into the environment and thus make them available just
           like stdin, stdout, stderr file descriptors, meaning, in case user
           applications run from within this fd-owner shell, they can
           terminate and restart without losing eBPF maps file descriptors.
           Example invocation with the previous classifier and action
           mixture:
    
               **tc exec bpf imp /tmp/bpf**
               **tc filter add dev em1 parent 1: bpf obj bpf.o exp /tmp/bpf**
               **flowid 1:1 \**
                                        **action bpf obj bpf.o sec action-mark**
                                        **\**
                                        **action bpf obj bpf.o sec action-rand**
                                        **ok**
    
           Assuming that eBPF maps are shared with classifier and actions,
           it's enough to export them once, for example, from within the
           classifier or action command. tc will setup all eBPF map file
           descriptors at the time when the object file is first parsed.
    
           When a shell has been spawned, the environment will have a couple
           of eBPF related variables. BPF_NUM_MAPS provides the total number
           of maps that have been transferred over the Unix domain socket.
           BPF_MAP<X>'s value is the file descriptor number that can be
           accessed in eBPF agent applications, in other words, it can
           directly be used as the file descriptor value for the bpf(2)
           system call to retrieve or alter eBPF map values. <X> denotes the
           identifier of the eBPF map. It corresponds to the **id** member of
           **struct bpf_elf_map** from the tc eBPF map specification.
    
           The environment in this example looks as follows:
    
               sh# env | grep BPF
                   BPF_NUM_MAPS=3
                   BPF_MAP1=6
                   BPF_MAP0=5
                   BPF_MAP2=7
               sh# ls -la /proc/self/fd
                   [...]
                   lrwx------. 1 root root 64 Apr 14 16:46 5 -> anon_inode:bpf-map
                   lrwx------. 1 root root 64 Apr 14 16:46 6 -> anon_inode:bpf-map
                   lrwx------. 1 root root 64 Apr 14 16:46 7 -> anon_inode:bpf-map
               sh# my_bpf_agent
    
           eBPF agents are very useful in that they can prepopulate eBPF maps
           from user space, monitor statistics via maps and based on that
           feedback, for example, rewrite classids in eBPF map values during
           runtime. Given that eBPF agents are implemented as normal
           applications, they can also dynamically receive traffic control
           policies from external controllers and thus push them down into
           eBPF maps to dynamically adapt to network conditions. Moreover,
           eBPF maps can also be shared with other eBPF program types (e.g.
           tracing), thus very powerful combination can therefore be
           implemented.
    
       **eBPF PROGRAMMING**
           eBPF classifier and actions are being implemented in restricted C
           syntax (in future, there could additionally be new language
           frontends supported).
    
           The header file **linux/bpf.h** provides eBPF helper functions that
           can be called from an eBPF program.  This man page will only
           provide two minimal, stand-alone examples, have a look at
           **examples/bpf** from the iproute2 source package for a fully fledged
           flow dissector example to better demonstrate some of the
           possibilities with eBPF.
    
           Supported 32 bit classifier return codes from the C program and
           their meanings:
               **0** , denotes a mismatch
               **-1** , denotes the default classid configured from the command
               line
               **else** , everything else will override the default classid to
               provide a facility for non-linear matching
    
           Supported 32 bit action return codes from the C program and their
           meanings ( **linux/pkt_cls.h**):
               **TC_ACT_OK (0)** , will terminate the packet processing pipeline
               and allows the packet to proceed
               **TC_ACT_SHOT (2)** , will terminate the packet processing
               pipeline and drops the packet
               **TC_ACT_UNSPEC (-1)** , will use the default action configured
               from tc (similarly as returning **-1** from a classifier)
               **TC_ACT_PIPE (3)** , will iterate to the next action, if
               available
               **TC_ACT_RECLASSIFY (1)** , will terminate the packet processing
               pipeline and start classification from the beginning
               **else** , everything else is an unspecified return code
    
           Both classifier and action return codes are supported in eBPF and
           cBPF programs.
    
           To demonstrate restricted C syntax, a minimal toy classifier
           example is provided, which assumes that egress packets, for
           instance originating from a container, have previously been marked
           in interval [0, 255]. The program keeps statistics on different
           marks for user space and maps the classid to the root qdisc with
           the marking itself as the minor handle:
    
               #include <stdint.h>
               #include <asm/types.h>
    
               #include <linux/bpf.h>
               #include <linux/pkt_sched.h>
    
               #include "helpers.h"
    
               struct tuple {
                       long packets;
                       long bytes;
               };
    
               #define BPF_MAP_ID_STATS        1 /* agent's map identifier */
               #define BPF_MAX_MARK            256
    
               struct bpf_elf_map __section("maps") map_stats = {
                       .type           =       BPF_MAP_TYPE_ARRAY,
                       .id             =       BPF_MAP_ID_STATS,
                       .size_key       =       sizeof(uint32_t),
                       .size_value     =       sizeof(struct tuple),
                       .max_elem       =       BPF_MAX_MARK,
                       .pinning        =       PIN_GLOBAL_NS,
               };
    
               static inline void cls_update_stats(const struct __sk_buff *skb,
                                                   uint32_t mark)
               {
                       struct tuple *tu;
    
                       tu = bpf_map_lookup_elem(&map_stats, &mark);
                       if (likely(tu)) {
                               __sync_fetch_and_add(&tu->packets, 1);
                               __sync_fetch_and_add(&tu->bytes, skb->len);
                       }
               }
    
               __section("cls") int cls_main(struct __sk_buff *skb)
               {
                       uint32_t mark = skb->mark;
    
                       if (unlikely(mark >= BPF_MAX_MARK))
                               return 0;
    
                       cls_update_stats(skb, mark);
    
                       return TC_H_MAKE(TC_H_ROOT, mark);
               }
    
               char __license[] __section("license") = "GPL";
    
           Another small example is a port redirector which demuxes
           destination port 80 into the interval [8080, 8087] steered by RSS,
           that can then be attached to ingress qdisc. The exercise of adding
           the egress counterpart and IPv6 support is left to the reader:
    
               #include <asm/types.h>
               #include <asm/byteorder.h>
    
               #include <linux/bpf.h>
               #include <linux/filter.h>
               #include <linux/in.h>
               #include <linux/if_ether.h>
               #include <linux/ip.h>
               #include <linux/tcp.h>
    
               #include "helpers.h"
    
               static inline void set_tcp_dport(struct __sk_buff *skb, int nh_off,
                                                __u16 old_port, __u16 new_port)
               {
                       bpf_l4_csum_replace(skb, nh_off + offsetof(struct tcphdr, check),
                                           old_port, new_port, sizeof(new_port));
                       bpf_skb_store_bytes(skb, nh_off + offsetof(struct tcphdr, dest),
                                           &new_port, sizeof(new_port), 0);
               }
    
               static inline int lb_do_ipv4(struct __sk_buff *skb, int nh_off)
               {
                       __u16 dport, dport_new = 8080, off;
                       __u8 ip_proto, ip_vl;
    
                       ip_proto = load_byte(skb, nh_off +
                                            offsetof(struct iphdr, protocol));
                       if (ip_proto != IPPROTO_TCP)
                               return 0;
    
                       ip_vl = load_byte(skb, nh_off);
                       if (likely(ip_vl == 0x45))
                               nh_off += sizeof(struct iphdr);
                       else
                               nh_off += (ip_vl & 0xF) << 2;
    
                       dport = load_half(skb, nh_off + offsetof(struct tcphdr, dest));
                       if (dport != 80)
                               return 0;
    
                       off = skb->queue_mapping & 7;
                       set_tcp_dport(skb, nh_off - BPF_LL_OFF, __constant_htons(80),
                                     __cpu_to_be16(dport_new + off));
                       return -1;
               }
    
               __section("lb") int lb_main(struct __sk_buff *skb)
               {
                       int ret = 0, nh_off = BPF_LL_OFF + ETH_HLEN;
    
                       if (likely(skb->protocol == __constant_htons(ETH_P_IP)))
                               ret = lb_do_ipv4(skb, nh_off);
    
                       return ret;
               }
    
               char __license[] __section("license") = "GPL";
    
           The related helper header file **helpers.h** in both examples was:
    
               /* Misc helper macros. */
               #define __section(x) __attribute__((section(x), used))
               #define offsetof(x, y) __builtin_offsetof(x, y)
               #define likely(x) __builtin_expect(!!(x), 1)
               #define unlikely(x) __builtin_expect(!!(x), 0)
    
               /* Object pinning settings */
               #define PIN_NONE       0
               #define PIN_OBJECT_NS  1
               #define PIN_GLOBAL_NS  2
    
               /* ELF map definition */
               struct bpf_elf_map {
                   __u32 type;
                   __u32 size_key;
                   __u32 size_value;
                   __u32 max_elem;
                   __u32 flags;
                   __u32 id;
                   __u32 pinning;
                   __u32 inner_id;
                   __u32 inner_idx;
               };
    
               /* Some used BPF function calls. */
               static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from,
                                                 int len, int flags) =
                     (void *) BPF_FUNC_skb_store_bytes;
               static int (*bpf_l4_csum_replace)(void *ctx, int off, int from,
                                                 int to, int flags) =
                     (void *) BPF_FUNC_l4_csum_replace;
               static void *(*bpf_map_lookup_elem)(void *map, void *key) =
                     (void *) BPF_FUNC_map_lookup_elem;
    
               /* Some used BPF intrinsics. */
               unsigned long long load_byte(void *skb, unsigned long long off)
                   asm ("llvm.bpf.load.byte");
               unsigned long long load_half(void *skb, unsigned long long off)
                   asm ("llvm.bpf.load.half");
    
           Best practice, we recommend to only have a single eBPF classifier
           loaded in tc and perform **all** necessary matching and mangling from
           there instead of a list of individual classifier and separate
           actions. Just a single classifier tailored for a given use-case
           will be most efficient to run.
    
       **eBPF DEBUGGING**
           Both tc **filter** and **action** commands for **bpf** support an optional
           **verbose** parameter that can be used to inspect the eBPF verifier
           log. It is dumped by default in case of an error.
    
           In case the eBPF/cBPF JIT compiler has been enabled, it can also
           be instructed to emit a debug output of the resulting opcode image
           into the kernel log, which can be read via dmesg(1) :
    
               **echo 2 > /proc/sys/net/core/bpf_jit_enable**
    
           The Linux kernel source tree ships additionally under **tools/net/** a
           small helper called **bpf_jit_disasm** that reads out the opcode image
           dump from the kernel log and dumps the resulting disassembly:
    
               **bpf_jit_disasm -o**
    
           Other than that, the Linux kernel also contains an extensive
           eBPF/cBPF test suite module called **test_bpf**. Upon ...
    
               **modprobe test_bpf**
    
           ... it performs a diversity of test cases and dumps the results
           into the kernel log that can be inspected with dmesg(1) . The
           results can differ depending on whether the JIT compiler is
           enabled or not. In case of failed test cases, the module will fail
           to load. In such cases, we urge you to file a bug report to the
           related JIT authors, Linux kernel and networking mailing lists.
    
       **cBPF**
           Although we generally recommend switching to implementing **eBPF**
           classifier and actions, for the sake of completeness, a few words
           on how to program in cBPF will be lost here.
    
           Likewise, the **bpf_jit_enable** switch can be enabled as mentioned
           already. Tooling such as **bpf_jit_disasm** is also independent
           whether eBPF or cBPF code is being loaded.
    
           Unlike in eBPF, classifier and action are not implemented in
           restricted C, but rather in a minimal assembler-like language or
           with the help of other tooling.
    
           The raw interface with tc takes opcodes directly. For example, the
           most minimal classifier matching on every packet resulting in the
           default classid of 1:1 looks like:
    
               **tc filter add dev em1 parent 1: bpf bytecode '1,6 0 0**
               **4294967295,' flowid 1:1**
    
           The first decimal of the bytecode sequence denotes the number of
           subsequent 4-tuples of cBPF opcodes. As mentioned, such a 4-tuple
           consists of **c t f k** decimals, where **c** represents the cBPF opcode,
           **t** the jump true offset target, **f** the jump false offset target and
           **k** the immediate constant/literal. Here, this denotes an
           unconditional return from the program with immediate value of -1.
    
           Thus, for egress classification, Willem de Bruijn implemented a
           minimal stand-alone helper tool under the GNU General Public
           License version 2 for iptables(8) BPF extension, which abuses the
           **libpcap** internal classic BPF compiler, his code derived here for
           usage with tc(8) :
    
               #include <pcap.h>
               #include <stdio.h>
    
               int main(int argc, char **argv)
               {
                       struct bpf_program prog;
                       struct bpf_insn *ins;
                       int i, ret, dlt = DLT_RAW;
    
                       if (argc < 2 || argc > 3)
                               return 1;
                       if (argc == 3) {
                               dlt = pcap_datalink_name_to_val(argv[1]);
                               if (dlt == -1)
                                       return 1;
                       }
    
                       ret = pcap_compile_nopcap(-1, dlt, &prog, argv[argc - 1],
                                                 1, PCAP_NETMASK_UNKNOWN);
                       if (ret)
                               return 1;
    
                       printf("%d,", prog.bf_len);
                       ins = prog.bf_insns;
    
                       for (i = 0; i < prog.bf_len - 1; ++ins, ++i)
                               printf("%u %u %u %u,", ins->code,
                                      ins->jt, ins->jf, ins->k);
                       printf("%u %u %u %u",
                              ins->code, ins->jt, ins->jf, ins->k);
    
                       pcap_freecode(&prog);
                       return 0;
               }
    
           Given this small helper, any tcpdump(8) filter expression can be
           abused as a classifier where a match will result in the default
           classid:
    
               **bpftool EN10MB 'tcp[tcpflags] & tcp-syn != 0' > /var/bpf/tcp-**
               **syn**
               **tc filter add dev em1 parent 1: bpf bytecode-file**
               **/var/bpf/tcp-syn flowid 1:1**
    
           Basically, such a minimal generator is equivalent to:
    
               **tcpdump -iem1 -ddd 'tcp[tcpflags] & tcp-syn != 0' | tr '\n'**
               **',' > /var/bpf/tcp-syn**
    
           Since **libpcap** does not support all Linux' specific cBPF extensions
           in its compiler, the Linux kernel also ships under **tools/net/** a
           minimal BPF assembler called **bpf_asm** for providing full control.
           For detailed syntax and semantics on implementing such programs by
           hand, see references under **FURTHER READING**.
    
           Trivial toy example in **bpf_asm** for classifying IPv4/TCP packets,
           saved in a text file called **foobar** :
    
               ldh [12]
               jne #0x800, drop
               ldb [23]
               jneq #6, drop
               ret #-1
               drop: ret #0
    
           Similarly, such a classifier can be loaded as:
    
               **bpf_asm foobar > /var/bpf/tcp-syn**
               **tc filter add dev em1 parent 1: bpf bytecode-file**
               **/var/bpf/tcp-syn flowid 1:1**
    
           For BPF classifiers, the Linux kernel provides additionally under
           **tools/net/** a small BPF debugger called **bpf_dbg** , which can be used
           to test a classifier against pcap files, single-step or add
           various breakpoints into the classifier program and dump register
           contents during runtime.
    
           Implementing an action in classic BPF is rather limited in the
           sense that packet mangling is not supported. Therefore, it's
           generally recommended to make the switch to eBPF, whenever
           possible.
    


## FURTHER READING



           Further and more technical details about the BPF architecture can
           be found in the Linux kernel source tree under
           **Documentation/networking/filter.txt**.
    
           Further details on eBPF tc(8) examples can be found in the
           iproute2 source tree under **examples/bpf/**.
    


* * *