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, 4); |
11 | __type(key, __u32); |
12 | __type(value, __u32); |
13 | } xsk SEC(".maps" ); |
14 | |
15 | struct { |
16 | __uint(type, BPF_MAP_TYPE_PROG_ARRAY); |
17 | __uint(max_entries, 1); |
18 | __type(key, __u32); |
19 | __type(value, __u32); |
20 | } prog_arr SEC(".maps" ); |
21 | |
22 | extern int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx, |
23 | __u64 *timestamp) __ksym; |
24 | extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash, |
25 | enum *rss_type) __ksym; |
26 | extern int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx, |
27 | __be16 *vlan_proto, |
28 | __u16 *vlan_tci) __ksym; |
29 | |
30 | SEC("xdp" ) |
31 | int rx(struct xdp_md *ctx) |
32 | { |
33 | void *data, *data_meta, *data_end; |
34 | struct ipv6hdr *ip6h = NULL; |
35 | struct ethhdr *eth = NULL; |
36 | struct udphdr *udp = NULL; |
37 | struct iphdr *iph = NULL; |
38 | struct xdp_meta *meta; |
39 | u64 timestamp = -1; |
40 | int ret; |
41 | |
42 | data = (void *)(long)ctx->data; |
43 | data_end = (void *)(long)ctx->data_end; |
44 | eth = data; |
45 | if (eth + 1 < data_end) { |
46 | if (eth->h_proto == bpf_htons(ETH_P_IP)) { |
47 | iph = (void *)(eth + 1); |
48 | if (iph + 1 < data_end && iph->protocol == IPPROTO_UDP) |
49 | udp = (void *)(iph + 1); |
50 | } |
51 | if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { |
52 | ip6h = (void *)(eth + 1); |
53 | if (ip6h + 1 < data_end && ip6h->nexthdr == IPPROTO_UDP) |
54 | udp = (void *)(ip6h + 1); |
55 | } |
56 | if (udp && udp + 1 > data_end) |
57 | udp = NULL; |
58 | } |
59 | |
60 | if (!udp) |
61 | return XDP_PASS; |
62 | |
63 | /* Forwarding UDP:8080 to AF_XDP */ |
64 | if (udp->dest != bpf_htons(8080)) |
65 | return XDP_PASS; |
66 | |
67 | /* Reserve enough for all custom metadata. */ |
68 | |
69 | ret = bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct xdp_meta)); |
70 | if (ret != 0) |
71 | return XDP_DROP; |
72 | |
73 | data = (void *)(long)ctx->data; |
74 | data_meta = (void *)(long)ctx->data_meta; |
75 | |
76 | if (data_meta + sizeof(struct xdp_meta) > data) |
77 | return XDP_DROP; |
78 | |
79 | meta = data_meta; |
80 | |
81 | /* Export metadata. */ |
82 | |
83 | /* We expect veth bpf_xdp_metadata_rx_timestamp to return 0 HW |
84 | * timestamp, so put some non-zero value into AF_XDP frame for |
85 | * the userspace. |
86 | */ |
87 | bpf_xdp_metadata_rx_timestamp(ctx, ×tamp); |
88 | if (timestamp == 0) |
89 | meta->rx_timestamp = 1; |
90 | |
91 | bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type); |
92 | bpf_xdp_metadata_rx_vlan_tag(ctx, &meta->rx_vlan_proto, |
93 | &meta->rx_vlan_tci); |
94 | |
95 | return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS); |
96 | } |
97 | |
98 | char _license[] SEC("license" ) = "GPL" ; |
99 | |