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>
27 char bpf_log_buf
[BPF_LOG_BUF_SIZE
];
29 static int prog_load(__u32 idx
, __u32 mark
, __u32 prio
)
31 /* save pointer to context */
32 struct bpf_insn prog_start
[] = {
33 BPF_MOV64_REG(BPF_REG_6
, BPF_REG_1
),
35 struct bpf_insn prog_end
[] = {
36 BPF_MOV64_IMM(BPF_REG_0
, 1), /* r0 = verdict */
40 /* set sk_bound_dev_if on socket */
41 struct bpf_insn prog_dev
[] = {
42 BPF_MOV64_IMM(BPF_REG_3
, idx
),
43 BPF_MOV64_IMM(BPF_REG_2
, offsetof(struct bpf_sock
, bound_dev_if
)),
44 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_3
, offsetof(struct bpf_sock
, bound_dev_if
)),
47 /* set mark on socket */
48 struct bpf_insn prog_mark
[] = {
49 /* get uid of process */
50 BPF_RAW_INSN(BPF_JMP
| BPF_CALL
, 0, 0, 0,
51 BPF_FUNC_get_current_uid_gid
),
52 BPF_ALU64_IMM(BPF_AND
, BPF_REG_0
, 0xffffffff),
54 /* if uid is 0, use given mark, else use the uid as the mark */
55 BPF_MOV64_REG(BPF_REG_3
, BPF_REG_0
),
56 BPF_JMP_IMM(BPF_JNE
, BPF_REG_0
, 0, 1),
57 BPF_MOV64_IMM(BPF_REG_3
, mark
),
59 /* set the mark on the new socket */
60 BPF_MOV64_REG(BPF_REG_1
, BPF_REG_6
),
61 BPF_MOV64_IMM(BPF_REG_2
, offsetof(struct bpf_sock
, mark
)),
62 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_3
, offsetof(struct bpf_sock
, mark
)),
65 /* set priority on socket */
66 struct bpf_insn prog_prio
[] = {
67 BPF_MOV64_REG(BPF_REG_1
, BPF_REG_6
),
68 BPF_MOV64_IMM(BPF_REG_3
, prio
),
69 BPF_MOV64_IMM(BPF_REG_2
, offsetof(struct bpf_sock
, priority
)),
70 BPF_STX_MEM(BPF_W
, BPF_REG_1
, BPF_REG_3
, offsetof(struct bpf_sock
, priority
)),
73 struct bpf_insn
*prog
;
78 insns_cnt
= sizeof(prog_start
) + sizeof(prog_end
);
80 insns_cnt
+= sizeof(prog_dev
);
83 insns_cnt
+= sizeof(prog_mark
);
86 insns_cnt
+= sizeof(prog_prio
);
88 p
= prog
= malloc(insns_cnt
);
90 fprintf(stderr
, "Failed to allocate memory for instructions\n");
94 memcpy(p
, prog_start
, sizeof(prog_start
));
95 p
+= sizeof(prog_start
);
98 memcpy(p
, prog_dev
, sizeof(prog_dev
));
99 p
+= sizeof(prog_dev
);
103 memcpy(p
, prog_mark
, sizeof(prog_mark
));
104 p
+= sizeof(prog_mark
);
108 memcpy(p
, prog_prio
, sizeof(prog_prio
));
109 p
+= sizeof(prog_prio
);
112 memcpy(p
, prog_end
, sizeof(prog_end
));
113 p
+= sizeof(prog_end
);
115 insns_cnt
/= sizeof(struct bpf_insn
);
117 ret
= bpf_load_program(BPF_PROG_TYPE_CGROUP_SOCK
, prog
, insns_cnt
,
118 "GPL", 0, bpf_log_buf
, BPF_LOG_BUF_SIZE
);
125 static int get_bind_to_device(int sd
, char *name
, size_t len
)
127 socklen_t optlen
= len
;
131 rc
= getsockopt(sd
, SOL_SOCKET
, SO_BINDTODEVICE
, name
, &optlen
);
133 perror("setsockopt(SO_BINDTODEVICE)");
138 static unsigned int get_somark(int sd
)
140 unsigned int mark
= 0;
141 socklen_t optlen
= sizeof(mark
);
144 rc
= getsockopt(sd
, SOL_SOCKET
, SO_MARK
, &mark
, &optlen
);
146 perror("getsockopt(SO_MARK)");
151 static unsigned int get_priority(int sd
)
153 unsigned int prio
= 0;
154 socklen_t optlen
= sizeof(prio
);
157 rc
= getsockopt(sd
, SOL_SOCKET
, SO_PRIORITY
, &prio
, &optlen
);
159 perror("getsockopt(SO_PRIORITY)");
164 static int show_sockopts(int family
)
166 unsigned int mark
, prio
;
170 sd
= socket(family
, SOCK_DGRAM
, 17);
176 if (get_bind_to_device(sd
, name
, sizeof(name
)) < 0)
179 mark
= get_somark(sd
);
180 prio
= get_priority(sd
);
184 printf("sd %d: dev %s, mark %u, priority %u\n", sd
, name
, mark
, prio
);
189 static int usage(const char *argv0
)
192 printf(" Attach a program\n");
193 printf(" %s -b bind-to-dev -m mark -p prio cg-path\n", argv0
);
195 printf(" Detach a program\n");
196 printf(" %s -d cg-path\n", argv0
);
198 printf(" Show inherited socket settings (mark, priority, and device)\n");
199 printf(" %s [-6]\n", argv0
);
203 int main(int argc
, char **argv
)
205 __u32 idx
= 0, mark
= 0, prio
= 0;
206 const char *cgrp_path
= NULL
;
207 int cg_fd
, prog_fd
, ret
;
208 int family
= PF_INET
;
212 while ((rc
= getopt(argc
, argv
, "db:m:p:6")) != -1) {
218 idx
= if_nametoindex(optarg
);
220 idx
= strtoumax(optarg
, NULL
, 0);
222 printf("Invalid device name\n");
228 mark
= strtoumax(optarg
, NULL
, 0);
231 prio
= strtoumax(optarg
, NULL
, 0);
237 return usage(argv
[0]);
242 return show_sockopts(family
);
244 cgrp_path
= argv
[optind
];
246 fprintf(stderr
, "cgroup path not given\n");
250 if (do_attach
&& !idx
&& !mark
&& !prio
) {
252 "One of device, mark or priority must be given\n");
256 cg_fd
= open(cgrp_path
, O_DIRECTORY
| O_RDONLY
);
258 printf("Failed to open cgroup path: '%s'\n", strerror(errno
));
263 prog_fd
= prog_load(idx
, mark
, prio
);
265 printf("Failed to load prog: '%s'\n", strerror(errno
));
266 printf("Output from kernel verifier:\n%s\n-------\n",
271 ret
= bpf_prog_attach(prog_fd
, cg_fd
,
272 BPF_CGROUP_INET_SOCK_CREATE
, 0);
274 printf("Failed to attach prog to cgroup: '%s'\n",
279 ret
= bpf_prog_detach(cg_fd
, BPF_CGROUP_INET_SOCK_CREATE
);
281 printf("Failed to detach prog from cgroup: '%s'\n",