1 /* eBPF example program:
5 * The eBPF program sets the sk_bound_dev_if index in new AF_INET{6}
6 * sockets opened by processes in the cgroup.
8 * - Attaches the new program to a cgroup using BPF_PROG_ATTACH
23 #include <linux/bpf.h>
28 char bpf_log_buf
[BPF_LOG_BUF_SIZE
];
30 static int prog_load(__u32 idx
, __u32 mark
, __u32 prio
)
32 /* save pointer to context */
33 struct bpf_insn prog_start
[] = {
34 BPF_MOV64_REG(BPF_REG_6
, BPF_REG_1
),
36 struct bpf_insn prog_end
[] = {
37 BPF_MOV64_IMM(BPF_REG_0
, 1), /* r0 = verdict */
41 /* set sk_bound_dev_if on socket */
42 struct bpf_insn prog_dev
[] = {
43 BPF_MOV64_IMM(BPF_REG_3
, idx
),
44 BPF_MOV64_IMM(BPF_REG_2
, offsetof(struct bpf_sock
, bound_dev_if
)),
45 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_3
, offsetof(struct bpf_sock
, bound_dev_if
)),
48 /* set mark on socket */
49 struct bpf_insn prog_mark
[] = {
50 /* get uid of process */
51 BPF_RAW_INSN(BPF_JMP
| BPF_CALL
, 0, 0, 0,
52 BPF_FUNC_get_current_uid_gid
),
53 BPF_ALU64_IMM(BPF_AND
, BPF_REG_0
, 0xffffffff),
55 /* if uid is 0, use given mark, else use the uid as the mark */
56 BPF_MOV64_REG(BPF_REG_3
, BPF_REG_0
),
57 BPF_JMP_IMM(BPF_JNE
, BPF_REG_0
, 0, 1),
58 BPF_MOV64_IMM(BPF_REG_3
, mark
),
60 /* set the mark on the new socket */
61 BPF_MOV64_REG(BPF_REG_1
, BPF_REG_6
),
62 BPF_MOV64_IMM(BPF_REG_2
, offsetof(struct bpf_sock
, mark
)),
63 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_3
, offsetof(struct bpf_sock
, mark
)),
66 /* set priority on socket */
67 struct bpf_insn prog_prio
[] = {
68 BPF_MOV64_REG(BPF_REG_1
, BPF_REG_6
),
69 BPF_MOV64_IMM(BPF_REG_3
, prio
),
70 BPF_MOV64_IMM(BPF_REG_2
, offsetof(struct bpf_sock
, priority
)),
71 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_3
, offsetof(struct bpf_sock
, priority
)),
74 struct bpf_insn
*prog
;
79 insns_cnt
= sizeof(prog_start
) + sizeof(prog_end
);
81 insns_cnt
+= sizeof(prog_dev
);
84 insns_cnt
+= sizeof(prog_mark
);
87 insns_cnt
+= sizeof(prog_prio
);
89 p
= prog
= malloc(insns_cnt
);
91 fprintf(stderr
, "Failed to allocate memory for instructions\n");
95 memcpy(p
, prog_start
, sizeof(prog_start
));
96 p
+= sizeof(prog_start
);
99 memcpy(p
, prog_dev
, sizeof(prog_dev
));
100 p
+= sizeof(prog_dev
);
104 memcpy(p
, prog_mark
, sizeof(prog_mark
));
105 p
+= sizeof(prog_mark
);
109 memcpy(p
, prog_prio
, sizeof(prog_prio
));
110 p
+= sizeof(prog_prio
);
113 memcpy(p
, prog_end
, sizeof(prog_end
));
114 p
+= sizeof(prog_end
);
116 insns_cnt
/= sizeof(struct bpf_insn
);
118 ret
= bpf_load_program(BPF_PROG_TYPE_CGROUP_SOCK
, prog
, insns_cnt
,
119 "GPL", 0, bpf_log_buf
, BPF_LOG_BUF_SIZE
);
126 static int get_bind_to_device(int sd
, char *name
, size_t len
)
128 socklen_t optlen
= len
;
132 rc
= getsockopt(sd
, SOL_SOCKET
, SO_BINDTODEVICE
, name
, &optlen
);
134 perror("setsockopt(SO_BINDTODEVICE)");
139 static unsigned int get_somark(int sd
)
141 unsigned int mark
= 0;
142 socklen_t optlen
= sizeof(mark
);
145 rc
= getsockopt(sd
, SOL_SOCKET
, SO_MARK
, &mark
, &optlen
);
147 perror("getsockopt(SO_MARK)");
152 static unsigned int get_priority(int sd
)
154 unsigned int prio
= 0;
155 socklen_t optlen
= sizeof(prio
);
158 rc
= getsockopt(sd
, SOL_SOCKET
, SO_PRIORITY
, &prio
, &optlen
);
160 perror("getsockopt(SO_PRIORITY)");
165 static int show_sockopts(int family
)
167 unsigned int mark
, prio
;
171 sd
= socket(family
, SOCK_DGRAM
, 17);
177 if (get_bind_to_device(sd
, name
, sizeof(name
)) < 0)
180 mark
= get_somark(sd
);
181 prio
= get_priority(sd
);
185 printf("sd %d: dev %s, mark %u, priority %u\n", sd
, name
, mark
, prio
);
190 static int usage(const char *argv0
)
193 printf(" Attach a program\n");
194 printf(" %s -b bind-to-dev -m mark -p prio cg-path\n", argv0
);
196 printf(" Detach a program\n");
197 printf(" %s -d cg-path\n", argv0
);
199 printf(" Show inherited socket settings (mark, priority, and device)\n");
200 printf(" %s [-6]\n", argv0
);
204 int main(int argc
, char **argv
)
206 __u32 idx
= 0, mark
= 0, prio
= 0;
207 const char *cgrp_path
= NULL
;
208 int cg_fd
, prog_fd
, ret
;
209 int family
= PF_INET
;
213 while ((rc
= getopt(argc
, argv
, "db:m:p:6")) != -1) {
219 idx
= if_nametoindex(optarg
);
221 idx
= strtoumax(optarg
, NULL
, 0);
223 printf("Invalid device name\n");
229 mark
= strtoumax(optarg
, NULL
, 0);
232 prio
= strtoumax(optarg
, NULL
, 0);
238 return usage(argv
[0]);
243 return show_sockopts(family
);
245 cgrp_path
= argv
[optind
];
247 fprintf(stderr
, "cgroup path not given\n");
251 if (do_attach
&& !idx
&& !mark
&& !prio
) {
253 "One of device, mark or priority must be given\n");
257 cg_fd
= open(cgrp_path
, O_DIRECTORY
| O_RDONLY
);
259 printf("Failed to open cgroup path: '%s'\n", strerror(errno
));
264 prog_fd
= prog_load(idx
, mark
, prio
);
266 printf("Failed to load prog: '%s'\n", strerror(errno
));
267 printf("Output from kernel verifier:\n%s\n-------\n",
272 ret
= bpf_prog_attach(prog_fd
, cg_fd
,
273 BPF_CGROUP_INET_SOCK_CREATE
, 0);
275 printf("Failed to attach prog to cgroup: '%s'\n",
280 ret
= bpf_prog_detach(cg_fd
, BPF_CGROUP_INET_SOCK_CREATE
);
282 printf("Failed to detach prog from cgroup: '%s'\n",