Commit | Line | Data |
---|---|---|
36e04a2d JDB |
1 | /* SPDX-License-Identifier: GPL-2.0 |
2 | * Copyright (c) 2018 Jesper Dangaard Brouer, Red Hat Inc. | |
3 | * | |
4 | * Example howto transfer info from XDP to SKB, e.g. skb->mark | |
5 | * ----------------------------------------------------------- | |
6 | * This uses the XDP data_meta infrastructure, and is a cooperation | |
7 | * between two bpf-programs (1) XDP and (2) clsact at TC-ingress hook. | |
8 | * | |
ceb5dea5 | 9 | * Notice: This example does not use the BPF C-loader, |
36e04a2d JDB |
10 | * but instead rely on the iproute2 TC tool for loading BPF-objects. |
11 | */ | |
12 | #include <uapi/linux/bpf.h> | |
13 | #include <uapi/linux/pkt_cls.h> | |
14 | ||
7cf245a3 | 15 | #include <bpf/bpf_helpers.h> |
36e04a2d JDB |
16 | |
17 | /* | |
18 | * This struct is stored in the XDP 'data_meta' area, which is located | |
19 | * just in-front-of the raw packet payload data. The meaning is | |
20 | * specific to these two BPF programs that use it as a communication | |
21 | * channel. XDP adjust/increase the area via a bpf-helper, and TC use | |
22 | * boundary checks to see if data have been provided. | |
23 | * | |
24 | * The struct must be 4 byte aligned, which here is enforced by the | |
25 | * struct __attribute__((aligned(4))). | |
26 | */ | |
27 | struct meta_info { | |
28 | __u32 mark; | |
29 | } __attribute__((aligned(4))); | |
30 | ||
31 | SEC("xdp_mark") | |
32 | int _xdp_mark(struct xdp_md *ctx) | |
33 | { | |
34 | struct meta_info *meta; | |
35 | void *data, *data_end; | |
36 | int ret; | |
37 | ||
e2e32241 | 38 | /* Reserve space in-front of data pointer for our meta info. |
36e04a2d JDB |
39 | * (Notice drivers not supporting data_meta will fail here!) |
40 | */ | |
41 | ret = bpf_xdp_adjust_meta(ctx, -(int)sizeof(*meta)); | |
42 | if (ret < 0) | |
43 | return XDP_ABORTED; | |
44 | ||
e2e32241 JDB |
45 | /* Notice: Kernel-side verifier requires that loading of |
46 | * ctx->data MUST happen _after_ helper bpf_xdp_adjust_meta(), | |
47 | * as pkt-data pointers are invalidated. Helpers that require | |
48 | * this are determined/marked by bpf_helper_changes_pkt_data() | |
36e04a2d JDB |
49 | */ |
50 | data = (void *)(unsigned long)ctx->data; | |
51 | ||
52 | /* Check data_meta have room for meta_info struct */ | |
53 | meta = (void *)(unsigned long)ctx->data_meta; | |
54 | if (meta + 1 > data) | |
55 | return XDP_ABORTED; | |
56 | ||
57 | meta->mark = 42; | |
58 | ||
59 | return XDP_PASS; | |
60 | } | |
61 | ||
62 | SEC("tc_mark") | |
63 | int _tc_mark(struct __sk_buff *ctx) | |
64 | { | |
65 | void *data = (void *)(unsigned long)ctx->data; | |
66 | void *data_end = (void *)(unsigned long)ctx->data_end; | |
67 | void *data_meta = (void *)(unsigned long)ctx->data_meta; | |
68 | struct meta_info *meta = data_meta; | |
69 | ||
70 | /* Check XDP gave us some data_meta */ | |
71 | if (meta + 1 > data) { | |
72 | ctx->mark = 41; | |
73 | /* Skip "accept" if no data_meta is avail */ | |
74 | return TC_ACT_OK; | |
75 | } | |
76 | ||
77 | /* Hint: See func tc_cls_act_is_valid_access() for BPF_WRITE access */ | |
78 | ctx->mark = meta->mark; /* Transfer XDP-mark to SKB-mark */ | |
79 | ||
80 | return TC_ACT_OK; | |
81 | } | |
82 | ||
83 | /* Manually attaching these programs: | |
84 | export DEV=ixgbe2 | |
85 | export FILE=xdp2skb_meta_kern.o | |
86 | ||
87 | # via TC command | |
88 | tc qdisc del dev $DEV clsact 2> /dev/null | |
89 | tc qdisc add dev $DEV clsact | |
90 | tc filter add dev $DEV ingress prio 1 handle 1 bpf da obj $FILE sec tc_mark | |
91 | tc filter show dev $DEV ingress | |
92 | ||
93 | # XDP via IP command: | |
94 | ip link set dev $DEV xdp off | |
95 | ip link set dev $DEV xdp obj $FILE sec xdp_mark | |
96 | ||
97 | # Use iptable to "see" if SKBs are marked | |
98 | iptables -I INPUT -p icmp -m mark --mark 41 # == 0x29 | |
99 | iptables -I INPUT -p icmp -m mark --mark 42 # == 0x2a | |
100 | ||
101 | # Hint: catch XDP_ABORTED errors via | |
102 | perf record -e xdp:* | |
103 | perf script | |
104 | ||
105 | */ |