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