155fcaccaSToke Høiland-Jørgensen // SPDX-License-Identifier: GPL-2.0
255fcaccaSToke Høiland-Jørgensen #include <vmlinux.h>
355fcaccaSToke Høiland-Jørgensen #include <bpf/bpf_helpers.h>
455fcaccaSToke Høiland-Jørgensen 
555fcaccaSToke Høiland-Jørgensen #define ETH_ALEN 6
655fcaccaSToke Høiland-Jørgensen #define HDR_SZ (sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + sizeof(struct udphdr))
7487deb3eSAlexander Lobakin 
8487deb3eSAlexander Lobakin /**
9487deb3eSAlexander Lobakin  * enum frame_mark - magics to distinguish page/packet paths
10487deb3eSAlexander Lobakin  * @MARK_XMIT: page was recycled due to the frame being "xmitted" by the NIC.
11487deb3eSAlexander Lobakin  * @MARK_IN: frame is being processed by the input XDP prog.
12487deb3eSAlexander Lobakin  * @MARK_SKB: frame did hit the TC ingress hook as an skb.
13487deb3eSAlexander Lobakin  */
14487deb3eSAlexander Lobakin enum frame_mark {
15487deb3eSAlexander Lobakin 	MARK_XMIT	= 0U,
16487deb3eSAlexander Lobakin 	MARK_IN		= 0x42,
17487deb3eSAlexander Lobakin 	MARK_SKB	= 0x45,
18487deb3eSAlexander Lobakin };
19487deb3eSAlexander Lobakin 
2055fcaccaSToke Høiland-Jørgensen const volatile int ifindex_out;
2155fcaccaSToke Høiland-Jørgensen const volatile int ifindex_in;
2255fcaccaSToke Høiland-Jørgensen const volatile __u8 expect_dst[ETH_ALEN];
2355fcaccaSToke Høiland-Jørgensen volatile int pkts_seen_xdp = 0;
2455fcaccaSToke Høiland-Jørgensen volatile int pkts_seen_zero = 0;
2555fcaccaSToke Høiland-Jørgensen volatile int pkts_seen_tc = 0;
2655fcaccaSToke Høiland-Jørgensen volatile int retcode = XDP_REDIRECT;
2755fcaccaSToke Høiland-Jørgensen 
2855fcaccaSToke Høiland-Jørgensen SEC("xdp")
xdp_redirect(struct xdp_md * xdp)2955fcaccaSToke Høiland-Jørgensen int xdp_redirect(struct xdp_md *xdp)
3055fcaccaSToke Høiland-Jørgensen {
3155fcaccaSToke Høiland-Jørgensen 	__u32 *metadata = (void *)(long)xdp->data_meta;
3255fcaccaSToke Høiland-Jørgensen 	void *data_end = (void *)(long)xdp->data_end;
3355fcaccaSToke Høiland-Jørgensen 	void *data = (void *)(long)xdp->data;
3455fcaccaSToke Høiland-Jørgensen 
3555fcaccaSToke Høiland-Jørgensen 	__u8 *payload = data + HDR_SZ;
3655fcaccaSToke Høiland-Jørgensen 	int ret = retcode;
3755fcaccaSToke Høiland-Jørgensen 
3855fcaccaSToke Høiland-Jørgensen 	if (payload + 1 > data_end)
3955fcaccaSToke Høiland-Jørgensen 		return XDP_ABORTED;
4055fcaccaSToke Høiland-Jørgensen 
4155fcaccaSToke Høiland-Jørgensen 	if (xdp->ingress_ifindex != ifindex_in)
4255fcaccaSToke Høiland-Jørgensen 		return XDP_ABORTED;
4355fcaccaSToke Høiland-Jørgensen 
4455fcaccaSToke Høiland-Jørgensen 	if (metadata + 1 > data)
4555fcaccaSToke Høiland-Jørgensen 		return XDP_ABORTED;
4655fcaccaSToke Høiland-Jørgensen 
4755fcaccaSToke Høiland-Jørgensen 	if (*metadata != 0x42)
4855fcaccaSToke Høiland-Jørgensen 		return XDP_ABORTED;
4955fcaccaSToke Høiland-Jørgensen 
50487deb3eSAlexander Lobakin 	if (*payload == MARK_XMIT)
5155fcaccaSToke Høiland-Jørgensen 		pkts_seen_zero++;
52487deb3eSAlexander Lobakin 
53487deb3eSAlexander Lobakin 	*payload = MARK_IN;
5455fcaccaSToke Høiland-Jørgensen 
55*5640b6d8SAlexander Lobakin 	if (bpf_xdp_adjust_meta(xdp, sizeof(__u64)))
5655fcaccaSToke Høiland-Jørgensen 		return XDP_ABORTED;
5755fcaccaSToke Høiland-Jørgensen 
5855fcaccaSToke Høiland-Jørgensen 	if (retcode > XDP_PASS)
5955fcaccaSToke Høiland-Jørgensen 		retcode--;
6055fcaccaSToke Høiland-Jørgensen 
6155fcaccaSToke Høiland-Jørgensen 	if (ret == XDP_REDIRECT)
6255fcaccaSToke Høiland-Jørgensen 		return bpf_redirect(ifindex_out, 0);
6355fcaccaSToke Høiland-Jørgensen 
6455fcaccaSToke Høiland-Jørgensen 	return ret;
6555fcaccaSToke Høiland-Jørgensen }
6655fcaccaSToke Høiland-Jørgensen 
check_pkt(void * data,void * data_end,const __u32 mark)67487deb3eSAlexander Lobakin static bool check_pkt(void *data, void *data_end, const __u32 mark)
6855fcaccaSToke Høiland-Jørgensen {
6955fcaccaSToke Høiland-Jørgensen 	struct ipv6hdr *iph = data + sizeof(struct ethhdr);
7055fcaccaSToke Høiland-Jørgensen 	__u8 *payload = data + HDR_SZ;
7155fcaccaSToke Høiland-Jørgensen 
7255fcaccaSToke Høiland-Jørgensen 	if (payload + 1 > data_end)
7355fcaccaSToke Høiland-Jørgensen 		return false;
7455fcaccaSToke Høiland-Jørgensen 
75487deb3eSAlexander Lobakin 	if (iph->nexthdr != IPPROTO_UDP || *payload != MARK_IN)
7655fcaccaSToke Høiland-Jørgensen 		return false;
7755fcaccaSToke Høiland-Jørgensen 
7855fcaccaSToke Høiland-Jørgensen 	/* reset the payload so the same packet doesn't get counted twice when
7955fcaccaSToke Høiland-Jørgensen 	 * it cycles back through the kernel path and out the dst veth
8055fcaccaSToke Høiland-Jørgensen 	 */
81487deb3eSAlexander Lobakin 	*payload = mark;
8255fcaccaSToke Høiland-Jørgensen 	return true;
8355fcaccaSToke Høiland-Jørgensen }
8455fcaccaSToke Høiland-Jørgensen 
8555fcaccaSToke Høiland-Jørgensen SEC("xdp")
xdp_count_pkts(struct xdp_md * xdp)8655fcaccaSToke Høiland-Jørgensen int xdp_count_pkts(struct xdp_md *xdp)
8755fcaccaSToke Høiland-Jørgensen {
8855fcaccaSToke Høiland-Jørgensen 	void *data = (void *)(long)xdp->data;
8955fcaccaSToke Høiland-Jørgensen 	void *data_end = (void *)(long)xdp->data_end;
9055fcaccaSToke Høiland-Jørgensen 
91487deb3eSAlexander Lobakin 	if (check_pkt(data, data_end, MARK_XMIT))
9255fcaccaSToke Høiland-Jørgensen 		pkts_seen_xdp++;
9355fcaccaSToke Høiland-Jørgensen 
94487deb3eSAlexander Lobakin 	/* Return %XDP_DROP to recycle the data page with %MARK_XMIT, like
95487deb3eSAlexander Lobakin 	 * it exited a physical NIC. Those pages will be counted in the
9655fcaccaSToke Høiland-Jørgensen 	 * pkts_seen_zero counter above.
9755fcaccaSToke Høiland-Jørgensen 	 */
9855fcaccaSToke Høiland-Jørgensen 	return XDP_DROP;
9955fcaccaSToke Høiland-Jørgensen }
10055fcaccaSToke Høiland-Jørgensen 
10155fcaccaSToke Høiland-Jørgensen SEC("tc")
tc_count_pkts(struct __sk_buff * skb)10255fcaccaSToke Høiland-Jørgensen int tc_count_pkts(struct __sk_buff *skb)
10355fcaccaSToke Høiland-Jørgensen {
10455fcaccaSToke Høiland-Jørgensen 	void *data = (void *)(long)skb->data;
10555fcaccaSToke Høiland-Jørgensen 	void *data_end = (void *)(long)skb->data_end;
10655fcaccaSToke Høiland-Jørgensen 
107487deb3eSAlexander Lobakin 	if (check_pkt(data, data_end, MARK_SKB))
10855fcaccaSToke Høiland-Jørgensen 		pkts_seen_tc++;
10955fcaccaSToke Høiland-Jørgensen 
110487deb3eSAlexander Lobakin 	/* Will be either recycled or freed, %MARK_SKB makes sure it won't
111487deb3eSAlexander Lobakin 	 * hit any of the counters above.
112487deb3eSAlexander Lobakin 	 */
11355fcaccaSToke Høiland-Jørgensen 	return 0;
11455fcaccaSToke Høiland-Jørgensen }
11555fcaccaSToke Høiland-Jørgensen 
11655fcaccaSToke Høiland-Jørgensen char _license[] SEC("license") = "GPL";
117