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