1*4882a593Smuzhiyun /* eBPF example program:
2*4882a593Smuzhiyun * - creates arraymap in kernel with key 4 bytes and value 8 bytes
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * - loads eBPF program:
5*4882a593Smuzhiyun * r0 = skb->data[ETH_HLEN + offsetof(struct iphdr, protocol)];
6*4882a593Smuzhiyun * *(u32*)(fp - 4) = r0;
7*4882a593Smuzhiyun * // assuming packet is IPv4, lookup ip->proto in a map
8*4882a593Smuzhiyun * value = bpf_map_lookup_elem(map_fd, fp - 4);
9*4882a593Smuzhiyun * if (value)
10*4882a593Smuzhiyun * (*(u64*)value) += 1;
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * - attaches this program to loopback interface "lo" raw socket
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * - every second user space reads map[tcp], map[udp], map[icmp] to see
15*4882a593Smuzhiyun * how many packets of given protocol were seen on "lo"
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun #include <stdio.h>
18*4882a593Smuzhiyun #include <unistd.h>
19*4882a593Smuzhiyun #include <assert.h>
20*4882a593Smuzhiyun #include <linux/bpf.h>
21*4882a593Smuzhiyun #include <string.h>
22*4882a593Smuzhiyun #include <stdlib.h>
23*4882a593Smuzhiyun #include <errno.h>
24*4882a593Smuzhiyun #include <sys/socket.h>
25*4882a593Smuzhiyun #include <arpa/inet.h>
26*4882a593Smuzhiyun #include <linux/if_ether.h>
27*4882a593Smuzhiyun #include <linux/ip.h>
28*4882a593Smuzhiyun #include <stddef.h>
29*4882a593Smuzhiyun #include <bpf/bpf.h>
30*4882a593Smuzhiyun #include "bpf_insn.h"
31*4882a593Smuzhiyun #include "sock_example.h"
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun char bpf_log_buf[BPF_LOG_BUF_SIZE];
34*4882a593Smuzhiyun
test_sock(void)35*4882a593Smuzhiyun static int test_sock(void)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun int sock = -1, map_fd, prog_fd, i, key;
38*4882a593Smuzhiyun long long value = 0, tcp_cnt, udp_cnt, icmp_cnt;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
41*4882a593Smuzhiyun 256, 0);
42*4882a593Smuzhiyun if (map_fd < 0) {
43*4882a593Smuzhiyun printf("failed to create map '%s'\n", strerror(errno));
44*4882a593Smuzhiyun goto cleanup;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun struct bpf_insn prog[] = {
48*4882a593Smuzhiyun BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
49*4882a593Smuzhiyun BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol) /* R0 = ip->proto */),
50*4882a593Smuzhiyun BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
51*4882a593Smuzhiyun BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
52*4882a593Smuzhiyun BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
53*4882a593Smuzhiyun BPF_LD_MAP_FD(BPF_REG_1, map_fd),
54*4882a593Smuzhiyun BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
55*4882a593Smuzhiyun BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
56*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */
57*4882a593Smuzhiyun BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
58*4882a593Smuzhiyun BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */
59*4882a593Smuzhiyun BPF_EXIT_INSN(),
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun prog_fd = bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, insns_cnt,
64*4882a593Smuzhiyun "GPL", 0, bpf_log_buf, BPF_LOG_BUF_SIZE);
65*4882a593Smuzhiyun if (prog_fd < 0) {
66*4882a593Smuzhiyun printf("failed to load prog '%s'\n", strerror(errno));
67*4882a593Smuzhiyun goto cleanup;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun sock = open_raw_sock("lo");
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd,
73*4882a593Smuzhiyun sizeof(prog_fd)) < 0) {
74*4882a593Smuzhiyun printf("setsockopt %s\n", strerror(errno));
75*4882a593Smuzhiyun goto cleanup;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun for (i = 0; i < 10; i++) {
79*4882a593Smuzhiyun key = IPPROTO_TCP;
80*4882a593Smuzhiyun assert(bpf_map_lookup_elem(map_fd, &key, &tcp_cnt) == 0);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun key = IPPROTO_UDP;
83*4882a593Smuzhiyun assert(bpf_map_lookup_elem(map_fd, &key, &udp_cnt) == 0);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun key = IPPROTO_ICMP;
86*4882a593Smuzhiyun assert(bpf_map_lookup_elem(map_fd, &key, &icmp_cnt) == 0);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun printf("TCP %lld UDP %lld ICMP %lld packets\n",
89*4882a593Smuzhiyun tcp_cnt, udp_cnt, icmp_cnt);
90*4882a593Smuzhiyun sleep(1);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun cleanup:
94*4882a593Smuzhiyun /* maps, programs, raw sockets will auto cleanup on process exit */
95*4882a593Smuzhiyun return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
main(void)98*4882a593Smuzhiyun int main(void)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun FILE *f;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun f = popen("ping -4 -c5 localhost", "r");
103*4882a593Smuzhiyun (void)f;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun return test_sock();
106*4882a593Smuzhiyun }
107