Blame view

samples/bpf/test_cgrp2_attach.c 4.56 KB
d8c5b17f2   Daniel Mack   samples: bpf: add...
1
2
3
4
5
6
7
8
9
10
11
12
  /* eBPF example program:
   *
   * - Creates arraymap in kernel with 4 bytes keys and 8 byte values
   *
   * - Loads eBPF program
   *
   *   The eBPF program accesses the map passed in to store two pieces of
   *   information. The number of invocations of the program, which maps
   *   to the number of packets received, is stored to key 0. Key 1 is
   *   incremented on each iteration by the number of bytes stored in
   *   the skb.
   *
d8c5b17f2   Daniel Mack   samples: bpf: add...
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   * - Attaches the new program to a cgroup using BPF_PROG_ATTACH
   *
   * - Every second, reads map[0] and map[1] to see how many bytes and
   *   packets were seen on any socket of tasks in the given cgroup.
   */
  
  #define _GNU_SOURCE
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <stddef.h>
  #include <string.h>
  #include <unistd.h>
  #include <assert.h>
  #include <errno.h>
  #include <fcntl.h>
  
  #include <linux/bpf.h>
  
  #include "libbpf.h"
  
  enum {
  	MAP_KEY_PACKETS,
  	MAP_KEY_BYTES,
  };
d40fc181e   Joe Stringer   samples/bpf: Make...
38
  char bpf_log_buf[BPF_LOG_BUF_SIZE];
d8c5b17f2   Daniel Mack   samples: bpf: add...
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  static int prog_load(int map_fd, int verdict)
  {
  	struct bpf_insn prog[] = {
  		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), /* save r6 so it's not clobbered by BPF_CALL */
  
  		/* Count packets */
  		BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_PACKETS), /* r0 = 0 */
  		BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
  		BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
  		BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
  		BPF_LD_MAP_FD(BPF_REG_1, map_fd), /* load map fd to r1 */
  		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
  		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
  		BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */
  		BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
  
  		/* Count bytes */
  		BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_BYTES), /* r0 = 1 */
  		BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
  		BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
  		BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
  		BPF_LD_MAP_FD(BPF_REG_1, map_fd),
  		BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
  		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
  		BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offsetof(struct __sk_buff, len)), /* r1 = skb->len */
  		BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
  
  		BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
  		BPF_EXIT_INSN(),
  	};
43371c83f   Joe Stringer   samples/bpf: Swit...
69
  	size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
d8c5b17f2   Daniel Mack   samples: bpf: add...
70

d40fc181e   Joe Stringer   samples/bpf: Make...
71
  	return bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
43371c83f   Joe Stringer   samples/bpf: Swit...
72
  				prog, insns_cnt, "GPL", 0,
d40fc181e   Joe Stringer   samples/bpf: Make...
73
  				bpf_log_buf, BPF_LOG_BUF_SIZE);
d8c5b17f2   Daniel Mack   samples: bpf: add...
74
75
76
77
  }
  
  static int usage(const char *argv0)
  {
1379fd3c4   Sargun Dhillon   samples: bpf: Ref...
78
79
80
81
82
83
  	printf("Usage: %s [-d] [-D] <cg-path> <egress|ingress>
  ", argv0);
  	printf("	-d	Drop Traffic
  ");
  	printf("	-D	Detach filter, and exit
  ");
d8c5b17f2   Daniel Mack   samples: bpf: add...
84
85
  	return EXIT_FAILURE;
  }
1379fd3c4   Sargun Dhillon   samples: bpf: Ref...
86
  static int attach_filter(int cg_fd, int type, int verdict)
d8c5b17f2   Daniel Mack   samples: bpf: add...
87
  {
1379fd3c4   Sargun Dhillon   samples: bpf: Ref...
88
  	int prog_fd, map_fd, ret, key;
d8c5b17f2   Daniel Mack   samples: bpf: add...
89
  	long long pkt_cnt, byte_cnt;
d8c5b17f2   Daniel Mack   samples: bpf: add...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  
  	map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY,
  				sizeof(key), sizeof(byte_cnt),
  				256, 0);
  	if (map_fd < 0) {
  		printf("Failed to create map: '%s'
  ", strerror(errno));
  		return EXIT_FAILURE;
  	}
  
  	prog_fd = prog_load(map_fd, verdict);
  	printf("Output from kernel verifier:
  %s
  -------
  ", bpf_log_buf);
  
  	if (prog_fd < 0) {
  		printf("Failed to load prog: '%s'
  ", strerror(errno));
  		return EXIT_FAILURE;
  	}
7f6776333   Alexei Starovoitov   bpf: introduce BP...
111
  	ret = bpf_prog_attach(prog_fd, cg_fd, type, 0);
d8c5b17f2   Daniel Mack   samples: bpf: add...
112
113
114
115
116
117
  	if (ret < 0) {
  		printf("Failed to attach prog to cgroup: '%s'
  ",
  		       strerror(errno));
  		return EXIT_FAILURE;
  	}
d8c5b17f2   Daniel Mack   samples: bpf: add...
118
119
  	while (1) {
  		key = MAP_KEY_PACKETS;
d40fc181e   Joe Stringer   samples/bpf: Make...
120
  		assert(bpf_map_lookup_elem(map_fd, &key, &pkt_cnt) == 0);
d8c5b17f2   Daniel Mack   samples: bpf: add...
121
122
  
  		key = MAP_KEY_BYTES;
d40fc181e   Joe Stringer   samples/bpf: Make...
123
  		assert(bpf_map_lookup_elem(map_fd, &key, &byte_cnt) == 0);
d8c5b17f2   Daniel Mack   samples: bpf: add...
124
125
126
127
128
129
130
131
132
  
  		printf("cgroup received %lld packets, %lld bytes
  ",
  		       pkt_cnt, byte_cnt);
  		sleep(1);
  	}
  
  	return EXIT_SUCCESS;
  }
1379fd3c4   Sargun Dhillon   samples: bpf: Ref...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  
  int main(int argc, char **argv)
  {
  	int detach_only = 0, verdict = 1;
  	enum bpf_attach_type type;
  	int opt, cg_fd, ret;
  
  	while ((opt = getopt(argc, argv, "Dd")) != -1) {
  		switch (opt) {
  		case 'd':
  			verdict = 0;
  			break;
  		case 'D':
  			detach_only = 1;
  			break;
  		default:
  			return usage(argv[0]);
  		}
  	}
  
  	if (argc - optind < 2)
  		return usage(argv[0]);
  
  	if (strcmp(argv[optind + 1], "ingress") == 0)
  		type = BPF_CGROUP_INET_INGRESS;
  	else if (strcmp(argv[optind + 1], "egress") == 0)
  		type = BPF_CGROUP_INET_EGRESS;
  	else
  		return usage(argv[0]);
  
  	cg_fd = open(argv[optind], O_DIRECTORY | O_RDONLY);
  	if (cg_fd < 0) {
  		printf("Failed to open cgroup path: '%s'
  ", strerror(errno));
  		return EXIT_FAILURE;
  	}
  
  	if (detach_only) {
  		ret = bpf_prog_detach(cg_fd, type);
  		printf("bpf_prog_detach() returned '%s' (%d)
  ",
  		       strerror(errno), errno);
  	} else
  		ret = attach_filter(cg_fd, type, verdict);
  
  	return ret;
  }