Commit d182ee13 authored by Nicolas Dichtel's avatar Nicolas Dichtel Committed by Stephen Hemminger

ipnetns: allow to get and set netns ids

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: default avatarNicolas Dichtel <nicolas.dichtel@6wind.com>
parent c16298be
......@@ -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
......
......@@ -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);
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment