forked from mirrors/linux
		
	This commit applies vmlinux.h to BPF functionality testing program. Macros that were not defined despite migration to "vmlinux.h" were defined separately in individual files. Signed-off-by: Daniel T. Lee <danieltimlee@gmail.com> Link: https://lore.kernel.org/r/20230115071613.125791-10-danieltimlee@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
		
			
				
	
	
		
			245 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or
 | 
						|
 * modify it under the terms of version 2 of the GNU General Public
 | 
						|
 * License as published by the Free Software Foundation.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful, but
 | 
						|
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 | 
						|
 * General Public License for more details.
 | 
						|
 */
 | 
						|
 | 
						|
#include "vmlinux.h"
 | 
						|
#include "net_shared.h"
 | 
						|
#include <bpf/bpf_helpers.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
# define printk(fmt, ...)						\
 | 
						|
		({							\
 | 
						|
			char ____fmt[] = fmt;				\
 | 
						|
			bpf_trace_printk(____fmt, sizeof(____fmt),	\
 | 
						|
				     ##__VA_ARGS__);			\
 | 
						|
		})
 | 
						|
 | 
						|
#define CB_MAGIC 1234
 | 
						|
 | 
						|
/* Test: Pass all packets through */
 | 
						|
SEC("nop")
 | 
						|
int do_nop(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	return BPF_OK;
 | 
						|
}
 | 
						|
 | 
						|
/* Test: Verify context information can be accessed */
 | 
						|
SEC("test_ctx")
 | 
						|
int do_test_ctx(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	skb->cb[0] = CB_MAGIC;
 | 
						|
	printk("len %d hash %d protocol %d", skb->len, skb->hash,
 | 
						|
	       skb->protocol);
 | 
						|
	printk("cb %d ingress_ifindex %d ifindex %d", skb->cb[0],
 | 
						|
	       skb->ingress_ifindex, skb->ifindex);
 | 
						|
 | 
						|
	return BPF_OK;
 | 
						|
}
 | 
						|
 | 
						|
/* Test: Ensure skb->cb[] buffer is cleared */
 | 
						|
SEC("test_cb")
 | 
						|
int do_test_cb(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	printk("cb0: %x cb1: %x cb2: %x", skb->cb[0], skb->cb[1],
 | 
						|
	       skb->cb[2]);
 | 
						|
	printk("cb3: %x cb4: %x", skb->cb[3], skb->cb[4]);
 | 
						|
 | 
						|
	return BPF_OK;
 | 
						|
}
 | 
						|
 | 
						|
/* Test: Verify skb data can be read */
 | 
						|
SEC("test_data")
 | 
						|
int do_test_data(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	void *data = (void *)(long)skb->data;
 | 
						|
	void *data_end = (void *)(long)skb->data_end;
 | 
						|
	struct iphdr *iph = data;
 | 
						|
 | 
						|
	if (data + sizeof(*iph) > data_end) {
 | 
						|
		printk("packet truncated");
 | 
						|
		return BPF_DROP;
 | 
						|
	}
 | 
						|
 | 
						|
	printk("src: %x dst: %x", iph->saddr, iph->daddr);
 | 
						|
 | 
						|
	return BPF_OK;
 | 
						|
}
 | 
						|
 | 
						|
#define IP_CSUM_OFF offsetof(struct iphdr, check)
 | 
						|
#define IP_DST_OFF offsetof(struct iphdr, daddr)
 | 
						|
#define IP_SRC_OFF offsetof(struct iphdr, saddr)
 | 
						|
#define IP_PROTO_OFF offsetof(struct iphdr, protocol)
 | 
						|
#define TCP_CSUM_OFF offsetof(struct tcphdr, check)
 | 
						|
#define UDP_CSUM_OFF offsetof(struct udphdr, check)
 | 
						|
#define IS_PSEUDO 0x10
 | 
						|
 | 
						|
static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
 | 
						|
			  uint32_t new_ip, int rw_daddr)
 | 
						|
{
 | 
						|
	int ret, off = 0, flags = IS_PSEUDO;
 | 
						|
	uint8_t proto;
 | 
						|
 | 
						|
	ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1);
 | 
						|
	if (ret < 0) {
 | 
						|
		printk("bpf_l4_csum_replace failed: %d", ret);
 | 
						|
		return BPF_DROP;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (proto) {
 | 
						|
	case IPPROTO_TCP:
 | 
						|
		off = TCP_CSUM_OFF;
 | 
						|
		break;
 | 
						|
 | 
						|
	case IPPROTO_UDP:
 | 
						|
		off = UDP_CSUM_OFF;
 | 
						|
		flags |= BPF_F_MARK_MANGLED_0;
 | 
						|
		break;
 | 
						|
 | 
						|
	case IPPROTO_ICMPV6:
 | 
						|
		off = offsetof(struct icmp6hdr, icmp6_cksum);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (off) {
 | 
						|
		ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
 | 
						|
					  flags | sizeof(new_ip));
 | 
						|
		if (ret < 0) {
 | 
						|
			printk("bpf_l4_csum_replace failed: %d");
 | 
						|
			return BPF_DROP;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof(new_ip));
 | 
						|
	if (ret < 0) {
 | 
						|
		printk("bpf_l3_csum_replace failed: %d", ret);
 | 
						|
		return BPF_DROP;
 | 
						|
	}
 | 
						|
 | 
						|
	if (rw_daddr)
 | 
						|
		ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof(new_ip), 0);
 | 
						|
	else
 | 
						|
		ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof(new_ip), 0);
 | 
						|
 | 
						|
	if (ret < 0) {
 | 
						|
		printk("bpf_skb_store_bytes() failed: %d", ret);
 | 
						|
		return BPF_DROP;
 | 
						|
	}
 | 
						|
 | 
						|
	return BPF_OK;
 | 
						|
}
 | 
						|
 | 
						|
