Jesper Dangaard Brouer | 36e04a2 | 2018-01-10 18:21:44 +0100 | [diff] [blame] | 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 | * |
| 9 | * Notice: This example does not use the BPF C-loader (bpf_load.c), |
| 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 | |
Toke Høiland-Jørgensen | 7cf245a | 2020-01-20 14:06:49 +0100 | [diff] [blame] | 15 | #include <bpf/bpf_helpers.h> |
Jesper Dangaard Brouer | 36e04a2 | 2018-01-10 18:21:44 +0100 | [diff] [blame] | 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 | |
Jesper Dangaard Brouer | e2e3224 | 2018-01-17 11:17:37 +0100 | [diff] [blame] | 38 | /* Reserve space in-front of data pointer for our meta info. |
Jesper Dangaard Brouer | 36e04a2 | 2018-01-10 18:21:44 +0100 | [diff] [blame] | 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 | |
Jesper Dangaard Brouer | e2e3224 | 2018-01-17 11:17:37 +0100 | [diff] [blame] | 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() |
Jesper Dangaard Brouer | 36e04a2 | 2018-01-10 18:21:44 +0100 | [diff] [blame] | 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 | */ |