]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipvrf.c
utils: cleanup style
[mirror_iproute2.git] / ip / ipvrf.c
CommitLineData
1949f82c
DA
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
34static 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
43static 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;
85out:
86 close(fd);
87
88 return rc;
89}
90
91static 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", strerror(errno));
121 break;
122 } else if (n == 0) {
123 rc = 0;
124 break;
125 }
126 printf("%s", buf);
127 }
128
129 close(fd);
130
131 return rc;
132}
133
134/* load BPF program to set sk_bound_dev_if for sockets */
135static char bpf_log_buf[256*1024];
136
137static int prog_load(int idx)
138{
139 struct bpf_insn prog[] = {
140 BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
141 BPF_MOV64_IMM(BPF_REG_3, idx),
142 BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, bound_dev_if)),
143 BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, bound_dev_if)),
144 BPF_MOV64_IMM(BPF_REG_0, 1), /* r0 = verdict */
145 BPF_EXIT_INSN(),
146 };
147
148 return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, prog, sizeof(prog),
149 "GPL", bpf_log_buf, sizeof(bpf_log_buf));
150}
151
152static int vrf_configure_cgroup(const char *path, int ifindex)
153{
154 int rc = -1, cg_fd, prog_fd = -1;
155
156 cg_fd = open(path, O_DIRECTORY | O_RDONLY);
157 if (cg_fd < 0) {
158 fprintf(stderr, "Failed to open cgroup path: '%s'\n", strerror(errno));
159 goto out;
160 }
161
162 /*
163 * Load bpf program into kernel and attach to cgroup to affect
164 * socket creates
165 */
166 prog_fd = prog_load(ifindex);
167 if (prog_fd < 0) {
168 printf("Failed to load BPF prog: '%s'\n", strerror(errno));
169 goto out;
170 }
171
172 if (bpf_prog_attach_fd(prog_fd, cg_fd, BPF_CGROUP_INET_SOCK_CREATE)) {
173 fprintf(stderr, "Failed to attach prog to cgroup: '%s'\n",
174 strerror(errno));
175 fprintf(stderr, "Kernel compiled with CGROUP_BPF enabled?\n");
176 goto out;
177 }
178
179 rc = 0;
180out:
181 close(cg_fd);
182 close(prog_fd);
183
184 return rc;
185}
186
187static int vrf_switch(const char *name)
188{
189 char path[PATH_MAX], *mnt, pid[16];
190 int ifindex = name_is_vrf(name);
191 bool default_vrf = false;
192 int rc = -1, len, fd = -1;
193
194 if (!ifindex) {
195 if (strcmp(name, "default")) {
196 fprintf(stderr, "Invalid VRF name\n");
197 return -1;
198 }
199 default_vrf = true;
200 }
201
202 mnt = find_cgroup2_mount();
203 if (!mnt)
204 return -1;
205
206 /* path to cgroup; make sure buffer has room to cat "/cgroup.procs"
207 * to the end of the path
208 */
209 len = snprintf(path, sizeof(path) - sizeof(CGRP_PROC_FILE), "%s%s/%s",
210 mnt, default_vrf ? "" : "/vrf", name);
211 if (len > sizeof(path) - sizeof(CGRP_PROC_FILE)) {
212 fprintf(stderr, "Invalid path to cgroup2 mount\n");
213 goto out;
214 }
215
216 if (make_path(path, 0755)) {
217 fprintf(stderr, "Failed to setup vrf cgroup2 directory\n");
218 goto out;
219 }
220
221 if (!default_vrf && vrf_configure_cgroup(path, ifindex))
222 goto out;
223
224 /*
225 * write pid to cgroup.procs making process part of cgroup
226 */
227 strcat(path, CGRP_PROC_FILE);
228 fd = open(path, O_RDWR | O_APPEND);
229 if (fd < 0) {
230 fprintf(stderr, "Failed to open cgroups.procs file: %s.\n",
231 strerror(errno));
232 goto out;
233 }
234
235 snprintf(pid, sizeof(pid), "%d", getpid());
236 if (write(fd, pid, strlen(pid)) < 0) {
237 fprintf(stderr, "Failed to join cgroup\n");
238 goto out;
239 }
240
241 rc = 0;
242out:
243 free(mnt);
244 close(fd);
245
246 return rc;
247}
248
249static int ipvrf_exec(int argc, char **argv)
250{
251 if (argc < 1) {
252 fprintf(stderr, "No VRF name specified\n");
253 return -1;
254 }
255 if (argc < 2) {
256 fprintf(stderr, "No command specified\n");
257 return -1;
258 }
259
260 if (vrf_switch(argv[0]))
261 return -1;
262
263 return -cmd_exec(argv[1], argv + 1, !!batch_mode);
264}
265
266int do_ipvrf(int argc, char **argv)
267{
268 if (argc == 0) {
269 fprintf(stderr, "No command given. Try \"ip vrf help\".\n");
270 exit(-1);
271 }
272
273 if (matches(*argv, "identify") == 0)
274 return ipvrf_identify(argc-1, argv+1);
275
276 if (matches(*argv, "pids") == 0)
277 return ipvrf_pids(argc-1, argv+1);
278
279 if (matches(*argv, "exec") == 0)
280 return ipvrf_exec(argc-1, argv+1);
281
282 if (matches(*argv, "help") == 0)
283 usage();
284
285 fprintf(stderr, "Command \"%s\" is unknown, try \"ip vrf help\".\n",
286 *argv);
287
288 exit(-1);
289}