]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipvrf.c
ipvrf: cleanup style issues
[mirror_iproute2.git] / ip / ipvrf.c
1 /*
2 * ipvrf.c "ip vrf"
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: David Ahern <dsa@cumulusnetworks.com>
10 *
11 */
12
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/socket.h>
16 #include <sys/mount.h>
17 #include <linux/bpf.h>
18 #include <linux/if.h>
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <limits.h>
26
27 #include "rt_names.h"
28 #include "utils.h"
29 #include "ip_common.h"
30 #include "bpf_util.h"
31
32 #define CGRP_PROC_FILE "/cgroup.procs"
33
34 static void usage(void)
35 {
36 fprintf(stderr, "Usage: ip vrf exec [NAME] cmd ...\n");
37 fprintf(stderr, " ip vrf identify [PID]\n");
38 fprintf(stderr, " ip vrf pids [NAME]\n");
39
40 exit(-1);
41 }
42
43 static int ipvrf_identify(int argc, char **argv)
44 {
45 char path[PATH_MAX];
46 char buf[4096];
47 char *vrf, *end;
48 int fd, rc = -1;
49 unsigned int pid;
50 ssize_t n;
51
52 if (argc < 1)
53 pid = getpid();
54 else if (argc > 1)
55 invarg("Extra arguments specified\n", argv[1]);
56 else if (get_unsigned(&pid, argv[0], 10))
57 invarg("Invalid pid\n", argv[0]);
58
59 snprintf(path, sizeof(path), "/proc/%d/cgroup", pid);
60 fd = open(path, O_RDONLY);
61 if (fd < 0) {
62 fprintf(stderr,
63 "Failed to open cgroups file: %s\n", strerror(errno));
64 return -1;
65 }
66
67 n = read(fd, buf, sizeof(buf) - 1);
68 if (n < 0) {
69 fprintf(stderr,
70 "Failed to read cgroups file: %s\n", strerror(errno));
71 goto out;
72 }
73 buf[n] = '\0';
74 vrf = strstr(buf, "::/vrf/");
75 if (vrf) {
76 vrf += 7; /* skip past "::/vrf/" */
77 end = strchr(vrf, '\n');
78 if (end)
79 *end = '\0';
80
81 printf("%s\n", vrf);
82 }
83
84 rc = 0;
85 out:
86 close(fd);
87
88 return rc;
89 }
90
91 static int ipvrf_pids(int argc, char **argv)
92 {
93 char path[PATH_MAX];
94 char buf[4096];
95 char *mnt, *vrf;
96 int fd, rc = -1;
97 ssize_t n;
98
99 if (argc != 1) {
100 fprintf(stderr, "Invalid arguments\n");
101 return -1;
102 }
103
104 vrf = argv[0];
105
106 mnt = find_cgroup2_mount();
107 if (!mnt)
108 return -1;
109
110 snprintf(path, sizeof(path), "%s/vrf/%s%s", mnt, vrf, CGRP_PROC_FILE);
111 free(mnt);
112 fd = open(path, O_RDONLY);
113 if (fd < 0)
114 return 0; /* no cgroup file, nothing to show */
115
116 while (1) {
117 n = read(fd, buf, sizeof(buf) - 1);
118 if (n < 0) {
119 fprintf(stderr,
120 "Failed to read cgroups file: %s\n",
121 strerror(errno));
122 break;
123 } else if (n == 0) {
124 rc = 0;
125 break;
126 }
127 printf("%s", buf);
128 }
129
130 close(fd);
131
132 return rc;
133 }
134
135 /* load BPF program to set sk_bound_dev_if for sockets */
136 static char bpf_log_buf[256*1024];
137
138 static int prog_load(int idx)
139 {
140 struct bpf_insn prog[] = {
141 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
142 BPF_MOV64_IMM(BPF_REG_3, idx),
143 BPF_MOV64_IMM(BPF_REG_2,
144 offsetof(struct bpf_sock, bound_dev_if)),
145 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
146 offsetof(struct bpf_sock, bound_dev_if)),
147 BPF_MOV64_IMM(BPF_REG_0, 1), /* r0 = verdict */
148 BPF_EXIT_INSN(),
149 };
150
151 return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, prog, sizeof(prog),
152 "GPL", bpf_log_buf, sizeof(bpf_log_buf));
153 }
154
155 static int vrf_configure_cgroup(const char *path, int ifindex)
156 {
157 int rc = -1, cg_fd, prog_fd = -1;
158
159 cg_fd = open(path, O_DIRECTORY | O_RDONLY);
160 if (cg_fd < 0) {
161 fprintf(stderr,
162 "Failed to open cgroup path: '%s'\n",
163 strerror(errno));
164 goto out;
165 }
166
167 /*
168 * Load bpf program into kernel and attach to cgroup to affect
169 * socket creates
170 */
171 prog_fd = prog_load(ifindex);
172 if (prog_fd < 0) {
173 printf("Failed to load BPF prog: '%s'\n", strerror(errno));
174 goto out;
175 }
176
177 if (bpf_prog_attach_fd(prog_fd, cg_fd, BPF_CGROUP_INET_SOCK_CREATE)) {
178 fprintf(stderr, "Failed to attach prog to cgroup: '%s'\n",
179 strerror(errno));
180 fprintf(stderr, "Kernel compiled with CGROUP_BPF enabled?\n");
181 goto out;
182 }
183
184 rc = 0;
185 out:
186 close(cg_fd);
187 close(prog_fd);
188
189 return rc;
190 }
191
192 static int vrf_switch(const char *name)
193 {
194 char path[PATH_MAX], *mnt, pid[16];
195 int ifindex = name_is_vrf(name);
196 bool default_vrf = false;
197 int rc = -1, len, fd = -1;
198
199 if (!ifindex) {
200 if (strcmp(name, "default")) {
201 fprintf(stderr, "Invalid VRF name\n");
202 return -1;
203 }
204 default_vrf = true;
205 }
206
207 mnt = find_cgroup2_mount();
208 if (!mnt)
209 return -1;
210
211 /* path to cgroup; make sure buffer has room to cat "/cgroup.procs"
212 * to the end of the path
213 */
214 len = snprintf(path, sizeof(path) - sizeof(CGRP_PROC_FILE), "%s%s/%s",
215 mnt, default_vrf ? "" : "/vrf", name);
216 if (len > sizeof(path) - sizeof(CGRP_PROC_FILE)) {
217 fprintf(stderr, "Invalid path to cgroup2 mount\n");
218 goto out;
219 }
220
221 if (make_path(path, 0755)) {
222 fprintf(stderr, "Failed to setup vrf cgroup2 directory\n");
223 goto out;
224 }
225
226 if (!default_vrf && vrf_configure_cgroup(path, ifindex))
227 goto out;
228
229 /*
230 * write pid to cgroup.procs making process part of cgroup
231 */
232 strcat(path, CGRP_PROC_FILE);
233 fd = open(path, O_RDWR | O_APPEND);
234 if (fd < 0) {
235 fprintf(stderr, "Failed to open cgroups.procs file: %s.\n",
236 strerror(errno));
237 goto out;
238 }
239
240 snprintf(pid, sizeof(pid), "%d", getpid());
241 if (write(fd, pid, strlen(pid)) < 0) {
242 fprintf(stderr, "Failed to join cgroup\n");
243 goto out;
244 }
245
246 rc = 0;
247 out:
248 free(mnt);
249 close(fd);
250
251 return rc;
252 }
253
254 static int ipvrf_exec(int argc, char **argv)
255 {
256 if (argc < 1) {
257 fprintf(stderr, "No VRF name specified\n");
258 return -1;
259 }
260 if (argc < 2) {
261 fprintf(stderr, "No command specified\n");
262 return -1;
263 }
264
265 if (vrf_switch(argv[0]))
266 return -1;
267
268 return -cmd_exec(argv[1], argv + 1, !!batch_mode);
269 }
270
271 int do_ipvrf(int argc, char **argv)
272 {
273 if (argc == 0) {
274 fprintf(stderr, "No command given. Try \"ip vrf help\".\n");
275 exit(-1);
276 }
277
278 if (matches(*argv, "identify") == 0)
279 return ipvrf_identify(argc-1, argv+1);
280
281 if (matches(*argv, "pids") == 0)
282 return ipvrf_pids(argc-1, argv+1);
283
284 if (matches(*argv, "exec") == 0)
285 return ipvrf_exec(argc-1, argv+1);
286
287 if (matches(*argv, "help") == 0)
288 usage();
289
290 fprintf(stderr, "Command \"%s\" is unknown, try \"ip vrf help\".\n",
291 *argv);
292
293 exit(-1);
294 }