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 bpf_obj_pin(int fd, const char *pathname)
107{
108	union bpf_attr attr = {
109		.pathname	= ptr_to_u64((void *)pathname),
110		.bpf_fd		= fd,
111	};
112
113	return syscall(__NR_bpf, BPF_OBJ_PIN, &attr, sizeof(attr));
114}
115
116int bpf_obj_get(const char *pathname)
117{
118	union bpf_attr attr = {
119		.pathname	= ptr_to_u64((void *)pathname),
120	};
121
122	return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
123}
124
125int open_raw_sock(const char *name)
126{
127	struct sockaddr_ll sll;
128	int sock;
129
130	sock = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, htons(ETH_P_ALL));
131	if (sock < 0) {
132		printf("cannot create raw socket\n");
133		return -1;
134	}
135
136	memset(&sll, 0, sizeof(sll));
137	sll.sll_family = AF_PACKET;
138	sll.sll_ifindex = if_nametoindex(name);
139	sll.sll_protocol = htons(ETH_P_ALL);
140	if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
141		printf("bind to %s: %s\n", name, strerror(errno));
142		close(sock);
143		return -1;
144	}
145
146	return sock;
147}
148
149int perf_event_open(struct perf_event_attr *attr, int pid, int cpu,
150		    int group_fd, unsigned long flags)
151{
152	return syscall(__NR_perf_event_open, attr, pid, cpu,
153		       group_fd, flags);
154}
155