/* Test: Verify skb data can be modified */
 | 
						|
SEC("test_rewrite")
 | 
						|
int do_test_rewrite(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	uint32_t old_ip, new_ip = 0x3fea8c0;
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4);
 | 
						|
	if (ret < 0) {
 | 
						|
		printk("bpf_skb_load_bytes failed: %d", ret);
 | 
						|
		return BPF_DROP;
 | 
						|
	}
 | 
						|
 | 
						|
	if (old_ip == 0x2fea8c0) {
 | 
						|
		printk("out: rewriting from %x to %x", old_ip, new_ip);
 | 
						|
		return rewrite(skb, old_ip, new_ip, 1);
 | 
						|
	}
 | 
						|
 | 
						|
	return BPF_OK;
 | 
						|
}
 | 
						|
 | 
						|
static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	uint64_t smac = SRC_MAC, dmac = DST_MAC;
 | 
						|
	int ret, ifindex = DST_IFINDEX;
 | 
						|
	struct ethhdr ehdr;
 | 
						|
 | 
						|
	ret = bpf_skb_change_head(skb, 14, 0);
 | 
						|
	if (ret < 0) {
 | 
						|
		printk("skb_change_head() failed: %d", ret);
 | 
						|
	}
 | 
						|
 | 
						|
	ehdr.h_proto = bpf_htons(ETH_P_IP);
 | 
						|
	memcpy(&ehdr.h_source, &smac, 6);
 | 
						|
	memcpy(&ehdr.h_dest, &dmac, 6);
 | 
						|
 | 
						|
	ret = bpf_skb_store_bytes(skb, 0, &ehdr, sizeof(ehdr), 0);
 | 
						|
	if (ret < 0) {
 | 
						|
		printk("skb_store_bytes() failed: %d", ret);
 | 
						|
		return BPF_DROP;
 | 
						|
	}
 | 
						|
 | 
						|
	return bpf_redirect(ifindex, 0);
 | 
						|
}
 | 
						|
 | 
						|
SEC("push_ll_and_redirect_silent")
 | 
						|
int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	return __do_push_ll_and_redirect(skb);
 | 
						|
}
 | 
						|
 | 
						|
SEC("push_ll_and_redirect")
 | 
						|
int do_push_ll_and_redirect(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	int ret, ifindex = DST_IFINDEX;
 | 
						|
 | 
						|
	ret = __do_push_ll_and_redirect(skb);
 | 
						|
	if (ret >= 0)
 | 
						|
		printk("redirected to %d", ifindex);
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
static inline void __fill_garbage(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	uint64_t f = 0xFFFFFFFFFFFFFFFF;
 | 
						|
 | 
						|
	bpf_skb_store_bytes(skb, 0, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 8, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 16, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 24, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 32, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 40, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 48, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 56, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 64, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 72, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 80, &f, sizeof(f), 0);
 | 
						|
	bpf_skb_store_bytes(skb, 88, &f, sizeof(f), 0);
 | 
						|
}
 | 
						|
 | 
						|
SEC("fill_garbage")
 | 
						|
int do_fill_garbage(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	__fill_garbage(skb);
 | 
						|
	printk("Set initial 96 bytes of header to FF");
 | 
						|
	return BPF_OK;
 | 
						|
}
 | 
						|
 | 
						|
SEC("fill_garbage_and_redirect")
 | 
						|
int do_fill_garbage_and_redirect(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	int ifindex = DST_IFINDEX;
 | 
						|
	__fill_garbage(skb);
 | 
						|
	printk("redirected to %d", ifindex);
 | 
						|
	return bpf_redirect(ifindex, 0);
 | 
						|
}
 | 
						|
 | 
						|
/* Drop all packets */
 | 
						|
SEC("drop_all")
 | 
						|
int do_drop_all(struct __sk_buff *skb)
 | 
						|
{
 | 
						|
	printk("dropping with: %d", BPF_DROP);
 | 
						|
	return BPF_DROP;
 | 
						|
}
 | 
						|
 | 
						|
char _license[] SEC("license") = "GPL";
 |