]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blame - samples/bpf/test_cgrp2_sock.c
samples/bpf: Update sock test to allow setting mark and priority
[mirror_ubuntu-eoan-kernel.git] / samples / bpf / test_cgrp2_sock.c
CommitLineData
ad2805dc
DA
1/* eBPF example program:
2 *
3 * - Loads eBPF program
4 *
5 * The eBPF program sets the sk_bound_dev_if index in new AF_INET{6}
6 * sockets opened by processes in the cgroup.
7 *
8 * - Attaches the new program to a cgroup using BPF_PROG_ATTACH
9 */
10
11#define _GNU_SOURCE
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <stddef.h>
16#include <string.h>
17#include <unistd.h>
18#include <assert.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <net/if.h>
fa38aa17 22#include <inttypes.h>
ad2805dc
DA
23#include <linux/bpf.h>
24
25#include "libbpf.h"
26
d40fc181
JS
27char bpf_log_buf[BPF_LOG_BUF_SIZE];
28
fa38aa17 29static int prog_load(__u32 idx, __u32 mark, __u32 prio)
ad2805dc 30{
fa38aa17
DA
31 /* save pointer to context */
32 struct bpf_insn prog_start[] = {
ad2805dc 33 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
fa38aa17
DA
34 };
35 struct bpf_insn prog_end[] = {
36 BPF_MOV64_IMM(BPF_REG_0, 1), /* r0 = verdict */
37 BPF_EXIT_INSN(),
38 };
39
40 /* set sk_bound_dev_if on socket */
41 struct bpf_insn prog_dev[] = {
ad2805dc
DA
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)),
ad2805dc
DA
45 };
46
fa38aa17
DA
47 /* set mark on socket */
48 struct bpf_insn prog_mark[] = {
49 BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
50 BPF_MOV64_IMM(BPF_REG_3, mark),
51 BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, mark)),
52 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, mark)),
53 };
54
55 /* set priority on socket */
56 struct bpf_insn prog_prio[] = {
57 BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
58 BPF_MOV64_IMM(BPF_REG_3, prio),
59 BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, priority)),
60 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, priority)),
61 };
62
63 struct bpf_insn *prog;
64 size_t insns_cnt;
65 void *p;
66 int ret;
67
68 insns_cnt = sizeof(prog_start) + sizeof(prog_end);
69 if (idx)
70 insns_cnt += sizeof(prog_dev);
71
72 if (mark)
73 insns_cnt += sizeof(prog_mark);
74
75 if (prio)
76 insns_cnt += sizeof(prog_prio);
77
78 p = prog = malloc(insns_cnt);
79 if (!prog) {
80 fprintf(stderr, "Failed to allocate memory for instructions\n");
81 return EXIT_FAILURE;
82 }
83
84 memcpy(p, prog_start, sizeof(prog_start));
85 p += sizeof(prog_start);
86
87 if (idx) {
88 memcpy(p, prog_dev, sizeof(prog_dev));
89 p += sizeof(prog_dev);
90 }
91
92 if (mark) {
93 memcpy(p, prog_mark, sizeof(prog_mark));
94 p += sizeof(prog_mark);
95 }
96
97 if (prio) {
98 memcpy(p, prog_prio, sizeof(prog_prio));
99 p += sizeof(prog_prio);
100 }
101
102 memcpy(p, prog_end, sizeof(prog_end));
103 p += sizeof(prog_end);
104
105 insns_cnt /= sizeof(struct bpf_insn);
106
107 ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SOCK, prog, insns_cnt,
d40fc181 108 "GPL", 0, bpf_log_buf, BPF_LOG_BUF_SIZE);
fa38aa17
DA
109
110 free(prog);
111
112 return ret;
ad2805dc
DA
113}
114
115static int usage(const char *argv0)
116{
fa38aa17 117 printf("Usage: %s -b bind-to-dev -m mark -p prio cg-path\n", argv0);
ad2805dc
DA
118 return EXIT_FAILURE;
119}
120
121int main(int argc, char **argv)
122{
fa38aa17
DA
123 __u32 idx = 0, mark = 0, prio = 0;
124 const char *cgrp_path = NULL;
ad2805dc 125 int cg_fd, prog_fd, ret;
fa38aa17
DA
126 int rc;
127
128 while ((rc = getopt(argc, argv, "b:m:p:")) != -1) {
129 switch (rc) {
130 case 'b':
131 idx = if_nametoindex(optarg);
132 if (!idx) {
133 idx = strtoumax(optarg, NULL, 0);
134 if (!idx) {
135 printf("Invalid device name\n");
136 return EXIT_FAILURE;
137 }
138 }
139 break;
140 case 'm':
141 mark = strtoumax(optarg, NULL, 0);
142 break;
143 case 'p':
144 prio = strtoumax(optarg, NULL, 0);
145 break;
146 default:
147 return usage(argv[0]);
148 }
149 }
ad2805dc 150
fa38aa17 151 if (optind == argc)
ad2805dc
DA
152 return usage(argv[0]);
153
fa38aa17
DA
154 cgrp_path = argv[optind];
155 if (!cgrp_path) {
156 fprintf(stderr, "cgroup path not given\n");
ad2805dc
DA
157 return EXIT_FAILURE;
158 }
159
fa38aa17
DA
160 if (!idx && !mark && !prio) {
161 fprintf(stderr,
162 "One of device, mark or priority must be given\n");
163 return EXIT_FAILURE;
164 }
165
166 cg_fd = open(cgrp_path, O_DIRECTORY | O_RDONLY);
ad2805dc
DA
167 if (cg_fd < 0) {
168 printf("Failed to open cgroup path: '%s'\n", strerror(errno));
169 return EXIT_FAILURE;
170 }
171
fa38aa17 172 prog_fd = prog_load(idx, mark, prio);
ad2805dc
DA
173 if (prog_fd < 0) {
174 printf("Failed to load prog: '%s'\n", strerror(errno));
fa38aa17
DA
175 printf("Output from kernel verifier:\n%s\n-------\n",
176 bpf_log_buf);
ad2805dc
DA
177 return EXIT_FAILURE;
178 }
179
7f677633 180 ret = bpf_prog_attach(prog_fd, cg_fd, BPF_CGROUP_INET_SOCK_CREATE, 0);
ad2805dc
DA
181 if (ret < 0) {
182 printf("Failed to attach prog to cgroup: '%s'\n",
183 strerror(errno));
184 return EXIT_FAILURE;
185 }
186
187 return EXIT_SUCCESS;
188}