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