### Initialize Work-Queue with bpf_wq_init Source: https://docs.ebpf.io/linux/kfuncs/bpf_wq_init This example demonstrates the initialization of a work-queue using `bpf_wq_init`. It shows how to set up a `struct bpf_wq` within a map value, initialize it, associate a callback function using `bpf_wq_set_callback`, and then start the work-queue. This is the standard procedure for enabling asynchronous operations in eBPF. ```c #include char _license[] SEC("license") = "GPL"; struct elem { struct bpf_wq w; }; struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, 2); __type(key, int); __type(value, struct elem); } array SEC(".maps"); __u32 ok; __u32 ok_sleepable; void bpf_kfunc_common_test(void) __ksym; static int test_elem_callback(void *map, int *key, int (callback_fn)(void *map, int *key, struct bpf_wq *wq)) { struct elem init = {}, *val; struct bpf_wq *wq; if ((ok & (1 << *key) || (ok_sleepable & (1 << *key)))) return -22; if (map == &lru && bpf_map_update_elem(map, key, &init, 0)) return -1; val = bpf_map_lookup_elem(map, key); if (!val) return -2; wq = &val->w; if (bpf_wq_init(wq, map, 0) != 0) return -3; if (bpf_wq_set_callback(wq, callback_fn, 0)) return -4; if (bpf_wq_start(wq, 0)) return -5; return 0; } /* callback for non sleepable workqueue */ static int wq_callback(void *map, int *key, struct bpf_wq *work) { bpf_kfunc_common_test(); ok |= (1 << *key); return 0; } SEC("tc") long test_call_array_sleepable(void *ctx) { int key = 0; return test_elem_callback(&array, &key, wq_cb_sleepable); } ``` -------------------------------- ### BPF_KPROBE Usage Example Source: https://docs.ebpf.io/ebpf-library/libbpf/ebpf/BPF_KPROBE An example demonstrating how to use the BPF_KPROBE macro to write a kprobe program that attaches to the start of the `bpf_map_copy_value` function. It shows how to access map types and perf event values. ```c SEC("kprobe/bpf_map_copy_value") int BPF_KPROBE(bpf_prog2, struct bpf_map *map) { u32 key = bpf_get_smp_processor_id(); struct bpf_perf_event_value *val, buf; enum bpf_map_type type; int error; type = BPF_CORE_READ(map, map_type); if (type != BPF_MAP_TYPE_HASH) return 0; error = bpf_perf_event_read_value(&counters, key, &buf, sizeof(buf)); if (error) return 0; val = bpf_map_lookup_elem(&values2, &key); if (val) *val = buf; else bpf_map_update_elem(&values2, &key, &buf, BPF_NOEXIST); return 0; } ``` -------------------------------- ### BPF Crypto Context Creation and Management Source: https://docs.ebpf.io/linux/kfuncs/bpf_crypto_ctx_create This example demonstrates the creation of a BPF crypto context using bpf_crypto_ctx_create, its insertion into a map, and subsequent release. It includes necessary includes, map definitions, and a syscall program for setup. The crypto_ctx_insert helper handles updating the map and releasing the old context if one exists. ```c #include "vmlinux.h" #include "bpf_tracing_net.h" #include #include #include #include "bpf_misc.h" #include "bpf_kfuncs.h" struct bpf_crypto_ctx *bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz, int *err) __ksym; struct bpf_crypto_ctx *bpf_crypto_acquire(struct bpf_crypto_ctx *ctx) __ksym; void bpf_crypto_ctx_release(struct bpf_crypto_ctx *ctx) __ksym; struct __crypto_ctx_value { struct bpf_crypto_ctx __kptr * ctx; }; struct array_map { __uint(type, BPF_MAP_TYPE_ARRAY); __type(key, int); __type(value, struct __crypto_ctx_value); __uint(max_entries, 1); } __crypto_ctx_map SEC(".maps"); static inline int crypto_ctx_insert(struct bpf_crypto_ctx *ctx) { struct __crypto_ctx_value local, *v; struct bpf_crypto_ctx *old; u32 key = 0; int err; local.ctx = NULL; err = bpf_map_update_elem(&__crypto_ctx_map, &key, &local, 0); if (err) { bpf_crypto_ctx_release(ctx); return err; } v = bpf_map_lookup_elem(&__crypto_ctx_map, &key); if (!v) { bpf_crypto_ctx_release(ctx); return -ENOENT; } old = bpf_kptr_xchg(&v->ctx, ctx); if (old) { bpf_crypto_ctx_release(old); return -EEXIST; } return 0; } char cipher[128] = {}; u32 key_len, authsize; u8 key[256] = {}; int status; SEC("syscall") int crypto_setup(void *args) { struct bpf_crypto_ctx *cctx; struct bpf_crypto_params params = { .type = "skcipher", .key_len = key_len, .authsize = authsize, }; int err = 0; status = 0; if (!cipher[0] || !key_len || key_len > 256) { status = -EINVAL; return 0; } __builtin_memcpy(¶ms.algo, cipher, sizeof(cipher)); __builtin_memcpy(¶ms.key, key, sizeof(key)); cctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &err); if (!cctx) { status = err; return 0; } err = crypto_ctx_insert(cctx); if (err && err != -EEXIST) status = err; return 0; } ``` -------------------------------- ### Example Usage of __ksym Macro Source: https://docs.ebpf.io/ebpf-library/libbpf/ebpf/__ksym Demonstrates how to use the __ksym macro to access kernel symbols like 'bpf_task_storage_busy'. This example shows retrieving the address of a global variable and checking a configuration macro. ```c // SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2022. Huawei Technologies Co., Ltd */ #include "vmlinux.h" #include #include extern bool CONFIG_PREEMPT __kconfig __weak; extern const int bpf_task_storage_busy __ksym; char _license[] SEC("license") = "GPL"; int pid = 0; int busy = 0; struct { __uint(type, BPF_MAP_TYPE_TASK_STORAGE); __uint(map_flags, BPF_F_NO_PREALLOC); __type(key, int); __type(value, long); } task SEC(".maps"); SEC("raw_tp/sys_enter") int BPF_PROG(read_bpf_task_storage_busy) { int *value; if (!CONFIG_PREEMPT) return 0; if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; value = bpf_this_cpu_ptr(&bpf_task_storage_busy); if (value) busy = *value; return 0; } ``` -------------------------------- ### Example kretprobe program using BPF_KRETPROBE Source: https://docs.ebpf.io/ebpf-library/libbpf/ebpf/BPF_KRETPROBE An example of a kretprobe program that attaches to the exit of the 'do_unlinkat' function. It logs the process ID and the return value of the function. ```c SEC("kretprobe/do_unlinkat") int BPF_KRETPROBE(do_unlinkat_exit, long ret) { pid_t pid; pid = bpf_get_current_pid_tgid() >> 32; bpf_printk("KPROBE EXIT: pid = %d, ret = %ld\n", pid, ret); return 0; } ``` -------------------------------- ### bpf_skb_output Example Usage Source: https://docs.ebpf.io/linux/helper-function/bpf_skb_output An example demonstrating how to use the bpf_skb_output helper function within an eBPF program. ```APIDOC ## Example ```c #include "vmlinux.h" #include #include #include struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); __uint(key_size, sizeof(int)); __uint(value_size, sizeof(u32)); __uint(max_entries, 2); } my_map SEC(".maps"); SEC("tp_btf/netif_receive_skb") int BPF_PROG(handle_netif_receive_skb, struct sk_buff *skb) { struct S { u32 len; u64 cookie; } data = {}; data.len = BPF_CORE_READ(skb, len); data.cookie = 0x12345678; bpf_skb_output(skb, &my_map, 0, &data, sizeof(data)); return 0; } char _license[] SEC("license") = "GPL"; u32 _version SEC("version") = LINUX_VERSION_CODE; ``` ``` -------------------------------- ### Get FOU Encapsulation Parameters Source: https://docs.ebpf.io/linux/kfuncs/bpf_skb_get_fou_encap This example demonstrates retrieving FOU encapsulation parameters using bpf_skb_get_tunnel_key and bpf_skb_get_fou_encap. It checks if the retrieved destination port matches an expected value and prints tunnel information using bpf_printk. This is suitable for ingress path processing. ```c // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2016 VMware * Copyright (c) 2016 Facebook * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ SEC("tc") int ipip_encap_get_tunnel(struct __sk_buff *skb) { int ret; struct bpf_tunnel_key key = {}; struct bpf_fou_encap encap = {}; ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); if (ret < 0) { log_err(ret); return TC_ACT_SHOT; } ret = bpf_skb_get_fou_encap(skb, &encap); if (ret < 0) { log_err(ret); return TC_ACT_SHOT; } if (bpf_ntohs(encap.dport) != 5555) return TC_ACT_SHOT; bpf_printk("%d remote ip 0x%x, sport %d, dport %d\n", ret, key.remote_ipv4, bpf_ntohs(encap.sport), bpf_ntohs(encap.dport)); return TC_ACT_OK; } ``` -------------------------------- ### XDP Program Example using SEC Source: https://docs.ebpf.io/ebpf-library/libbpf/ebpf/SEC This example demonstrates how to use the `SEC` macro to define an eBPF program that will be placed in the `xdp` ELF section. Programs in this section are typically loaded as `BPF_PROG_TYPE_XDP`. ```c SEC("xdp") int example_prog(struct xdp_md *ctx) { void *data_end = (void *)(long)ctx->data_end; void *data = (void *)(long)ctx->data; if (data + sizeof(struct ethhdr) > data_end) return XDP_DROP; struct ethhdr *eth = data; if (eth->h_proto == htons(ETH_P_IP)) return XDP_PASS; } ``` -------------------------------- ### Trace Output Example Source: https://docs.ebpf.io/linux/helper-function/bpf_trace_printk An example of the typical output format seen in the kernel trace log when bpf_trace_printk is used. This format includes task name, PID, CPU, timestamp, and the formatted message. ```text telnet-470 [001] .N.. 419421.045894: 0x00000001: ``` -------------------------------- ### Example of bpf_map_create usage Source: https://docs.ebpf.io/ebpf-library/libbpf/userspace/bpf_map_create Demonstrates how to use the `bpf_map_create` function to create a BPF hash map. This example shows the necessary parameters for key size, value size, and maximum entries. It also includes basic error handling for map creation. ```c // struct example_map{ // __uint(type, BPF_MAP_TYPE_HASH); // __uint(max_entries, 10); // __type(key, __u32); // __type(value, __u32); // }; int main(){ int fd = bpf_map_create( BPF_MAP_TYPE_HASH, NULL, sizeof(__u32), sizeof(__u32), INNER_MAP_MAX_ENTRY, NULL ); if(fd < 0) puts("error creating map"); } ``` -------------------------------- ### Example Usage of bpf_timer_cancel Source: https://docs.ebpf.io/linux/helper-function/bpf_timer_cancel This C code demonstrates how to initialize, set a callback for, start, and then cancel a timer using eBPF helper functions. It includes map setup, timer initialization, and callback definition. ```c #include #include #include #include #include #include struct elem { struct bpf_timer t; }; struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, 1); __type(key, int); __type(value, struct elem); } hmap SEC(".maps"); static int timer_callback(void* hmap, int* key, struct bpf_timer *timer) { bpf_printk("Callback was invoked do something useful"); return 0; } SEC("cgroup_skb/egress") int bpf_prog1(void *ctx) { struct bpf_timer *timer; int err, key = 0; struct elem init; struct elem* ele; __builtin_memset(&init, 0, sizeof(struct elem)); bpf_map_update_elem(&hmap, &key, &init, BPF_ANY); ele = bpf_map_lookup_elem(&hmap, &key); if (!ele) return 1; timer = &ele->t; err = bpf_timer_init(timer, &hmap, CLOCK_MONOTONIC); if (err && err != -EBUSY) return 1; bpf_timer_set_callback(timer, timer_callback); bpf_timer_start(timer, 0, 0); bpf_timer_cancel(timer); return 0; } char _license[] SEC("license") = "GPL"; ``` -------------------------------- ### XDP Entry Point with bpf_dynptr_from_xdp Source: https://docs.ebpf.io/linux/kfuncs/bpf_dynptr_from_xdp This is the main XDP program entry point. It uses bpf_dynptr_from_xdp to get a dynamic pointer to the packet, slices the Ethernet header, and then dispatches to handle_ipv4 or handle_ipv6 based on the protocol. ```c SEC("xdp") int _xdp_tx_iptunnel(struct xdp_md *xdp) { __u8 buffer[ethhdr_sz]; struct bpf_dynptr ptr; struct ethhdr *eth; __u16 h_proto; __builtin_memset(buffer, 0, sizeof(buffer)); bpf_dynptr_from_xdp(xdp, 0, &ptr); eth = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer)); if (!eth) return XDP_DROP; h_proto = eth->h_proto; if (h_proto == bpf_htons(ETH_P_IP)) return handle_ipv4(xdp, &ptr); else if (h_proto == bpf_htons(ETH_P_IPV6)) return handle_ipv6(xdp, &ptr); else return XDP_DROP; } char _license[] SEC("license") = "GPL"; ``` -------------------------------- ### eBPF Tracepoint Example: Get and Print Processor ID Source: https://docs.ebpf.io/linux/helper-function/bpf_get_smp_processor_id This eBPF program, designed for a tracepoint on syscalls/sys_enter_open, demonstrates how to use bpf_get_smp_processor_id to get the current processor ID and print it using bpf_printk. It requires including vmlinux.h and bpf/bpf_helpers.h. ```c #include #include SEC("tp/syscalls/sys_enter_open") int sys_open_trace(void *ctx) { __u32 processor = bpf_get_smp_processor_id(); bpf_printk("Executed on processor %u.\n", processor); return 0; } ``` -------------------------------- ### init Source: https://docs.ebpf.io/linux/program-type/BPF_PROG_TYPE_STRUCT_OPS/Qdisc_ops Initializes a qdisc instance `sch` using the current ops. `arg` contains netlink arguments for creation, and `extack` is for verbose error messages (not usable by BPF qdiscs as of v6.16). ```APIDOC ## init ### Description This op is called to initialize a qdisc instance `sch` which will use the current ops for its implementation. `arg` are the netlink arguments used to create this new qdisc instance. `extack` is the extended acknowledge, used to carry verbose error messages, which BPF qdiscs cannot utilize as of v6.16. ### Signature `int (*init)(struct Qdisc *sch, struct nlattr *arg, struct netlink_ext_ack *extack);` ``` -------------------------------- ### Example Usage of bpf_core_field_offset Source: https://docs.ebpf.io/ebpf-library/libbpf/ebpf/bpf_core_field_offset Demonstrates how to use bpf_core_field_offset within a kprobe to get the byte offset of 'field2' from a 'some_kernel_struct'. The offset is determined at load time. ```c struct some_kernel_struct { __u16 field1; // This field might be smaller or larger on the target kernel __u32 field2; } SEC("kprobe") int kprobe__example(struct pt_regs *ctx) { struct some_kernel_struct *a = PT_REGS_PARM1(ctx); int field_offset = bpf_core_field_offset(a->field2); // Do something with field_offset // ... return 0; } ``` -------------------------------- ### Example Usage of __kconfig Source: https://docs.ebpf.io/ebpf-library/libbpf/ebpf/__kconfig Demonstrates how to use __kconfig to access CONFIG_HZ and adapt time calculations. The loader initializes CONFIG_HZ with the system's kernel configuration value. ```c extern unsigned CONFIG_HZ __kconfig; #define USER_HZ 100 #define NSEC_PER_SEC 1000000000ULL static clock_t jiffies_to_clock_t(unsigned long x) { /* The implementation here tailored to a particular * setting of USER_HZ. */ u64 tick_nsec = (NSEC_PER_SEC + CONFIG_HZ/2) / CONFIG_HZ; u64 user_hz_nsec = NSEC_PER_SEC / USER_HZ; if ((tick_nsec % user_hz_nsec) == 0) { if (CONFIG_HZ < USER_HZ) return x * (USER_HZ / CONFIG_HZ); else return x / (CONFIG_HZ / USER_HZ); } return x * tick_nsec/user_hz_nsec; } ``` -------------------------------- ### Get XFRM Info Example Source: https://docs.ebpf.io/linux/kfuncs/bpf_skb_get_xfrm_info Demonstrates how to use bpf_skb_get_xfrm_info to retrieve XFRM metadata and store the interface ID. This snippet is intended for use in TC programs. ```c // SPDX-License-Identifier: GPL-2.0 #include "vmlinux.h" #include "bpf_tracing_net.h" #include __u32 req_if_id; __u32 resp_if_id; int bpf_skb_set_xfrm_info(struct __sk_buff *skb_ctx, const struct bpf_xfrm_info *from) __ksym; int bpf_skb_get_xfrm_info(struct __sk_buff *skb_ctx, struct bpf_xfrm_info *to) __ksym; SEC("tc") int set_xfrm_info(struct __sk_buff *skb) { struct bpf_xfrm_info info = { .if_id = req_if_id }; return bpf_skb_set_xfrm_info(skb, &info) ? TC_ACT_SHOT : TC_ACT_UNSPEC; } SEC("tc") int get_xfrm_info(struct __sk_buff *skb) { struct bpf_xfrm_info info = {}; if (bpf_skb_get_xfrm_info(skb, &info) < 0) return TC_ACT_SHOT; resp_if_id = info.if_id; return TC_ACT_UNSPEC; } char _license[] SEC("license") = "GPL"; ``` -------------------------------- ### HID BPF Example: Modifying HID Reports Source: https://docs.ebpf.io/linux/kfuncs/hid_bpf_allocate_context This example demonstrates modifying HID reports within a BPF program. It uses hid_bpf_allocate_context to get a context, hid_bpf_get_data to access report data, and hid_bpf_hw_request to send reports. The program also includes logic for setting haptic feedback parameters. ```c // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2022 Benjamin Tissoires */ #include "vmlinux.h" #include #include #include "hid_bpf_helpers.h" #define HID_UP_BUTTON 0x0009 #define HID_GD_WHEEL 0x0038 SEC("fmod_ret/hid_bpf_device_event") int BPF_PROG(hid_event, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 9 /* size */); if (!data) return 0; /* EPERM check */ /* Touch */ data[1] &= 0xfd; /* X */ data[4] = 0; data[5] = 0; /* Y */ data[6] = 0; data[7] = 0; return 0; } /* 72 == 360 / 5 -> 1 report every 5 degrees */ int resolution = 72; int physical = 5; struct haptic_syscall_args { unsigned int hid; int retval; }; static __u8 haptic_data[8]; SEC("syscall") int set_haptic(struct haptic_syscall_args *args) { struct hid_bpf_ctx *ctx; const size_t size = sizeof(haptic_data); u16 *res; int ret; if (size > sizeof(haptic_data)) return -7; /* -E2BIG */ ctx = hid_bpf_allocate_context(args->hid); if (!ctx) return -1; /* EPERM check */ haptic_data[0] = 1; /* report ID */ ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); bpf_printk("probed/remove event ret value: %d", ret); bpf_printk("buf: %02x %02x %02x", haptic_data[0], haptic_data[1], haptic_data[2]); bpf_printk(" %02x %02x %02x", haptic_data[3], haptic_data[4], haptic_data[5]); bpf_printk(" %02x %02x", haptic_data[6], haptic_data[7]); /* whenever resolution multiplier is not 3600, we have the fixed report descriptor */ res = (u16 *)&haptic_data[1]; if (*res != 3600) { // haptic_data[1] = 72; /* resolution multiplier */ // haptic_data[2] = 0; /* resolution multiplier */ // haptic_data[3] = 0; /* Repeat Count */ haptic_data[4] = 3; /* haptic Auto Trigger */ // haptic_data[5] = 5; /* Waveform Cutoff Time */ // haptic_data[6] = 80; /* Retrigger Period */ // haptic_data[7] = 0; /* Retrigger Period */ } else { haptic_data[4] = 0; } ret = hid_bpf_hw_request(ctx, haptic_data, size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); bpf_printk("set haptic ret value: %d -> %d", ret, haptic_data[4]); args->retval = ret; hid_bpf_release_context(ctx); return 0; } /* Convert REL_DIAL into REL_WHEEL */ SEC("fmod_ret/hid_bpf_rdesc_fixup") int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx) { __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */); __u16 *res, *phys; if (!data) return 0; /* EPERM check */ /* Convert TOUCH into a button */ data[31] = HID_UP_BUTTON; data[33] = 2; /* Convert REL_DIAL into REL_WHEEL */ data[45] = HID_GD_WHEEL; /* Change Resolution Multiplier */ phys = (__u16 *)&data[61]; *phys = physical; res = (__u16 *)&data[66]; *res = resolution; /* Convert X,Y from Abs to Rel */ data[88] = 0x06; data[98] = 0x06; return 0; } char _license[] SEC("license") = "GPL"; u32 _version SEC("version") = 1; ``` -------------------------------- ### Profiling Example with Stack Traces Source: https://docs.ebpf.io/linux/program-type/BPF_PROG_TYPE_PERF_EVENT This BPF program collects performance events and records kernel and user-space stack traces. It filters out warmup events and updates a map with counts based on command name and stack IDs. Use this for detailed performance profiling. ```c /* Copyright (c) 2016 Facebook * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ #include #include #include #include #include #include struct key_t { char comm[TASK_COMM_LEN]; u32 kernstack; u32 userstack; }; struct { __uint(type, BPF_MAP_TYPE_HASH); __type(key, struct key_t); __type(value, u64); __uint(max_entries, 10000); } counts SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_STACK_TRACE); __uint(key_size, sizeof(u32)); __uint(value_size, PERF_MAX_STACK_DEPTH * sizeof(u64)); __uint(max_entries, 10000); } stackmap SEC(".maps"); #define KERN_STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP) #define USER_STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP | BPF_F_USER_STACK) SEC("perf_event") int bpf_prog1(struct bpf_perf_event_data *ctx) { char time_fmt1[] = "Time Enabled: %llu, Time Running: %llu"; char time_fmt2[] = "Get Time Failed, ErrCode: %d"; char addr_fmt[] = "Address recorded on event: %llx"; char fmt[] = "CPU-%d period %lld ip %llx"; u32 cpu = bpf_get_smp_processor_id(); struct bpf_perf_event_value value_buf; struct key_t key; u64 *val, one = 1; int ret; if (ctx->sample_period < 10000) /* ignore warmup */ return 0; bpf_get_current_comm(&key.comm, sizeof(key.comm)); key.kernstack = bpf_get_stackid(ctx, &stackmap, KERN_STACKID_FLAGS); key.userstack = bpf_get_stackid(ctx, &stackmap, USER_STACKID_FLAGS); if ((int)key.kernstack < 0 && (int)key.userstack < 0) { bpf_trace_printk(fmt, sizeof(fmt), cpu, ctx->sample_period, PT_REGS_IP(&ctx->regs)); return 0; } ret = bpf_perf_prog_read_value(ctx, (void *)&value_buf, sizeof(struct bpf_perf_event_value)); if (!ret) bpf_trace_printk(time_fmt1, sizeof(time_fmt1), value_buf.enabled, value_buf.running); else bpf_trace_printk(time_fmt2, sizeof(time_fmt2), ret); if (ctx->addr != 0) bpf_trace_printk(addr_fmt, sizeof(addr_fmt), ctx->addr); val = bpf_map_lookup_elem(&counts, &key); if (val) (*val)++; else bpf_map_update_elem(&counts, &key, &one, BPF_NOEXIST); return 0; } char _license[] SEC("license") = "GPL"; ``` -------------------------------- ### BPF Ring Buffer and Dynptr Example Source: https://docs.ebpf.io/linux/helper-function/bpf_ringbuf_discard_dynptr This example demonstrates the usage of bpf_ringbuf_reserve_dynptr, bpf_dynptr_write, bpf_dynptr_read, bpf_ringbuf_submit_dynptr, and bpf_ringbuf_discard_dynptr. It reserves space in a ring buffer using a dynamic pointer, writes data to it, reads the data back to verify, and then either submits or discards the sample. ```c #include #include #include struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } ringbuf SEC(".maps"); SEC("tp/syscalls/sys_enter_openat") int bpf_prog1(void *ctx) { char write_data[64] = "hello there, world!!"; char read_data[64] = {}; struct bpf_dynptr ptr; int i; int local_err = 0; local_err = bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); if (local_err < 0) goto discard; /* Write data into the dynptr */ local_err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); if (local_err) { goto discard; } /* Read the data that was written into the dynptr */ local_err = bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); if (local_err) { goto discard; } /* Ensure the data we read matches the data we wrote */ for (i = 0; i < sizeof(read_data); i++) { if (read_data[i] != write_data[i]) { break; } } bpf_printk("Read matches write, dynptr API works"); bpf_ringbuf_submit_dynptr(&ptr, 0); return 0; discard: bpf_ringbuf_discard_dynptr(&ptr, 0); return 0; } ``` -------------------------------- ### xsk_ring_prod__fill_addr Usage Example Source: https://docs.ebpf.io/ebpf-library/libxdp/functions/xsk_ring_prod__fill_addr This snippet shows the function signature for `xsk_ring_prod__fill_addr`. Use this function to get a pointer to a slot in the fill ring to set the address of a packet buffer. ```c __u64 *xsk_ring_prod__fill_addr(struct xsk_ring_prod *fill, __u32 idx); ``` -------------------------------- ### Get kmem_cache for task_struct Source: https://docs.ebpf.io/linux/kfuncs/bpf_get_kmem_cache This example demonstrates how to use bpf_get_kmem_cache to retrieve the kmem_cache for the current task's structure. It then looks up the slab name in a hash map to verify if it's 'task_struct'. ```c // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2024 Google */ #include #include #include #include "bpf_experimental.h" char _license[] SEC("license") = "GPL"; #define SLAB_NAME_MAX 32 struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(key_size, sizeof(void *)); __uint(value_size, SLAB_NAME_MAX); __uint(max_entries, 1); } slab_hash SEC(".maps"); extern struct kmem_cache *bpf_get_kmem_cache(u64 addr) __ksym; /* Result, will be checked by userspace */ int task_struct_found; SEC("raw_tp/bpf_test_finish") int BPF_PROG(check_task_struct) { u64 curr = bpf_get_current_task(); struct kmem_cache *s; char *name; s = bpf_get_kmem_cache(curr); if (s == NULL) { task_struct_found = -1; return 0; } name = bpf_map_lookup_elem(&slab_hash, &s); if (name && !bpf_strncmp(name, 11, "task_struct")) task_struct_found = 1; else task_struct_found = -2; return 0; } ``` -------------------------------- ### Initialize percpu object using bpf_percpu_obj_new Source: https://docs.ebpf.io/ebpf-library/libbpf/ebpf/__percpu_kptr Example of initializing a per-CPU object using bpf_percpu_obj_new and associating it with a map element's per-CPU pointer field using bpf_kptr_xchg. If a previous pointer exists, it is dropped. ```c struct val_t __percpu_kptr *p; struct elem *e; int index = 0; e = bpf_map_lookup_elem(&array, &index); if (!e) return 0; p = bpf_percpu_obj_new(struct val_t); if (!p) return 0; p = bpf_kptr_xchg(&e->pc, p); if (p) bpf_percpu_obj_drop(p); return 0; ``` -------------------------------- ### Get Time Elapsed in Nanoseconds Source: https://docs.ebpf.io/linux/helper-function/bpf_ktime_get_ns This snippet demonstrates how to use bpf_ktime_get_ns to measure the duration of a task. It captures the start time, performs some operations, and then captures the end time to calculate the elapsed duration. ```c __u64 start_time = bpf_ktime_get_ns(); /* some tasks */ __u64 end_time = bpf_ktime_get_ns(); __u64 duration = end_time - start_time; ``` -------------------------------- ### bpf_wq_start Source: https://docs.ebpf.io/linux/kfuncs/bpf_wq_start Starts a work-queue, allowing eBPF programs to schedule work for asynchronous execution. The work-queue must be initialized and have a callback function set prior to calling this kfunc. ```APIDOC ## bpf_wq_start ### Description Starts a work-queue which allows eBPF programs to schedule work to be executed asynchronously. ### Signature `int bpf_wq_start(struct bpf_wq *wq, unsigned int flags)` ### Parameters #### Arguments - **wq** (`struct bpf_wq *`) - A pointer to a `struct bpf_wq` which must reside in a map value. - **flags** (`unsigned int`) - Flags to allow for future extensions. ### Returns - `0` on success. - A negative error code on failure. ``` -------------------------------- ### Get and Filter Tunnel Key Information Source: https://docs.ebpf.io/linux/helper-function/bpf_skb_get_tunnel_key Example of using bpf_skb_get_tunnel_key to retrieve tunnel metadata and filter packets based on the remote IPv4 address. This snippet is intended for use in TC ingress programs. ```c int ret; struct bpf_tunnel_key key = {}; ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); if (ret < 0) return TC_ACT_SHOT; // drop packet if (key.remote_ipv4 != 0x0a000001) return TC_ACT_SHOT; // drop packet return TC_ACT_OK; // accept packet ``` -------------------------------- ### eBPF Tracepoint Example using bpf_strncmp Source: https://docs.ebpf.io/linux/helper-function/bpf_strncmp This snippet demonstrates how to use bpf_strncmp within an eBPF tracepoint program to check if the current task's command name starts with 'cat'. It requires including vmlinux.h and bpf/bpf_helpers.h. ```c #include #include SEC("tp_btf/sys_enter") int sys_enter_trace(void *ctx) { struct task_struct *task = (struct task_struct *)bpf_get_current_task_btf(); if (bpf_strncmp(task->comm, TASK_COMM_LEN, "cat") != 0) { return 0; } bpf_printk("Hello, I'm a cat!\n"); return 0; } ``` -------------------------------- ### BPF Cgroup Connect, Getsockname, Getpeername Example Source: https://docs.ebpf.io/linux/program-type/BPF_PROG_TYPE_CGROUP_SOCK_ADDR This example demonstrates BPF programs for cgroup connect, getsockname, and getpeername events. It uses bpf_sk_storage to map original service addresses and ports, allowing for service rewiring and exposure. ```c // SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include #include #include #include char _license[] SEC("license") = "GPL"; struct svc_addr { __be32 addr; __be16 port; }; struct { __uint(type, BPF_MAP_TYPE_SK_STORAGE); __uint(map_flags, BPF_F_NO_PREALLOC); __type(key, int); __type(value, struct svc_addr); } service_mapping SEC ".maps"; SEC("cgroup/connect4") int connect4(struct bpf_sock_addr *ctx) { struct sockaddr_in sa = {}; struct svc_addr *orig; /* Force local address to 127.0.0.1:22222. */ sa.sin_family = AF_INET; sa.sin_port = bpf_htons(22222); sa.sin_addr.s_addr = bpf_htonl(0x7f000001); if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) return 0; /* Rewire service 1.2.3.4:60000 to backend 127.0.0.1:60123. */ if (ctx->user_port == bpf_htons(60000)) { orig = bpf_sk_storage_get(&service_mapping, ctx->sk, 0, BPF_SK_STORAGE_GET_F_CREATE); if (!orig) return 0; orig->addr = ctx->user_ip4; orig->port = ctx->user_port; ctx->user_ip4 = bpf_htonl(0x7f000001); ctx->user_port = bpf_htons(60123); } return 1; } SEC("cgroup/getsockname4") int getsockname4(struct bpf_sock_addr *ctx) { if (!get_set_sk_priority(ctx)) return 1; /* Expose local server as 1.2.3.4:60000 to client. */ if (ctx->user_port == bpf_htons(60123)) { ctx->user_ip4 = bpf_htonl(0x01020304); ctx->user_port = bpf_htons(60000); } return 1; } SEC("cgroup/getpeername4") int getpeername4(struct bpf_sock_addr *ctx) { struct svc_addr *orig; if (!get_set_sk_priority(ctx)) return 1; /* Expose service 1.2.3.4:60000 as peer instead of backend. */ if (ctx->user_port == bpf_htons(60123)) { orig = bpf_sk_storage_get(&service_mapping, ctx->sk, 0, 0); if (orig) { ctx->user_ip4 = orig->addr; ctx->user_port = orig->port; } } return 1; } ``` -------------------------------- ### Get Boot Time in Nanoseconds Source: https://docs.ebpf.io/linux/helper-function/bpf_ktime_get_boot_ns This snippet demonstrates how to use bpf_ktime_get_boot_ns to capture a start time, perform some tasks, and then capture an end time to calculate a duration. It is useful for measuring time intervals within eBPF programs. ```c __u64 start_time = bpf_ktime_get_boot_ns(); /* some tasks */ __u64 end_time = bpf_ktime_get_boot_ns(); __u64 duration = end_time - start_time; ``` -------------------------------- ### bpf_wq_init Source: https://docs.ebpf.io/linux/kfuncs/bpf_wq_init Initializes a work-queue for asynchronous execution. This is the first step in using a work-queue, followed by setting a callback and starting the work. ```APIDOC ## bpf_wq_init ### Description Initializes a work-queue which allows eBPF programs to schedule work to be executed asynchronously. ### Signature `int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags)` ### Parameters * `wq` (struct bpf_wq *): A pointer to a `struct bpf_wq` which must reside in a map value. * `p__map` (void *): A pointer to a map that contains the `wq` as value. * `flags` (unsigned int): Flags to allow for future extensions. ### Returns * `0` on success. * A negative error code on failure. ``` -------------------------------- ### Lookup Element in Per-CPU Map Source: https://docs.ebpf.io/linux/helper-function/bpf_map_lookup_percpu_elem This example demonstrates how to use bpf_map_lookup_percpu_elem to retrieve a value from a per-CPU map. It first gets the current CPU ID and then attempts to look up the element using the provided key. The result is printed to the eBPF log. ```c int key, *value, cpuid; key=0; cpuid=bpf_get_smp_processor_id(); value = bpf_map_lookup_percpu_elem(&percpu_map, &key, cpuid); if (value) bpf_printk("Read value '%d' from the map on CPU '%d'\n", *value, cpuid); else bpf_printk("Failed to read value from the map\n"); ``` -------------------------------- ### Set FOU Encapsulation Parameters Source: https://docs.ebpf.io/linux/kfuncs/bpf_skb_set_fou_encap This example demonstrates setting up FOU encapsulation for packets. It first sets tunnel key information and then configures the FOU encapsulation with a specific destination port and auto-assigned source port. Ensure `bpf_skb_set_tunnel_key` is called successfully before this function. ```c // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2016 VMware * Copyright (c) 2016 Facebook * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ SEC("tc") int ipip_fou_set_tunnel(struct __sk_buff *skb) { struct bpf_tunnel_key key = {}; struct bpf_fou_encap encap = {}; void *data = (void *)(long)skb->data; struct iphdr *iph = data; void *data_end = (void *)(long)skb->data_end; int ret; if (data + sizeof(*iph) > data_end) { log_err(1); return TC_ACT_SHOT; } key.tunnel_ttl = 64; if (iph->protocol == IPPROTO_ICMP) key.remote_ipv4 = 0xac100164; /* 172.16.1.100 */ ret = bpf_skb_set_tunnel_key(skb, &key, sizeof(key), 0); if (ret < 0) { log_err(ret); return TC_ACT_SHOT; } encap.sport = 0; encap.dport = bpf_htons(5555); ret = bpf_skb_set_fou_encap(skb, &encap, FOU_BPF_ENCAP_FOU); if (ret < 0) { log_err(ret); return TC_ACT_SHOT; } return TC_ACT_OK; } ```