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