1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <vmlinux.h> |
4 | #include "xdp_metadata.h" |
5 | #include <bpf/bpf_helpers.h> |
6 | #include <bpf/bpf_endian.h> |
7 | |
8 | struct { |
9 | __uint(type, BPF_MAP_TYPE_XSKMAP); |
10 | __uint(max_entries, 256); |
11 | __type(key, __u32); |
12 | __type(value, __u32); |
13 | } xsk SEC(".maps" ); |
14 | |
15 | __u64 pkts_skip = 0; |
16 | __u64 pkts_fail = 0; |
17 | __u64 pkts_redir = 0; |
18 | |
19 | extern int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx, |
20 | __u64 *timestamp) __ksym; |
21 | extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash, |
22 | enum *rss_type) __ksym; |
23 | extern int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, |
24 | __be16 *vlan_proto, |
25 | __u16 *vlan_tci) __ksym; |
26 | |
27 | SEC("xdp.frags" ) |
28 | int rx(struct xdp_md *ctx) |
29 | { |
30 | void *data, *data_meta, *data_end; |
31 | struct ipv6hdr *ip6h = NULL; |
32 | struct udphdr *udp = NULL; |
33 | struct iphdr *iph = NULL; |
34 | struct xdp_meta *meta; |
35 | struct ethhdr *eth; |
36 | int err; |
37 | |
38 | data = (void *)(long)ctx->data; |
39 | data_end = (void *)(long)ctx->data_end; |
40 | eth = data; |
41 | |
42 | if (eth + 1 < data_end && (eth->h_proto == bpf_htons(ETH_P_8021AD) || |
43 | eth->h_proto == bpf_htons(ETH_P_8021Q))) |
44 | eth = (void *)eth + sizeof(struct vlan_hdr); |
45 | |
46 | if (eth + 1 < data_end && eth->h_proto == bpf_htons(ETH_P_8021Q)) |
47 | eth = (void *)eth + sizeof(struct vlan_hdr); |
48 | |
49 | if (eth + 1 < data_end) { |
50 | if (eth->h_proto == bpf_htons(ETH_P_IP)) { |
51 | iph = (void *)(eth + 1); |
52 | if (iph + 1 < data_end && iph->protocol == IPPROTO_UDP) |
53 | udp = (void *)(iph + 1); |
54 | } |
55 | if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { |
56 | ip6h = (void *)(eth + 1); |
57 | if (ip6h + 1 < data_end && ip6h->nexthdr == IPPROTO_UDP) |
58 | udp = (void *)(ip6h + 1); |
59 | } |
60 | if (udp && udp + 1 > data_end) |
61 | udp = NULL; |
62 | } |
63 | |
64 | if (!udp) { |
65 | __sync_add_and_fetch(&pkts_skip, 1); |
66 | return XDP_PASS; |
67 | } |
68 | |
69 | /* Forwarding UDP:9091 to AF_XDP */ |
70 | if (udp->dest != bpf_htons(9091)) { |
71 | __sync_add_and_fetch(&pkts_skip, 1); |
72 | return XDP_PASS; |
73 | } |
74 | |
75 | err = bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct xdp_meta)); |
76 | if (err) { |
77 | __sync_add_and_fetch(&pkts_fail, 1); |
78 | return XDP_PASS; |
79 | } |
80 | |
81 | data = (void *)(long)ctx->data; |
82 | data_meta = (void *)(long)ctx->data_meta; |
83 | meta = data_meta; |
84 | |
85 | if (meta + 1 > data) { |
86 | __sync_add_and_fetch(&pkts_fail, 1); |
87 | return XDP_PASS; |
88 | } |
89 | |
90 | meta->hint_valid = 0; |
91 | |
92 | meta->xdp_timestamp = bpf_ktime_get_tai_ns(); |
93 | err = bpf_xdp_metadata_rx_timestamp(ctx, &meta->rx_timestamp); |
94 | if (err) |
95 | meta->rx_timestamp_err = err; |
96 | else |
97 | meta->hint_valid |= XDP_META_FIELD_TS; |
98 | |
99 | err = bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, |
100 | &meta->rx_hash_type); |
101 | if (err) |
102 | meta->rx_hash_err = err; |
103 | else |
104 | meta->hint_valid |= XDP_META_FIELD_RSS; |
105 | |
106 | err = bpf_xdp_metadata_rx_vlan_tag(ctx, &meta->rx_vlan_proto, |
107 | &meta->rx_vlan_tci); |
108 | if (err) |
109 | meta->rx_vlan_tag_err = err; |
110 | else |
111 | meta->hint_valid |= XDP_META_FIELD_VLAN_TAG; |
112 | |
113 | __sync_add_and_fetch(&pkts_redir, 1); |
114 | return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS); |
115 | } |
116 | |
117 | char _license[] SEC("license" ) = "GPL" ; |
118 | |