eBPF Documentation

repository·master·Indexed 20 days ago

https://github.com/isovalent/ebpf-docs

Technical documentation for developers building projects with eBPF technology. Covers core concepts such as BPF Type Format (BTF), Compile Once - Run Everywhere (CO-RE), and the use of libbpf. Includes detailed references for libbpf eBPF macros including __always_inline, __arg_ctx, __arg_nonnull, __arg_nullable, __arg_trusted, and others used for verifier tagging and memory management.

Tokens
355.7K
Snippets
927
Records
1.4K
Agent score
66%

What's inside ebpf-docs

  1. What is BTF (BPF Type Format)?

    master

    BTF (BPF Type Format) is a metadata format used to encode debug information for BPF programs and maps. It describes data types and function information for defined subroutines.

    Key use cases for BTF include:

    • Map visualization: Providing structure to BPF maps.
    • Function signature enhancement: Improving the clarity of BPF program signatures.
    • Code generation and debugging: Aiding in the generation of annotated source code, JIT-ed code, and verifier logs.

    BTF is designed as a space-efficient alternative to DWARF debug information, utilizing a deduplication algorithm to maintain the expressiveness of C programs while minimizing storage requirements.

  2. What is AF_XDP and when to use it

    master

    AF_XDP (Address Family Express Data Path) is a special socket type, also known as a XSK (XDP Socket), that works in conjunction with an XDP program to perform full or partial kernel bypass. By bypassing the standard Linux network stack, you can significantly increase performance for specific workloads.

    Common Use Cases

    • Custom protocol implementations: Avoid the overhead of the kernel attempting to process protocols it doesn't understand.
    • DDoS protection: Forward complex traffic to user space for analysis when eBPF programs alone cannot handle the required processing logic.
    • Application-specific optimization: Implement a custom, lightweight network stack tailored to your specific needs, avoiding the performance cost of the general-purpose Linux network stack.

    How it differs from other bypass techniques

    Unlike PACKET_MMAP or PF_RING, which require you to handle all traffic and re-implement every protocol necessary for the host to function, AF_XDP allows an XDP program to selectively decide which traffic to pass to the kernel stack and which to bypass to a XSK. This enables bypassing traffic for specific applications, ports, or protocols without disrupting normal host networking.

  3. What is BPF CO-RE?

    master
    BPF CO-RE (Compile Once - Run Everywhere) is a concept designed to enable building cross-version kernel eBPF applications. It allows a single binary to run on different kernel versions by combining BTF (BPF Type Format) type information, libbpf, and the compiler to handle differences in kernel memory layouts and structure field renames.
  4. What is HID BPF ops and how to use it

    master

    HID BPF ops is a struct_ops type that allows developers to create and distribute HID (Human Interface Device) drivers using BPF. This enables manipulating HID device events (like rebinding buttons) outside of the main Linux kernel release cycle, which is useful for fixing hardware or firmware deficiencies.

    To use it, you define a struct hid_bpf_ops and attach it to a specific device using its unique HID ID.

    struct hid_bpf_ops {
    	int   hid_id;
    	u32   flags;
    	int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type, u64 source);
    	int (*hid_rdesc_fixup)(struct hid_bpf_ctx *ctx);
    	int (*hid_hw_request)(struct hid_bpf_ctx *ctx, unsigned char reportnum, enum hid_report_type rtype, enum hid_class_request reqtype, u64 source);
    	int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source);
    };
  5. Mix tail calls and functions

    master

    Since Linux v5.10, it is possible to mix tail calls and functions. Previously, a program had to use one or the other.

    Important considerations:

    • Stack Size: Mixing these causes the available stack size per function to shrink from 512 bytes to 256 bytes. This is because when a tail call is made from a function, the caller's stack cannot be reused.
    • Architecture Support: Support depends on the JIT's ability to propagate the tail call counter.
    ArchitectureSupport added
    x86v5.10
    ARM64v6.0
    s390v6.3
    LoongArchv6.4

    Note: Architectures not listed do not support mixing as of v6.15.

  6. Use `smc_hs_ctrl_ops` to control SMC negotiation

    master

    The smc_hs_ctrl_ops struct ops allows BPF programs to selectively enable or disable SMC (Shared Memory Communications) negotiation for individual TCP connections. This is useful for controlling high-performance socket protocol usage based on runtime information like IP addresses or port numbers.

    Workflow

    1. Define a struct smc_hs_ctrl instance: Implement the syn_option and synack_option BPF programs and associate them with a named instance.
    2. Register the instance: The instance is associated with a network namespace.
    3. Activate the controller: Use the sysctl net.smc.hs_ctrl to set the active controller for a network namespace by providing the name of your registered instance.

    Inheritance

    By default, the controller is associated with its network namespace. If the SMC_HS_CTRL_FLAG_INHERITABLE flag is set, child network namespaces will inherit the controller.

    // Example of defining the struct ops
    SEC(".struct_ops")
    struct smc_hs_ctrl my_smc_hs_ctrl = {
        .name           = "my_ctrl",
        .flags          = 0,
        .syn_option     = (void *)my_syn_option,
        .synack_option  = (void *)my_synack_option,
    };
  7. Understand the `sched_ext_ops` struct for BPF schedulers

    master

    A BPF scheduler implements arbitrary scheduling policies by providing a table of operations defined in struct sched_ext_ops. This structure allows the BPF program to hook into various stages of the task lifecycle, such as waking up, enqueuing, dispatching, and running tasks. A userland scheduling policy can also be implemented by using the BPF scheduler as a shim layer.

    struct sched_ext_ops {
        char [name][SCX_OPS_NAME_LEN];
        u32  [dispatch_max_batch];
        u64  [flags];
        u32  [timeout_ms];
        u32  [exit_dump_len];
        u64  [hotplug_seq];
    
        s32  (*[select_cpu])([struct task_struct] *p, s32 prev_cpu, u64 wake_flags);
        void (*[enqueue])([struct task_struct] *p, u64 enq_flags);
        void (*[dequeue])([struct task_struct] *p, u64 deq_flags);
        void (*[dispatch])(s32 cpu, [struct task_struct] *prev);
        void (*[tick])([struct task_struct] *p);
        void (*[runnable])([struct task_struct] *p, u64 enq_flags);
        void (*[running])([struct task_struct] *p);
        void (*[stopping])([struct task_struct] *p, bool runnable);
        void (*[quiescent])([struct task_struct] *p, u64 deq_flags);
        bool (*[yield])([struct task_struct] *from, [struct task_struct] *to);
        bool (*[core_sched_before])([struct task_struct] *a, [struct task_struct] *b);
        void (*[set_weight])([struct task_struct] *p, u32 weight);
        void (*[set_cpumask])([struct task_struct] *p, const [struct cpumask] *cpumask);
        void (*[update_idle])(s32 cpu, bool idle);
        void (*[cpu_acquire])(s32 cpu, [struct scx_cpu_acquire_args] *args);
        void (*[cpu_release])(s32 cpu, [struct scx_cpu_release_args] *args);
        
        s32  (*[init_task])([struct task_struct] *p, [struct scx_init_task_args] *args);
        void (*[exit_task])([struct task_struct] *p, [struct scx_exit_task_args] *args);
        
        void (*[enable])([struct task_struct] *p);
        void (*[disable])([struct task_struct] *p);
        
        void (*[dump])([struct scx_dump_ctx] *ctx);
        void (*[dump_cpu])([struct scx_dump_ctx] *ctx, s32 cpu, bool idle);
        void (*[dump_task])([struct scx_dump_ctx] *ctx, [struct task_struct] *p);
    
    #ifdef CONFIG_EXT_GROUP_SCHED
        s32  (*[cgroup_init])([struct cgroup] *cgrp, [struct scx_cgroup_init_args] *args);
        void (*[cgroup_exit])([struct cgroup] *cgrp);
        s32  (*[cgroup_prep_move])([struct task_struct] *p, [struct cgroup] *from, [struct cgroup] *to);
        void (*[cgroup_move])([struct task_struct] *p, [struct cgroup] *from, [struct cgroup] *to);
        void (*[cgroup_cancel_move])([struct task_struct] *p, [struct cgroup] *from, [struct cgroup] *to);
        void (*[cgroup_set_weight])([struct cgroup] *cgrp, u32 weight);
    #endif
    
        void (*[cpu_online])(s32 cpu);
        void (*[cpu_offline])(s32 cpu);
    
        s32  (*[init])(void);
        void (*[exit])([struct scx_exit_info] *info);
    };
  8. Handle VLAN headers in XDP programs

    master

    When VLAN hardware offload is enabled, the NIC driver strips the outermost VLAN header before the XDP program sees the packet. Consequently, the XDP program sees an Ethernet header without the VLAN tag, even though tcpdump may still show the VLAN tag (as the driver preserves the VLAN info in the socket buffer's vlan_proto and vlan_tci fields).

    To see the VLAN header within an XDP program, you have two options:

    1. Disable VLAN offloads using ethtool.
    2. Use the kernel function bpf_xdp_metadata_rx_vlan_tag (supported by some recent drivers).
    # Option 1: Disable VLAN offloads
    ettool -K <dev_name> rxvlan off txvlan off
  9. Use Iterator programs to collect kernel data

    master

    Iterator programs are used to efficiently iterate over in-kernel data structures to collect or summarize data, bypassing the performance bottleneck of the kernel-userspace boundary.

    Key Characteristics:

    • Attachment: Can only be attached to specific pre-defined iterators following the naming convention bpf_iter__<iter_name> (found in the kernel's vmlinux).
    • Output Mechanism: Uses a seq_file via the meta field in the context to output data to userspace. Recommended helpers include bpf_seq_printf, bpf_seq_printf_btf, and bpf_seq_write.
    • ELF Section: Typically located in an ELF section prefixed with iter/.

    Context Structure: The first field of every iterator context is a meta pointer to struct bpf_iter_meta:

    struct bpf_iter_meta {
    	struct seq_file *seq;
    	__u64 session_id;
    	__u64 seq_num;
    };
    struct bpf_iter_meta {
    	struct seq_file *seq;
    	__u64 session_id;
    	__u64 seq_num;
    };
  10. Use the BPF_MAP_TYPE_HASH map type

    master

    The BPF_MAP_TYPE_HASH is a generic eBPF map type that uses a hash table implementation. It allows for lookups using arbitrary keys and values with no restrictions on their structure.

    Constraints:

    • key_size and value_size must be at least zero.
    • The combined size of key_size and value_size must not exceed KMALLOC_MAX_SIZE (the maximum size allocatable by the kernel memory allocator). Exceeding this limit results in a -E2BIG error during the map create syscall.