eBPF is an extended version of the Berkeley Packet Filter (BPF). It is an abstract virtual machine (VM) that runs within the Linux kernel, much like the Java Virtual Machine (JVM) can run applications in a controlled environment. eBPF can execute user-defined programs inside a sandbox in the kernel—it is typically used to enable developers to write low-level monitoring, tracing, or networking programs in Linux in a way that ensures optimal performance.
eXpress Data Path (XDP) is a framework that makes it possible to perform high-speed packet processing within BPF applications. To enable faster response to network operations, XDP runs a BPF program as soon as possible, usually immediately as a packet is received by the network interface.
XDP is a technology that allows developers to attach eBPF programs to low-level hooks, implemented by network device drivers in the Linux kernel, as well as generic hooks that run after the device driver.
XDP can be used to achieve high-performance packet processing in an eBPF architecture, primarily using kernel bypass. This greatly reduces the overhead needed for the kernel, because it does not need to process context switches, network layer processing, interrupts, and so on. Control of the network interface card (NIC) is transferred to an eBPF program. This is especially important if you are working at higher network speeds—10 Gbps and above.
However, the kernel bypass method has some drawbacks:
These limitations created the need for XDP. XDP makes it easier to implement high-performance networking in eBPF, by allowing eBPF programs to directly read and write network packet data, and determine how to process the packets, before reaching the kernel level.
XDP programs can be directly attached to a network interface. Whenever a new packet is received on the network interface, XDP programs receive a callback, and can perform operations on the packet very quickly.
You can connect an XDP program to an interface using the following models:
Here are some of the operations an XDP program can perform with the packets it receives, once it is connected to a network interface:
Here are a few common use cases for XDP in eBPF.
One of the basic functions of XDP in eBPF is to use XDP_DROP, which tells the driver to drop packets at an early stage. This lets you apply a variety of efficient network strategies, while keeping the cost of each packet very low.
This is great for situations where you need to deal with any type of DDoS attack, but more generally, using XDP, eBPF can implement any type of firewall policy with very little overhead. XDP can handle these scenarios, for example, by scrubbing illegitimate traffic and forwarding legitimate packets to their destination using XDP_TX.
XDP can either be deployed in a standalone network appliance, or distributed to multiple nodes that protect the host. The latter scenario can be implemented using XDP_PASS or cpumap XDP_REDIRECT. To boost performance, you can use offloaded XDP, which shifts the already small cost of each data packet entirely to the NIC, which is processed at wire speed.
Another major use case for XDP is the use of XDP_TX or XDP_REDIRECT operations for packet forwarding and load balancing. Data packets can be manipulated by BPF programs running on the XDP layer. BPF helpers—functions used by BPF programs to interact with the system or with the context in which they operate—can be used to increase or decrease the headroom of data packets, to encapsulate and decapsulate data packets before sending them back.
There are two common ways to implement a load balancer:
XDP is commonly used for packet monitoring, sampling, and other forms of network analysis. It can be used, for example, to monitor traffic on an intermediate node in the path of an end host, or in conjunction with any of the above use cases.
For complex packet analysis, XDP maps network packets (either truncated or full payloads) and custom metadata to eBPF programs. This can also support situations where only initial data in the flow is analyzed, and then bypasses monitoring when it determines the traffic is legitimate.
The flexibility provided by BPF with XDP lets you implement any type of custom monitoring or sampling.
This section is abbreviated from the full tutorial by Hangbin Liu of Red Hat.
Install the required packages using the following code:
$ sudo dnf install clang llvm gcc libbpf libbpf-devel libxdp libxdp-devel xdp-tools bpftool kernel-headers
The following C program uses the xdp_drop command to drop all data packets.
Including the linux/bpf.h header provides access to XDP commands. The SEC macro places part of the compiled object in a specific section within the Executable and Linkable Format (ELF) file.
You can use the clang utility to build the program, as follows:
$ clang -O2 -g -Wall -target bpf -c xdp_drop.c -o xdp_drop.o
You can use the command llvm-objdump to show the ELF code generated by the clang command. The -h flag lets you show all sections in the object.
Before proceeding, it is important to use Linux veth (Virtual Ethernet Device) for testing. The test program drops all packets, so if you run it on your default interface, you will lose connectivity.
You can load the BPF object like this:
$ sudo ip link set veth1 xdpgeneric obj xdp_drop.o sec xdp_drop
However, this method does not support type maps (using the BTF format), which are needed for more advanced operations. To enable it, you can use the xdp-loader utility.
Here is how to load the object on a veth interface with xdp-loader. The -m sbk flag is used for generic XDP loading, which does not require a compliant hardware device.
$ sudo xdp-loader load -m skb -s xdp_drop veth1 xdp_drop.o
Depending on how you ran the BPF object, there will be either one program running (if you used the ip command) or two programs (if you used xdp-loader, which runs both the loader utility itself and your custom program).
Here is how to show running BPF programs and activity on your virtual ethernet interface.
The xdp-loader utility has its own status command that can show XDP programs currently running.
If you loaded the program using ip command, unload it like this. Note you should use the same flags you used when loading the program.
$ sudo ip link set veth1 xdpgeneric off
If you used xdp-loader, to unload XDP programs, use this command:
$ sudo xdp-loader unload -a veth1
Now that you understand how to create and load a minimal XDP program, see the code below, which analyzes traffic and drops only IPv6 packets.
Calico offers support for multiple data planes, including standard Linux, Windows HNS, and Linux eBPF. Compared to the standard Linux networking data plane, Calico’s eBPF data plane scales to higher throughput, uses less CPU per GBit, and has native support for Kubernetes services (without needing kube-proxy).
The data plane’s native support for Kubernetes services achieves the following:
With Calico, you can easily load and unload the eBPF data plane to suit your needs. Calico offers you the ability to leverage eBPF as needed, as an additional control to build your Kubernetes cluster security.
Beyond the three data planes Calico currently supports, there are plans to add support for even more data planes in the near future, including Vector Packet Processing (VPP). Calico lets the user decide what works best for what they need to do.