#define CGRP_PROC_FILE "/cgroup.procs"
+static struct link_filter vrf_filter;
+
static void usage(void)
{
- fprintf(stderr, "Usage: ip vrf exec [NAME] cmd ...\n");
+ fprintf(stderr, "Usage: ip vrf show [NAME] ...\n");
+ fprintf(stderr, " ip vrf exec [NAME] cmd ...\n");
fprintf(stderr, " ip vrf identify [PID]\n");
fprintf(stderr, " ip vrf pids [NAME]\n");
if (end)
*end = '\0';
- strncpy(name, vrf, len - 1);
+ strlcpy(name, vrf, len);
break;
}
}
{
char path[PATH_MAX];
char buf[4096];
- ssize_t n;
- int fd;
+ FILE *fp;
if (snprintf(path, sizeof(path), "%s/vrf/%s%s",
base_path, name, CGRP_PROC_FILE) >= sizeof(path))
return;
- fd = open(path, O_RDONLY);
- if (fd < 0)
+ fp = fopen(path, "r");
+ if (!fp)
return; /* no cgroup file, nothing to show */
/* dump contents (pids) of cgroup.procs */
- while (1) {
- n = read(fd, buf, sizeof(buf) - 1);
- if (n <= 0)
- break;
+ while (fgets(buf, sizeof(buf), fp)) {
+ char *nl, comm[32];
+
+ nl = strchr(buf, '\n');
+ if (nl)
+ *nl = '\0';
+
+ if (get_command_name(buf, comm, sizeof(comm)))
+ strcpy(comm, "<terminated?>");
- printf("%s", buf);
+ printf("%5s %s\n", buf, comm);
}
- close(fd);
+ fclose(fp);
}
/* recurse path looking for PATH[/NETNS]/vrf/NAME */
if (vrf)
*vrf = '\0';
- strncpy(vpath, start, len - 1);
- vpath[len - 1] = '\0';
+ strlcpy(vpath, start, len);
/* if vrf path is just / then return nothing */
if (!strcmp(vpath, "/"))
/* -1 on length to add '/' to the end */
if (ipvrf_get_netns(netns, sizeof(netns) - 1) < 0)
- return -1;
+ goto out;
if (vrf_path(vpath, sizeof(vpath)) < 0) {
fprintf(stderr, "Failed to get base cgroup path: %s\n",
strerror(errno));
- return -1;
+ goto out;
}
/* if path already ends in netns then don't add it again */
snprintf(pid, sizeof(pid), "%d", getpid());
if (write(fd, pid, strlen(pid)) < 0) {
fprintf(stderr, "Failed to join cgroup\n");
- goto out;
+ goto out2;
}
rc = 0;
+out2:
+ close(fd);
out:
free(mnt);
- close(fd);
+
+ drop_cap();
return rc;
}
vrf_switch("default");
}
-int do_ipvrf(int argc, char **argv)
+static int ipvrf_filter_req(struct nlmsghdr *nlh, int reqlen)
{
- if (argc == 0) {
- fprintf(stderr, "No command given. Try \"ip vrf help\".\n");
- exit(-1);
+ struct rtattr *linkinfo;
+ int err;
+
+ if (vrf_filter.kind) {
+ linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO);
+
+ err = addattr_l(nlh, reqlen, IFLA_INFO_KIND, vrf_filter.kind,
+ strlen(vrf_filter.kind));
+ if (err)
+ return err;
+
+ addattr_nest_end(nlh, linkinfo);
}
+ return 0;
+}
+
+/* input arg is linkinfo */
+static __u32 vrf_table_linkinfo(struct rtattr *li[])
+{
+ struct rtattr *attr[IFLA_VRF_MAX + 1];
+
+ if (li[IFLA_INFO_DATA]) {
+ parse_rtattr_nested(attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]);
+
+ if (attr[IFLA_VRF_TABLE])
+ return rta_getattr_u32(attr[IFLA_VRF_TABLE]);
+ }
+
+ return 0;
+}
+
+static int ipvrf_print(struct nlmsghdr *n)
+{
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr *tb[IFLA_MAX+1];
+ struct rtattr *li[IFLA_INFO_MAX+1];
+ int len = n->nlmsg_len;
+ const char *name;
+ __u32 tb_id;
+
+ len -= NLMSG_LENGTH(sizeof(*ifi));
+ if (len < 0)
+ return 0;
+
+ if (vrf_filter.ifindex && vrf_filter.ifindex != ifi->ifi_index)
+ return 0;
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+
+ /* kernel does not support filter by master device */
+ if (tb[IFLA_MASTER]) {
+ int master = *(int *)RTA_DATA(tb[IFLA_MASTER]);
+
+ if (vrf_filter.master && master != vrf_filter.master)
+ return 0;
+ }
+
+ if (!tb[IFLA_IFNAME]) {
+ fprintf(stderr,
+ "BUG: device with ifindex %d has nil ifname\n",
+ ifi->ifi_index);
+ return 0;
+ }
+ name = rta_getattr_str(tb[IFLA_IFNAME]);
+
+ /* missing LINKINFO means not VRF. e.g., kernel does not
+ * support filtering on kind, so userspace needs to handle
+ */
+ if (!tb[IFLA_LINKINFO])
+ return 0;
+
+ parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+ if (!li[IFLA_INFO_KIND])
+ return 0;
+
+ if (strcmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf"))
+ return 0;
+
+ tb_id = vrf_table_linkinfo(li);
+ if (!tb_id) {
+ fprintf(stderr,
+ "BUG: VRF %s is missing table id\n", name);
+ return 0;
+ }
+
+ printf("%-16s %5u", name, tb_id);
+
+ printf("\n");
+ return 1;
+}
+
+static int ipvrf_show(int argc, char **argv)
+{
+ struct nlmsg_chain linfo = { NULL, NULL};
+ int rc = 0;
+
+ vrf_filter.kind = "vrf";
+
+ if (argc > 1)
+ usage();
+
+ if (argc == 1) {
+ __u32 tb_id;
+
+ tb_id = ipvrf_get_table(argv[0]);
+ if (!tb_id) {
+ fprintf(stderr, "Invalid VRF\n");
+ return 1;
+ }
+ printf("%s %u\n", argv[0], tb_id);
+ return 0;
+ }
+
+ if (ip_link_list(ipvrf_filter_req, &linfo) == 0) {
+ struct nlmsg_list *l;
+ unsigned nvrf = 0;
+ int n;
+
+ n = printf("%-16s %5s\n", "Name", "Table");
+ printf("%.*s\n", n-1, "-----------------------");
+ for (l = linfo.head; l; l = l->next)
+ nvrf += ipvrf_print(&l->h);
+
+ if (!nvrf)
+ printf("No VRF has been configured\n");
+ } else
+ rc = 1;
+
+ free_nlmsg_chain(&linfo);
+
+ return rc;
+}
+
+int do_ipvrf(int argc, char **argv)
+{
+ if (argc == 0)
+ return ipvrf_show(0, NULL);
+
if (matches(*argv, "identify") == 0)
return ipvrf_identify(argc-1, argv+1);
if (matches(*argv, "exec") == 0)
return ipvrf_exec(argc-1, argv+1);
+ if (matches(*argv, "show") == 0 ||
+ matches(*argv, "lst") == 0 ||
+ matches(*argv, "list") == 0)
+ return ipvrf_show(argc-1, argv+1);
+
if (matches(*argv, "help") == 0)
usage();