]>
Commit | Line | Data |
---|---|---|
0fca931a JDB |
1 | /* SPDX-License-Identifier: GPL-2.0 |
2 | * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc. | |
3 | * | |
4 | * Example howto extract XDP RX-queue info | |
5 | */ | |
6 | #include <uapi/linux/bpf.h> | |
0d25c43a JDB |
7 | #include <uapi/linux/if_ether.h> |
8 | #include <uapi/linux/in.h> | |
0fca931a JDB |
9 | #include "bpf_helpers.h" |
10 | ||
11 | /* Config setup from with userspace | |
12 | * | |
13 | * User-side setup ifindex in config_map, to verify that | |
14 | * ctx->ingress_ifindex is correct (against configured ifindex) | |
15 | */ | |
16 | struct config { | |
17 | __u32 action; | |
18 | int ifindex; | |
0d25c43a JDB |
19 | __u32 options; |
20 | }; | |
21 | enum cfg_options_flags { | |
22 | NO_TOUCH = 0x0U, | |
23 | READ_MEM = 0x1U, | |
509fda10 | 24 | SWAP_MAC = 0x2U, |
0fca931a | 25 | }; |
451d1dc8 DL |
26 | |
27 | struct { | |
28 | __uint(type, BPF_MAP_TYPE_ARRAY); | |
29 | __type(key, int); | |
30 | __type(value, struct config); | |
31 | __uint(max_entries, 1); | |
32 | } config_map SEC(".maps"); | |
0fca931a JDB |
33 | |
34 | /* Common stats data record (shared with userspace) */ | |
35 | struct datarec { | |
36 | __u64 processed; | |
37 | __u64 issue; | |
38 | }; | |
39 | ||
451d1dc8 DL |
40 | struct { |
41 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); | |
42 | __type(key, u32); | |
43 | __type(value, struct datarec); | |
44 | __uint(max_entries, 1); | |
45 | } stats_global_map SEC(".maps"); | |
0fca931a JDB |
46 | |
47 | #define MAX_RXQs 64 | |
48 | ||
49 | /* Stats per rx_queue_index (per CPU) */ | |
451d1dc8 DL |
50 | struct { |
51 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); | |
52 | __type(key, u32); | |
53 | __type(value, struct datarec); | |
54 | __uint(max_entries, MAX_RXQs + 1); | |
55 | } rx_queue_index_map SEC(".maps"); | |
0fca931a | 56 | |
509fda10 JDB |
57 | static __always_inline |
58 | void swap_src_dst_mac(void *data) | |
59 | { | |
60 | unsigned short *p = data; | |
61 | unsigned short dst[3]; | |
62 | ||
63 | dst[0] = p[0]; | |
64 | dst[1] = p[1]; | |
65 | dst[2] = p[2]; | |
66 | p[0] = p[3]; | |
67 | p[1] = p[4]; | |
68 | p[2] = p[5]; | |
69 | p[3] = dst[0]; | |
70 | p[4] = dst[1]; | |
71 | p[5] = dst[2]; | |
72 | } | |
73 | ||
0fca931a JDB |
74 | SEC("xdp_prog0") |
75 | int xdp_prognum0(struct xdp_md *ctx) | |
76 | { | |
77 | void *data_end = (void *)(long)ctx->data_end; | |
78 | void *data = (void *)(long)ctx->data; | |
79 | struct datarec *rec, *rxq_rec; | |
80 | int ingress_ifindex; | |
81 | struct config *config; | |
82 | u32 key = 0; | |
83 | ||
84 | /* Global stats record */ | |
85 | rec = bpf_map_lookup_elem(&stats_global_map, &key); | |
86 | if (!rec) | |
87 | return XDP_ABORTED; | |
88 | rec->processed++; | |
89 | ||
90 | /* Accessing ctx->ingress_ifindex, cause BPF to rewrite BPF | |
91 | * instructions inside kernel to access xdp_rxq->dev->ifindex | |
92 | */ | |
93 | ingress_ifindex = ctx->ingress_ifindex; | |
94 | ||
95 | config = bpf_map_lookup_elem(&config_map, &key); | |
96 | if (!config) | |
97 | return XDP_ABORTED; | |
98 | ||
99 | /* Simple test: check ctx provided ifindex is as expected */ | |
100 | if (ingress_ifindex != config->ifindex) { | |
101 | /* count this error case */ | |
102 | rec->issue++; | |
103 | return XDP_ABORTED; | |
104 | } | |
105 | ||
106 | /* Update stats per rx_queue_index. Handle if rx_queue_index | |
107 | * is larger than stats map can contain info for. | |
108 | */ | |
109 | key = ctx->rx_queue_index; | |
110 | if (key >= MAX_RXQs) | |
111 | key = MAX_RXQs; | |
112 | rxq_rec = bpf_map_lookup_elem(&rx_queue_index_map, &key); | |
113 | if (!rxq_rec) | |
114 | return XDP_ABORTED; | |
115 | rxq_rec->processed++; | |
116 | if (key == MAX_RXQs) | |
117 | rxq_rec->issue++; | |
118 | ||
0d25c43a | 119 | /* Default: Don't touch packet data, only count packets */ |
509fda10 | 120 | if (unlikely(config->options & (READ_MEM|SWAP_MAC))) { |
0d25c43a JDB |
121 | struct ethhdr *eth = data; |
122 | ||
123 | if (eth + 1 > data_end) | |
124 | return XDP_ABORTED; | |
125 | ||
126 | /* Avoid compiler removing this: Drop non 802.3 Ethertypes */ | |
127 | if (ntohs(eth->h_proto) < ETH_P_802_3_MIN) | |
128 | return XDP_ABORTED; | |
509fda10 JDB |
129 | |
130 | /* XDP_TX requires changing MAC-addrs, else HW may drop. | |
131 | * Can also be enabled with --swapmac (for test purposes) | |
132 | */ | |
133 | if (unlikely(config->options & SWAP_MAC)) | |
134 | swap_src_dst_mac(data); | |
0d25c43a JDB |
135 | } |
136 | ||
0fca931a JDB |
137 | return config->action; |
138 | } | |
139 | ||
140 | char _license[] SEC("license") = "GPL"; |