]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ipnetns: allow to get and set netns ids
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Tue, 17 Feb 2015 16:30:37 +0000 (17:30 +0100)
committerStephen Hemminger <shemming@brocade.com>
Sun, 22 Feb 2015 00:54:53 +0000 (16:54 -0800)
The kernel now provides ids for peer netns. This patch implements a new command
'set' to assign an id.
When netns are listed, if an id is assigned, it is now displayed.

Example:
 $ ip netns add foo
 $ ip netns set foo 1
 $ ip netns
 foo (id: 1)
 init_net

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
include/libnetlink.h
ip/ipnetns.c
man/man8/ip-netns.8

index d081e54210eab6bbc822c767ab483742219829e3..898275b824d4976fe088d582ff7eeba8df7dc96c 100644 (file)
@@ -158,6 +158,14 @@ extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
 #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg))
 #endif
 
+#ifndef NETNS_RTA
+#define NETNS_RTA(r) \
+       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))))
+#endif
+#ifndef NETNS_PAYLOAD
+#define NETNS_PAYLOAD(n)       NLMSG_PAYLOAD(n,sizeof(struct rtgenmsg))
+#endif
+
 /* User defined nlmsg_type which is used mostly for logging netlink
  * messages from dump file */
 #define NLMSG_TSTAMP   15
index e4038ea72d7161d205b041344a5c0e405dcf79e2..5a213dcf46cd0b69f775bd5d213cc46c3fc35d43 100644 (file)
@@ -15,6 +15,8 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include <linux/net_namespace.h>
+
 #include "utils.h"
 #include "ip_common.h"
 #include "namespace.h"
@@ -23,6 +25,7 @@ static int usage(void)
 {
        fprintf(stderr, "Usage: ip netns list\n");
        fprintf(stderr, "       ip netns add NAME\n");
+       fprintf(stderr, "       ip netns set NAME NETNSID\n");
        fprintf(stderr, "       ip [-all] netns delete [NAME]\n");
        fprintf(stderr, "       ip netns identify [PID]\n");
        fprintf(stderr, "       ip netns pids NAME\n");
@@ -31,10 +34,56 @@ static int usage(void)
        exit(-1);
 }
 
+static int get_netnsid_from_name(const char *name)
+{
+       struct {
+               struct nlmsghdr n;
+               struct rtgenmsg g;
+               char            buf[1024];
+       } req, answer;
+       struct rtattr *tb[NETNSA_MAX + 1];
+       struct rtgenmsg *rthdr;
+       int len, fd;
+
+       memset(&req, 0, sizeof(req));
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = RTM_GETNSID;
+       req.g.rtgen_family = AF_UNSPEC;
+
+       fd = netns_get_fd(name);
+       if (fd < 0)
+               return fd;
+
+       addattr32(&req.n, 1024, NETNSA_FD, fd);
+       if (rtnl_talk(&rth, &req.n, 0, 0, &answer.n) < 0) {
+               close(fd);
+               return -2;
+       }
+       close(fd);
+
+       /* Validate message and parse attributes */
+       if (answer.n.nlmsg_type == NLMSG_ERROR)
+               return -1;
+
+       rthdr = NLMSG_DATA(&answer.n);
+       len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
+       if (len < 0)
+               return -1;
+
+       parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
+
+       if (tb[NETNSA_NSID])
+               return rta_getattr_u32(tb[NETNSA_NSID]);
+
+       return -1;
+}
+
 static int netns_list(int argc, char **argv)
 {
        struct dirent *entry;
        DIR *dir;
+       int id;
 
        dir = opendir(NETNS_RUN_DIR);
        if (!dir)
@@ -45,7 +94,11 @@ static int netns_list(int argc, char **argv)
                        continue;
                if (strcmp(entry->d_name, "..") == 0)
                        continue;
-               printf("%s\n", entry->d_name);
+               printf("%s", entry->d_name);
+               id = get_netnsid_from_name(entry->d_name);
+               if (id >= 0)
+                       printf(" (id: %d)", id);
+               printf("\n");
        }
        closedir(dir);
        return 0;
@@ -375,6 +428,61 @@ out_delete:
        return -1;
 }
 
+static int set_netnsid_from_name(const char *name, int nsid)
+{
+       struct {
+               struct nlmsghdr n;
+               struct rtgenmsg g;
+               char            buf[1024];
+       } req;
+       int fd, err = 0;
+
+       memset(&req, 0, sizeof(req));
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = RTM_NEWNSID;
+       req.g.rtgen_family = AF_UNSPEC;
+
+       fd = netns_get_fd(name);
+       if (fd < 0)
+               return fd;
+
+       addattr32(&req.n, 1024, NETNSA_FD, fd);
+       addattr32(&req.n, 1024, NETNSA_NSID, nsid);
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+               err = -2;
+
+       close(fd);
+       return err;
+}
+
+static int netns_set(int argc, char **argv)
+{
+       char netns_path[MAXPATHLEN];
+       const char *name;
+       int netns, nsid;
+
+       if (argc < 1) {
+               fprintf(stderr, "No netns name specified\n");
+               return -1;
+       }
+       if (argc < 2) {
+               fprintf(stderr, "No nsid specified\n");
+               return -1;
+       }
+       name = argv[0];
+       nsid = atoi(argv[1]);
+
+       snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
+       netns = open(netns_path, O_RDONLY | O_CLOEXEC);
+       if (netns < 0) {
+               fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
+                       name, strerror(errno));
+               return -1;
+       }
+
+       return set_netnsid_from_name(name, nsid);
+}
 
 static int netns_monitor(int argc, char **argv)
 {
@@ -430,6 +538,9 @@ int do_netns(int argc, char **argv)
        if (matches(*argv, "add") == 0)
                return netns_add(argc-1, argv+1);
 
+       if (matches(*argv, "set") == 0)
+               return netns_set(argc-1, argv+1);
+
        if (matches(*argv, "delete") == 0)
                return netns_delete(argc-1, argv+1);
 
index 8e6999c0abcb72b9bb56e771a9498f59eee42de3..28a9544143e5154ac69dd36a22fb4d0de0b0db79 100644 (file)
@@ -23,6 +23,10 @@ ip-netns \- process network namespace management
 .B ip [-all] netns del
 .RI "[ " NETNSNAME " ]"
 
+.ti -8
+.BR "ip netns" " { " set " } "
+.I NETNSNAME NETNSID
+
 .ti -8
 .BR "ip netns identify"
 .RI "[ " PID " ]"
@@ -92,6 +96,16 @@ If
 .B -all
 option was specified then all the network namespace names will be removed.
 
+.TP
+.B ip netns set NAME NETNSID - assign an id to a peer network namespace
+.sp
+This command assigns a id to a peer network namespace. This id is valid
+only in the current network namespace.
+This id will be used by the kernel in some netlink messages. If no id is
+assigned when the kernel needs it, it will be automatically assigned by
+the kernel.
+Once it is assigned, it's not possible to change it.
+
 .TP
 .B ip netns identify [PID] - Report network namespaces names for process
 .sp