1/* eBPF mini library */
2#include <stdlib.h>
3#include <stdio.h>
4#include <linux/unistd.h>
5#include <unistd.h>
6#include <string.h>
7#include <linux/netlink.h>
8#include <linux/bpf.h>
9#include <errno.h>
10#include <net/ethernet.h>
11#include <net/if.h>
12#include <linux/if_packet.h>
13#include <arpa/inet.h>
14#include "libbpf.h"
15
16static __u64 ptr_to_u64(void *ptr)
17{
18	return (__u64) (unsigned long) ptr;
19}
20
21int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
22		   int max_entries)
23{
24	union bpf_attr attr = {
25		.map_type = map_type,
26		.key_size = key_size,
27		.value_size = value_size,
28		.max_entries = max_entries
29	};
30
31	return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
32}
33
34int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags)
35{
36	union bpf_attr attr = {
37		.map_fd = fd,
38		.key = ptr_to_u64(key),
39		.value = ptr_to_u64(value),
40		.flags = flags,
41	};
42
43	return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
44}
45
46int bpf_lookup_elem(int fd, void *key, void *value)
47{
48	union bpf_attr attr = {
49		.map_fd = fd,
50		.key = ptr_to_u64(key),
51		.value = ptr_to_u64(value),
52	};
53
54	return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
55}
56
57int bpf_delete_elem(int fd, void *key)
58{
59	union bpf_attr attr = {
60		.map_fd = fd,
61		.key = ptr_to_u64(key),
62	};
63
64	return syscall(__NR_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
65}
66
67int bpf_get_next_key(int fd, void *key, void *next_key)
68{
69	union bpf_attr attr = {
70		.map_fd = fd,
71		.key = ptr_to_u64(key),
72		.next_key = ptr_to_u64(next_key),
73	};
74
75	return syscall(__NR_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
76}
77
78#define ROUND_UP(x, n) (((x) + (n) - 1u) & ~((n) - 1u))
79
80char bpf_log_buf[LOG_BUF_SIZE];
81
82int bpf_prog_load(enum bpf_prog_type prog_type,
83		  const struct bpf_insn *insns, int prog_len,
84		  const char *license, int kern_version)
85{
86	union bpf_attr attr = {
87		.prog_type = prog_type,
88		.insns = ptr_to_u64((void *) insns),
89		.insn_cnt = prog_len / sizeof(struct bpf_insn),
90		.license = ptr_to_u64((void *) license),
91		.log_buf = ptr_to_u64(bpf_log_buf),
92		.log_size = LOG_BUF_SIZE,
93		.log_level = 1,
94	};
95
96	/* assign one field outside of struct init to make sure any
97	 * padding is zero initialized
98	 */
99	attr.kern_version = kern_version;
100
101	bpf_log_buf[0] = 0;
102
103	return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
104}
105
106int open_raw_sock(const char *name)
107{
108	struct sockaddr_ll sll;
109	int sock;
110
111	sock = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, htons(ETH_P_ALL));
112	if (sock < 0) {
113		printf("cannot create raw socket\n");
114		return -1;
115	}
116
117	memset(&sll, 0, sizeof(sll));
118	sll.sll_family = AF_PACKET;
119	sll.sll_ifindex = if_nametoindex(name);
120	sll.sll_protocol = htons(ETH_P_ALL);
121	if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
122		printf("bind to %s: %s\n", name, strerror(errno));
123		close(sock);
124		return -1;
125	}
126
127	return sock;
128}
129
130int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
131		    int group_fd, unsigned long flags)
132{
133	return syscall(__NR_perf_event_open, attr, pid, cpu,
134		       group_fd, flags);
135}
136