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.
9 * Authors: David Ahern <dsa@cumulusnetworks.com>
13 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <sys/mount.h>
17 #include <linux/bpf.h>
29 #include "ip_common.h"
32 #define CGRP_PROC_FILE "/cgroup.procs"
34 static void usage(void)
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");
43 static int ipvrf_identify(int argc
, char **argv
)
55 invarg("Extra arguments specified\n", argv
[1]);
56 else if (get_unsigned(&pid
, argv
[0], 10))
57 invarg("Invalid pid\n", argv
[0]);
59 snprintf(path
, sizeof(path
), "/proc/%d/cgroup", pid
);
60 fd
= open(path
, O_RDONLY
);
63 "Failed to open cgroups file: %s\n", strerror(errno
));
67 n
= read(fd
, buf
, sizeof(buf
) - 1);
70 "Failed to read cgroups file: %s\n", strerror(errno
));
74 vrf
= strstr(buf
, "::/vrf/");
76 vrf
+= 7; /* skip past "::/vrf/" */
77 end
= strchr(vrf
, '\n');
91 static int ipvrf_pids(int argc
, char **argv
)
100 fprintf(stderr
, "Invalid arguments\n");
106 mnt
= find_cgroup2_mount();
110 snprintf(path
, sizeof(path
), "%s/vrf/%s%s", mnt
, vrf
, CGRP_PROC_FILE
);
112 fd
= open(path
, O_RDONLY
);
114 return 0; /* no cgroup file, nothing to show */
117 n
= read(fd
, buf
, sizeof(buf
) - 1);
120 "Failed to read cgroups file: %s\n",
135 /* load BPF program to set sk_bound_dev_if for sockets */
136 static char bpf_log_buf
[256*1024];
138 static int prog_load(int idx
)
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 */
151 return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK
, prog
, sizeof(prog
),
152 "GPL", bpf_log_buf
, sizeof(bpf_log_buf
));
155 static int vrf_configure_cgroup(const char *path
, int ifindex
)
157 int rc
= -1, cg_fd
, prog_fd
= -1;
159 cg_fd
= open(path
, O_DIRECTORY
| O_RDONLY
);
162 "Failed to open cgroup path: '%s'\n",
168 * Load bpf program into kernel and attach to cgroup to affect
171 prog_fd
= prog_load(ifindex
);
173 printf("Failed to load BPF prog: '%s'\n", strerror(errno
));
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",
180 fprintf(stderr
, "Kernel compiled with CGROUP_BPF enabled?\n");
192 static int vrf_switch(const char *name
)
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;
200 if (strcmp(name
, "default")) {
201 fprintf(stderr
, "Invalid VRF name\n");
207 mnt
= find_cgroup2_mount();
211 /* path to cgroup; make sure buffer has room to cat "/cgroup.procs"
212 * to the end of the path
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");
221 if (make_path(path
, 0755)) {
222 fprintf(stderr
, "Failed to setup vrf cgroup2 directory\n");
226 if (!default_vrf
&& vrf_configure_cgroup(path
, ifindex
))
230 * write pid to cgroup.procs making process part of cgroup
232 strcat(path
, CGRP_PROC_FILE
);
233 fd
= open(path
, O_RDWR
| O_APPEND
);
235 fprintf(stderr
, "Failed to open cgroups.procs file: %s.\n",
240 snprintf(pid
, sizeof(pid
), "%d", getpid());
241 if (write(fd
, pid
, strlen(pid
)) < 0) {
242 fprintf(stderr
, "Failed to join cgroup\n");
254 static int ipvrf_exec(int argc
, char **argv
)
257 fprintf(stderr
, "No VRF name specified\n");
261 fprintf(stderr
, "No command specified\n");
265 if (vrf_switch(argv
[0]))
268 return -cmd_exec(argv
[1], argv
+ 1, !!batch_mode
);
271 int do_ipvrf(int argc
, char **argv
)
274 fprintf(stderr
, "No command given. Try \"ip vrf help\".\n");
278 if (matches(*argv
, "identify") == 0)
279 return ipvrf_identify(argc
-1, argv
+1);
281 if (matches(*argv
, "pids") == 0)
282 return ipvrf_pids(argc
-1, argv
+1);
284 if (matches(*argv
, "exec") == 0)
285 return ipvrf_exec(argc
-1, argv
+1);
287 if (matches(*argv
, "help") == 0)
290 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip vrf help\".\n",