1 // SPDX-License-Identifier: GPL-2.0 2 #include <vmlinux.h> 3 #include <bpf/bpf_helpers.h> 4 5 #define ETH_ALEN 6 6 #define HDR_SZ (sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + sizeof(struct udphdr)) 7 const volatile int ifindex_out; 8 const volatile int ifindex_in; 9 const volatile __u8 expect_dst[ETH_ALEN]; 10 volatile int pkts_seen_xdp = 0; 11 volatile int pkts_seen_zero = 0; 12 volatile int pkts_seen_tc = 0; 13 volatile int retcode = XDP_REDIRECT; 14 15 SEC("xdp") xdp_redirect(struct xdp_md * xdp)16int xdp_redirect(struct xdp_md *xdp) 17 { 18 __u32 *metadata = (void *)(long)xdp->data_meta; 19 void *data_end = (void *)(long)xdp->data_end; 20 void *data = (void *)(long)xdp->data; 21 22 __u8 *payload = data + HDR_SZ; 23 int ret = retcode; 24 25 if (payload + 1 > data_end) 26 return XDP_ABORTED; 27 28 if (xdp->ingress_ifindex != ifindex_in) 29 return XDP_ABORTED; 30 31 if (metadata + 1 > data) 32 return XDP_ABORTED; 33 34 if (*metadata != 0x42) 35 return XDP_ABORTED; 36 37 if (*payload == 0) { 38 *payload = 0x42; 39 pkts_seen_zero++; 40 } 41 42 if (bpf_xdp_adjust_meta(xdp, 4)) 43 return XDP_ABORTED; 44 45 if (retcode > XDP_PASS) 46 retcode--; 47 48 if (ret == XDP_REDIRECT) 49 return bpf_redirect(ifindex_out, 0); 50 51 return ret; 52 } 53 check_pkt(void * data,void * data_end)54static bool check_pkt(void *data, void *data_end) 55 { 56 struct ipv6hdr *iph = data + sizeof(struct ethhdr); 57 __u8 *payload = data + HDR_SZ; 58 59 if (payload + 1 > data_end) 60 return false; 61 62 if (iph->nexthdr != IPPROTO_UDP || *payload != 0x42) 63 return false; 64 65 /* reset the payload so the same packet doesn't get counted twice when 66 * it cycles back through the kernel path and out the dst veth 67 */ 68 *payload = 0; 69 return true; 70 } 71 72 SEC("xdp") xdp_count_pkts(struct xdp_md * xdp)73int xdp_count_pkts(struct xdp_md *xdp) 74 { 75 void *data = (void *)(long)xdp->data; 76 void *data_end = (void *)(long)xdp->data_end; 77 78 if (check_pkt(data, data_end)) 79 pkts_seen_xdp++; 80 81 /* Return XDP_DROP to make sure the data page is recycled, like when it 82 * exits a physical NIC. Recycled pages will be counted in the 83 * pkts_seen_zero counter above. 84 */ 85 return XDP_DROP; 86 } 87 88 SEC("tc") tc_count_pkts(struct __sk_buff * skb)89int tc_count_pkts(struct __sk_buff *skb) 90 { 91 void *data = (void *)(long)skb->data; 92 void *data_end = (void *)(long)skb->data_end; 93 94 if (check_pkt(data, data_end)) 95 pkts_seen_tc++; 96 97 return 0; 98 } 99 100 char _license[] SEC("license") = "GPL"; 101