mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
7cf245a37e
Fix all files in samples/bpf to include libbpf header files with the bpf/
prefix, to be consistent with external users of the library. Also ensure
that all includes of exported libbpf header files (those that are exported
on 'make install' of the library) use bracketed includes instead of quoted.
To make sure no new files are introduced that doesn't include the bpf/
prefix in its include, remove tools/lib/bpf from the include path entirely,
and use tools/lib instead.
Fixes: 6910d7d386
("selftests/bpf: Ensure bpf_helper_defs.h are taken from selftests dir")
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Link: https://lore.kernel.org/bpf/157952560911.1683545.8795966751309534150.stgit@toke.dk
254 lines
6.0 KiB
C
254 lines
6.0 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 <stdint.h>
|
|
#include <stddef.h>
|
|
#include <linux/bpf.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/in.h>
|
|
#include <linux/in6.h>
|
|
#include <linux/tcp.h>
|
|
#include <linux/udp.h>
|
|
#include <linux/icmpv6.h>
|
|
#include <linux/if_ether.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\n", skb->len, skb->hash,
|
|
skb->protocol);
|
|
printk("cb %d ingress_ifindex %d ifindex %d\n", 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\n", skb->cb[0], skb->cb[1],
|
|
skb->cb[2]);
|
|
printk("cb3: %x cb4: %x\n", 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\n");
|
|
return BPF_DROP;
|
|
}
|
|
|
|
printk("src: %x dst: %x\n", 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\n", 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\n");
|
|
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\n", 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\n", 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\n", ret);
|
|
return BPF_DROP;
|
|
}
|
|
|
|
if (old_ip == 0x2fea8c0) {
|
|
printk("out: rewriting from %x to %x\n", 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\n", ret);
|
|
}
|
|
|
|
ehdr.h_proto = __constant_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\n", 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\n", 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\n");
|
|
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\n", ifindex);
|
|
return bpf_redirect(ifindex, 0);
|
|
}
|
|
|
|
/* Drop all packets */
|
|
SEC("drop_all")
|
|
int do_drop_all(struct __sk_buff *skb)
|
|
{
|
|
printk("dropping with: %d\n", BPF_DROP);
|
|
return BPF_DROP;
|
|
}
|
|
|
|
char _license[] SEC("license") = "GPL";
|