linux/samples/bpf/test_lwt_bpf.c
Daniel T. Lee e8acf8f47a samples/bpf: use vmlinux.h instead of implicit headers in BPF test program
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>
2023-01-15 13:32:45 -08:00

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";