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", strerror(errno
));
134 /* load BPF program to set sk_bound_dev_if for sockets */
135 static char bpf_log_buf
[256*1024];
137 static int prog_load(int idx
)
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 */
148 return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK
, prog
, sizeof(prog
),
149 "GPL", bpf_log_buf
, sizeof(bpf_log_buf
));
152 static int vrf_configure_cgroup(const char *path
, int ifindex
)
154 int rc
= -1, cg_fd
, prog_fd
= -1;
156 cg_fd
= open(path
, O_DIRECTORY
| O_RDONLY
);
158 fprintf(stderr
, "Failed to open cgroup path: '%s'\n", strerror(errno
));
163 * Load bpf program into kernel and attach to cgroup to affect
166 prog_fd
= prog_load(ifindex
);
168 printf("Failed to load BPF prog: '%s'\n", strerror(errno
));
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",
175 fprintf(stderr
, "Kernel compiled with CGROUP_BPF enabled?\n");
187 static int vrf_switch(const char *name
)
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;
195 if (strcmp(name
, "default")) {
196 fprintf(stderr
, "Invalid VRF name\n");
202 mnt
= find_cgroup2_mount();
206 /* path to cgroup; make sure buffer has room to cat "/cgroup.procs"
207 * to the end of the path
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");
216 if (make_path(path
, 0755)) {
217 fprintf(stderr
, "Failed to setup vrf cgroup2 directory\n");
221 if (!default_vrf
&& vrf_configure_cgroup(path
, ifindex
))
225 * write pid to cgroup.procs making process part of cgroup
227 strcat(path
, CGRP_PROC_FILE
);
228 fd
= open(path
, O_RDWR
| O_APPEND
);
230 fprintf(stderr
, "Failed to open cgroups.procs file: %s.\n",
235 snprintf(pid
, sizeof(pid
), "%d", getpid());
236 if (write(fd
, pid
, strlen(pid
)) < 0) {
237 fprintf(stderr
, "Failed to join cgroup\n");
249 static int ipvrf_exec(int argc
, char **argv
)
252 fprintf(stderr
, "No VRF name specified\n");
256 fprintf(stderr
, "No command specified\n");
260 if (vrf_switch(argv
[0]))
263 return -cmd_exec(argv
[1], argv
+ 1, !!batch_mode
);
266 int do_ipvrf(int argc
, char **argv
)
269 fprintf(stderr
, "No command given. Try \"ip vrf help\".\n");
273 if (matches(*argv
, "identify") == 0)
274 return ipvrf_identify(argc
-1, argv
+1);
276 if (matches(*argv
, "pids") == 0)
277 return ipvrf_pids(argc
-1, argv
+1);
279 if (matches(*argv
, "exec") == 0)
280 return ipvrf_exec(argc
-1, argv
+1);
282 if (matches(*argv
, "help") == 0)
285 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip vrf help\".\n",