]> git.proxmox.com Git - mirror_frr.git/blame - lib/ns.c
Merge branch 'vtysh-grammar' of ssh://stash.cumulusnetworks.com:7999/quag/quagga...
[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{
560 ns_id_t ns_id = NS_DEFAULT;
561 struct ns *ns = NULL;
c0c053fa 562 char *pathname = ns_netns_pathname (vty, argv[3]->arg);
13460c44
FL
563
564 if (!pathname)
565 return CMD_WARNING;
566
c0c053fa 567 VTY_GET_INTEGER ("NS ID", ns_id, argv[1]->arg);
13460c44
FL
568 ns = ns_get (ns_id);
569
570 if (ns->name && strcmp (ns->name, pathname) != 0)
571 {
572 vty_out (vty, "NS %u is already configured with NETNS %s%s",
573 ns->ns_id, ns->name, VTY_NEWLINE);
574 return CMD_WARNING;
575 }
576
577 if (!ns->name)
578 ns->name = XSTRDUP (MTYPE_NS_NAME, pathname);
579
580 if (!ns_enable (ns))
581 {
582 vty_out (vty, "Can not associate NS %u with NETNS %s%s",
583 ns->ns_id, ns->name, VTY_NEWLINE);
584 return CMD_WARNING;
585 }
586
587 return CMD_SUCCESS;
588}
589
590DEFUN (no_ns_netns,
591 no_ns_netns_cmd,
6147e2c6 592 "no logical-router (1-65535) ns NAME",
13460c44
FL
593 NO_STR
594 "Enable a Logical-Router\n"
595 "Specify the Logical-Router identifier\n"
596 "The Name Space\n"
597 "The file name in " NS_RUN_DIR ", or a full pathname\n")
598{
599 ns_id_t ns_id = NS_DEFAULT;
600 struct ns *ns = NULL;
c0c053fa 601 char *pathname = ns_netns_pathname (vty, argv[4]->arg);
13460c44
FL
602
603 if (!pathname)
604 return CMD_WARNING;
605
c0c053fa 606 VTY_GET_INTEGER ("NS ID", ns_id, argv[2]->arg);
13460c44
FL
607 ns = ns_lookup (ns_id);
608
609 if (!ns)
610 {
611 vty_out (vty, "NS %u is not found%s", ns_id, VTY_NEWLINE);
612 return CMD_SUCCESS;
613 }
614
615 if (ns->name && strcmp (ns->name, pathname) != 0)
616 {
617 vty_out (vty, "Incorrect NETNS file name%s", VTY_NEWLINE);
618 return CMD_WARNING;
619 }
620
621 ns_disable (ns);
622
623 if (ns->name)
624 {
625 XFREE (MTYPE_NS_NAME, ns->name);
626 ns->name = NULL;
627 }
628
629 return CMD_SUCCESS;
630}
631
632/* NS node. */
633static struct cmd_node ns_node =
634{
635 NS_NODE,
636 "", /* NS node has no interface. */
637 1
638};
639
640/* NS configuration write function. */
641static int
642ns_config_write (struct vty *vty)
643{
644 struct route_node *rn;
645 struct ns *ns;
646 int write = 0;
647
648 for (rn = route_top (ns_table); rn; rn = route_next (rn))
649 if ((ns = rn->info) != NULL &&
650 ns->ns_id != NS_DEFAULT && ns->name)
651 {
652 vty_out (vty, "logical-router %u netns %s%s", ns->ns_id, ns->name, VTY_NEWLINE);
653 write++;
654 }
655
656 return write;
657}
658
32bcb8b0
DS
659/* Initialize NS module. */
660void
661ns_init (void)
662{
663 struct ns *default_ns;
664
665 /* Allocate NS table. */
666 ns_table = route_table_init ();
667
668 /* The default NS always exists. */
669 default_ns = ns_get (NS_DEFAULT);
670 if (!default_ns)
671 {
672 zlog_err ("ns_init: failed to create the default NS!");
673 exit (1);
674 }
675
676 /* Set the default NS name. */
677 default_ns->name = XSTRDUP (MTYPE_NS_NAME, NS_DEFAULT_NAME);
678
679 /* Enable the default NS. */
680 if (!ns_enable (default_ns))
681 {
682 zlog_err ("ns_init: failed to enable the default NS!");
683 exit (1);
684 }
13460c44 685
c253dcb5
ND
686 if (have_netns())
687 {
688 /* Install NS commands. */
689 install_node (&ns_node, ns_config_write);
690 install_element (CONFIG_NODE, &ns_netns_cmd);
691 install_element (CONFIG_NODE, &no_ns_netns_cmd);
692 }
32bcb8b0
DS
693}
694
695/* Terminate NS module. */
696void
697ns_terminate (void)
698{
699 struct route_node *rn;
700 struct ns *ns;
701
702 for (rn = route_top (ns_table); rn; rn = route_next (rn))
703 if ((ns = rn->info) != NULL)
704 ns_delete (ns);
705
706 route_table_finish (ns_table);
707 ns_table = NULL;
708}
709
710/* Create a socket for the NS. */
711int
712ns_socket (int domain, int type, int protocol, ns_id_t ns_id)
713{
13460c44 714 struct ns *ns = ns_lookup (ns_id);
32bcb8b0
DS
715 int ret = -1;
716
13460c44 717 if (!ns_is_enabled (ns))
32bcb8b0
DS
718 {
719 errno = ENOSYS;
720 return -1;
721 }
722
c253dcb5 723 if (have_netns())
13460c44 724 {
c253dcb5
ND
725 ret = (ns_id != NS_DEFAULT) ? setns (ns->fd, CLONE_NEWNET) : 0;
726 if (ret >= 0)
727 {
728 ret = socket (domain, type, protocol);
729 if (ns_id != NS_DEFAULT)
730 setns (ns_lookup (NS_DEFAULT)->fd, CLONE_NEWNET);
731 }
13460c44 732 }
c253dcb5
ND
733 else
734 ret = socket (domain, type, protocol);
32bcb8b0
DS
735
736 return ret;
737}