]> git.proxmox.com Git - mirror_frr.git/blob - lib/netns_linux.c
Merge pull request #2010 from donaldsharp/ns_fixes
[mirror_frr.git] / lib / netns_linux.c
1 /*
2 * NS functions.
3 * Copyright (C) 2014 6WIND S.A.
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2, or (at your
10 * option) any later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <zebra.h>
23
24 #ifdef HAVE_NETNS
25 #undef _GNU_SOURCE
26 #define _GNU_SOURCE
27
28 #include <sched.h>
29 #endif
30
31 /* for basename */
32 #include <libgen.h>
33
34 #include "if.h"
35 #include "ns.h"
36 #include "log.h"
37 #include "memory.h"
38
39 #include "command.h"
40 #include "vty.h"
41 #include "vrf.h"
42
43 DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
44 DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
45
46 /* default NS ID value used when VRF backend is not NETNS */
47 #define NS_DEFAULT_INTERNAL 0
48
49 static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
50 static struct ns *ns_lookup_name_internal(const char *name);
51
52 RB_GENERATE(ns_head, ns, entry, ns_compare)
53
54 struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
55
56 static struct ns *default_ns;
57 static int ns_current_ns_fd;
58 static int ns_default_ns_fd;
59
60 static int ns_debug;
61
62 #ifndef CLONE_NEWNET
63 #define CLONE_NEWNET 0x40000000
64 /* New network namespace (lo, device, names sockets, etc) */
65 #endif
66
67 #ifndef HAVE_SETNS
68 static inline int setns(int fd, int nstype)
69 {
70 #ifdef __NR_setns
71 return syscall(__NR_setns, fd, nstype);
72 #else
73 errno = EINVAL;
74 return -1;
75 #endif
76 }
77 #endif /* !HAVE_SETNS */
78
79 #ifdef HAVE_NETNS
80 static int have_netns_enabled = -1;
81 #endif /* HAVE_NETNS */
82
83 /* default NS ID value used when VRF backend is not NETNS */
84 #define NS_DEFAULT_INTERNAL 0
85
86 static int have_netns(void)
87 {
88 #ifdef HAVE_NETNS
89 if (have_netns_enabled < 0) {
90 int fd = open(NS_DEFAULT_NAME, O_RDONLY);
91
92 if (fd < 0)
93 have_netns_enabled = 0;
94 else {
95 have_netns_enabled = 1;
96 close(fd);
97 }
98 }
99 return have_netns_enabled;
100 #else
101 return 0;
102 #endif
103 }
104
105 /* Holding NS hooks */
106 struct ns_master {
107 int (*ns_new_hook)(struct ns *ns);
108 int (*ns_delete_hook)(struct ns *ns);
109 int (*ns_enable_hook)(struct ns *ns);
110 int (*ns_disable_hook)(struct ns *ns);
111 } ns_master = {
112 0,
113 };
114
115 static int ns_is_enabled(struct ns *ns);
116
117 static inline int ns_compare(const struct ns *a, const struct ns *b)
118 {
119 return (a->ns_id - b->ns_id);
120 }
121
122 /* Look up a NS by identifier. */
123 static struct ns *ns_lookup_internal(ns_id_t ns_id)
124 {
125 struct ns ns;
126
127 ns.ns_id = ns_id;
128 return RB_FIND(ns_head, &ns_tree, &ns);
129 }
130
131 /* Look up a NS by name */
132 static struct ns *ns_lookup_name_internal(const char *name)
133 {
134 struct ns *ns = NULL;
135
136 RB_FOREACH (ns, ns_head, &ns_tree) {
137 if (ns->name != NULL) {
138 if (strcmp(name, ns->name) == 0)
139 return ns;
140 }
141 }
142 return NULL;
143 }
144
145 static struct ns *ns_get_created_internal(struct ns *ns, char *name,
146 ns_id_t ns_id)
147 {
148 int created = 0;
149 /*
150 * Initialize interfaces.
151 */
152 if (!ns && !name && ns_id != NS_UNKNOWN)
153 ns = ns_lookup_internal(ns_id);
154 if (!ns && name)
155 ns = ns_lookup_name_internal(name);
156 if (!ns) {
157 ns = XCALLOC(MTYPE_NS, sizeof(struct ns));
158 ns->ns_id = ns_id;
159 if (name)
160 ns->name = XSTRDUP(MTYPE_NS_NAME, name);
161 ns->fd = -1;
162 RB_INSERT(ns_head, &ns_tree, ns);
163 created = 1;
164 }
165 if (ns_id != ns->ns_id) {
166 RB_REMOVE(ns_head, &ns_tree, ns);
167 ns->ns_id = ns_id;
168 RB_INSERT(ns_head, &ns_tree, ns);
169 }
170 if (!created)
171 return ns;
172 if (ns_debug) {
173 if (ns->ns_id != NS_UNKNOWN)
174 zlog_info("NS %u is created.", ns->ns_id);
175 else
176 zlog_info("NS %s is created.", ns->name);
177 }
178 if (ns_master.ns_new_hook)
179 (*ns_master.ns_new_hook)(ns);
180 return ns;
181 }
182
183 /*
184 * Enable a NS - that is, let the NS be ready to use.
185 * The NS_ENABLE_HOOK callback will be called to inform
186 * that they can allocate resources in this NS.
187 *
188 * RETURN: 1 - enabled successfully; otherwise, 0.
189 */
190 static int ns_enable_internal(struct ns *ns, void (*func)(ns_id_t, void *))
191 {
192 if (!ns_is_enabled(ns)) {
193 if (have_netns()) {
194 ns->fd = open(ns->name, O_RDONLY);
195 } else {
196 ns->fd = -2;
197 /* Remember ns_enable_hook has been called */
198 errno = -ENOTSUP;
199 }
200
201 if (!ns_is_enabled(ns)) {
202 zlog_err("Can not enable NS %u: %s!", ns->ns_id,
203 safe_strerror(errno));
204 return 0;
205 }
206
207 /* Non default NS. leave */
208 if (ns->ns_id == NS_UNKNOWN) {
209 zlog_err("Can not enable NS %s %u: Invalid NSID",
210 ns->name, ns->ns_id);
211 return 0;
212 }
213 if (func)
214 func(ns->ns_id, (void *)ns->vrf_ctxt);
215 if (ns_debug) {
216 if (have_netns())
217 zlog_info("NS %u is associated with NETNS %s.",
218 ns->ns_id, ns->name);
219 zlog_info("NS %u is enabled.", ns->ns_id);
220 }
221 /* zebra first receives NS enable event,
222 * then VRF enable event
223 */
224 if (ns_master.ns_enable_hook)
225 (*ns_master.ns_enable_hook)(ns);
226 }
227
228 return 1;
229 }
230
231 /*
232 * Check whether the NS is enabled - that is, whether the NS
233 * is ready to allocate resources. Currently there's only one
234 * type of resource: socket.
235 */
236 static int ns_is_enabled(struct ns *ns)
237 {
238 if (have_netns())
239 return ns && ns->fd >= 0;
240 else
241 return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT;
242 }
243
244 /*
245 * Disable a NS - that is, let the NS be unusable.
246 * The NS_DELETE_HOOK callback will be called to inform
247 * that they must release the resources in the NS.
248 */
249 static void ns_disable_internal(struct ns *ns)
250 {
251 if (ns_is_enabled(ns)) {
252 if (ns_debug)
253 zlog_info("NS %u is to be disabled.", ns->ns_id);
254
255 if (ns_master.ns_disable_hook)
256 (*ns_master.ns_disable_hook)(ns);
257
258 if (have_netns())
259 close(ns->fd);
260
261 ns->fd = -1;
262 }
263 }
264
265 struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id)
266 {
267 return ns_get_created_internal(ns, name, ns_id);
268 }
269
270 int ns_have_netns(void)
271 {
272 return have_netns();
273 }
274
275 /* Delete a NS. This is called in ns_terminate(). */
276 void ns_delete(struct ns *ns)
277 {
278 if (ns_debug)
279 zlog_info("NS %u is to be deleted.", ns->ns_id);
280
281 ns_disable(ns);
282
283 if (ns_master.ns_delete_hook)
284 (*ns_master.ns_delete_hook)(ns);
285
286 /*
287 * I'm not entirely sure if the vrf->iflist
288 * needs to be moved into here or not.
289 */
290 // if_terminate (&ns->iflist);
291
292 RB_REMOVE(ns_head, &ns_tree, ns);
293 if (ns->name)
294 XFREE(MTYPE_NS_NAME, ns->name);
295
296 XFREE(MTYPE_NS, ns);
297 }
298
299 /* Look up the data pointer of the specified VRF. */
300 void *ns_info_lookup(ns_id_t ns_id)
301 {
302 struct ns *ns = ns_lookup_internal(ns_id);
303
304 return ns ? ns->info : NULL;
305 }
306
307 /* Look up a NS by name */
308 struct ns *ns_lookup_name(const char *name)
309 {
310 return ns_lookup_name_internal(name);
311 }
312
313 int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *))
314 {
315 return ns_enable_internal(ns, func);
316 }
317
318 void ns_disable(struct ns *ns)
319 {
320 return ns_disable_internal(ns);
321 }
322
323 struct ns *ns_lookup(ns_id_t ns_id)
324 {
325 return ns_lookup_internal(ns_id);
326 }
327
328 void ns_walk_func(int (*func)(struct ns *))
329 {
330 struct ns *ns = NULL;
331
332 RB_FOREACH (ns, ns_head, &ns_tree)
333 func(ns);
334 }
335
336 const char *ns_get_name(struct ns *ns)
337 {
338 if (!ns)
339 return NULL;
340 return ns->name;
341 }
342
343 /* Add a NS hook. Please add hooks before calling ns_init(). */
344 void ns_add_hook(int type, int (*func)(struct ns *))
345 {
346 switch (type) {
347 case NS_NEW_HOOK:
348 ns_master.ns_new_hook = func;
349 break;
350 case NS_DELETE_HOOK:
351 ns_master.ns_delete_hook = func;
352 break;
353 case NS_ENABLE_HOOK:
354 ns_master.ns_enable_hook = func;
355 break;
356 case NS_DISABLE_HOOK:
357 ns_master.ns_disable_hook = func;
358 break;
359 default:
360 break;
361 }
362 }
363
364 /*
365 * NS realization with NETNS
366 */
367
368 char *ns_netns_pathname(struct vty *vty, const char *name)
369 {
370 static char pathname[PATH_MAX];
371 char *result;
372 char *check_base;
373
374 if (name[0] == '/') /* absolute pathname */
375 result = realpath(name, pathname);
376 else {
377 /* relevant pathname */
378 char tmp_name[PATH_MAX];
379
380 snprintf(tmp_name, PATH_MAX, "%s/%s", NS_RUN_DIR, name);
381 result = realpath(tmp_name, pathname);
382 }
383
384 if (!result) {
385 if (vty)
386 vty_out(vty, "Invalid pathname: %s\n",
387 safe_strerror(errno));
388 else
389 zlog_warn("Invalid pathname: %s", safe_strerror(errno));
390 return NULL;
391 }
392 check_base = basename(pathname);
393 if (check_base != NULL && strlen(check_base) + 1 > NS_NAMSIZ) {
394 if (vty)
395 vty_out(vty, "NS name (%s) invalid: too long (>%d)\n",
396 check_base, NS_NAMSIZ - 1);
397 else
398 zlog_warn("NS name (%s) invalid: too long (>%d)",
399 check_base, NS_NAMSIZ - 1);
400 return NULL;
401 }
402 return pathname;
403 }
404
405 void ns_init(void)
406 {
407 static int ns_initialised;
408
409 ns_debug = 0;
410 /* silently return as initialisation done */
411 if (ns_initialised == 1)
412 return;
413 errno = 0;
414 #ifdef HAVE_NETNS
415 if (have_netns_enabled < 0) {
416 ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
417 if (ns_default_ns_fd == -1)
418 zlog_err("NS initialization failure %d(%s)",
419 errno, safe_strerror(errno));
420 } else {
421 ns_default_ns_fd = -1;
422 default_ns = NULL;
423 }
424 #else
425 ns_default_ns_fd = -1;
426 default_ns = NULL;
427 #endif /* HAVE_NETNS */
428 ns_current_ns_fd = -1;
429 ns_initialised = 1;
430 }
431
432 /* Initialize NS module. */
433 void ns_init_management(ns_id_t default_ns_id)
434 {
435 int fd;
436
437 ns_init();
438 default_ns = ns_get_created_internal(NULL, NULL, default_ns_id);
439 if (!default_ns) {
440 zlog_err("%s: failed to create the default NS!", __func__);
441 exit(1);
442 }
443 if (have_netns()) {
444 fd = open(NS_DEFAULT_NAME, O_RDONLY);
445 default_ns->fd = fd;
446 }
447 /* Set the default NS name. */
448 default_ns->name = XSTRDUP(MTYPE_NS_NAME, NS_DEFAULT_NAME);
449 if (ns_debug)
450 zlog_info("%s: default NSID is %u", __func__,
451 default_ns->ns_id);
452
453 /* Enable the default NS. */
454 if (!ns_enable(default_ns, NULL)) {
455 zlog_err("%s: failed to enable the default NS!", __func__);
456 exit(1);
457 }
458 }
459
460 /* Terminate NS module. */
461 void ns_terminate(void)
462 {
463 struct ns *ns;
464
465 while (!RB_EMPTY(ns_head, &ns_tree)) {
466 ns = RB_ROOT(ns_head, &ns_tree);
467
468 ns_delete(ns);
469 }
470 }
471
472 int ns_switch_to_netns(const char *name)
473 {
474 int ret;
475 int fd;
476
477 if (name == NULL)
478 return -1;
479 if (ns_default_ns_fd == -1)
480 return -1;
481 fd = open(name, O_RDONLY);
482 if (fd == -1) {
483 errno = EINVAL;
484 return -1;
485 }
486 ret = setns(fd, CLONE_NEWNET);
487 ns_current_ns_fd = fd;
488 close(fd);
489 return ret;
490 }
491
492 /* returns 1 if switch() was not called before
493 * return status of setns() otherwise
494 */
495 int ns_switchback_to_initial(void)
496 {
497 if (ns_current_ns_fd != -1 && ns_default_ns_fd != -1) {
498 int ret;
499
500 ret = setns(ns_default_ns_fd, CLONE_NEWNET);
501 ns_current_ns_fd = -1;
502 return ret;
503 }
504 /* silently ignore if setns() is not called */
505 return 1;
506 }
507
508 /* Create a socket for the NS. */
509 int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
510 {
511 struct ns *ns = ns_lookup(ns_id);
512 int ret;
513
514 if (!ns || !ns_is_enabled(ns)) {
515 errno = EINVAL;
516 return -1;
517 }
518 if (have_netns()) {
519 ret = (ns_id != NS_DEFAULT) ? setns(ns->fd, CLONE_NEWNET) : 0;
520 if (ret >= 0) {
521 ret = socket(domain, type, protocol);
522 if (ns_id != NS_DEFAULT) {
523 setns(ns_lookup(NS_DEFAULT)->fd, CLONE_NEWNET);
524 ns_current_ns_fd = ns_id;
525 }
526 }
527 } else
528 ret = socket(domain, type, protocol);
529
530 return ret;
531 }
532
533 ns_id_t ns_get_default_id(void)
534 {
535 if (default_ns)
536 return default_ns->ns_id;
537 return NS_DEFAULT_INTERNAL;
538 }