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 xdp_rss_hash_type *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