xref: /aosp_15_r20/external/iproute2/ip/ipnetns.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker #define _ATFILE_SOURCE
2*de1e4e89SAndroid Build Coastguard Worker #include <sys/types.h>
3*de1e4e89SAndroid Build Coastguard Worker #include <sys/stat.h>
4*de1e4e89SAndroid Build Coastguard Worker #include <sys/wait.h>
5*de1e4e89SAndroid Build Coastguard Worker #include <sys/inotify.h>
6*de1e4e89SAndroid Build Coastguard Worker #include <sys/mount.h>
7*de1e4e89SAndroid Build Coastguard Worker #include <sys/syscall.h>
8*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
9*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
10*de1e4e89SAndroid Build Coastguard Worker #include <sched.h>
11*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
12*de1e4e89SAndroid Build Coastguard Worker #include <dirent.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <ctype.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <linux/limits.h>
17*de1e4e89SAndroid Build Coastguard Worker 
18*de1e4e89SAndroid Build Coastguard Worker #include <linux/net_namespace.h>
19*de1e4e89SAndroid Build Coastguard Worker 
20*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
21*de1e4e89SAndroid Build Coastguard Worker #include "list.h"
22*de1e4e89SAndroid Build Coastguard Worker #include "ip_common.h"
23*de1e4e89SAndroid Build Coastguard Worker #include "namespace.h"
24*de1e4e89SAndroid Build Coastguard Worker 
usage(void)25*de1e4e89SAndroid Build Coastguard Worker static int usage(void)
26*de1e4e89SAndroid Build Coastguard Worker {
27*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "Usage: ip netns list\n");
28*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip netns add NAME\n");
29*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip netns set NAME NETNSID\n");
30*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip [-all] netns delete [NAME]\n");
31*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip netns identify [PID]\n");
32*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip netns pids NAME\n");
33*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip [-all] netns exec [NAME] cmd ...\n");
34*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip netns monitor\n");
35*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "       ip netns list-id\n");
36*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
37*de1e4e89SAndroid Build Coastguard Worker }
38*de1e4e89SAndroid Build Coastguard Worker 
39*de1e4e89SAndroid Build Coastguard Worker /* This socket is used to get nsid */
40*de1e4e89SAndroid Build Coastguard Worker static struct rtnl_handle rtnsh = { .fd = -1 };
41*de1e4e89SAndroid Build Coastguard Worker 
42*de1e4e89SAndroid Build Coastguard Worker static int have_rtnl_getnsid = -1;
43*de1e4e89SAndroid Build Coastguard Worker 
ipnetns_accept_msg(const struct sockaddr_nl * who,struct rtnl_ctrl_data * ctrl,struct nlmsghdr * n,void * arg)44*de1e4e89SAndroid Build Coastguard Worker static int ipnetns_accept_msg(const struct sockaddr_nl *who,
45*de1e4e89SAndroid Build Coastguard Worker 			      struct rtnl_ctrl_data *ctrl,
46*de1e4e89SAndroid Build Coastguard Worker 			      struct nlmsghdr *n, void *arg)
47*de1e4e89SAndroid Build Coastguard Worker {
48*de1e4e89SAndroid Build Coastguard Worker 	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
49*de1e4e89SAndroid Build Coastguard Worker 
50*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type == NLMSG_ERROR &&
51*de1e4e89SAndroid Build Coastguard Worker 	    (err->error == -EOPNOTSUPP || err->error == -EINVAL))
52*de1e4e89SAndroid Build Coastguard Worker 		have_rtnl_getnsid = 0;
53*de1e4e89SAndroid Build Coastguard Worker 	else
54*de1e4e89SAndroid Build Coastguard Worker 		have_rtnl_getnsid = 1;
55*de1e4e89SAndroid Build Coastguard Worker 	return -1;
56*de1e4e89SAndroid Build Coastguard Worker }
57*de1e4e89SAndroid Build Coastguard Worker 
ipnetns_have_nsid(void)58*de1e4e89SAndroid Build Coastguard Worker static int ipnetns_have_nsid(void)
59*de1e4e89SAndroid Build Coastguard Worker {
60*de1e4e89SAndroid Build Coastguard Worker 	struct {
61*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr n;
62*de1e4e89SAndroid Build Coastguard Worker 		struct rtgenmsg g;
63*de1e4e89SAndroid Build Coastguard Worker 		char            buf[1024];
64*de1e4e89SAndroid Build Coastguard Worker 	} req = {
65*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
66*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST,
67*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = RTM_GETNSID,
68*de1e4e89SAndroid Build Coastguard Worker 		.g.rtgen_family = AF_UNSPEC,
69*de1e4e89SAndroid Build Coastguard Worker 	};
70*de1e4e89SAndroid Build Coastguard Worker 	int fd;
71*de1e4e89SAndroid Build Coastguard Worker 
72*de1e4e89SAndroid Build Coastguard Worker 	if (have_rtnl_getnsid < 0) {
73*de1e4e89SAndroid Build Coastguard Worker 		fd = open("/proc/self/ns/net", O_RDONLY);
74*de1e4e89SAndroid Build Coastguard Worker 		if (fd < 0) {
75*de1e4e89SAndroid Build Coastguard Worker 			have_rtnl_getnsid = 0;
76*de1e4e89SAndroid Build Coastguard Worker 			return 0;
77*de1e4e89SAndroid Build Coastguard Worker 		}
78*de1e4e89SAndroid Build Coastguard Worker 
79*de1e4e89SAndroid Build Coastguard Worker 		addattr32(&req.n, 1024, NETNSA_FD, fd);
80*de1e4e89SAndroid Build Coastguard Worker 
81*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
82*de1e4e89SAndroid Build Coastguard Worker 			perror("request send failed");
83*de1e4e89SAndroid Build Coastguard Worker 			exit(1);
84*de1e4e89SAndroid Build Coastguard Worker 		}
85*de1e4e89SAndroid Build Coastguard Worker 		rtnl_listen(&rth, ipnetns_accept_msg, NULL);
86*de1e4e89SAndroid Build Coastguard Worker 		close(fd);
87*de1e4e89SAndroid Build Coastguard Worker 	}
88*de1e4e89SAndroid Build Coastguard Worker 
89*de1e4e89SAndroid Build Coastguard Worker 	return have_rtnl_getnsid;
90*de1e4e89SAndroid Build Coastguard Worker }
91*de1e4e89SAndroid Build Coastguard Worker 
get_netnsid_from_name(const char * name)92*de1e4e89SAndroid Build Coastguard Worker static int get_netnsid_from_name(const char *name)
93*de1e4e89SAndroid Build Coastguard Worker {
94*de1e4e89SAndroid Build Coastguard Worker 	struct {
95*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr n;
96*de1e4e89SAndroid Build Coastguard Worker 		struct rtgenmsg g;
97*de1e4e89SAndroid Build Coastguard Worker 		char            buf[1024];
98*de1e4e89SAndroid Build Coastguard Worker 	} answer, req = {
99*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
100*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST,
101*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = RTM_GETNSID,
102*de1e4e89SAndroid Build Coastguard Worker 		.g.rtgen_family = AF_UNSPEC,
103*de1e4e89SAndroid Build Coastguard Worker 	};
104*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[NETNSA_MAX + 1];
105*de1e4e89SAndroid Build Coastguard Worker 	struct rtgenmsg *rthdr;
106*de1e4e89SAndroid Build Coastguard Worker 	int len, fd;
107*de1e4e89SAndroid Build Coastguard Worker 
108*de1e4e89SAndroid Build Coastguard Worker 	fd = netns_get_fd(name);
109*de1e4e89SAndroid Build Coastguard Worker 	if (fd < 0)
110*de1e4e89SAndroid Build Coastguard Worker 		return fd;
111*de1e4e89SAndroid Build Coastguard Worker 
112*de1e4e89SAndroid Build Coastguard Worker 	addattr32(&req.n, 1024, NETNSA_FD, fd);
113*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_talk(&rtnsh, &req.n, &answer.n, sizeof(answer)) < 0) {
114*de1e4e89SAndroid Build Coastguard Worker 		close(fd);
115*de1e4e89SAndroid Build Coastguard Worker 		return -2;
116*de1e4e89SAndroid Build Coastguard Worker 	}
117*de1e4e89SAndroid Build Coastguard Worker 	close(fd);
118*de1e4e89SAndroid Build Coastguard Worker 
119*de1e4e89SAndroid Build Coastguard Worker 	/* Validate message and parse attributes */
120*de1e4e89SAndroid Build Coastguard Worker 	if (answer.n.nlmsg_type == NLMSG_ERROR)
121*de1e4e89SAndroid Build Coastguard Worker 		return -1;
122*de1e4e89SAndroid Build Coastguard Worker 
123*de1e4e89SAndroid Build Coastguard Worker 	rthdr = NLMSG_DATA(&answer.n);
124*de1e4e89SAndroid Build Coastguard Worker 	len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
125*de1e4e89SAndroid Build Coastguard Worker 	if (len < 0)
126*de1e4e89SAndroid Build Coastguard Worker 		return -1;
127*de1e4e89SAndroid Build Coastguard Worker 
128*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
129*de1e4e89SAndroid Build Coastguard Worker 
130*de1e4e89SAndroid Build Coastguard Worker 	if (tb[NETNSA_NSID])
131*de1e4e89SAndroid Build Coastguard Worker 		return rta_getattr_u32(tb[NETNSA_NSID]);
132*de1e4e89SAndroid Build Coastguard Worker 
133*de1e4e89SAndroid Build Coastguard Worker 	return -1;
134*de1e4e89SAndroid Build Coastguard Worker }
135*de1e4e89SAndroid Build Coastguard Worker 
136*de1e4e89SAndroid Build Coastguard Worker struct nsid_cache {
137*de1e4e89SAndroid Build Coastguard Worker 	struct hlist_node	nsid_hash;
138*de1e4e89SAndroid Build Coastguard Worker 	struct hlist_node	name_hash;
139*de1e4e89SAndroid Build Coastguard Worker 	int			nsid;
140*de1e4e89SAndroid Build Coastguard Worker 	char			name[0];
141*de1e4e89SAndroid Build Coastguard Worker };
142*de1e4e89SAndroid Build Coastguard Worker 
143*de1e4e89SAndroid Build Coastguard Worker #define NSIDMAP_SIZE		128
144*de1e4e89SAndroid Build Coastguard Worker #define NSID_HASH_NSID(nsid)	(nsid & (NSIDMAP_SIZE - 1))
145*de1e4e89SAndroid Build Coastguard Worker #define NSID_HASH_NAME(name)	(namehash(name) & (NSIDMAP_SIZE - 1))
146*de1e4e89SAndroid Build Coastguard Worker 
147*de1e4e89SAndroid Build Coastguard Worker static struct hlist_head	nsid_head[NSIDMAP_SIZE];
148*de1e4e89SAndroid Build Coastguard Worker static struct hlist_head	name_head[NSIDMAP_SIZE];
149*de1e4e89SAndroid Build Coastguard Worker 
netns_map_get_by_nsid(int nsid)150*de1e4e89SAndroid Build Coastguard Worker static struct nsid_cache *netns_map_get_by_nsid(int nsid)
151*de1e4e89SAndroid Build Coastguard Worker {
152*de1e4e89SAndroid Build Coastguard Worker 	uint32_t h = NSID_HASH_NSID(nsid);
153*de1e4e89SAndroid Build Coastguard Worker 	struct hlist_node *n;
154*de1e4e89SAndroid Build Coastguard Worker 
155*de1e4e89SAndroid Build Coastguard Worker 	hlist_for_each(n, &nsid_head[h]) {
156*de1e4e89SAndroid Build Coastguard Worker 		struct nsid_cache *c = container_of(n, struct nsid_cache,
157*de1e4e89SAndroid Build Coastguard Worker 						    nsid_hash);
158*de1e4e89SAndroid Build Coastguard Worker 		if (c->nsid == nsid)
159*de1e4e89SAndroid Build Coastguard Worker 			return c;
160*de1e4e89SAndroid Build Coastguard Worker 	}
161*de1e4e89SAndroid Build Coastguard Worker 
162*de1e4e89SAndroid Build Coastguard Worker 	return NULL;
163*de1e4e89SAndroid Build Coastguard Worker }
164*de1e4e89SAndroid Build Coastguard Worker 
netns_map_add(int nsid,const char * name)165*de1e4e89SAndroid Build Coastguard Worker static int netns_map_add(int nsid, const char *name)
166*de1e4e89SAndroid Build Coastguard Worker {
167*de1e4e89SAndroid Build Coastguard Worker 	struct nsid_cache *c;
168*de1e4e89SAndroid Build Coastguard Worker 	uint32_t h;
169*de1e4e89SAndroid Build Coastguard Worker 
170*de1e4e89SAndroid Build Coastguard Worker 	if (netns_map_get_by_nsid(nsid) != NULL)
171*de1e4e89SAndroid Build Coastguard Worker 		return -EEXIST;
172*de1e4e89SAndroid Build Coastguard Worker 
173*de1e4e89SAndroid Build Coastguard Worker 	c = malloc(sizeof(*c) + strlen(name) + 1);
174*de1e4e89SAndroid Build Coastguard Worker 	if (c == NULL) {
175*de1e4e89SAndroid Build Coastguard Worker 		perror("malloc");
176*de1e4e89SAndroid Build Coastguard Worker 		return -ENOMEM;
177*de1e4e89SAndroid Build Coastguard Worker 	}
178*de1e4e89SAndroid Build Coastguard Worker 	c->nsid = nsid;
179*de1e4e89SAndroid Build Coastguard Worker 	strcpy(c->name, name);
180*de1e4e89SAndroid Build Coastguard Worker 
181*de1e4e89SAndroid Build Coastguard Worker 	h = NSID_HASH_NSID(nsid);
182*de1e4e89SAndroid Build Coastguard Worker 	hlist_add_head(&c->nsid_hash, &nsid_head[h]);
183*de1e4e89SAndroid Build Coastguard Worker 
184*de1e4e89SAndroid Build Coastguard Worker 	h = NSID_HASH_NAME(name);
185*de1e4e89SAndroid Build Coastguard Worker 	hlist_add_head(&c->name_hash, &name_head[h]);
186*de1e4e89SAndroid Build Coastguard Worker 
187*de1e4e89SAndroid Build Coastguard Worker 	return 0;
188*de1e4e89SAndroid Build Coastguard Worker }
189*de1e4e89SAndroid Build Coastguard Worker 
netns_map_del(struct nsid_cache * c)190*de1e4e89SAndroid Build Coastguard Worker static void netns_map_del(struct nsid_cache *c)
191*de1e4e89SAndroid Build Coastguard Worker {
192*de1e4e89SAndroid Build Coastguard Worker 	hlist_del(&c->name_hash);
193*de1e4e89SAndroid Build Coastguard Worker 	hlist_del(&c->nsid_hash);
194*de1e4e89SAndroid Build Coastguard Worker 	free(c);
195*de1e4e89SAndroid Build Coastguard Worker }
196*de1e4e89SAndroid Build Coastguard Worker 
netns_nsid_socket_init(void)197*de1e4e89SAndroid Build Coastguard Worker void netns_nsid_socket_init(void)
198*de1e4e89SAndroid Build Coastguard Worker {
199*de1e4e89SAndroid Build Coastguard Worker 	if (rtnsh.fd > -1 || !ipnetns_have_nsid())
200*de1e4e89SAndroid Build Coastguard Worker 		return;
201*de1e4e89SAndroid Build Coastguard Worker 
202*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_open(&rtnsh, 0) < 0) {
203*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot open rtnetlink\n");
204*de1e4e89SAndroid Build Coastguard Worker 		exit(1);
205*de1e4e89SAndroid Build Coastguard Worker 	}
206*de1e4e89SAndroid Build Coastguard Worker 
207*de1e4e89SAndroid Build Coastguard Worker }
208*de1e4e89SAndroid Build Coastguard Worker 
netns_map_init(void)209*de1e4e89SAndroid Build Coastguard Worker void netns_map_init(void)
210*de1e4e89SAndroid Build Coastguard Worker {
211*de1e4e89SAndroid Build Coastguard Worker 	static int initialized;
212*de1e4e89SAndroid Build Coastguard Worker 	struct dirent *entry;
213*de1e4e89SAndroid Build Coastguard Worker 	DIR *dir;
214*de1e4e89SAndroid Build Coastguard Worker 	int nsid;
215*de1e4e89SAndroid Build Coastguard Worker 
216*de1e4e89SAndroid Build Coastguard Worker 	if (initialized || !ipnetns_have_nsid())
217*de1e4e89SAndroid Build Coastguard Worker 		return;
218*de1e4e89SAndroid Build Coastguard Worker 
219*de1e4e89SAndroid Build Coastguard Worker 	dir = opendir(NETNS_RUN_DIR);
220*de1e4e89SAndroid Build Coastguard Worker 	if (!dir)
221*de1e4e89SAndroid Build Coastguard Worker 		return;
222*de1e4e89SAndroid Build Coastguard Worker 
223*de1e4e89SAndroid Build Coastguard Worker 	while ((entry = readdir(dir)) != NULL) {
224*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, ".") == 0)
225*de1e4e89SAndroid Build Coastguard Worker 			continue;
226*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, "..") == 0)
227*de1e4e89SAndroid Build Coastguard Worker 			continue;
228*de1e4e89SAndroid Build Coastguard Worker 		nsid = get_netnsid_from_name(entry->d_name);
229*de1e4e89SAndroid Build Coastguard Worker 
230*de1e4e89SAndroid Build Coastguard Worker 		if (nsid >= 0)
231*de1e4e89SAndroid Build Coastguard Worker 			netns_map_add(nsid, entry->d_name);
232*de1e4e89SAndroid Build Coastguard Worker 	}
233*de1e4e89SAndroid Build Coastguard Worker 	closedir(dir);
234*de1e4e89SAndroid Build Coastguard Worker 	initialized = 1;
235*de1e4e89SAndroid Build Coastguard Worker }
236*de1e4e89SAndroid Build Coastguard Worker 
netns_get_name(int nsid,char * name)237*de1e4e89SAndroid Build Coastguard Worker static int netns_get_name(int nsid, char *name)
238*de1e4e89SAndroid Build Coastguard Worker {
239*de1e4e89SAndroid Build Coastguard Worker 	struct dirent *entry;
240*de1e4e89SAndroid Build Coastguard Worker 	DIR *dir;
241*de1e4e89SAndroid Build Coastguard Worker 	int id;
242*de1e4e89SAndroid Build Coastguard Worker 
243*de1e4e89SAndroid Build Coastguard Worker 	dir = opendir(NETNS_RUN_DIR);
244*de1e4e89SAndroid Build Coastguard Worker 	if (!dir)
245*de1e4e89SAndroid Build Coastguard Worker 		return -ENOENT;
246*de1e4e89SAndroid Build Coastguard Worker 
247*de1e4e89SAndroid Build Coastguard Worker 	while ((entry = readdir(dir)) != NULL) {
248*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, ".") == 0)
249*de1e4e89SAndroid Build Coastguard Worker 			continue;
250*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, "..") == 0)
251*de1e4e89SAndroid Build Coastguard Worker 			continue;
252*de1e4e89SAndroid Build Coastguard Worker 		id = get_netnsid_from_name(entry->d_name);
253*de1e4e89SAndroid Build Coastguard Worker 
254*de1e4e89SAndroid Build Coastguard Worker 		if (nsid == id) {
255*de1e4e89SAndroid Build Coastguard Worker 			strcpy(name, entry->d_name);
256*de1e4e89SAndroid Build Coastguard Worker 			closedir(dir);
257*de1e4e89SAndroid Build Coastguard Worker 			return 0;
258*de1e4e89SAndroid Build Coastguard Worker 		}
259*de1e4e89SAndroid Build Coastguard Worker 	}
260*de1e4e89SAndroid Build Coastguard Worker 	closedir(dir);
261*de1e4e89SAndroid Build Coastguard Worker 	return -ENOENT;
262*de1e4e89SAndroid Build Coastguard Worker }
263*de1e4e89SAndroid Build Coastguard Worker 
print_nsid(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)264*de1e4e89SAndroid Build Coastguard Worker int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
265*de1e4e89SAndroid Build Coastguard Worker {
266*de1e4e89SAndroid Build Coastguard Worker 	struct rtgenmsg *rthdr = NLMSG_DATA(n);
267*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[NETNSA_MAX+1];
268*de1e4e89SAndroid Build Coastguard Worker 	int len = n->nlmsg_len;
269*de1e4e89SAndroid Build Coastguard Worker 	FILE *fp = (FILE *)arg;
270*de1e4e89SAndroid Build Coastguard Worker 	struct nsid_cache *c;
271*de1e4e89SAndroid Build Coastguard Worker 	char name[NAME_MAX];
272*de1e4e89SAndroid Build Coastguard Worker 	int nsid;
273*de1e4e89SAndroid Build Coastguard Worker 
274*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
275*de1e4e89SAndroid Build Coastguard Worker 		return 0;
276*de1e4e89SAndroid Build Coastguard Worker 
277*de1e4e89SAndroid Build Coastguard Worker 	len -= NLMSG_SPACE(sizeof(*rthdr));
278*de1e4e89SAndroid Build Coastguard Worker 	if (len < 0) {
279*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
280*de1e4e89SAndroid Build Coastguard Worker 			__func__);
281*de1e4e89SAndroid Build Coastguard Worker 		return -1;
282*de1e4e89SAndroid Build Coastguard Worker 	}
283*de1e4e89SAndroid Build Coastguard Worker 
284*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
285*de1e4e89SAndroid Build Coastguard Worker 	if (tb[NETNSA_NSID] == NULL) {
286*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
287*de1e4e89SAndroid Build Coastguard Worker 		return -1;
288*de1e4e89SAndroid Build Coastguard Worker 	}
289*de1e4e89SAndroid Build Coastguard Worker 
290*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type == RTM_DELNSID)
291*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fp, "Deleted ");
292*de1e4e89SAndroid Build Coastguard Worker 
293*de1e4e89SAndroid Build Coastguard Worker 	nsid = rta_getattr_u32(tb[NETNSA_NSID]);
294*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fp, "nsid %u ", nsid);
295*de1e4e89SAndroid Build Coastguard Worker 
296*de1e4e89SAndroid Build Coastguard Worker 	c = netns_map_get_by_nsid(nsid);
297*de1e4e89SAndroid Build Coastguard Worker 	if (c != NULL) {
298*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fp, "(iproute2 netns name: %s)", c->name);
299*de1e4e89SAndroid Build Coastguard Worker 		netns_map_del(c);
300*de1e4e89SAndroid Build Coastguard Worker 	}
301*de1e4e89SAndroid Build Coastguard Worker 
302*de1e4e89SAndroid Build Coastguard Worker 	/* During 'ip monitor nsid', no chance to have new nsid in cache. */
303*de1e4e89SAndroid Build Coastguard Worker 	if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
304*de1e4e89SAndroid Build Coastguard Worker 		if (netns_get_name(nsid, name) == 0) {
305*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "(iproute2 netns name: %s)", name);
306*de1e4e89SAndroid Build Coastguard Worker 			netns_map_add(nsid, name);
307*de1e4e89SAndroid Build Coastguard Worker 		}
308*de1e4e89SAndroid Build Coastguard Worker 
309*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fp, "\n");
310*de1e4e89SAndroid Build Coastguard Worker 	fflush(fp);
311*de1e4e89SAndroid Build Coastguard Worker 	return 0;
312*de1e4e89SAndroid Build Coastguard Worker }
313*de1e4e89SAndroid Build Coastguard Worker 
netns_list_id(int argc,char ** argv)314*de1e4e89SAndroid Build Coastguard Worker static int netns_list_id(int argc, char **argv)
315*de1e4e89SAndroid Build Coastguard Worker {
316*de1e4e89SAndroid Build Coastguard Worker 	if (!ipnetns_have_nsid()) {
317*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr,
318*de1e4e89SAndroid Build Coastguard Worker 			"RTM_GETNSID is not supported by the kernel.\n");
319*de1e4e89SAndroid Build Coastguard Worker 		return -ENOTSUP;
320*de1e4e89SAndroid Build Coastguard Worker 	}
321*de1e4e89SAndroid Build Coastguard Worker 
322*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETNSID) < 0) {
323*de1e4e89SAndroid Build Coastguard Worker 		perror("Cannot send dump request");
324*de1e4e89SAndroid Build Coastguard Worker 		exit(1);
325*de1e4e89SAndroid Build Coastguard Worker 	}
326*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
327*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Dump terminated\n");
328*de1e4e89SAndroid Build Coastguard Worker 		exit(1);
329*de1e4e89SAndroid Build Coastguard Worker 	}
330*de1e4e89SAndroid Build Coastguard Worker 	return 0;
331*de1e4e89SAndroid Build Coastguard Worker }
332*de1e4e89SAndroid Build Coastguard Worker 
netns_list(int argc,char ** argv)333*de1e4e89SAndroid Build Coastguard Worker static int netns_list(int argc, char **argv)
334*de1e4e89SAndroid Build Coastguard Worker {
335*de1e4e89SAndroid Build Coastguard Worker 	struct dirent *entry;
336*de1e4e89SAndroid Build Coastguard Worker 	DIR *dir;
337*de1e4e89SAndroid Build Coastguard Worker 	int id;
338*de1e4e89SAndroid Build Coastguard Worker 
339*de1e4e89SAndroid Build Coastguard Worker 	dir = opendir(NETNS_RUN_DIR);
340*de1e4e89SAndroid Build Coastguard Worker 	if (!dir)
341*de1e4e89SAndroid Build Coastguard Worker 		return 0;
342*de1e4e89SAndroid Build Coastguard Worker 
343*de1e4e89SAndroid Build Coastguard Worker 	while ((entry = readdir(dir)) != NULL) {
344*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, ".") == 0)
345*de1e4e89SAndroid Build Coastguard Worker 			continue;
346*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, "..") == 0)
347*de1e4e89SAndroid Build Coastguard Worker 			continue;
348*de1e4e89SAndroid Build Coastguard Worker 		printf("%s", entry->d_name);
349*de1e4e89SAndroid Build Coastguard Worker 		if (ipnetns_have_nsid()) {
350*de1e4e89SAndroid Build Coastguard Worker 			id = get_netnsid_from_name(entry->d_name);
351*de1e4e89SAndroid Build Coastguard Worker 			if (id >= 0)
352*de1e4e89SAndroid Build Coastguard Worker 				printf(" (id: %d)", id);
353*de1e4e89SAndroid Build Coastguard Worker 		}
354*de1e4e89SAndroid Build Coastguard Worker 		printf("\n");
355*de1e4e89SAndroid Build Coastguard Worker 	}
356*de1e4e89SAndroid Build Coastguard Worker 	closedir(dir);
357*de1e4e89SAndroid Build Coastguard Worker 	return 0;
358*de1e4e89SAndroid Build Coastguard Worker }
359*de1e4e89SAndroid Build Coastguard Worker 
on_netns_exec(char * nsname,void * arg)360*de1e4e89SAndroid Build Coastguard Worker static int on_netns_exec(char *nsname, void *arg)
361*de1e4e89SAndroid Build Coastguard Worker {
362*de1e4e89SAndroid Build Coastguard Worker 	char **argv = arg;
363*de1e4e89SAndroid Build Coastguard Worker 
364*de1e4e89SAndroid Build Coastguard Worker 	cmd_exec(argv[1], argv + 1, true);
365*de1e4e89SAndroid Build Coastguard Worker 	return 0;
366*de1e4e89SAndroid Build Coastguard Worker }
367*de1e4e89SAndroid Build Coastguard Worker 
netns_exec(int argc,char ** argv)368*de1e4e89SAndroid Build Coastguard Worker static int netns_exec(int argc, char **argv)
369*de1e4e89SAndroid Build Coastguard Worker {
370*de1e4e89SAndroid Build Coastguard Worker 	/* Setup the proper environment for apps that are not netns
371*de1e4e89SAndroid Build Coastguard Worker 	 * aware, and execute a program in that environment.
372*de1e4e89SAndroid Build Coastguard Worker 	 */
373*de1e4e89SAndroid Build Coastguard Worker 	const char *cmd;
374*de1e4e89SAndroid Build Coastguard Worker 
375*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1 && !do_all) {
376*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "No netns name specified\n");
377*de1e4e89SAndroid Build Coastguard Worker 		return -1;
378*de1e4e89SAndroid Build Coastguard Worker 	}
379*de1e4e89SAndroid Build Coastguard Worker 	if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
380*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "No command specified\n");
381*de1e4e89SAndroid Build Coastguard Worker 		return -1;
382*de1e4e89SAndroid Build Coastguard Worker 	}
383*de1e4e89SAndroid Build Coastguard Worker 
384*de1e4e89SAndroid Build Coastguard Worker 	if (do_all)
385*de1e4e89SAndroid Build Coastguard Worker 		return do_each_netns(on_netns_exec, --argv, 1);
386*de1e4e89SAndroid Build Coastguard Worker 
387*de1e4e89SAndroid Build Coastguard Worker 	if (netns_switch(argv[0]))
388*de1e4e89SAndroid Build Coastguard Worker 		return -1;
389*de1e4e89SAndroid Build Coastguard Worker 
390*de1e4e89SAndroid Build Coastguard Worker 	/* we just changed namespaces. clear any vrf association
391*de1e4e89SAndroid Build Coastguard Worker 	 * with prior namespace before exec'ing command
392*de1e4e89SAndroid Build Coastguard Worker 	 */
393*de1e4e89SAndroid Build Coastguard Worker 	vrf_reset();
394*de1e4e89SAndroid Build Coastguard Worker 
395*de1e4e89SAndroid Build Coastguard Worker 	/* ip must return the status of the child,
396*de1e4e89SAndroid Build Coastguard Worker 	 * but do_cmd() will add a minus to this,
397*de1e4e89SAndroid Build Coastguard Worker 	 * so let's add another one here to cancel it.
398*de1e4e89SAndroid Build Coastguard Worker 	 */
399*de1e4e89SAndroid Build Coastguard Worker 	cmd = argv[1];
400*de1e4e89SAndroid Build Coastguard Worker 	return -cmd_exec(cmd, argv + 1, !!batch_mode);
401*de1e4e89SAndroid Build Coastguard Worker }
402*de1e4e89SAndroid Build Coastguard Worker 
is_pid(const char * str)403*de1e4e89SAndroid Build Coastguard Worker static int is_pid(const char *str)
404*de1e4e89SAndroid Build Coastguard Worker {
405*de1e4e89SAndroid Build Coastguard Worker 	int ch;
406*de1e4e89SAndroid Build Coastguard Worker 
407*de1e4e89SAndroid Build Coastguard Worker 	for (; (ch = *str); str++) {
408*de1e4e89SAndroid Build Coastguard Worker 		if (!isdigit(ch))
409*de1e4e89SAndroid Build Coastguard Worker 			return 0;
410*de1e4e89SAndroid Build Coastguard Worker 	}
411*de1e4e89SAndroid Build Coastguard Worker 	return 1;
412*de1e4e89SAndroid Build Coastguard Worker }
413*de1e4e89SAndroid Build Coastguard Worker 
netns_pids(int argc,char ** argv)414*de1e4e89SAndroid Build Coastguard Worker static int netns_pids(int argc, char **argv)
415*de1e4e89SAndroid Build Coastguard Worker {
416*de1e4e89SAndroid Build Coastguard Worker 	const char *name;
417*de1e4e89SAndroid Build Coastguard Worker 	char net_path[PATH_MAX];
418*de1e4e89SAndroid Build Coastguard Worker 	int netns;
419*de1e4e89SAndroid Build Coastguard Worker 	struct stat netst;
420*de1e4e89SAndroid Build Coastguard Worker 	DIR *dir;
421*de1e4e89SAndroid Build Coastguard Worker 	struct dirent *entry;
422*de1e4e89SAndroid Build Coastguard Worker 
423*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1) {
424*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "No netns name specified\n");
425*de1e4e89SAndroid Build Coastguard Worker 		return -1;
426*de1e4e89SAndroid Build Coastguard Worker 	}
427*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 1) {
428*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "extra arguments specified\n");
429*de1e4e89SAndroid Build Coastguard Worker 		return -1;
430*de1e4e89SAndroid Build Coastguard Worker 	}
431*de1e4e89SAndroid Build Coastguard Worker 
432*de1e4e89SAndroid Build Coastguard Worker 	name = argv[0];
433*de1e4e89SAndroid Build Coastguard Worker 	snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
434*de1e4e89SAndroid Build Coastguard Worker 	netns = open(net_path, O_RDONLY);
435*de1e4e89SAndroid Build Coastguard Worker 	if (netns < 0) {
436*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot open network namespace: %s\n",
437*de1e4e89SAndroid Build Coastguard Worker 			strerror(errno));
438*de1e4e89SAndroid Build Coastguard Worker 		return -1;
439*de1e4e89SAndroid Build Coastguard Worker 	}
440*de1e4e89SAndroid Build Coastguard Worker 	if (fstat(netns, &netst) < 0) {
441*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Stat of netns failed: %s\n",
442*de1e4e89SAndroid Build Coastguard Worker 			strerror(errno));
443*de1e4e89SAndroid Build Coastguard Worker 		return -1;
444*de1e4e89SAndroid Build Coastguard Worker 	}
445*de1e4e89SAndroid Build Coastguard Worker 	dir = opendir("/proc/");
446*de1e4e89SAndroid Build Coastguard Worker 	if (!dir) {
447*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Open of /proc failed: %s\n",
448*de1e4e89SAndroid Build Coastguard Worker 			strerror(errno));
449*de1e4e89SAndroid Build Coastguard Worker 		return -1;
450*de1e4e89SAndroid Build Coastguard Worker 	}
451*de1e4e89SAndroid Build Coastguard Worker 	while ((entry = readdir(dir))) {
452*de1e4e89SAndroid Build Coastguard Worker 		char pid_net_path[PATH_MAX];
453*de1e4e89SAndroid Build Coastguard Worker 		struct stat st;
454*de1e4e89SAndroid Build Coastguard Worker 
455*de1e4e89SAndroid Build Coastguard Worker 		if (!is_pid(entry->d_name))
456*de1e4e89SAndroid Build Coastguard Worker 			continue;
457*de1e4e89SAndroid Build Coastguard Worker 		snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
458*de1e4e89SAndroid Build Coastguard Worker 			entry->d_name);
459*de1e4e89SAndroid Build Coastguard Worker 		if (stat(pid_net_path, &st) != 0)
460*de1e4e89SAndroid Build Coastguard Worker 			continue;
461*de1e4e89SAndroid Build Coastguard Worker 		if ((st.st_dev == netst.st_dev) &&
462*de1e4e89SAndroid Build Coastguard Worker 		    (st.st_ino == netst.st_ino)) {
463*de1e4e89SAndroid Build Coastguard Worker 			printf("%s\n", entry->d_name);
464*de1e4e89SAndroid Build Coastguard Worker 		}
465*de1e4e89SAndroid Build Coastguard Worker 	}
466*de1e4e89SAndroid Build Coastguard Worker 	closedir(dir);
467*de1e4e89SAndroid Build Coastguard Worker 	return 0;
468*de1e4e89SAndroid Build Coastguard Worker 
469*de1e4e89SAndroid Build Coastguard Worker }
470*de1e4e89SAndroid Build Coastguard Worker 
netns_identify_pid(const char * pidstr,char * name,int len)471*de1e4e89SAndroid Build Coastguard Worker int netns_identify_pid(const char *pidstr, char *name, int len)
472*de1e4e89SAndroid Build Coastguard Worker {
473*de1e4e89SAndroid Build Coastguard Worker 	char net_path[PATH_MAX];
474*de1e4e89SAndroid Build Coastguard Worker 	int netns;
475*de1e4e89SAndroid Build Coastguard Worker 	struct stat netst;
476*de1e4e89SAndroid Build Coastguard Worker 	DIR *dir;
477*de1e4e89SAndroid Build Coastguard Worker 	struct dirent *entry;
478*de1e4e89SAndroid Build Coastguard Worker 
479*de1e4e89SAndroid Build Coastguard Worker 	name[0] = '\0';
480*de1e4e89SAndroid Build Coastguard Worker 
481*de1e4e89SAndroid Build Coastguard Worker 	snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
482*de1e4e89SAndroid Build Coastguard Worker 	netns = open(net_path, O_RDONLY);
483*de1e4e89SAndroid Build Coastguard Worker 	if (netns < 0) {
484*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot open network namespace: %s\n",
485*de1e4e89SAndroid Build Coastguard Worker 			strerror(errno));
486*de1e4e89SAndroid Build Coastguard Worker 		return -1;
487*de1e4e89SAndroid Build Coastguard Worker 	}
488*de1e4e89SAndroid Build Coastguard Worker 	if (fstat(netns, &netst) < 0) {
489*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Stat of netns failed: %s\n",
490*de1e4e89SAndroid Build Coastguard Worker 			strerror(errno));
491*de1e4e89SAndroid Build Coastguard Worker 		return -1;
492*de1e4e89SAndroid Build Coastguard Worker 	}
493*de1e4e89SAndroid Build Coastguard Worker 	dir = opendir(NETNS_RUN_DIR);
494*de1e4e89SAndroid Build Coastguard Worker 	if (!dir) {
495*de1e4e89SAndroid Build Coastguard Worker 		/* Succeed treat a missing directory as an empty directory */
496*de1e4e89SAndroid Build Coastguard Worker 		if (errno == ENOENT)
497*de1e4e89SAndroid Build Coastguard Worker 			return 0;
498*de1e4e89SAndroid Build Coastguard Worker 
499*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Failed to open directory %s:%s\n",
500*de1e4e89SAndroid Build Coastguard Worker 			NETNS_RUN_DIR, strerror(errno));
501*de1e4e89SAndroid Build Coastguard Worker 		return -1;
502*de1e4e89SAndroid Build Coastguard Worker 	}
503*de1e4e89SAndroid Build Coastguard Worker 
504*de1e4e89SAndroid Build Coastguard Worker 	while ((entry = readdir(dir))) {
505*de1e4e89SAndroid Build Coastguard Worker 		char name_path[PATH_MAX];
506*de1e4e89SAndroid Build Coastguard Worker 		struct stat st;
507*de1e4e89SAndroid Build Coastguard Worker 
508*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, ".") == 0)
509*de1e4e89SAndroid Build Coastguard Worker 			continue;
510*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(entry->d_name, "..") == 0)
511*de1e4e89SAndroid Build Coastguard Worker 			continue;
512*de1e4e89SAndroid Build Coastguard Worker 
513*de1e4e89SAndroid Build Coastguard Worker 		snprintf(name_path, sizeof(name_path), "%s/%s",	NETNS_RUN_DIR,
514*de1e4e89SAndroid Build Coastguard Worker 			entry->d_name);
515*de1e4e89SAndroid Build Coastguard Worker 
516*de1e4e89SAndroid Build Coastguard Worker 		if (stat(name_path, &st) != 0)
517*de1e4e89SAndroid Build Coastguard Worker 			continue;
518*de1e4e89SAndroid Build Coastguard Worker 
519*de1e4e89SAndroid Build Coastguard Worker 		if ((st.st_dev == netst.st_dev) &&
520*de1e4e89SAndroid Build Coastguard Worker 		    (st.st_ino == netst.st_ino)) {
521*de1e4e89SAndroid Build Coastguard Worker 			strlcpy(name, entry->d_name, len);
522*de1e4e89SAndroid Build Coastguard Worker 		}
523*de1e4e89SAndroid Build Coastguard Worker 	}
524*de1e4e89SAndroid Build Coastguard Worker 	closedir(dir);
525*de1e4e89SAndroid Build Coastguard Worker 	return 0;
526*de1e4e89SAndroid Build Coastguard Worker 
527*de1e4e89SAndroid Build Coastguard Worker }
528*de1e4e89SAndroid Build Coastguard Worker 
netns_identify(int argc,char ** argv)529*de1e4e89SAndroid Build Coastguard Worker static int netns_identify(int argc, char **argv)
530*de1e4e89SAndroid Build Coastguard Worker {
531*de1e4e89SAndroid Build Coastguard Worker 	const char *pidstr;
532*de1e4e89SAndroid Build Coastguard Worker 	char name[256];
533*de1e4e89SAndroid Build Coastguard Worker 	int rc;
534*de1e4e89SAndroid Build Coastguard Worker 
535*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1) {
536*de1e4e89SAndroid Build Coastguard Worker 		pidstr = "self";
537*de1e4e89SAndroid Build Coastguard Worker 	} else if (argc > 1) {
538*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "extra arguments specified\n");
539*de1e4e89SAndroid Build Coastguard Worker 		return -1;
540*de1e4e89SAndroid Build Coastguard Worker 	} else {
541*de1e4e89SAndroid Build Coastguard Worker 		pidstr = argv[0];
542*de1e4e89SAndroid Build Coastguard Worker 		if (!is_pid(pidstr)) {
543*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Specified string '%s' is not a pid\n",
544*de1e4e89SAndroid Build Coastguard Worker 					pidstr);
545*de1e4e89SAndroid Build Coastguard Worker 			return -1;
546*de1e4e89SAndroid Build Coastguard Worker 		}
547*de1e4e89SAndroid Build Coastguard Worker 	}
548*de1e4e89SAndroid Build Coastguard Worker 
549*de1e4e89SAndroid Build Coastguard Worker 	rc = netns_identify_pid(pidstr, name, sizeof(name));
550*de1e4e89SAndroid Build Coastguard Worker 	if (!rc)
551*de1e4e89SAndroid Build Coastguard Worker 		printf("%s\n", name);
552*de1e4e89SAndroid Build Coastguard Worker 
553*de1e4e89SAndroid Build Coastguard Worker 	return rc;
554*de1e4e89SAndroid Build Coastguard Worker }
555*de1e4e89SAndroid Build Coastguard Worker 
on_netns_del(char * nsname,void * arg)556*de1e4e89SAndroid Build Coastguard Worker static int on_netns_del(char *nsname, void *arg)
557*de1e4e89SAndroid Build Coastguard Worker {
558*de1e4e89SAndroid Build Coastguard Worker 	char netns_path[PATH_MAX];
559*de1e4e89SAndroid Build Coastguard Worker 
560*de1e4e89SAndroid Build Coastguard Worker 	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
561*de1e4e89SAndroid Build Coastguard Worker 	umount2(netns_path, MNT_DETACH);
562*de1e4e89SAndroid Build Coastguard Worker 	if (unlink(netns_path) < 0) {
563*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
564*de1e4e89SAndroid Build Coastguard Worker 			netns_path, strerror(errno));
565*de1e4e89SAndroid Build Coastguard Worker 		return -1;
566*de1e4e89SAndroid Build Coastguard Worker 	}
567*de1e4e89SAndroid Build Coastguard Worker 	return 0;
568*de1e4e89SAndroid Build Coastguard Worker }
569*de1e4e89SAndroid Build Coastguard Worker 
netns_delete(int argc,char ** argv)570*de1e4e89SAndroid Build Coastguard Worker static int netns_delete(int argc, char **argv)
571*de1e4e89SAndroid Build Coastguard Worker {
572*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1 && !do_all) {
573*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "No netns name specified\n");
574*de1e4e89SAndroid Build Coastguard Worker 		return -1;
575*de1e4e89SAndroid Build Coastguard Worker 	}
576*de1e4e89SAndroid Build Coastguard Worker 
577*de1e4e89SAndroid Build Coastguard Worker 	if (do_all)
578*de1e4e89SAndroid Build Coastguard Worker 		return netns_foreach(on_netns_del, NULL);
579*de1e4e89SAndroid Build Coastguard Worker 
580*de1e4e89SAndroid Build Coastguard Worker 	return on_netns_del(argv[0], NULL);
581*de1e4e89SAndroid Build Coastguard Worker }
582*de1e4e89SAndroid Build Coastguard Worker 
create_netns_dir(void)583*de1e4e89SAndroid Build Coastguard Worker static int create_netns_dir(void)
584*de1e4e89SAndroid Build Coastguard Worker {
585*de1e4e89SAndroid Build Coastguard Worker 	/* Create the base netns directory if it doesn't exist */
586*de1e4e89SAndroid Build Coastguard Worker 	if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
587*de1e4e89SAndroid Build Coastguard Worker 		if (errno != EEXIST) {
588*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "mkdir %s failed: %s\n",
589*de1e4e89SAndroid Build Coastguard Worker 				NETNS_RUN_DIR, strerror(errno));
590*de1e4e89SAndroid Build Coastguard Worker 			return -1;
591*de1e4e89SAndroid Build Coastguard Worker 		}
592*de1e4e89SAndroid Build Coastguard Worker 	}
593*de1e4e89SAndroid Build Coastguard Worker 
594*de1e4e89SAndroid Build Coastguard Worker 	return 0;
595*de1e4e89SAndroid Build Coastguard Worker }
596*de1e4e89SAndroid Build Coastguard Worker 
netns_add(int argc,char ** argv)597*de1e4e89SAndroid Build Coastguard Worker static int netns_add(int argc, char **argv)
598*de1e4e89SAndroid Build Coastguard Worker {
599*de1e4e89SAndroid Build Coastguard Worker 	/* This function creates a new network namespace and
600*de1e4e89SAndroid Build Coastguard Worker 	 * a new mount namespace and bind them into a well known
601*de1e4e89SAndroid Build Coastguard Worker 	 * location in the filesystem based on the name provided.
602*de1e4e89SAndroid Build Coastguard Worker 	 *
603*de1e4e89SAndroid Build Coastguard Worker 	 * The mount namespace is created so that any necessary
604*de1e4e89SAndroid Build Coastguard Worker 	 * userspace tweaks like remounting /sys, or bind mounting
605*de1e4e89SAndroid Build Coastguard Worker 	 * a new /etc/resolv.conf can be shared between uers.
606*de1e4e89SAndroid Build Coastguard Worker 	 */
607*de1e4e89SAndroid Build Coastguard Worker 	char netns_path[PATH_MAX];
608*de1e4e89SAndroid Build Coastguard Worker 	const char *name;
609*de1e4e89SAndroid Build Coastguard Worker 	int fd;
610*de1e4e89SAndroid Build Coastguard Worker 	int made_netns_run_dir_mount = 0;
611*de1e4e89SAndroid Build Coastguard Worker 
612*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1) {
613*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "No netns name specified\n");
614*de1e4e89SAndroid Build Coastguard Worker 		return -1;
615*de1e4e89SAndroid Build Coastguard Worker 	}
616*de1e4e89SAndroid Build Coastguard Worker 	name = argv[0];
617*de1e4e89SAndroid Build Coastguard Worker 
618*de1e4e89SAndroid Build Coastguard Worker 	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
619*de1e4e89SAndroid Build Coastguard Worker 
620*de1e4e89SAndroid Build Coastguard Worker 	if (create_netns_dir())
621*de1e4e89SAndroid Build Coastguard Worker 		return -1;
622*de1e4e89SAndroid Build Coastguard Worker 
623*de1e4e89SAndroid Build Coastguard Worker 	/* Make it possible for network namespace mounts to propagate between
624*de1e4e89SAndroid Build Coastguard Worker 	 * mount namespaces.  This makes it likely that a unmounting a network
625*de1e4e89SAndroid Build Coastguard Worker 	 * namespace file in one namespace will unmount the network namespace
626*de1e4e89SAndroid Build Coastguard Worker 	 * file in all namespaces allowing the network namespace to be freed
627*de1e4e89SAndroid Build Coastguard Worker 	 * sooner.
628*de1e4e89SAndroid Build Coastguard Worker 	 */
629*de1e4e89SAndroid Build Coastguard Worker 	while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
630*de1e4e89SAndroid Build Coastguard Worker 		/* Fail unless we need to make the mount point */
631*de1e4e89SAndroid Build Coastguard Worker 		if (errno != EINVAL || made_netns_run_dir_mount) {
632*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "mount --make-shared %s failed: %s\n",
633*de1e4e89SAndroid Build Coastguard Worker 				NETNS_RUN_DIR, strerror(errno));
634*de1e4e89SAndroid Build Coastguard Worker 			return -1;
635*de1e4e89SAndroid Build Coastguard Worker 		}
636*de1e4e89SAndroid Build Coastguard Worker 
637*de1e4e89SAndroid Build Coastguard Worker 		/* Upgrade NETNS_RUN_DIR to a mount point */
638*de1e4e89SAndroid Build Coastguard Worker 		if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
639*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "mount --bind %s %s failed: %s\n",
640*de1e4e89SAndroid Build Coastguard Worker 				NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
641*de1e4e89SAndroid Build Coastguard Worker 			return -1;
642*de1e4e89SAndroid Build Coastguard Worker 		}
643*de1e4e89SAndroid Build Coastguard Worker 		made_netns_run_dir_mount = 1;
644*de1e4e89SAndroid Build Coastguard Worker 	}
645*de1e4e89SAndroid Build Coastguard Worker 
646*de1e4e89SAndroid Build Coastguard Worker 	/* Create the filesystem state */
647*de1e4e89SAndroid Build Coastguard Worker 	fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
648*de1e4e89SAndroid Build Coastguard Worker 	if (fd < 0) {
649*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
650*de1e4e89SAndroid Build Coastguard Worker 			netns_path, strerror(errno));
651*de1e4e89SAndroid Build Coastguard Worker 		return -1;
652*de1e4e89SAndroid Build Coastguard Worker 	}
653*de1e4e89SAndroid Build Coastguard Worker 	close(fd);
654*de1e4e89SAndroid Build Coastguard Worker 	if (unshare(CLONE_NEWNET) < 0) {
655*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
656*de1e4e89SAndroid Build Coastguard Worker 			name, strerror(errno));
657*de1e4e89SAndroid Build Coastguard Worker 		goto out_delete;
658*de1e4e89SAndroid Build Coastguard Worker 	}
659*de1e4e89SAndroid Build Coastguard Worker 
660*de1e4e89SAndroid Build Coastguard Worker 	/* Bind the netns last so I can watch for it */
661*de1e4e89SAndroid Build Coastguard Worker 	if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) {
662*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n",
663*de1e4e89SAndroid Build Coastguard Worker 			netns_path, strerror(errno));
664*de1e4e89SAndroid Build Coastguard Worker 		goto out_delete;
665*de1e4e89SAndroid Build Coastguard Worker 	}
666*de1e4e89SAndroid Build Coastguard Worker 	return 0;
667*de1e4e89SAndroid Build Coastguard Worker out_delete:
668*de1e4e89SAndroid Build Coastguard Worker 	netns_delete(argc, argv);
669*de1e4e89SAndroid Build Coastguard Worker 	return -1;
670*de1e4e89SAndroid Build Coastguard Worker }
671*de1e4e89SAndroid Build Coastguard Worker 
set_netnsid_from_name(const char * name,int nsid)672*de1e4e89SAndroid Build Coastguard Worker static int set_netnsid_from_name(const char *name, int nsid)
673*de1e4e89SAndroid Build Coastguard Worker {
674*de1e4e89SAndroid Build Coastguard Worker 	struct {
675*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr n;
676*de1e4e89SAndroid Build Coastguard Worker 		struct rtgenmsg g;
677*de1e4e89SAndroid Build Coastguard Worker 		char            buf[1024];
678*de1e4e89SAndroid Build Coastguard Worker 	} req = {
679*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
680*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST,
681*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = RTM_NEWNSID,
682*de1e4e89SAndroid Build Coastguard Worker 		.g.rtgen_family = AF_UNSPEC,
683*de1e4e89SAndroid Build Coastguard Worker 	};
684*de1e4e89SAndroid Build Coastguard Worker 	int fd, err = 0;
685*de1e4e89SAndroid Build Coastguard Worker 
686*de1e4e89SAndroid Build Coastguard Worker 	fd = netns_get_fd(name);
687*de1e4e89SAndroid Build Coastguard Worker 	if (fd < 0)
688*de1e4e89SAndroid Build Coastguard Worker 		return fd;
689*de1e4e89SAndroid Build Coastguard Worker 
690*de1e4e89SAndroid Build Coastguard Worker 	addattr32(&req.n, 1024, NETNSA_FD, fd);
691*de1e4e89SAndroid Build Coastguard Worker 	addattr32(&req.n, 1024, NETNSA_NSID, nsid);
692*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
693*de1e4e89SAndroid Build Coastguard Worker 		err = -2;
694*de1e4e89SAndroid Build Coastguard Worker 
695*de1e4e89SAndroid Build Coastguard Worker 	close(fd);
696*de1e4e89SAndroid Build Coastguard Worker 	return err;
697*de1e4e89SAndroid Build Coastguard Worker }
698*de1e4e89SAndroid Build Coastguard Worker 
netns_set(int argc,char ** argv)699*de1e4e89SAndroid Build Coastguard Worker static int netns_set(int argc, char **argv)
700*de1e4e89SAndroid Build Coastguard Worker {
701*de1e4e89SAndroid Build Coastguard Worker 	char netns_path[PATH_MAX];
702*de1e4e89SAndroid Build Coastguard Worker 	const char *name;
703*de1e4e89SAndroid Build Coastguard Worker 	unsigned int nsid;
704*de1e4e89SAndroid Build Coastguard Worker 	int netns;
705*de1e4e89SAndroid Build Coastguard Worker 
706*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1) {
707*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "No netns name specified\n");
708*de1e4e89SAndroid Build Coastguard Worker 		return -1;
709*de1e4e89SAndroid Build Coastguard Worker 	}
710*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 2) {
711*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "No nsid specified\n");
712*de1e4e89SAndroid Build Coastguard Worker 		return -1;
713*de1e4e89SAndroid Build Coastguard Worker 	}
714*de1e4e89SAndroid Build Coastguard Worker 	name = argv[0];
715*de1e4e89SAndroid Build Coastguard Worker 	if (get_unsigned(&nsid, argv[1], 0))
716*de1e4e89SAndroid Build Coastguard Worker 		invarg("Invalid \"netnsid\" value\n", argv[1]);
717*de1e4e89SAndroid Build Coastguard Worker 
718*de1e4e89SAndroid Build Coastguard Worker 	snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
719*de1e4e89SAndroid Build Coastguard Worker 	netns = open(netns_path, O_RDONLY | O_CLOEXEC);
720*de1e4e89SAndroid Build Coastguard Worker 	if (netns < 0) {
721*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
722*de1e4e89SAndroid Build Coastguard Worker 			name, strerror(errno));
723*de1e4e89SAndroid Build Coastguard Worker 		return -1;
724*de1e4e89SAndroid Build Coastguard Worker 	}
725*de1e4e89SAndroid Build Coastguard Worker 
726*de1e4e89SAndroid Build Coastguard Worker 	return set_netnsid_from_name(name, nsid);
727*de1e4e89SAndroid Build Coastguard Worker }
728*de1e4e89SAndroid Build Coastguard Worker 
netns_monitor(int argc,char ** argv)729*de1e4e89SAndroid Build Coastguard Worker static int netns_monitor(int argc, char **argv)
730*de1e4e89SAndroid Build Coastguard Worker {
731*de1e4e89SAndroid Build Coastguard Worker 	char buf[4096];
732*de1e4e89SAndroid Build Coastguard Worker 	struct inotify_event *event;
733*de1e4e89SAndroid Build Coastguard Worker 	int fd;
734*de1e4e89SAndroid Build Coastguard Worker 
735*de1e4e89SAndroid Build Coastguard Worker 	fd = inotify_init();
736*de1e4e89SAndroid Build Coastguard Worker 	if (fd < 0) {
737*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "inotify_init failed: %s\n",
738*de1e4e89SAndroid Build Coastguard Worker 			strerror(errno));
739*de1e4e89SAndroid Build Coastguard Worker 		return -1;
740*de1e4e89SAndroid Build Coastguard Worker 	}
741*de1e4e89SAndroid Build Coastguard Worker 
742*de1e4e89SAndroid Build Coastguard Worker 	if (create_netns_dir())
743*de1e4e89SAndroid Build Coastguard Worker 		return -1;
744*de1e4e89SAndroid Build Coastguard Worker 
745*de1e4e89SAndroid Build Coastguard Worker 	if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
746*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "inotify_add_watch failed: %s\n",
747*de1e4e89SAndroid Build Coastguard Worker 			strerror(errno));
748*de1e4e89SAndroid Build Coastguard Worker 		return -1;
749*de1e4e89SAndroid Build Coastguard Worker 	}
750*de1e4e89SAndroid Build Coastguard Worker 	for (;;) {
751*de1e4e89SAndroid Build Coastguard Worker 		ssize_t len = read(fd, buf, sizeof(buf));
752*de1e4e89SAndroid Build Coastguard Worker 
753*de1e4e89SAndroid Build Coastguard Worker 		if (len < 0) {
754*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "read failed: %s\n",
755*de1e4e89SAndroid Build Coastguard Worker 				strerror(errno));
756*de1e4e89SAndroid Build Coastguard Worker 			return -1;
757*de1e4e89SAndroid Build Coastguard Worker 		}
758*de1e4e89SAndroid Build Coastguard Worker 		for (event = (struct inotify_event *)buf;
759*de1e4e89SAndroid Build Coastguard Worker 		     (char *)event < &buf[len];
760*de1e4e89SAndroid Build Coastguard Worker 		     event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
761*de1e4e89SAndroid Build Coastguard Worker 			if (event->mask & IN_CREATE)
762*de1e4e89SAndroid Build Coastguard Worker 				printf("add %s\n", event->name);
763*de1e4e89SAndroid Build Coastguard Worker 			if (event->mask & IN_DELETE)
764*de1e4e89SAndroid Build Coastguard Worker 				printf("delete %s\n", event->name);
765*de1e4e89SAndroid Build Coastguard Worker 		}
766*de1e4e89SAndroid Build Coastguard Worker 	}
767*de1e4e89SAndroid Build Coastguard Worker 	return 0;
768*de1e4e89SAndroid Build Coastguard Worker }
769*de1e4e89SAndroid Build Coastguard Worker 
invalid_name(const char * name)770*de1e4e89SAndroid Build Coastguard Worker static int invalid_name(const char *name)
771*de1e4e89SAndroid Build Coastguard Worker {
772*de1e4e89SAndroid Build Coastguard Worker 	return !*name || strlen(name) > NAME_MAX ||
773*de1e4e89SAndroid Build Coastguard Worker 		strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
774*de1e4e89SAndroid Build Coastguard Worker }
775*de1e4e89SAndroid Build Coastguard Worker 
do_netns(int argc,char ** argv)776*de1e4e89SAndroid Build Coastguard Worker int do_netns(int argc, char **argv)
777*de1e4e89SAndroid Build Coastguard Worker {
778*de1e4e89SAndroid Build Coastguard Worker 	netns_nsid_socket_init();
779*de1e4e89SAndroid Build Coastguard Worker 
780*de1e4e89SAndroid Build Coastguard Worker 	if (argc < 1) {
781*de1e4e89SAndroid Build Coastguard Worker 		netns_map_init();
782*de1e4e89SAndroid Build Coastguard Worker 		return netns_list(0, NULL);
783*de1e4e89SAndroid Build Coastguard Worker 	}
784*de1e4e89SAndroid Build Coastguard Worker 
785*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 1 && invalid_name(argv[1])) {
786*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
787*de1e4e89SAndroid Build Coastguard Worker 		exit(-1);
788*de1e4e89SAndroid Build Coastguard Worker 	}
789*de1e4e89SAndroid Build Coastguard Worker 
790*de1e4e89SAndroid Build Coastguard Worker 	if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
791*de1e4e89SAndroid Build Coastguard Worker 	    (matches(*argv, "lst") == 0)) {
792*de1e4e89SAndroid Build Coastguard Worker 		netns_map_init();
793*de1e4e89SAndroid Build Coastguard Worker 		return netns_list(argc-1, argv+1);
794*de1e4e89SAndroid Build Coastguard Worker 	}
795*de1e4e89SAndroid Build Coastguard Worker 
796*de1e4e89SAndroid Build Coastguard Worker 	if ((matches(*argv, "list-id") == 0)) {
797*de1e4e89SAndroid Build Coastguard Worker 		netns_map_init();
798*de1e4e89SAndroid Build Coastguard Worker 		return netns_list_id(argc-1, argv+1);
799*de1e4e89SAndroid Build Coastguard Worker 	}
800*de1e4e89SAndroid Build Coastguard Worker 
801*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "help") == 0)
802*de1e4e89SAndroid Build Coastguard Worker 		return usage();
803*de1e4e89SAndroid Build Coastguard Worker 
804*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "add") == 0)
805*de1e4e89SAndroid Build Coastguard Worker 		return netns_add(argc-1, argv+1);
806*de1e4e89SAndroid Build Coastguard Worker 
807*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "set") == 0)
808*de1e4e89SAndroid Build Coastguard Worker 		return netns_set(argc-1, argv+1);
809*de1e4e89SAndroid Build Coastguard Worker 
810*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "delete") == 0)
811*de1e4e89SAndroid Build Coastguard Worker 		return netns_delete(argc-1, argv+1);
812*de1e4e89SAndroid Build Coastguard Worker 
813*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "identify") == 0)
814*de1e4e89SAndroid Build Coastguard Worker 		return netns_identify(argc-1, argv+1);
815*de1e4e89SAndroid Build Coastguard Worker 
816*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "pids") == 0)
817*de1e4e89SAndroid Build Coastguard Worker 		return netns_pids(argc-1, argv+1);
818*de1e4e89SAndroid Build Coastguard Worker 
819*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "exec") == 0)
820*de1e4e89SAndroid Build Coastguard Worker 		return netns_exec(argc-1, argv+1);
821*de1e4e89SAndroid Build Coastguard Worker 
822*de1e4e89SAndroid Build Coastguard Worker 	if (matches(*argv, "monitor") == 0)
823*de1e4e89SAndroid Build Coastguard Worker 		return netns_monitor(argc-1, argv+1);
824*de1e4e89SAndroid Build Coastguard Worker 
825*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
826*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
827*de1e4e89SAndroid Build Coastguard Worker }
828