blob: 5811c2274943fc824eb02b39da742df6cb672b1c [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
from bcc import BPF
from unittest import main, TestCase
class TestClang(TestCase):
def test_complex(self):
b = BPF(src_file="test_clang_complex.c", debug=0)
fn = b.load_func("handle_packet", BPF.SCHED_CLS)
def test_printk(self):
text = """
#include <bcc/proto.h>
int handle_packet(void *ctx) {
u8 *cursor = 0;
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
bpf_trace_printk("ethernet->dst = %llx, ethernet->src = %llx\\n",
ethernet->dst, ethernet->src);
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("handle_packet", BPF.SCHED_CLS)
def test_probe_read1(self):
text = """
#include <linux/sched.h>
#include <uapi/linux/ptrace.h>
int count_sched(struct pt_regs *ctx, struct task_struct *prev) {
pid_t p = prev->pid;
return (p != -1);
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("count_sched", BPF.KPROBE)
def test_probe_read2(self):
text = """
#include <linux/sched.h>
#include <uapi/linux/ptrace.h>
int count_foo(struct pt_regs *ctx, unsigned long a, unsigned long b) {
return (a != b);
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("count_foo", BPF.KPROBE)
def test_probe_read_keys(self):
text = """
#include <uapi/linux/ptrace.h>
#include <linux/blkdev.h>
BPF_HASH(start, struct request *);
int do_request(struct pt_regs *ctx, struct request *req) {
u64 ts = bpf_ktime_get_ns();
start.update(&req, &ts);
return 0;
}
int do_completion(struct pt_regs *ctx, struct request *req) {
u64 *tsp = start.lookup(&req);
if (tsp != 0) {
start.delete(&req);
}
return 0;
}
"""
b = BPF(text=text, debug=0)
fns = b.load_funcs(BPF.KPROBE)
def test_sscanf(self):
text = """
BPF_TABLE("hash", int, struct { u64 a; u64 b; u64 c:36; u64 d:28; struct { u32 a; u32 b; } s; }, stats, 10);
int foo(void *ctx) {
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("foo", BPF.KPROBE)
t = b.get_table("stats")
s1 = t.key_sprintf(t.Key(2))
self.assertEqual(s1, b"0x2")
s2 = t.leaf_sprintf(t.Leaf(2, 3, 4, 1, (5, 6)))
l = t.leaf_scanf(s2)
self.assertEqual(l.a, 2)
self.assertEqual(l.b, 3)
self.assertEqual(l.c, 4)
self.assertEqual(l.d, 1)
self.assertEqual(l.s.a, 5)
self.assertEqual(l.s.b, 6)
def test_iosnoop(self):
text = """
#include <linux/blkdev.h>
#include <uapi/linux/ptrace.h>
struct key_t {
struct request *req;
};
BPF_TABLE("hash", struct key_t, u64, start, 1024);
int do_request(struct pt_regs *ctx, struct request *req) {
struct key_t key = {};
bpf_trace_printk("traced start %d\\n", req->__data_len);
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("do_request", BPF.KPROBE)
def test_blk_start_request(self):
text = """
#include <linux/blkdev.h>
#include <uapi/linux/ptrace.h>
int do_request(struct pt_regs *ctx, int req) {
bpf_trace_printk("req ptr: 0x%x\\n", req);
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("do_request", BPF.KPROBE)
def test_bpf_hash(self):
text = """
BPF_HASH(table1);
BPF_HASH(table2, u32);
BPF_HASH(table3, u32, int);
"""
b = BPF(text=text, debug=0)
def test_consecutive_probe_read(self):
text = """
#include <linux/fs.h>
#include <linux/mount.h>
BPF_HASH(table1, struct super_block *);
int trace_entry(struct pt_regs *ctx, struct file *file) {
if (!file) return 0;
struct vfsmount *mnt = file->f_path.mnt;
if (mnt) {
struct super_block *k = mnt->mnt_sb;
u64 zero = 0;
table1.update(&k, &zero);
k = mnt->mnt_sb;
table1.update(&k, &zero);
}
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("trace_entry", BPF.KPROBE)
def test_nested_probe_read(self):
text = """
#include <linux/fs.h>
int trace_entry(struct pt_regs *ctx, struct file *file) {
if (!file) return 0;
const char *name = file->f_path.dentry->d_name.name;
bpf_trace_printk("%s\\n", name);
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("trace_entry", BPF.KPROBE)
def test_char_array_probe(self):
BPF(text="""#include <linux/blkdev.h>
int kprobe__blk_update_request(struct pt_regs *ctx, struct request *req) {
bpf_trace_printk("%s\\n", req->rq_disk->disk_name);
return 0;
}""")
def test_probe_read_helper(self):
b = BPF(text="""
#include <linux/fs.h>
static void print_file_name(struct file *file) {
if (!file) return;
const char *name = file->f_path.dentry->d_name.name;
bpf_trace_printk("%s\\n", name);
}
static void print_file_name2(int unused, struct file *file) {
print_file_name(file);
}
int trace_entry1(struct pt_regs *ctx, struct file *file) {
print_file_name(file);
return 0;
}
int trace_entry2(struct pt_regs *ctx, int unused, struct file *file) {
print_file_name2(unused, file);
return 0;
}
""")
fn = b.load_func("trace_entry1", BPF.KPROBE)
fn = b.load_func("trace_entry2", BPF.KPROBE)
def test_probe_struct_assign(self):
b = BPF(text = """
#include <uapi/linux/ptrace.h>
struct args_t {
const char *filename;
int flags;
int mode;
};
int kprobe__sys_open(struct pt_regs *ctx, const char *filename,
int flags, int mode) {
struct args_t args = {};
args.filename = filename;
args.flags = flags;
args.mode = mode;
bpf_trace_printk("%s\\n", args.filename);
return 0;
};
""")
def test_task_switch(self):
b = BPF(text="""
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
struct key_t {
u32 prev_pid;
u32 curr_pid;
};
BPF_TABLE("hash", struct key_t, u64, stats, 1024);
int kprobe__finish_task_switch(struct pt_regs *ctx, struct task_struct *prev) {
struct key_t key = {};
u64 zero = 0, *val;
key.curr_pid = bpf_get_current_pid_tgid();
key.prev_pid = prev->pid;
val = stats.lookup_or_init(&key, &zero);
(*val)++;
return 0;
}
""")
def test_probe_simple_assign(self):
b = BPF(text="""
#include <uapi/linux/ptrace.h>
#include <linux/gfp.h>
struct leaf { size_t size; };
BPF_HASH(simple_map, u32, struct leaf);
int kprobe____kmalloc(struct pt_regs *ctx, size_t size) {
u32 pid = bpf_get_current_pid_tgid();
struct leaf* leaf = simple_map.lookup(&pid);
if (leaf)
leaf->size += size;
return 0;
}""")
def test_unop_probe_read(self):
text = """
#include <linux/blkdev.h>
int trace_entry(struct pt_regs *ctx, struct request *req) {
if (!(req->bio->bi_rw & 1))
return 1;
if (((req->bio->bi_rw)))
return 1;
return 0;
}
"""
b = BPF(text=text)
fn = b.load_func("trace_entry", BPF.KPROBE)
def test_complex_leaf_types(self):
text = """
struct list;
struct list {
struct list *selfp;
struct list *another_selfp;
struct list *selfp_array[2];
};
struct empty {
};
union emptyu {
struct empty *em1;
struct empty em2;
struct empty em3;
struct empty em4;
};
BPF_TABLE("array", int, struct list, t1, 1);
BPF_TABLE("array", int, struct list *, t2, 1);
BPF_TABLE("array", int, union emptyu, t3, 1);
"""
b = BPF(text=text)
import ctypes
self.assertEqual(ctypes.sizeof(b["t3"].Leaf), 8)
def test_cflags(self):
text = """
#ifndef MYFLAG
#error "MYFLAG not set as expected"
#endif
"""
b = BPF(text=text, cflags=["-DMYFLAG"])
def test_exported_maps(self):
b1 = BPF(text="""BPF_TABLE_PUBLIC("hash", int, int, table1, 10);""")
b2 = BPF(text="""BPF_TABLE("extern", int, int, table1, 10);""")
if __name__ == "__main__":
main()