162306a36Sopenharmony_ci/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or
462306a36Sopenharmony_ci * modify it under the terms of version 2 of the GNU General Public
562306a36Sopenharmony_ci * License as published by the Free Software Foundation.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include "vmlinux.h"
862306a36Sopenharmony_ci#include <linux/version.h>
962306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
1062306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
1162306a36Sopenharmony_ci#include <bpf/bpf_core_read.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct {
1462306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_HASH);
1562306a36Sopenharmony_ci	__type(key, long);
1662306a36Sopenharmony_ci	__type(value, long);
1762306a36Sopenharmony_ci	__uint(max_entries, 1024);
1862306a36Sopenharmony_ci} my_map SEC(".maps");
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* kprobe is NOT a stable ABI. If kernel internals change this bpf+kprobe
2162306a36Sopenharmony_ci * example will no longer be meaningful
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ciSEC("kprobe/kfree_skb_reason")
2462306a36Sopenharmony_ciint bpf_prog2(struct pt_regs *ctx)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	long loc = 0;
2762306a36Sopenharmony_ci	long init_val = 1;
2862306a36Sopenharmony_ci	long *value;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* read ip of kfree_skb_reason caller.
3162306a36Sopenharmony_ci	 * non-portable version of __builtin_return_address(0)
3262306a36Sopenharmony_ci	 */
3362306a36Sopenharmony_ci	BPF_KPROBE_READ_RET_IP(loc, ctx);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	value = bpf_map_lookup_elem(&my_map, &loc);
3662306a36Sopenharmony_ci	if (value)
3762306a36Sopenharmony_ci		*value += 1;
3862306a36Sopenharmony_ci	else
3962306a36Sopenharmony_ci		bpf_map_update_elem(&my_map, &loc, &init_val, BPF_ANY);
4062306a36Sopenharmony_ci	return 0;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic unsigned int log2(unsigned int v)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	unsigned int r;
4662306a36Sopenharmony_ci	unsigned int shift;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	r = (v > 0xFFFF) << 4; v >>= r;
4962306a36Sopenharmony_ci	shift = (v > 0xFF) << 3; v >>= shift; r |= shift;
5062306a36Sopenharmony_ci	shift = (v > 0xF) << 2; v >>= shift; r |= shift;
5162306a36Sopenharmony_ci	shift = (v > 0x3) << 1; v >>= shift; r |= shift;
5262306a36Sopenharmony_ci	r |= (v >> 1);
5362306a36Sopenharmony_ci	return r;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic unsigned int log2l(unsigned long v)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	unsigned int hi = v >> 32;
5962306a36Sopenharmony_ci	if (hi)
6062306a36Sopenharmony_ci		return log2(hi) + 32;
6162306a36Sopenharmony_ci	else
6262306a36Sopenharmony_ci		return log2(v);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct hist_key {
6662306a36Sopenharmony_ci	char comm[16];
6762306a36Sopenharmony_ci	u64 pid_tgid;
6862306a36Sopenharmony_ci	u64 uid_gid;
6962306a36Sopenharmony_ci	u64 index;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct {
7362306a36Sopenharmony_ci	__uint(type, BPF_MAP_TYPE_PERCPU_HASH);
7462306a36Sopenharmony_ci	__uint(key_size, sizeof(struct hist_key));
7562306a36Sopenharmony_ci	__uint(value_size, sizeof(long));
7662306a36Sopenharmony_ci	__uint(max_entries, 1024);
7762306a36Sopenharmony_ci} my_hist_map SEC(".maps");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ciSEC("ksyscall/write")
8062306a36Sopenharmony_ciint BPF_KSYSCALL(bpf_prog3, unsigned int fd, const char *buf, size_t count)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	long init_val = 1;
8362306a36Sopenharmony_ci	long *value;
8462306a36Sopenharmony_ci	struct hist_key key;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	key.index = log2l(count);
8762306a36Sopenharmony_ci	key.pid_tgid = bpf_get_current_pid_tgid();
8862306a36Sopenharmony_ci	key.uid_gid = bpf_get_current_uid_gid();
8962306a36Sopenharmony_ci	bpf_get_current_comm(&key.comm, sizeof(key.comm));
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	value = bpf_map_lookup_elem(&my_hist_map, &key);
9262306a36Sopenharmony_ci	if (value)
9362306a36Sopenharmony_ci		__sync_fetch_and_add(value, 1);
9462306a36Sopenharmony_ci	else
9562306a36Sopenharmony_ci		bpf_map_update_elem(&my_hist_map, &key, &init_val, BPF_ANY);
9662306a36Sopenharmony_ci	return 0;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_cichar _license[] SEC("license") = "GPL";
9962306a36Sopenharmony_ciu32 _version SEC("version") = LINUX_VERSION_CODE;
100