1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * ipvrf.c "ip vrf"
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker *
9*de1e4e89SAndroid Build Coastguard Worker * Authors: David Ahern <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker *
11*de1e4e89SAndroid Build Coastguard Worker */
12*de1e4e89SAndroid Build Coastguard Worker
13*de1e4e89SAndroid Build Coastguard Worker #include <sys/types.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <sys/stat.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <sys/mount.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <linux/bpf.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <linux/if.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
24*de1e4e89SAndroid Build Coastguard Worker #include <dirent.h>
25*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
26*de1e4e89SAndroid Build Coastguard Worker #include <limits.h>
27*de1e4e89SAndroid Build Coastguard Worker
28*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
29*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
30*de1e4e89SAndroid Build Coastguard Worker #include "ip_common.h"
31*de1e4e89SAndroid Build Coastguard Worker #include "bpf_util.h"
32*de1e4e89SAndroid Build Coastguard Worker
33*de1e4e89SAndroid Build Coastguard Worker #define CGRP_PROC_FILE "/cgroup.procs"
34*de1e4e89SAndroid Build Coastguard Worker
35*de1e4e89SAndroid Build Coastguard Worker static struct link_filter vrf_filter;
36*de1e4e89SAndroid Build Coastguard Worker
usage(void)37*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
38*de1e4e89SAndroid Build Coastguard Worker {
39*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Usage: ip vrf show [NAME] ...\n");
40*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip vrf exec [NAME] cmd ...\n");
41*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip vrf identify [PID]\n");
42*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " ip vrf pids [NAME]\n");
43*de1e4e89SAndroid Build Coastguard Worker
44*de1e4e89SAndroid Build Coastguard Worker exit(-1);
45*de1e4e89SAndroid Build Coastguard Worker }
46*de1e4e89SAndroid Build Coastguard Worker
47*de1e4e89SAndroid Build Coastguard Worker /*
48*de1e4e89SAndroid Build Coastguard Worker * parse process based cgroup file looking for PATH/vrf/NAME where
49*de1e4e89SAndroid Build Coastguard Worker * NAME is the name of the vrf the process is associated with
50*de1e4e89SAndroid Build Coastguard Worker */
vrf_identify(pid_t pid,char * name,size_t len)51*de1e4e89SAndroid Build Coastguard Worker static int vrf_identify(pid_t pid, char *name, size_t len)
52*de1e4e89SAndroid Build Coastguard Worker {
53*de1e4e89SAndroid Build Coastguard Worker char path[PATH_MAX];
54*de1e4e89SAndroid Build Coastguard Worker char buf[4096];
55*de1e4e89SAndroid Build Coastguard Worker char *vrf, *end;
56*de1e4e89SAndroid Build Coastguard Worker FILE *fp;
57*de1e4e89SAndroid Build Coastguard Worker
58*de1e4e89SAndroid Build Coastguard Worker snprintf(path, sizeof(path), "/proc/%d/cgroup", pid);
59*de1e4e89SAndroid Build Coastguard Worker fp = fopen(path, "r");
60*de1e4e89SAndroid Build Coastguard Worker if (!fp)
61*de1e4e89SAndroid Build Coastguard Worker return -1;
62*de1e4e89SAndroid Build Coastguard Worker
63*de1e4e89SAndroid Build Coastguard Worker memset(name, 0, len);
64*de1e4e89SAndroid Build Coastguard Worker
65*de1e4e89SAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), fp)) {
66*de1e4e89SAndroid Build Coastguard Worker /* want the controller-less cgroup */
67*de1e4e89SAndroid Build Coastguard Worker if (strstr(buf, "::/") == NULL)
68*de1e4e89SAndroid Build Coastguard Worker continue;
69*de1e4e89SAndroid Build Coastguard Worker
70*de1e4e89SAndroid Build Coastguard Worker vrf = strstr(buf, "/vrf/");
71*de1e4e89SAndroid Build Coastguard Worker if (vrf) {
72*de1e4e89SAndroid Build Coastguard Worker vrf += 5; /* skip past "/vrf/" */
73*de1e4e89SAndroid Build Coastguard Worker end = strchr(vrf, '\n');
74*de1e4e89SAndroid Build Coastguard Worker if (end)
75*de1e4e89SAndroid Build Coastguard Worker *end = '\0';
76*de1e4e89SAndroid Build Coastguard Worker
77*de1e4e89SAndroid Build Coastguard Worker strlcpy(name, vrf, len);
78*de1e4e89SAndroid Build Coastguard Worker break;
79*de1e4e89SAndroid Build Coastguard Worker }
80*de1e4e89SAndroid Build Coastguard Worker }
81*de1e4e89SAndroid Build Coastguard Worker
82*de1e4e89SAndroid Build Coastguard Worker fclose(fp);
83*de1e4e89SAndroid Build Coastguard Worker
84*de1e4e89SAndroid Build Coastguard Worker return 0;
85*de1e4e89SAndroid Build Coastguard Worker }
86*de1e4e89SAndroid Build Coastguard Worker
ipvrf_identify(int argc,char ** argv)87*de1e4e89SAndroid Build Coastguard Worker static int ipvrf_identify(int argc, char **argv)
88*de1e4e89SAndroid Build Coastguard Worker {
89*de1e4e89SAndroid Build Coastguard Worker char vrf[32];
90*de1e4e89SAndroid Build Coastguard Worker int rc;
91*de1e4e89SAndroid Build Coastguard Worker unsigned int pid;
92*de1e4e89SAndroid Build Coastguard Worker
93*de1e4e89SAndroid Build Coastguard Worker if (argc < 1)
94*de1e4e89SAndroid Build Coastguard Worker pid = getpid();
95*de1e4e89SAndroid Build Coastguard Worker else if (argc > 1)
96*de1e4e89SAndroid Build Coastguard Worker invarg("Extra arguments specified\n", argv[1]);
97*de1e4e89SAndroid Build Coastguard Worker else if (get_unsigned(&pid, argv[0], 10))
98*de1e4e89SAndroid Build Coastguard Worker invarg("Invalid pid\n", argv[0]);
99*de1e4e89SAndroid Build Coastguard Worker
100*de1e4e89SAndroid Build Coastguard Worker rc = vrf_identify(pid, vrf, sizeof(vrf));
101*de1e4e89SAndroid Build Coastguard Worker if (!rc) {
102*de1e4e89SAndroid Build Coastguard Worker if (vrf[0] != '\0')
103*de1e4e89SAndroid Build Coastguard Worker printf("%s\n", vrf);
104*de1e4e89SAndroid Build Coastguard Worker } else {
105*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to lookup vrf association: %s\n",
106*de1e4e89SAndroid Build Coastguard Worker strerror(errno));
107*de1e4e89SAndroid Build Coastguard Worker }
108*de1e4e89SAndroid Build Coastguard Worker
109*de1e4e89SAndroid Build Coastguard Worker return rc;
110*de1e4e89SAndroid Build Coastguard Worker }
111*de1e4e89SAndroid Build Coastguard Worker
112*de1e4e89SAndroid Build Coastguard Worker /* read PATH/vrf/NAME/cgroup.procs file */
read_cgroup_pids(const char * base_path,char * name)113*de1e4e89SAndroid Build Coastguard Worker static void read_cgroup_pids(const char *base_path, char *name)
114*de1e4e89SAndroid Build Coastguard Worker {
115*de1e4e89SAndroid Build Coastguard Worker char path[PATH_MAX];
116*de1e4e89SAndroid Build Coastguard Worker char buf[4096];
117*de1e4e89SAndroid Build Coastguard Worker FILE *fp;
118*de1e4e89SAndroid Build Coastguard Worker
119*de1e4e89SAndroid Build Coastguard Worker if (snprintf(path, sizeof(path), "%s/vrf/%s%s",
120*de1e4e89SAndroid Build Coastguard Worker base_path, name, CGRP_PROC_FILE) >= sizeof(path))
121*de1e4e89SAndroid Build Coastguard Worker return;
122*de1e4e89SAndroid Build Coastguard Worker
123*de1e4e89SAndroid Build Coastguard Worker fp = fopen(path, "r");
124*de1e4e89SAndroid Build Coastguard Worker if (!fp)
125*de1e4e89SAndroid Build Coastguard Worker return; /* no cgroup file, nothing to show */
126*de1e4e89SAndroid Build Coastguard Worker
127*de1e4e89SAndroid Build Coastguard Worker /* dump contents (pids) of cgroup.procs */
128*de1e4e89SAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), fp)) {
129*de1e4e89SAndroid Build Coastguard Worker char *nl, comm[32];
130*de1e4e89SAndroid Build Coastguard Worker
131*de1e4e89SAndroid Build Coastguard Worker nl = strchr(buf, '\n');
132*de1e4e89SAndroid Build Coastguard Worker if (nl)
133*de1e4e89SAndroid Build Coastguard Worker *nl = '\0';
134*de1e4e89SAndroid Build Coastguard Worker
135*de1e4e89SAndroid Build Coastguard Worker if (get_command_name(buf, comm, sizeof(comm)))
136*de1e4e89SAndroid Build Coastguard Worker strcpy(comm, "<terminated?>");
137*de1e4e89SAndroid Build Coastguard Worker
138*de1e4e89SAndroid Build Coastguard Worker printf("%5s %s\n", buf, comm);
139*de1e4e89SAndroid Build Coastguard Worker }
140*de1e4e89SAndroid Build Coastguard Worker
141*de1e4e89SAndroid Build Coastguard Worker fclose(fp);
142*de1e4e89SAndroid Build Coastguard Worker }
143*de1e4e89SAndroid Build Coastguard Worker
144*de1e4e89SAndroid Build Coastguard Worker /* recurse path looking for PATH[/NETNS]/vrf/NAME */
recurse_dir(char * base_path,char * name,const char * netns)145*de1e4e89SAndroid Build Coastguard Worker static int recurse_dir(char *base_path, char *name, const char *netns)
146*de1e4e89SAndroid Build Coastguard Worker {
147*de1e4e89SAndroid Build Coastguard Worker char path[PATH_MAX];
148*de1e4e89SAndroid Build Coastguard Worker struct dirent *de;
149*de1e4e89SAndroid Build Coastguard Worker struct stat fstat;
150*de1e4e89SAndroid Build Coastguard Worker int rc;
151*de1e4e89SAndroid Build Coastguard Worker DIR *d;
152*de1e4e89SAndroid Build Coastguard Worker
153*de1e4e89SAndroid Build Coastguard Worker d = opendir(base_path);
154*de1e4e89SAndroid Build Coastguard Worker if (!d)
155*de1e4e89SAndroid Build Coastguard Worker return -1;
156*de1e4e89SAndroid Build Coastguard Worker
157*de1e4e89SAndroid Build Coastguard Worker while ((de = readdir(d)) != NULL) {
158*de1e4e89SAndroid Build Coastguard Worker if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
159*de1e4e89SAndroid Build Coastguard Worker continue;
160*de1e4e89SAndroid Build Coastguard Worker
161*de1e4e89SAndroid Build Coastguard Worker if (!strcmp(de->d_name, "vrf")) {
162*de1e4e89SAndroid Build Coastguard Worker const char *pdir = strrchr(base_path, '/');
163*de1e4e89SAndroid Build Coastguard Worker
164*de1e4e89SAndroid Build Coastguard Worker /* found a 'vrf' directory. if it is for the given
165*de1e4e89SAndroid Build Coastguard Worker * namespace then dump the cgroup pids
166*de1e4e89SAndroid Build Coastguard Worker */
167*de1e4e89SAndroid Build Coastguard Worker if (*netns == '\0' ||
168*de1e4e89SAndroid Build Coastguard Worker (pdir && !strcmp(pdir+1, netns)))
169*de1e4e89SAndroid Build Coastguard Worker read_cgroup_pids(base_path, name);
170*de1e4e89SAndroid Build Coastguard Worker
171*de1e4e89SAndroid Build Coastguard Worker continue;
172*de1e4e89SAndroid Build Coastguard Worker }
173*de1e4e89SAndroid Build Coastguard Worker
174*de1e4e89SAndroid Build Coastguard Worker /* is this a subdir that needs to be walked */
175*de1e4e89SAndroid Build Coastguard Worker if (snprintf(path, sizeof(path), "%s/%s",
176*de1e4e89SAndroid Build Coastguard Worker base_path, de->d_name) >= sizeof(path))
177*de1e4e89SAndroid Build Coastguard Worker continue;
178*de1e4e89SAndroid Build Coastguard Worker
179*de1e4e89SAndroid Build Coastguard Worker if (lstat(path, &fstat) < 0)
180*de1e4e89SAndroid Build Coastguard Worker continue;
181*de1e4e89SAndroid Build Coastguard Worker
182*de1e4e89SAndroid Build Coastguard Worker if (S_ISDIR(fstat.st_mode)) {
183*de1e4e89SAndroid Build Coastguard Worker rc = recurse_dir(path, name, netns);
184*de1e4e89SAndroid Build Coastguard Worker if (rc != 0)
185*de1e4e89SAndroid Build Coastguard Worker goto out;
186*de1e4e89SAndroid Build Coastguard Worker }
187*de1e4e89SAndroid Build Coastguard Worker }
188*de1e4e89SAndroid Build Coastguard Worker
189*de1e4e89SAndroid Build Coastguard Worker rc = 0;
190*de1e4e89SAndroid Build Coastguard Worker out:
191*de1e4e89SAndroid Build Coastguard Worker closedir(d);
192*de1e4e89SAndroid Build Coastguard Worker
193*de1e4e89SAndroid Build Coastguard Worker return rc;
194*de1e4e89SAndroid Build Coastguard Worker }
195*de1e4e89SAndroid Build Coastguard Worker
ipvrf_get_netns(char * netns,int len)196*de1e4e89SAndroid Build Coastguard Worker static int ipvrf_get_netns(char *netns, int len)
197*de1e4e89SAndroid Build Coastguard Worker {
198*de1e4e89SAndroid Build Coastguard Worker if (netns_identify_pid("self", netns, len-3)) {
199*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to get name of network namespace: %s\n",
200*de1e4e89SAndroid Build Coastguard Worker strerror(errno));
201*de1e4e89SAndroid Build Coastguard Worker return -1;
202*de1e4e89SAndroid Build Coastguard Worker }
203*de1e4e89SAndroid Build Coastguard Worker
204*de1e4e89SAndroid Build Coastguard Worker if (*netns != '\0')
205*de1e4e89SAndroid Build Coastguard Worker strcat(netns, "-ns");
206*de1e4e89SAndroid Build Coastguard Worker
207*de1e4e89SAndroid Build Coastguard Worker return 0;
208*de1e4e89SAndroid Build Coastguard Worker }
209*de1e4e89SAndroid Build Coastguard Worker
ipvrf_pids(int argc,char ** argv)210*de1e4e89SAndroid Build Coastguard Worker static int ipvrf_pids(int argc, char **argv)
211*de1e4e89SAndroid Build Coastguard Worker {
212*de1e4e89SAndroid Build Coastguard Worker char *mnt, *vrf;
213*de1e4e89SAndroid Build Coastguard Worker char netns[256];
214*de1e4e89SAndroid Build Coastguard Worker int ret = -1;
215*de1e4e89SAndroid Build Coastguard Worker
216*de1e4e89SAndroid Build Coastguard Worker if (argc != 1) {
217*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Invalid arguments\n");
218*de1e4e89SAndroid Build Coastguard Worker return -1;
219*de1e4e89SAndroid Build Coastguard Worker }
220*de1e4e89SAndroid Build Coastguard Worker
221*de1e4e89SAndroid Build Coastguard Worker vrf = argv[0];
222*de1e4e89SAndroid Build Coastguard Worker if (!name_is_vrf(vrf)) {
223*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Invalid VRF name\n");
224*de1e4e89SAndroid Build Coastguard Worker return -1;
225*de1e4e89SAndroid Build Coastguard Worker }
226*de1e4e89SAndroid Build Coastguard Worker
227*de1e4e89SAndroid Build Coastguard Worker mnt = find_cgroup2_mount();
228*de1e4e89SAndroid Build Coastguard Worker if (!mnt)
229*de1e4e89SAndroid Build Coastguard Worker return -1;
230*de1e4e89SAndroid Build Coastguard Worker
231*de1e4e89SAndroid Build Coastguard Worker if (ipvrf_get_netns(netns, sizeof(netns)) < 0)
232*de1e4e89SAndroid Build Coastguard Worker goto out;
233*de1e4e89SAndroid Build Coastguard Worker
234*de1e4e89SAndroid Build Coastguard Worker ret = recurse_dir(mnt, vrf, netns);
235*de1e4e89SAndroid Build Coastguard Worker
236*de1e4e89SAndroid Build Coastguard Worker out:
237*de1e4e89SAndroid Build Coastguard Worker free(mnt);
238*de1e4e89SAndroid Build Coastguard Worker
239*de1e4e89SAndroid Build Coastguard Worker return ret;
240*de1e4e89SAndroid Build Coastguard Worker }
241*de1e4e89SAndroid Build Coastguard Worker
242*de1e4e89SAndroid Build Coastguard Worker /* load BPF program to set sk_bound_dev_if for sockets */
243*de1e4e89SAndroid Build Coastguard Worker static char bpf_log_buf[256*1024];
244*de1e4e89SAndroid Build Coastguard Worker
prog_load(int idx)245*de1e4e89SAndroid Build Coastguard Worker static int prog_load(int idx)
246*de1e4e89SAndroid Build Coastguard Worker {
247*de1e4e89SAndroid Build Coastguard Worker struct bpf_insn prog[] = {
248*de1e4e89SAndroid Build Coastguard Worker BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
249*de1e4e89SAndroid Build Coastguard Worker BPF_MOV64_IMM(BPF_REG_3, idx),
250*de1e4e89SAndroid Build Coastguard Worker BPF_MOV64_IMM(BPF_REG_2,
251*de1e4e89SAndroid Build Coastguard Worker offsetof(struct bpf_sock, bound_dev_if)),
252*de1e4e89SAndroid Build Coastguard Worker BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
253*de1e4e89SAndroid Build Coastguard Worker offsetof(struct bpf_sock, bound_dev_if)),
254*de1e4e89SAndroid Build Coastguard Worker BPF_MOV64_IMM(BPF_REG_0, 1), /* r0 = verdict */
255*de1e4e89SAndroid Build Coastguard Worker BPF_EXIT_INSN(),
256*de1e4e89SAndroid Build Coastguard Worker };
257*de1e4e89SAndroid Build Coastguard Worker
258*de1e4e89SAndroid Build Coastguard Worker return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, prog, sizeof(prog),
259*de1e4e89SAndroid Build Coastguard Worker "GPL", bpf_log_buf, sizeof(bpf_log_buf));
260*de1e4e89SAndroid Build Coastguard Worker }
261*de1e4e89SAndroid Build Coastguard Worker
vrf_configure_cgroup(const char * path,int ifindex)262*de1e4e89SAndroid Build Coastguard Worker static int vrf_configure_cgroup(const char *path, int ifindex)
263*de1e4e89SAndroid Build Coastguard Worker {
264*de1e4e89SAndroid Build Coastguard Worker int rc = -1, cg_fd, prog_fd = -1;
265*de1e4e89SAndroid Build Coastguard Worker
266*de1e4e89SAndroid Build Coastguard Worker cg_fd = open(path, O_DIRECTORY | O_RDONLY);
267*de1e4e89SAndroid Build Coastguard Worker if (cg_fd < 0) {
268*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
269*de1e4e89SAndroid Build Coastguard Worker "Failed to open cgroup path: '%s'\n",
270*de1e4e89SAndroid Build Coastguard Worker strerror(errno));
271*de1e4e89SAndroid Build Coastguard Worker goto out;
272*de1e4e89SAndroid Build Coastguard Worker }
273*de1e4e89SAndroid Build Coastguard Worker
274*de1e4e89SAndroid Build Coastguard Worker /*
275*de1e4e89SAndroid Build Coastguard Worker * Load bpf program into kernel and attach to cgroup to affect
276*de1e4e89SAndroid Build Coastguard Worker * socket creates
277*de1e4e89SAndroid Build Coastguard Worker */
278*de1e4e89SAndroid Build Coastguard Worker prog_fd = prog_load(ifindex);
279*de1e4e89SAndroid Build Coastguard Worker if (prog_fd < 0) {
280*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to load BPF prog: '%s'\n",
281*de1e4e89SAndroid Build Coastguard Worker strerror(errno));
282*de1e4e89SAndroid Build Coastguard Worker
283*de1e4e89SAndroid Build Coastguard Worker if (errno != EPERM) {
284*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
285*de1e4e89SAndroid Build Coastguard Worker "Kernel compiled with CGROUP_BPF enabled?\n");
286*de1e4e89SAndroid Build Coastguard Worker }
287*de1e4e89SAndroid Build Coastguard Worker goto out;
288*de1e4e89SAndroid Build Coastguard Worker }
289*de1e4e89SAndroid Build Coastguard Worker
290*de1e4e89SAndroid Build Coastguard Worker if (bpf_prog_attach_fd(prog_fd, cg_fd, BPF_CGROUP_INET_SOCK_CREATE)) {
291*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to attach prog to cgroup: '%s'\n",
292*de1e4e89SAndroid Build Coastguard Worker strerror(errno));
293*de1e4e89SAndroid Build Coastguard Worker goto out;
294*de1e4e89SAndroid Build Coastguard Worker }
295*de1e4e89SAndroid Build Coastguard Worker
296*de1e4e89SAndroid Build Coastguard Worker rc = 0;
297*de1e4e89SAndroid Build Coastguard Worker out:
298*de1e4e89SAndroid Build Coastguard Worker close(cg_fd);
299*de1e4e89SAndroid Build Coastguard Worker close(prog_fd);
300*de1e4e89SAndroid Build Coastguard Worker
301*de1e4e89SAndroid Build Coastguard Worker return rc;
302*de1e4e89SAndroid Build Coastguard Worker }
303*de1e4e89SAndroid Build Coastguard Worker
304*de1e4e89SAndroid Build Coastguard Worker /* get base path for controller-less cgroup for a process.
305*de1e4e89SAndroid Build Coastguard Worker * path returned does not include /vrf/NAME if it exists
306*de1e4e89SAndroid Build Coastguard Worker */
vrf_path(char * vpath,size_t len)307*de1e4e89SAndroid Build Coastguard Worker static int vrf_path(char *vpath, size_t len)
308*de1e4e89SAndroid Build Coastguard Worker {
309*de1e4e89SAndroid Build Coastguard Worker char path[PATH_MAX];
310*de1e4e89SAndroid Build Coastguard Worker char buf[4096];
311*de1e4e89SAndroid Build Coastguard Worker char *vrf;
312*de1e4e89SAndroid Build Coastguard Worker FILE *fp;
313*de1e4e89SAndroid Build Coastguard Worker
314*de1e4e89SAndroid Build Coastguard Worker snprintf(path, sizeof(path), "/proc/%d/cgroup", getpid());
315*de1e4e89SAndroid Build Coastguard Worker fp = fopen(path, "r");
316*de1e4e89SAndroid Build Coastguard Worker if (!fp)
317*de1e4e89SAndroid Build Coastguard Worker return -1;
318*de1e4e89SAndroid Build Coastguard Worker
319*de1e4e89SAndroid Build Coastguard Worker vpath[0] = '\0';
320*de1e4e89SAndroid Build Coastguard Worker
321*de1e4e89SAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), fp)) {
322*de1e4e89SAndroid Build Coastguard Worker char *start, *nl;
323*de1e4e89SAndroid Build Coastguard Worker
324*de1e4e89SAndroid Build Coastguard Worker start = strstr(buf, "::/");
325*de1e4e89SAndroid Build Coastguard Worker if (!start)
326*de1e4e89SAndroid Build Coastguard Worker continue;
327*de1e4e89SAndroid Build Coastguard Worker
328*de1e4e89SAndroid Build Coastguard Worker /* advance past '::' */
329*de1e4e89SAndroid Build Coastguard Worker start += 2;
330*de1e4e89SAndroid Build Coastguard Worker
331*de1e4e89SAndroid Build Coastguard Worker nl = strchr(start, '\n');
332*de1e4e89SAndroid Build Coastguard Worker if (nl)
333*de1e4e89SAndroid Build Coastguard Worker *nl = '\0';
334*de1e4e89SAndroid Build Coastguard Worker
335*de1e4e89SAndroid Build Coastguard Worker vrf = strstr(start, "/vrf");
336*de1e4e89SAndroid Build Coastguard Worker if (vrf)
337*de1e4e89SAndroid Build Coastguard Worker *vrf = '\0';
338*de1e4e89SAndroid Build Coastguard Worker
339*de1e4e89SAndroid Build Coastguard Worker strlcpy(vpath, start, len);
340*de1e4e89SAndroid Build Coastguard Worker
341*de1e4e89SAndroid Build Coastguard Worker /* if vrf path is just / then return nothing */
342*de1e4e89SAndroid Build Coastguard Worker if (!strcmp(vpath, "/"))
343*de1e4e89SAndroid Build Coastguard Worker vpath[0] = '\0';
344*de1e4e89SAndroid Build Coastguard Worker
345*de1e4e89SAndroid Build Coastguard Worker break;
346*de1e4e89SAndroid Build Coastguard Worker }
347*de1e4e89SAndroid Build Coastguard Worker
348*de1e4e89SAndroid Build Coastguard Worker fclose(fp);
349*de1e4e89SAndroid Build Coastguard Worker
350*de1e4e89SAndroid Build Coastguard Worker return 0;
351*de1e4e89SAndroid Build Coastguard Worker }
352*de1e4e89SAndroid Build Coastguard Worker
vrf_switch(const char * name)353*de1e4e89SAndroid Build Coastguard Worker static int vrf_switch(const char *name)
354*de1e4e89SAndroid Build Coastguard Worker {
355*de1e4e89SAndroid Build Coastguard Worker char path[PATH_MAX], *mnt, pid[16];
356*de1e4e89SAndroid Build Coastguard Worker char vpath[PATH_MAX], netns[256];
357*de1e4e89SAndroid Build Coastguard Worker int ifindex = 0;
358*de1e4e89SAndroid Build Coastguard Worker int rc = -1, len, fd = -1;
359*de1e4e89SAndroid Build Coastguard Worker
360*de1e4e89SAndroid Build Coastguard Worker if (strcmp(name, "default")) {
361*de1e4e89SAndroid Build Coastguard Worker ifindex = name_is_vrf(name);
362*de1e4e89SAndroid Build Coastguard Worker if (!ifindex) {
363*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Invalid VRF name\n");
364*de1e4e89SAndroid Build Coastguard Worker return -1;
365*de1e4e89SAndroid Build Coastguard Worker }
366*de1e4e89SAndroid Build Coastguard Worker }
367*de1e4e89SAndroid Build Coastguard Worker
368*de1e4e89SAndroid Build Coastguard Worker mnt = find_cgroup2_mount();
369*de1e4e89SAndroid Build Coastguard Worker if (!mnt)
370*de1e4e89SAndroid Build Coastguard Worker return -1;
371*de1e4e89SAndroid Build Coastguard Worker
372*de1e4e89SAndroid Build Coastguard Worker /* -1 on length to add '/' to the end */
373*de1e4e89SAndroid Build Coastguard Worker if (ipvrf_get_netns(netns, sizeof(netns) - 1) < 0)
374*de1e4e89SAndroid Build Coastguard Worker goto out;
375*de1e4e89SAndroid Build Coastguard Worker
376*de1e4e89SAndroid Build Coastguard Worker if (vrf_path(vpath, sizeof(vpath)) < 0) {
377*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to get base cgroup path: %s\n",
378*de1e4e89SAndroid Build Coastguard Worker strerror(errno));
379*de1e4e89SAndroid Build Coastguard Worker goto out;
380*de1e4e89SAndroid Build Coastguard Worker }
381*de1e4e89SAndroid Build Coastguard Worker
382*de1e4e89SAndroid Build Coastguard Worker /* if path already ends in netns then don't add it again */
383*de1e4e89SAndroid Build Coastguard Worker if (*netns != '\0') {
384*de1e4e89SAndroid Build Coastguard Worker char *pdir = strrchr(vpath, '/');
385*de1e4e89SAndroid Build Coastguard Worker
386*de1e4e89SAndroid Build Coastguard Worker if (!pdir)
387*de1e4e89SAndroid Build Coastguard Worker pdir = vpath;
388*de1e4e89SAndroid Build Coastguard Worker else
389*de1e4e89SAndroid Build Coastguard Worker pdir++;
390*de1e4e89SAndroid Build Coastguard Worker
391*de1e4e89SAndroid Build Coastguard Worker if (strcmp(pdir, netns) == 0)
392*de1e4e89SAndroid Build Coastguard Worker *pdir = '\0';
393*de1e4e89SAndroid Build Coastguard Worker
394*de1e4e89SAndroid Build Coastguard Worker strcat(netns, "/");
395*de1e4e89SAndroid Build Coastguard Worker }
396*de1e4e89SAndroid Build Coastguard Worker
397*de1e4e89SAndroid Build Coastguard Worker /* path to cgroup; make sure buffer has room to cat "/cgroup.procs"
398*de1e4e89SAndroid Build Coastguard Worker * to the end of the path
399*de1e4e89SAndroid Build Coastguard Worker */
400*de1e4e89SAndroid Build Coastguard Worker len = snprintf(path, sizeof(path) - sizeof(CGRP_PROC_FILE),
401*de1e4e89SAndroid Build Coastguard Worker "%s%s/%svrf/%s",
402*de1e4e89SAndroid Build Coastguard Worker mnt, vpath, netns, ifindex ? name : "");
403*de1e4e89SAndroid Build Coastguard Worker if (len > sizeof(path) - sizeof(CGRP_PROC_FILE)) {
404*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Invalid path to cgroup2 mount\n");
405*de1e4e89SAndroid Build Coastguard Worker goto out;
406*de1e4e89SAndroid Build Coastguard Worker }
407*de1e4e89SAndroid Build Coastguard Worker
408*de1e4e89SAndroid Build Coastguard Worker if (make_path(path, 0755)) {
409*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to setup vrf cgroup2 directory\n");
410*de1e4e89SAndroid Build Coastguard Worker goto out;
411*de1e4e89SAndroid Build Coastguard Worker }
412*de1e4e89SAndroid Build Coastguard Worker
413*de1e4e89SAndroid Build Coastguard Worker if (ifindex && vrf_configure_cgroup(path, ifindex))
414*de1e4e89SAndroid Build Coastguard Worker goto out;
415*de1e4e89SAndroid Build Coastguard Worker
416*de1e4e89SAndroid Build Coastguard Worker /*
417*de1e4e89SAndroid Build Coastguard Worker * write pid to cgroup.procs making process part of cgroup
418*de1e4e89SAndroid Build Coastguard Worker */
419*de1e4e89SAndroid Build Coastguard Worker strcat(path, CGRP_PROC_FILE);
420*de1e4e89SAndroid Build Coastguard Worker fd = open(path, O_RDWR | O_APPEND);
421*de1e4e89SAndroid Build Coastguard Worker if (fd < 0) {
422*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to open cgroups.procs file: %s.\n",
423*de1e4e89SAndroid Build Coastguard Worker strerror(errno));
424*de1e4e89SAndroid Build Coastguard Worker goto out;
425*de1e4e89SAndroid Build Coastguard Worker }
426*de1e4e89SAndroid Build Coastguard Worker
427*de1e4e89SAndroid Build Coastguard Worker snprintf(pid, sizeof(pid), "%d", getpid());
428*de1e4e89SAndroid Build Coastguard Worker if (write(fd, pid, strlen(pid)) < 0) {
429*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Failed to join cgroup\n");
430*de1e4e89SAndroid Build Coastguard Worker goto out2;
431*de1e4e89SAndroid Build Coastguard Worker }
432*de1e4e89SAndroid Build Coastguard Worker
433*de1e4e89SAndroid Build Coastguard Worker rc = 0;
434*de1e4e89SAndroid Build Coastguard Worker out2:
435*de1e4e89SAndroid Build Coastguard Worker close(fd);
436*de1e4e89SAndroid Build Coastguard Worker out:
437*de1e4e89SAndroid Build Coastguard Worker free(mnt);
438*de1e4e89SAndroid Build Coastguard Worker
439*de1e4e89SAndroid Build Coastguard Worker return rc;
440*de1e4e89SAndroid Build Coastguard Worker }
441*de1e4e89SAndroid Build Coastguard Worker
ipvrf_exec(int argc,char ** argv)442*de1e4e89SAndroid Build Coastguard Worker static int ipvrf_exec(int argc, char **argv)
443*de1e4e89SAndroid Build Coastguard Worker {
444*de1e4e89SAndroid Build Coastguard Worker if (argc < 1) {
445*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "No VRF name specified\n");
446*de1e4e89SAndroid Build Coastguard Worker return -1;
447*de1e4e89SAndroid Build Coastguard Worker }
448*de1e4e89SAndroid Build Coastguard Worker if (argc < 2) {
449*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "No command specified\n");
450*de1e4e89SAndroid Build Coastguard Worker return -1;
451*de1e4e89SAndroid Build Coastguard Worker }
452*de1e4e89SAndroid Build Coastguard Worker
453*de1e4e89SAndroid Build Coastguard Worker if (vrf_switch(argv[0]))
454*de1e4e89SAndroid Build Coastguard Worker return -1;
455*de1e4e89SAndroid Build Coastguard Worker
456*de1e4e89SAndroid Build Coastguard Worker return -cmd_exec(argv[1], argv + 1, !!batch_mode);
457*de1e4e89SAndroid Build Coastguard Worker }
458*de1e4e89SAndroid Build Coastguard Worker
459*de1e4e89SAndroid Build Coastguard Worker /* reset VRF association of current process to default VRF;
460*de1e4e89SAndroid Build Coastguard Worker * used by netns_exec
461*de1e4e89SAndroid Build Coastguard Worker */
vrf_reset(void)462*de1e4e89SAndroid Build Coastguard Worker void vrf_reset(void)
463*de1e4e89SAndroid Build Coastguard Worker {
464*de1e4e89SAndroid Build Coastguard Worker char vrf[32];
465*de1e4e89SAndroid Build Coastguard Worker
466*de1e4e89SAndroid Build Coastguard Worker if (vrf_identify(getpid(), vrf, sizeof(vrf)) ||
467*de1e4e89SAndroid Build Coastguard Worker (vrf[0] == '\0'))
468*de1e4e89SAndroid Build Coastguard Worker return;
469*de1e4e89SAndroid Build Coastguard Worker
470*de1e4e89SAndroid Build Coastguard Worker vrf_switch("default");
471*de1e4e89SAndroid Build Coastguard Worker }
472*de1e4e89SAndroid Build Coastguard Worker
ipvrf_filter_req(struct nlmsghdr * nlh,int reqlen)473*de1e4e89SAndroid Build Coastguard Worker static int ipvrf_filter_req(struct nlmsghdr *nlh, int reqlen)
474*de1e4e89SAndroid Build Coastguard Worker {
475*de1e4e89SAndroid Build Coastguard Worker struct rtattr *linkinfo;
476*de1e4e89SAndroid Build Coastguard Worker int err;
477*de1e4e89SAndroid Build Coastguard Worker
478*de1e4e89SAndroid Build Coastguard Worker if (vrf_filter.kind) {
479*de1e4e89SAndroid Build Coastguard Worker linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO);
480*de1e4e89SAndroid Build Coastguard Worker
481*de1e4e89SAndroid Build Coastguard Worker err = addattr_l(nlh, reqlen, IFLA_INFO_KIND, vrf_filter.kind,
482*de1e4e89SAndroid Build Coastguard Worker strlen(vrf_filter.kind));
483*de1e4e89SAndroid Build Coastguard Worker if (err)
484*de1e4e89SAndroid Build Coastguard Worker return err;
485*de1e4e89SAndroid Build Coastguard Worker
486*de1e4e89SAndroid Build Coastguard Worker addattr_nest_end(nlh, linkinfo);
487*de1e4e89SAndroid Build Coastguard Worker }
488*de1e4e89SAndroid Build Coastguard Worker
489*de1e4e89SAndroid Build Coastguard Worker return 0;
490*de1e4e89SAndroid Build Coastguard Worker }
491*de1e4e89SAndroid Build Coastguard Worker
492*de1e4e89SAndroid Build Coastguard Worker /* input arg is linkinfo */
vrf_table_linkinfo(struct rtattr * li[])493*de1e4e89SAndroid Build Coastguard Worker static __u32 vrf_table_linkinfo(struct rtattr *li[])
494*de1e4e89SAndroid Build Coastguard Worker {
495*de1e4e89SAndroid Build Coastguard Worker struct rtattr *attr[IFLA_VRF_MAX + 1];
496*de1e4e89SAndroid Build Coastguard Worker
497*de1e4e89SAndroid Build Coastguard Worker if (li[IFLA_INFO_DATA]) {
498*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]);
499*de1e4e89SAndroid Build Coastguard Worker
500*de1e4e89SAndroid Build Coastguard Worker if (attr[IFLA_VRF_TABLE])
501*de1e4e89SAndroid Build Coastguard Worker return rta_getattr_u32(attr[IFLA_VRF_TABLE]);
502*de1e4e89SAndroid Build Coastguard Worker }
503*de1e4e89SAndroid Build Coastguard Worker
504*de1e4e89SAndroid Build Coastguard Worker return 0;
505*de1e4e89SAndroid Build Coastguard Worker }
506*de1e4e89SAndroid Build Coastguard Worker
ipvrf_print(struct nlmsghdr * n)507*de1e4e89SAndroid Build Coastguard Worker static int ipvrf_print(struct nlmsghdr *n)
508*de1e4e89SAndroid Build Coastguard Worker {
509*de1e4e89SAndroid Build Coastguard Worker struct ifinfomsg *ifi = NLMSG_DATA(n);
510*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[IFLA_MAX+1];
511*de1e4e89SAndroid Build Coastguard Worker struct rtattr *li[IFLA_INFO_MAX+1];
512*de1e4e89SAndroid Build Coastguard Worker int len = n->nlmsg_len;
513*de1e4e89SAndroid Build Coastguard Worker const char *name;
514*de1e4e89SAndroid Build Coastguard Worker __u32 tb_id;
515*de1e4e89SAndroid Build Coastguard Worker
516*de1e4e89SAndroid Build Coastguard Worker len -= NLMSG_LENGTH(sizeof(*ifi));
517*de1e4e89SAndroid Build Coastguard Worker if (len < 0)
518*de1e4e89SAndroid Build Coastguard Worker return 0;
519*de1e4e89SAndroid Build Coastguard Worker
520*de1e4e89SAndroid Build Coastguard Worker if (vrf_filter.ifindex && vrf_filter.ifindex != ifi->ifi_index)
521*de1e4e89SAndroid Build Coastguard Worker return 0;
522*de1e4e89SAndroid Build Coastguard Worker
523*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
524*de1e4e89SAndroid Build Coastguard Worker
525*de1e4e89SAndroid Build Coastguard Worker /* kernel does not support filter by master device */
526*de1e4e89SAndroid Build Coastguard Worker if (tb[IFLA_MASTER]) {
527*de1e4e89SAndroid Build Coastguard Worker int master = *(int *)RTA_DATA(tb[IFLA_MASTER]);
528*de1e4e89SAndroid Build Coastguard Worker
529*de1e4e89SAndroid Build Coastguard Worker if (vrf_filter.master && master != vrf_filter.master)
530*de1e4e89SAndroid Build Coastguard Worker return 0;
531*de1e4e89SAndroid Build Coastguard Worker }
532*de1e4e89SAndroid Build Coastguard Worker
533*de1e4e89SAndroid Build Coastguard Worker if (!tb[IFLA_IFNAME]) {
534*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
535*de1e4e89SAndroid Build Coastguard Worker "BUG: device with ifindex %d has nil ifname\n",
536*de1e4e89SAndroid Build Coastguard Worker ifi->ifi_index);
537*de1e4e89SAndroid Build Coastguard Worker return 0;
538*de1e4e89SAndroid Build Coastguard Worker }
539*de1e4e89SAndroid Build Coastguard Worker name = rta_getattr_str(tb[IFLA_IFNAME]);
540*de1e4e89SAndroid Build Coastguard Worker
541*de1e4e89SAndroid Build Coastguard Worker /* missing LINKINFO means not VRF. e.g., kernel does not
542*de1e4e89SAndroid Build Coastguard Worker * support filtering on kind, so userspace needs to handle
543*de1e4e89SAndroid Build Coastguard Worker */
544*de1e4e89SAndroid Build Coastguard Worker if (!tb[IFLA_LINKINFO])
545*de1e4e89SAndroid Build Coastguard Worker return 0;
546*de1e4e89SAndroid Build Coastguard Worker
547*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
548*de1e4e89SAndroid Build Coastguard Worker
549*de1e4e89SAndroid Build Coastguard Worker if (!li[IFLA_INFO_KIND])
550*de1e4e89SAndroid Build Coastguard Worker return 0;
551*de1e4e89SAndroid Build Coastguard Worker
552*de1e4e89SAndroid Build Coastguard Worker if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf"))
553*de1e4e89SAndroid Build Coastguard Worker return 0;
554*de1e4e89SAndroid Build Coastguard Worker
555*de1e4e89SAndroid Build Coastguard Worker tb_id = vrf_table_linkinfo(li);
556*de1e4e89SAndroid Build Coastguard Worker if (!tb_id) {
557*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
558*de1e4e89SAndroid Build Coastguard Worker "BUG: VRF %s is missing table id\n", name);
559*de1e4e89SAndroid Build Coastguard Worker return 0;
560*de1e4e89SAndroid Build Coastguard Worker }
561*de1e4e89SAndroid Build Coastguard Worker
562*de1e4e89SAndroid Build Coastguard Worker printf("%-16s %5u", name, tb_id);
563*de1e4e89SAndroid Build Coastguard Worker
564*de1e4e89SAndroid Build Coastguard Worker printf("\n");
565*de1e4e89SAndroid Build Coastguard Worker return 1;
566*de1e4e89SAndroid Build Coastguard Worker }
567*de1e4e89SAndroid Build Coastguard Worker
ipvrf_show(int argc,char ** argv)568*de1e4e89SAndroid Build Coastguard Worker static int ipvrf_show(int argc, char **argv)
569*de1e4e89SAndroid Build Coastguard Worker {
570*de1e4e89SAndroid Build Coastguard Worker struct nlmsg_chain linfo = { NULL, NULL};
571*de1e4e89SAndroid Build Coastguard Worker int rc = 0;
572*de1e4e89SAndroid Build Coastguard Worker
573*de1e4e89SAndroid Build Coastguard Worker vrf_filter.kind = "vrf";
574*de1e4e89SAndroid Build Coastguard Worker
575*de1e4e89SAndroid Build Coastguard Worker if (argc > 1)
576*de1e4e89SAndroid Build Coastguard Worker usage();
577*de1e4e89SAndroid Build Coastguard Worker
578*de1e4e89SAndroid Build Coastguard Worker if (argc == 1) {
579*de1e4e89SAndroid Build Coastguard Worker __u32 tb_id;
580*de1e4e89SAndroid Build Coastguard Worker
581*de1e4e89SAndroid Build Coastguard Worker tb_id = ipvrf_get_table(argv[0]);
582*de1e4e89SAndroid Build Coastguard Worker if (!tb_id) {
583*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Invalid VRF\n");
584*de1e4e89SAndroid Build Coastguard Worker return 1;
585*de1e4e89SAndroid Build Coastguard Worker }
586*de1e4e89SAndroid Build Coastguard Worker printf("%s %u\n", argv[0], tb_id);
587*de1e4e89SAndroid Build Coastguard Worker return 0;
588*de1e4e89SAndroid Build Coastguard Worker }
589*de1e4e89SAndroid Build Coastguard Worker
590*de1e4e89SAndroid Build Coastguard Worker if (ip_linkaddr_list(0, ipvrf_filter_req, &linfo, NULL) == 0) {
591*de1e4e89SAndroid Build Coastguard Worker struct nlmsg_list *l;
592*de1e4e89SAndroid Build Coastguard Worker unsigned nvrf = 0;
593*de1e4e89SAndroid Build Coastguard Worker int n;
594*de1e4e89SAndroid Build Coastguard Worker
595*de1e4e89SAndroid Build Coastguard Worker n = printf("%-16s %5s\n", "Name", "Table");
596*de1e4e89SAndroid Build Coastguard Worker printf("%.*s\n", n-1, "-----------------------");
597*de1e4e89SAndroid Build Coastguard Worker for (l = linfo.head; l; l = l->next)
598*de1e4e89SAndroid Build Coastguard Worker nvrf += ipvrf_print(&l->h);
599*de1e4e89SAndroid Build Coastguard Worker
600*de1e4e89SAndroid Build Coastguard Worker if (!nvrf)
601*de1e4e89SAndroid Build Coastguard Worker printf("No VRF has been configured\n");
602*de1e4e89SAndroid Build Coastguard Worker } else
603*de1e4e89SAndroid Build Coastguard Worker rc = 1;
604*de1e4e89SAndroid Build Coastguard Worker
605*de1e4e89SAndroid Build Coastguard Worker free_nlmsg_chain(&linfo);
606*de1e4e89SAndroid Build Coastguard Worker
607*de1e4e89SAndroid Build Coastguard Worker return rc;
608*de1e4e89SAndroid Build Coastguard Worker }
609*de1e4e89SAndroid Build Coastguard Worker
do_ipvrf(int argc,char ** argv)610*de1e4e89SAndroid Build Coastguard Worker int do_ipvrf(int argc, char **argv)
611*de1e4e89SAndroid Build Coastguard Worker {
612*de1e4e89SAndroid Build Coastguard Worker if (argc == 0)
613*de1e4e89SAndroid Build Coastguard Worker return ipvrf_show(0, NULL);
614*de1e4e89SAndroid Build Coastguard Worker
615*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "identify") == 0)
616*de1e4e89SAndroid Build Coastguard Worker return ipvrf_identify(argc-1, argv+1);
617*de1e4e89SAndroid Build Coastguard Worker
618*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "pids") == 0)
619*de1e4e89SAndroid Build Coastguard Worker return ipvrf_pids(argc-1, argv+1);
620*de1e4e89SAndroid Build Coastguard Worker
621*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "exec") == 0)
622*de1e4e89SAndroid Build Coastguard Worker return ipvrf_exec(argc-1, argv+1);
623*de1e4e89SAndroid Build Coastguard Worker
624*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "show") == 0 ||
625*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "lst") == 0 ||
626*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "list") == 0)
627*de1e4e89SAndroid Build Coastguard Worker return ipvrf_show(argc-1, argv+1);
628*de1e4e89SAndroid Build Coastguard Worker
629*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0)
630*de1e4e89SAndroid Build Coastguard Worker usage();
631*de1e4e89SAndroid Build Coastguard Worker
632*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Command \"%s\" is unknown, try \"ip vrf help\".\n",
633*de1e4e89SAndroid Build Coastguard Worker *argv);
634*de1e4e89SAndroid Build Coastguard Worker
635*de1e4e89SAndroid Build Coastguard Worker exit(-1);
636*de1e4e89SAndroid Build Coastguard Worker }
637