mirror of
https://github.com/torvalds/linux.git
synced 2024-12-18 09:02:17 +00:00
ffeedafbf0
eBPF programs attached to kprobes need to filter based on current->pid, uid and other fields, so introduce helper functions: u64 bpf_get_current_pid_tgid(void) Return: current->tgid << 32 | current->pid u64 bpf_get_current_uid_gid(void) Return: current_gid << 32 | current_uid bpf_get_current_comm(char *buf, int size_of_buf) stores current->comm into buf They can be used from the programs attached to TC as well to classify packets based on current task fields. Update tracex2 example to print histogram of write syscalls for each process instead of aggregated for all. Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
101 lines
2.3 KiB
C
101 lines
2.3 KiB
C
/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
|
|
*
|
|
* 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.
|
|
*/
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/version.h>
|
|
#include <uapi/linux/bpf.h>
|
|
#include "bpf_helpers.h"
|
|
|
|
struct bpf_map_def SEC("maps") my_map = {
|
|
.type = BPF_MAP_TYPE_HASH,
|
|
.key_size = sizeof(long),
|
|
.value_size = sizeof(long),
|
|
.max_entries = 1024,
|
|
};
|
|
|
|
/* kprobe is NOT a stable ABI. If kernel internals change this bpf+kprobe
|
|
* example will no longer be meaningful
|
|
*/
|
|
SEC("kprobe/kfree_skb")
|
|
int bpf_prog2(struct pt_regs *ctx)
|
|
{
|
|
long loc = 0;
|
|
long init_val = 1;
|
|
long *value;
|
|
|
|
/* x64 specific: read ip of kfree_skb caller.
|
|
* non-portable version of __builtin_return_address(0)
|
|
*/
|
|
bpf_probe_read(&loc, sizeof(loc), (void *)ctx->sp);
|
|
|
|
value = bpf_map_lookup_elem(&my_map, &loc);
|
|
if (value)
|
|
*value += 1;
|
|
else
|
|
bpf_map_update_elem(&my_map, &loc, &init_val, BPF_ANY);
|
|
return 0;
|
|
}
|
|
|
|
static unsigned int log2(unsigned int v)
|
|
{
|
|
unsigned int r;
|
|
unsigned int shift;
|
|
|
|
r = (v > 0xFFFF) << 4; v >>= r;
|
|
shift = (v > 0xFF) << 3; v >>= shift; r |= shift;
|
|
shift = (v > 0xF) << 2; v >>= shift; r |= shift;
|
|
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
|
|
r |= (v >> 1);
|
|
return r;
|
|
}
|
|
|
|
static unsigned int log2l(unsigned long v)
|
|
{
|
|
unsigned int hi = v >> 32;
|
|
if (hi)
|
|
return log2(hi) + 32;
|
|
else
|
|
return log2(v);
|
|
}
|
|
|
|
struct hist_key {
|
|
char comm[16];
|
|
u64 pid_tgid;
|
|
u64 uid_gid;
|
|
u32 index;
|
|
};
|
|
|
|
struct bpf_map_def SEC("maps") my_hist_map = {
|
|
.type = BPF_MAP_TYPE_HASH,
|
|
.key_size = sizeof(struct hist_key),
|
|
.value_size = sizeof(long),
|
|
.max_entries = 1024,
|
|
};
|
|
|
|
SEC("kprobe/sys_write")
|
|
int bpf_prog3(struct pt_regs *ctx)
|
|
{
|
|
long write_size = ctx->dx; /* arg3 */
|
|
long init_val = 1;
|
|
long *value;
|
|
struct hist_key key = {};
|
|
|
|
key.index = log2l(write_size);
|
|
key.pid_tgid = bpf_get_current_pid_tgid();
|
|
key.uid_gid = bpf_get_current_uid_gid();
|
|
bpf_get_current_comm(&key.comm, sizeof(key.comm));
|
|
|
|
value = bpf_map_lookup_elem(&my_hist_map, &key);
|
|
if (value)
|
|
__sync_fetch_and_add(value, 1);
|
|
else
|
|
bpf_map_update_elem(&my_hist_map, &key, &init_val, BPF_ANY);
|
|
return 0;
|
|
}
|
|
char _license[] SEC("license") = "GPL";
|
|
u32 _version SEC("version") = LINUX_VERSION_CODE;
|