]> git.proxmox.com Git - mirror_frr.git/blame - lib/ns.c
zebra: collect and get netnamespaces information
[mirror_frr.git] / lib / ns.c
CommitLineData
32bcb8b0
DS
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 *
896014f4
DL
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
32bcb8b0
DS
20 */
21
22#include <zebra.h>
23
13460c44 24#ifdef HAVE_NETNS
d62a17ae 25#undef _GNU_SOURCE
13460c44
FL
26#define _GNU_SOURCE
27
28#include <sched.h>
29#endif
30
4691b65a
PG
31/* for basename */
32#include <libgen.h>
33
32bcb8b0
DS
34#include "if.h"
35#include "ns.h"
32bcb8b0
DS
36#include "log.h"
37#include "memory.h"
38
13460c44
FL
39#include "command.h"
40#include "vty.h"
b95c1883 41#include "vrf.h"
13460c44 42
b95c1883
PG
43DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
44DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
13460c44 45
d62a17ae 46static __inline int ns_compare(const struct ns *, const struct ns *);
47static struct ns *ns_lookup(ns_id_t);
b95c1883 48static struct ns *ns_lookup_name(const char *);
c7fdd84f 49
d62a17ae 50RB_GENERATE(ns_head, ns, entry, ns_compare)
c7fdd84f 51
d62a17ae 52struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
13460c44 53
ce1be369
PG
54static int ns_current_ns_fd;
55static int ns_default_ns_fd;
56
13460c44
FL
57#ifndef CLONE_NEWNET
58#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
59#endif
60
61#ifndef HAVE_SETNS
62static inline int setns(int fd, int nstype)
63{
64#ifdef __NR_setns
d62a17ae 65 return syscall(__NR_setns, fd, nstype);
13460c44 66#else
d62a17ae 67 errno = ENOSYS;
68 return -1;
13460c44
FL
69#endif
70}
71#endif /* HAVE_SETNS */
72
c253dcb5
ND
73#ifdef HAVE_NETNS
74
13460c44 75#define NS_DEFAULT_NAME "/proc/self/ns/net"
c253dcb5 76static int have_netns_enabled = -1;
13460c44 77
d62a17ae 78#else /* !HAVE_NETNS */
13460c44 79
32bcb8b0
DS
80#define NS_DEFAULT_NAME "Default-logical-router"
81
13460c44
FL
82#endif /* HAVE_NETNS */
83
c253dcb5
ND
84static int have_netns(void)
85{
86#ifdef HAVE_NETNS
d62a17ae 87 if (have_netns_enabled < 0) {
88 int fd = open(NS_DEFAULT_NAME, O_RDONLY);
89
90 if (fd < 0)
91 have_netns_enabled = 0;
92 else {
93 have_netns_enabled = 1;
94 close(fd);
95 }
96 }
97 return have_netns_enabled;
c253dcb5 98#else
d62a17ae 99 return 0;
c253dcb5
ND
100#endif
101}
102
32bcb8b0 103/* Holding NS hooks */
d62a17ae 104struct ns_master {
3347430b
PG
105 int (*ns_new_hook)(struct ns *ns);
106 int (*ns_delete_hook)(struct ns *ns);
107 int (*ns_enable_hook)(struct ns *ns);
108 int (*ns_disable_hook)(struct ns *ns);
d62a17ae 109} ns_master = {
110 0,
111};
112
113static int ns_is_enabled(struct ns *ns);
114static int ns_enable(struct ns *ns);
115static void ns_disable(struct ns *ns);
b95c1883 116static void ns_get_created(struct ns *ns);
d62a17ae 117
118static __inline int ns_compare(const struct ns *a, const struct ns *b)
32bcb8b0 119{
d62a17ae 120 return (a->ns_id - b->ns_id);
32bcb8b0
DS
121}
122
b95c1883
PG
123static void ns_get_created(struct ns *ns)
124{
125 /*
126 * Initialize interfaces.
127 *
128 * I'm not sure if this belongs here or in
129 * the vrf code.
130 */
131 // if_init (&ns->iflist);
132
133 if (ns->ns_id != NS_UNKNOWN)
134 zlog_info("NS %u is created.", ns->ns_id);
135 else
136 zlog_info("NS %s is created.", ns->name);
137 if (ns_master.ns_new_hook)
3347430b
PG
138 (*ns_master.ns_new_hook) (ns);
139 return;
b95c1883
PG
140}
141
32bcb8b0 142/* Get a NS. If not found, create one. */
d62a17ae 143static struct ns *ns_get(ns_id_t ns_id)
32bcb8b0 144{
d62a17ae 145 struct ns *ns;
32bcb8b0 146
d62a17ae 147 ns = ns_lookup(ns_id);
148 if (ns)
149 return (ns);
32bcb8b0 150
d62a17ae 151 ns = XCALLOC(MTYPE_NS, sizeof(struct ns));
152 ns->ns_id = ns_id;
153 ns->fd = -1;
154 RB_INSERT(ns_head, &ns_tree, ns);
b95c1883
PG
155 ns_get_created(ns);
156 return ns;
157}
32bcb8b0 158
b95c1883
PG
159/* Get a NS. If not found, create one. */
160static struct ns *ns_get_by_name(char *ns_name)
161{
162 struct ns *ns;
32bcb8b0 163
b95c1883
PG
164 ns = ns_lookup_name(ns_name);
165 if (ns)
166 return (ns);
32bcb8b0 167
b95c1883
PG
168 ns = XCALLOC(MTYPE_NS, sizeof(struct ns));
169 ns->ns_id = NS_UNKNOWN;
170 ns->name = XSTRDUP(MTYPE_NS_NAME, ns_name);
171 ns->fd = -1;
172 RB_INSERT(ns_head, &ns_tree, ns);
32bcb8b0 173
b95c1883
PG
174 /* ns_id not initialised */
175 ns_get_created(ns);
d62a17ae 176 return ns;
32bcb8b0
DS
177}
178
179/* Delete a NS. This is called in ns_terminate(). */
d62a17ae 180static void ns_delete(struct ns *ns)
32bcb8b0 181{
d62a17ae 182 zlog_info("NS %u is to be deleted.", ns->ns_id);
32bcb8b0 183
d62a17ae 184 ns_disable(ns);
32bcb8b0 185
d62a17ae 186 if (ns_master.ns_delete_hook)
3347430b 187 (*ns_master.ns_delete_hook)(ns);
32bcb8b0 188
d62a17ae 189 /*
190 * I'm not entirely sure if the vrf->iflist
191 * needs to be moved into here or not.
192 */
193 // if_terminate (&ns->iflist);
32bcb8b0 194
d62a17ae 195 RB_REMOVE(ns_head, &ns_tree, ns);
196 if (ns->name)
197 XFREE(MTYPE_NS_NAME, ns->name);
32bcb8b0 198
d62a17ae 199 XFREE(MTYPE_NS, ns);
32bcb8b0
DS
200}
201
202/* Look up a NS by identifier. */
d62a17ae 203static struct ns *ns_lookup(ns_id_t ns_id)
32bcb8b0 204{
d62a17ae 205 struct ns ns;
206 ns.ns_id = ns_id;
207 return (RB_FIND(ns_head, &ns_tree, &ns));
32bcb8b0
DS
208}
209
ff705b15
PG
210/* Look up the data pointer of the specified VRF. */
211void *
212ns_info_lookup(ns_id_t ns_id)
213{
214 struct ns *ns = ns_lookup(ns_id);
215
216 return ns ? ns->info : NULL;
217}
218
219void ns_walk_func(int (*func)(struct ns *))
220{
221 struct ns *ns = NULL;
222
223 RB_FOREACH(ns, ns_head, &ns_tree)
224 func(ns);
225}
226
81c9005f
PG
227const char *ns_get_name(struct ns *ns)
228{
229 if (!ns)
230 return NULL;
231 return ns->name;
232}
233
b95c1883
PG
234/* Look up a NS by name */
235static struct ns *ns_lookup_name(const char *name)
236{
237 struct ns *ns = NULL;
238
239 RB_FOREACH(ns, ns_head, &ns_tree) {
240 if (ns->name != NULL) {
241 if (strcmp(name, ns->name) == 0)
242 return ns;
243 }
244 }
245 return NULL;
246}
247
32bcb8b0
DS
248/*
249 * Check whether the NS is enabled - that is, whether the NS
250 * is ready to allocate resources. Currently there's only one
251 * type of resource: socket.
252 */
d62a17ae 253static int ns_is_enabled(struct ns *ns)
32bcb8b0 254{
d62a17ae 255 if (have_netns())
256 return ns && ns->fd >= 0;
257 else
258 return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT;
32bcb8b0
DS
259}
260
261/*
262 * Enable a NS - that is, let the NS be ready to use.
263 * The NS_ENABLE_HOOK callback will be called to inform
264 * that they can allocate resources in this NS.
265 *
266 * RETURN: 1 - enabled successfully; otherwise, 0.
267 */
d62a17ae 268static int ns_enable(struct ns *ns)
32bcb8b0 269{
697d3ec7 270 int vrf_on = 0;
13460c44 271
d62a17ae 272 if (!ns_is_enabled(ns)) {
273 if (have_netns()) {
274 ns->fd = open(ns->name, O_RDONLY);
275 } else {
276 ns->fd = -2; /* Remember that ns_enable_hook has been
277 called */
278 errno = -ENOTSUP;
279 }
280
281 if (!ns_is_enabled(ns)) {
282 zlog_err("Can not enable NS %u: %s!", ns->ns_id,
283 safe_strerror(errno));
284 return 0;
285 }
286
697d3ec7
PG
287 /* Non default NS. leave */
288 if (ns->ns_id == NS_UNKNOWN) {
289 zlog_err("Can not enable NS %s %u: Invalid NSID",
290 ns->name, ns->ns_id);
291 return 0;
292 }
293 vrf_on = vrf_update_vrf_id((vrf_id_t)ns->ns_id,
294 (struct vrf *)ns->vrf_ctxt);
d62a17ae 295 if (have_netns())
296 zlog_info("NS %u is associated with NETNS %s.",
297 ns->ns_id, ns->name);
298
299 zlog_info("NS %u is enabled.", ns->ns_id);
697d3ec7
PG
300 /* zebra first receives NS enable event,
301 * then VRF enable event
302 */
d62a17ae 303 if (ns_master.ns_enable_hook)
3347430b 304 (*ns_master.ns_enable_hook)(ns);
697d3ec7
PG
305 if (vrf_on == 1)
306 vrf_enable((struct vrf *)ns->vrf_ctxt);
d62a17ae 307 }
308
309 return 1;
32bcb8b0
DS
310}
311
312/*
313 * Disable a NS - that is, let the NS be unusable.
314 * The NS_DELETE_HOOK callback will be called to inform
315 * that they must release the resources in the NS.
316 */
d62a17ae 317static void ns_disable(struct ns *ns)
32bcb8b0 318{
d62a17ae 319 if (ns_is_enabled(ns)) {
320 zlog_info("NS %u is to be disabled.", ns->ns_id);
32bcb8b0 321
d62a17ae 322 if (ns_master.ns_disable_hook)
3347430b 323 (*ns_master.ns_disable_hook)(ns);
13460c44 324
d62a17ae 325 if (have_netns())
326 close(ns->fd);
c253dcb5 327
d62a17ae 328 ns->fd = -1;
329 }
32bcb8b0
DS
330}
331
332
333/* Add a NS hook. Please add hooks before calling ns_init(). */
3347430b 334void ns_add_hook(int type, int (*func)(struct ns *))
32bcb8b0 335{
d62a17ae 336 switch (type) {
337 case NS_NEW_HOOK:
338 ns_master.ns_new_hook = func;
339 break;
340 case NS_DELETE_HOOK:
341 ns_master.ns_delete_hook = func;
342 break;
343 case NS_ENABLE_HOOK:
344 ns_master.ns_enable_hook = func;
345 break;
346 case NS_DISABLE_HOOK:
347 ns_master.ns_disable_hook = func;
348 break;
349 default:
350 break;
351 }
32bcb8b0
DS
352}
353
13460c44
FL
354/*
355 * NS realization with NETNS
356 */
357
697d3ec7 358char *ns_netns_pathname(struct vty *vty, const char *name)
13460c44 359{
d62a17ae 360 static char pathname[PATH_MAX];
361 char *result;
4691b65a 362 char *check_base;
d62a17ae 363
364 if (name[0] == '/') /* absolute pathname */
365 result = realpath(name, pathname);
366 else /* relevant pathname */
367 {
368 char tmp_name[PATH_MAX];
369 snprintf(tmp_name, PATH_MAX, "%s/%s", NS_RUN_DIR, name);
370 result = realpath(tmp_name, pathname);
371 }
372
373 if (!result) {
697d3ec7
PG
374 if (vty)
375 vty_out(vty, "Invalid pathname: %s\n",
376 safe_strerror(errno));
4691b65a
PG
377 else
378 zlog_warn("Invalid pathname: %s",
379 safe_strerror(errno));
380 return NULL;
381 }
382 check_base = basename(pathname);
383 if (check_base != NULL && strlen(check_base) + 1 > NS_NAMSIZ) {
384 if (vty)
385 vty_out(vty, "NS name (%s) invalid:"
386 " too long( %d needed)\n",
387 check_base, NS_NAMSIZ-1);
388 else
389 zlog_warn("NS name (%s) invalid:"
390 " too long ( %d needed)",
391 check_base, NS_NAMSIZ-1);
d62a17ae 392 return NULL;
393 }
394 return pathname;
13460c44
FL
395}
396
b95c1883
PG
397DEFUN_NOSH (ns_logicalrouter,
398 ns_logicalrouter_cmd,
6147e2c6 399 "logical-router (1-65535) ns NAME",
13460c44
FL
400 "Enable a logical-router\n"
401 "Specify the logical-router indentifier\n"
402 "The Name Space\n"
403 "The file name in " NS_RUN_DIR ", or a full pathname\n")
404{
d62a17ae 405 int idx_number = 1;
406 int idx_name = 3;
b95c1883 407 ns_id_t ns_id;
d62a17ae 408 struct ns *ns = NULL;
409 char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
410
411 if (!pathname)
412 return CMD_WARNING_CONFIG_FAILED;
413
414 ns_id = strtoul(argv[idx_number]->arg, NULL, 10);
415 ns = ns_get(ns_id);
416
417 if (ns->name && strcmp(ns->name, pathname) != 0) {
418 vty_out(vty, "NS %u is already configured with NETNS %s\n",
419 ns->ns_id, ns->name);
851fcbae 420 return CMD_WARNING;
d62a17ae 421 }
422
423 if (!ns->name)
424 ns->name = XSTRDUP(MTYPE_NS_NAME, pathname);
425
426 if (!ns_enable(ns)) {
427 vty_out(vty, "Can not associate NS %u with NETNS %s\n",
428 ns->ns_id, ns->name);
429 return CMD_WARNING_CONFIG_FAILED;
430 }
431
432 return CMD_SUCCESS;
13460c44
FL
433}
434
b95c1883
PG
435static struct cmd_node logicalrouter_node = {NS_NODE, "", /* NS node has no interface. */
436 1};
437
438DEFUN (no_ns_logicalrouter,
439 no_ns_logicalrouter_cmd,
6147e2c6 440 "no logical-router (1-65535) ns NAME",
13460c44
FL
441 NO_STR
442 "Enable a Logical-Router\n"
443 "Specify the Logical-Router identifier\n"
444 "The Name Space\n"
445 "The file name in " NS_RUN_DIR ", or a full pathname\n")
446{
d62a17ae 447 int idx_number = 2;
448 int idx_name = 4;
b95c1883 449 ns_id_t ns_id;
d62a17ae 450 struct ns *ns = NULL;
451 char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
452
453 if (!pathname)
454 return CMD_WARNING_CONFIG_FAILED;
455
456 ns_id = strtoul(argv[idx_number]->arg, NULL, 10);
457 ns = ns_lookup(ns_id);
458
459 if (!ns) {
460 vty_out(vty, "NS %u is not found\n", ns_id);
461 return CMD_SUCCESS;
462 }
463
464 if (ns->name && strcmp(ns->name, pathname) != 0) {
465 vty_out(vty, "Incorrect NETNS file name\n");
466 return CMD_WARNING_CONFIG_FAILED;
467 }
468
469 ns_disable(ns);
470
471 if (ns->name) {
472 XFREE(MTYPE_NS_NAME, ns->name);
473 ns->name = NULL;
474 }
475
476 return CMD_SUCCESS;
13460c44
FL
477}
478
697d3ec7
PG
479int ns_handler_create(struct vty *vty, struct vrf *vrf,
480 char *pathname, ns_id_t ns_id)
b95c1883 481{
b95c1883 482 struct ns *ns = NULL;
b95c1883
PG
483
484 if (!vrf)
485 return CMD_WARNING_CONFIG_FAILED;
486 if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) {
697d3ec7
PG
487 if (vty)
488 vty_out(vty,
489 "VRF %u is already configured with VRF %s\n",
490 vrf->vrf_id, vrf->name);
491 else
492 zlog_warn("VRF %u is already configured with VRF %s\n",
493 vrf->vrf_id, vrf->name);
b95c1883
PG
494 return CMD_WARNING_CONFIG_FAILED;
495 }
496 if (vrf->ns_ctxt != NULL) {
497 ns = (struct ns *) vrf->ns_ctxt;
498 if (ns && 0 != strcmp(ns->name, pathname)) {
697d3ec7
PG
499 if (vty)
500 vty_out(vty,
501 "VRF %u is already configured"
502 " with NETNS %s\n",
503 vrf->vrf_id, ns->name);
504 else
505 zlog_warn("VRF %u is already configured with NETNS %s",
506 vrf->vrf_id, ns->name);
b95c1883
PG
507 return CMD_WARNING_CONFIG_FAILED;
508 }
509 }
510 ns = ns_lookup_name(pathname);
511 if (ns && ns->vrf_ctxt) {
512 struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt;
513
4691b65a
PG
514 if (vrf2 == vrf)
515 return CMD_SUCCESS;
697d3ec7
PG
516 if (vty)
517 vty_out(vty, "NS %s is already configured"
518 " with VRF %u(%s)\n",
519 ns->name, vrf2->vrf_id, vrf2->name);
520 else
521 zlog_warn("NS %s is already configured with VRF %u(%s)",
522 ns->name, vrf2->vrf_id, vrf2->name);
b95c1883
PG
523 return CMD_WARNING_CONFIG_FAILED;
524 } else if (!ns)
525 ns = ns_get_by_name(pathname);
13460c44 526
697d3ec7
PG
527 if (ns_id != ns->ns_id) {
528 RB_REMOVE(ns_head, &ns_tree, ns);
529 ns->ns_id = ns_id;
530 RB_INSERT(ns_head, &ns_tree, ns);
531 }
532 ns->vrf_ctxt = (void *)vrf;
533 vrf->ns_ctxt = (void *)ns;
4691b65a
PG
534 /* update VRF netns NAME */
535 if (vrf)
536 strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ);
537
b95c1883 538 if (!ns_enable(ns)) {
697d3ec7
PG
539 if (vty)
540 vty_out(vty, "Can not associate NS %u with NETNS %s\n",
541 ns->ns_id, ns->name);
542 else
543 zlog_warn("Can not associate NS %u with NETNS %s",
544 ns->ns_id, ns->name);
b95c1883
PG
545 return CMD_WARNING_CONFIG_FAILED;
546 }
547
b95c1883
PG
548 return CMD_SUCCESS;
549}
550
697d3ec7 551
b95c1883 552static int ns_logicalrouter_config_write(struct vty *vty)
13460c44 553{
d62a17ae 554 struct ns *ns;
555 int write = 0;
13460c44 556
78dd30b2 557 RB_FOREACH(ns, ns_head, &ns_tree) {
d62a17ae 558 if (ns->ns_id == NS_DEFAULT || ns->name == NULL)
559 continue;
d62a17ae 560 vty_out(vty, "logical-router %u netns %s\n", ns->ns_id,
561 ns->name);
562 write = 1;
563 }
d62a17ae 564 return write;
13460c44
FL
565}
566
697d3ec7
PG
567DEFUN_NOSH (ns_netns,
568 ns_netns_cmd,
569 "netns NAME",
570 "Attach VRF to a Namespace\n"
571 "The file name in " NS_RUN_DIR ", or a full pathname\n")
572{
573 int idx_name = 1;
574 char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg);
575
576 VTY_DECLVAR_CONTEXT(vrf, vrf);
577
578 if (!pathname)
579 return CMD_WARNING_CONFIG_FAILED;
580 return ns_handler_create(vty, vrf, pathname, NS_UNKNOWN);
581}
582
b95c1883
PG
583DEFUN (no_ns_netns,
584 no_ns_netns_cmd,
585 "no netns [NAME]",
586 NO_STR
587 "Detach VRF from a Namespace\n"
588 "The file name in " NS_RUN_DIR ", or a full pathname\n")
589{
590 struct ns *ns = NULL;
591
592 VTY_DECLVAR_CONTEXT(vrf, vrf);
593
c17d4838
PG
594 if (!vrf_is_backend_netns()) {
595 vty_out(vty, "VRF backend is not Netns. Aborting\n");
596 return CMD_WARNING_CONFIG_FAILED;
597 }
b95c1883
PG
598 if (!vrf->ns_ctxt) {
599 vty_out(vty, "VRF %s(%u) is not configured with NetNS\n",
600 vrf->name, vrf->vrf_id);
601 return CMD_WARNING_CONFIG_FAILED;
602 }
603
604 ns = (struct ns *)vrf->ns_ctxt;
605
606 ns->vrf_ctxt = NULL;
697d3ec7
PG
607 vrf_disable(vrf);
608 /* vrf ID from VRF is necessary for Zebra
609 * so that propagate to other clients is done
610 */
611 RB_REMOVE(ns_head, &ns_tree, ns);
612 ns->ns_id = NS_UNKNOWN;
613 RB_INSERT(ns_head, &ns_tree, ns);
b95c1883
PG
614 ns_delete(ns);
615 vrf->ns_ctxt = NULL;
616 return CMD_SUCCESS;
617}
618
ce1be369
PG
619void ns_init(void)
620{
621#ifdef HAVE_NETNS
622 if (have_netns_enabled < 0) {
623 ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
624 return;
625 }
626#endif /* HAVE_NETNS */
627 ns_default_ns_fd = -1;
628}
629
32bcb8b0 630/* Initialize NS module. */
3347430b 631void ns_init_zebra(void)
32bcb8b0 632{
d62a17ae 633 struct ns *default_ns;
634
ce1be369 635 ns_init();
d62a17ae 636 /* The default NS always exists. */
637 default_ns = ns_get(NS_DEFAULT);
ce1be369 638 ns_current_ns_fd = -1;
d62a17ae 639 if (!default_ns) {
640 zlog_err("ns_init: failed to create the default NS!");
641 exit(1);
642 }
643
644 /* Set the default NS name. */
645 default_ns->name = XSTRDUP(MTYPE_NS_NAME, NS_DEFAULT_NAME);
646
647 /* Enable the default NS. */
648 if (!ns_enable(default_ns)) {
649 zlog_err("ns_init: failed to enable the default NS!");
650 exit(1);
651 }
652
78dd30b2 653 if (have_netns() && !vrf_is_backend_netns()) {
d62a17ae 654 /* Install NS commands. */
b95c1883
PG
655 install_node(&logicalrouter_node,
656 ns_logicalrouter_config_write);
657 install_element(CONFIG_NODE, &ns_logicalrouter_cmd);
658 install_element(CONFIG_NODE, &no_ns_logicalrouter_cmd);
659 }
660}
661
662void ns_cmd_init(void)
663{
c17d4838 664 if (have_netns() && vrf_is_backend_netns()) {
b95c1883
PG
665 /* Install NS commands. */
666 install_element(VRF_NODE, &ns_netns_cmd);
667 install_element(VRF_NODE, &no_ns_netns_cmd);
d62a17ae 668 }
32bcb8b0
DS
669}
670
671/* Terminate NS module. */
d62a17ae 672void ns_terminate(void)
32bcb8b0 673{
d62a17ae 674 struct ns *ns;
32bcb8b0 675
55cd0f61
DS
676 while (!RB_EMPTY(ns_head, &ns_tree)) {
677 ns = RB_ROOT(ns_head, &ns_tree);
678
d62a17ae 679 ns_delete(ns);
55cd0f61 680 }
32bcb8b0
DS
681}
682
ce1be369
PG
683int ns_switch_to_netns(const char *name)
684{
685 int ret;
686 int fd;
687
688 if (name == NULL)
689 return -1;
690 fd = open(name, O_RDONLY);
691 if (fd == -1) {
692 errno = ENOSYS;
693 return -1;
694 }
695 ret = setns(fd, CLONE_NEWNET);
696 ns_current_ns_fd = fd;
697 close(fd);
698 return ret;
699}
700
701/* returns 1 if switch() was not called before
702 * return status of setns() otherwise
703 */
704int ns_switchback_to_initial(void)
705{
706 if (ns_current_ns_fd != -1) {
707 int ret;
708
709 ret = setns(ns_default_ns_fd, CLONE_NEWNET);
710 ns_current_ns_fd = -1;
711 return ret;
712 }
713 /* silently ignore if setns() is not called */
714 return 1;
715}
716
32bcb8b0 717/* Create a socket for the NS. */
d62a17ae 718int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
32bcb8b0 719{
d62a17ae 720 struct ns *ns = ns_lookup(ns_id);
fe533c56 721 int ret;
d62a17ae 722
fe533c56 723 if (!ns || !ns_is_enabled(ns)) {
d62a17ae 724 errno = ENOSYS;
725 return -1;
726 }
727
728 if (have_netns()) {
729 ret = (ns_id != NS_DEFAULT) ? setns(ns->fd, CLONE_NEWNET) : 0;
730 if (ret >= 0) {
731 ret = socket(domain, type, protocol);
ce1be369 732 if (ns_id != NS_DEFAULT) {
d62a17ae 733 setns(ns_lookup(NS_DEFAULT)->fd, CLONE_NEWNET);
ce1be369
PG
734 ns_current_ns_fd = ns_id;
735 }
d62a17ae 736 }
737 } else
738 ret = socket(domain, type, protocol);
739
740 return ret;
32bcb8b0 741}