|
| 1 | +# -*- fill-column: 76; -*- |
| 2 | +#+TITLE: Tutorial: Tracing01 - monitor xdp tracepoint |
| 3 | +#+OPTIONS: ^:nil |
| 4 | + |
| 5 | +In this lesson we will show how to create and load eBPF program that |
| 6 | +hooks on xdp:exception tracepoint and get its values to user space |
| 7 | +stats application. |
| 8 | + |
| 9 | +* Table of Contents :TOC: |
| 10 | +- [[#using-libbpf][XDP tracepoints]] |
| 11 | + - [[#xdp-tracepoints][XDP tracepoints]] |
| 12 | + - [[#tracepoint-program-section][Tracepoint program section]] |
| 13 | + - [[#tracepoint-arguments][Tracepoint arguments]] |
| 14 | + - [[#tracepoint-attaching][Tracepoint attaching]] |
| 15 | + - [[#hash-map][HASH map]] |
| 16 | +- [[#assignments][Assignments]] |
| 17 | + - [[#assignment-1][Assignment 1: Setting up your test lab]] |
| 18 | + - [[#assignment-2][Assignment 2: Load tracepoint monitor program]] |
| 19 | + |
| 20 | + |
| 21 | +* XDP tracepoints |
| 22 | + |
| 23 | +The eBPF programs can be attached also to tracepoints. There are |
| 24 | +several tracepoints related to xdp: |
| 25 | + |
| 26 | +#+begin_example sh |
| 27 | +ls /sys/kernel/debug/tracing/events/xdp/ |
| 28 | +xdp_cpumap_enqueue |
| 29 | +xdp_cpumap_kthread |
| 30 | +xdp_devmap_xmit |
| 31 | +xdp_exception |
| 32 | +xdp_redirect |
| 33 | +xdp_redirect_err |
| 34 | +xdp_redirect_map |
| 35 | +xdp_redirect_map_err |
| 36 | +#+end_example |
| 37 | + |
| 38 | +** Tracepoint program section |
| 39 | + |
| 40 | +The bpf library expects the tracepoint eBPF program to be stored |
| 41 | +in a section with following name: |
| 42 | + |
| 43 | +#+begin_example sh |
| 44 | +tracepoint/sys/tracepoint |
| 45 | +#+end_example |
| 46 | + |
| 47 | +where 'sys' is the tracepoint subsystem and 'tracepoint' is |
| 48 | +the tracepoint name. |
| 49 | + |
| 50 | +which can be done with following construct: |
| 51 | + |
| 52 | +#+begin_example sh |
| 53 | +SEC("tracepoint/xdp/xdp_exception") |
| 54 | +int trace_xdp_exception(struct xdp_exception_ctx *ctx) |
| 55 | +#+end_example |
| 56 | + |
| 57 | +** Tracepoint arguments |
| 58 | + |
| 59 | +There's single program pointer argument which points |
| 60 | +to the structure, that defines the tracepoint fields. |
| 61 | + |
| 62 | +Like for xdp:xdp_exception tracepoint: |
| 63 | + |
| 64 | +#+begin_example sh |
| 65 | +struct xdp_exception_ctx { |
| 66 | + __u64 __pad; // First 8 bytes are not accessible by bpf code |
| 67 | + __s32 prog_id; // offset:8; size:4; signed:1; |
| 68 | + __u32 act; // offset:12; size:4; signed:0; |
| 69 | + __s32 ifindex; // offset:16; size:4; signed:1; |
| 70 | +}; |
| 71 | + |
| 72 | +int trace_xdp_exception(struct xdp_exception_ctx *ctx) |
| 73 | +#+end_example |
| 74 | + |
| 75 | +This struct is exported in tracepoint format file: |
| 76 | + |
| 77 | +#+begin_example sh |
| 78 | +# cat /sys/kernel/debug/tracing/events/xdp/xdp_exception/format |
| 79 | +... |
| 80 | + field:unsigned short common_type; offset:0; size:2; signed:0; |
| 81 | + field:unsigned char common_flags; offset:2; size:1; signed:0; |
| 82 | + field:unsigned char common_preempt_count; offset:3; size:1; signed:0; |
| 83 | + field:int common_pid; offset:4; size:4; signed:1; |
| 84 | + |
| 85 | + field:int prog_id; offset:8; size:4; signed:1; |
| 86 | + field:u32 act; offset:12; size:4; signed:0; |
| 87 | + field:int ifindex; offset:16; size:4; signed:1; |
| 88 | +... |
| 89 | +#+end_example |
| 90 | + |
| 91 | +** Tracepoint attaching |
| 92 | + |
| 93 | +To load a tracepoint program for this example we use following bpf |
| 94 | +library helper function: |
| 95 | + |
| 96 | +#+begin_example sh |
| 97 | +bpf_prog_load(cfg->filename, BPF_PROG_TYPE_TRACEPOINT, &obj, &bpf_fd)) |
| 98 | +#+end_example |
| 99 | + |
| 100 | +It loads all the programs from the object together with maps and |
| 101 | +returns file descriptor of the first one. |
| 102 | + |
| 103 | +To attach the program to the tracepoint we need to create a tracepoint |
| 104 | +perf event and attach the eBPF program to it, using its file descriptor |
| 105 | +via PERF_EVENT_IOC_SET_BPF ioctl call: |
| 106 | + |
| 107 | +#+begin_example sh |
| 108 | +err = ioctl(fd, PERF_EVENT_IOC_SET_BPF, bpf_fd); |
| 109 | +#+end_example |
| 110 | + |
| 111 | +Please check trace_load_and_stats.c load_bpf_and_trace_attach function |
| 112 | +for all the details. |
| 113 | + |
| 114 | +* HASH map |
| 115 | + |
| 116 | +This example is using PERCPU HASH map, that stores number of aborted |
| 117 | +packets for interface |
| 118 | +#+begin_example sh |
| 119 | +struct bpf_map_def SEC("maps") xdp_stats_map = { |
| 120 | + .type = BPF_MAP_TYPE_PERCPU_HASH, |
| 121 | + .key_size = sizeof(__s32), |
| 122 | + .value_size = sizeof(__u64), |
| 123 | + .max_entries = 10, |
| 124 | +}; |
| 125 | +#+end_example |
| 126 | + |
| 127 | +The interface is similar to the ARRAY map except that we need to specifically |
| 128 | +create new element in the hash if it does not exist: |
| 129 | + |
| 130 | +#+begin_example sh |
| 131 | +/* Lookup in kernel BPF-side returns pointer to actual data. */ |
| 132 | +valp = bpf_map_lookup_elem(&xdp_stats_map, &key); |
| 133 | + |
| 134 | +/* If there's no record for interface, we need to create one, |
| 135 | + * with number of packets == 1 |
| 136 | + */ |
| 137 | +if (!valp) { |
| 138 | + __u64 one = 1; |
| 139 | + return bpf_map_update_elem(&xdp_stats_map, &key, &one, 0) ? 1 : 0; |
| 140 | +} |
| 141 | + |
| 142 | +(*valp)++; |
| 143 | +#+end_example |
| 144 | + |
| 145 | +Please check trace_prog_kern.c for the full code. |
| 146 | + |
| 147 | +* Assignments |
| 148 | + |
| 149 | +** Assignment 1: Setting up your test lab |
| 150 | + |
| 151 | +In this lesson we will use the setup of the previous lesson: |
| 152 | +Basic02 - loading a program by name [[https://github.com/xdp-project/xdp-tutorial/tree/master/basic02-prog-by-name#assignment-2-add-xdp_abort-program]] |
| 153 | + |
| 154 | +and load XDP program from xdp_prog_kern.o that will abort every |
| 155 | +incoming packet: |
| 156 | + |
| 157 | +#+begin_example sh |
| 158 | +SEC("xdp_abort") |
| 159 | +int xdp_drop_func(struct xdp_md *ctx) |
| 160 | +{ |
| 161 | + return XDP_ABORTED; |
| 162 | +} |
| 163 | +#+end_example |
| 164 | + |
| 165 | +with xdp_loader from previous lessson: |
| 166 | +Assignment 2: Add xdp_abort program [[https://github.com/xdp-project/xdp-tutorial/tree/master/basic02-prog-by-name#assignment-2-add-xdp_abort-program]] |
| 167 | + |
| 168 | +Setup the environment: |
| 169 | + |
| 170 | +#+begin_example sh |
| 171 | +$ sudo ../testenv/testenv.sh setup --name veth-basic02 |
| 172 | +#+end_example |
| 173 | + |
| 174 | +Load the XDP program, tak produces aborted packets: |
| 175 | + |
| 176 | +#+begin_example sh |
| 177 | +$ sudo ../basic02-prog-by-name/xdp_loader --dev veth-basic02 --force --progsec xdp_abort |
| 178 | +#+end_example |
| 179 | + |
| 180 | +and make some packets: |
| 181 | + |
| 182 | +#+begin_example sh |
| 183 | +$ sudo ../testenv/testenv.sh enter --name veth-basic02 |
| 184 | +# ping fc00:dead:cafe:1::1 |
| 185 | +PING fc00:dead:cafe:1::1(fc00:dead:cafe:1::1) 56 data bytes |
| 186 | +#+end_example |
| 187 | + |
| 188 | +** Assignment 2: Load tracepoint monitor program |
| 189 | + |
| 190 | +Now when you run the trace_load_and_stats application it will |
| 191 | +load and attach the tracepoint eBPF program and display number |
| 192 | +of aborted packets per interface: |
| 193 | + |
| 194 | +#+begin_example |
| 195 | +# ./trace_load_and_stats |
| 196 | +Success: Loaded BPF-object(trace_prog_kern.o) |
| 197 | + |
| 198 | +Collecting stats from BPF map |
| 199 | + - BPF map (bpf_map_type:1) id:46 name:xdp_stats_map key_size:4 value_size:4 max_entries:10 |
| 200 | + |
| 201 | +veth-basic02 (2) |
| 202 | +veth-basic02 (4) |
| 203 | +veth-basic02 (6) |
| 204 | +... |
| 205 | +#+end_example |
0 commit comments