Line data Source code
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 : #include "command.h"
39 : #include "vty.h"
40 : #include "vrf.h"
41 : #include "lib_errors.h"
42 :
43 11 : DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context");
44 11 : DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name");
45 :
46 : static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
47 : static struct ns *ns_lookup_name_internal(const char *name);
48 :
49 10 : RB_GENERATE(ns_head, ns, entry, ns_compare)
50 :
51 : static struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
52 :
53 : static struct ns *default_ns;
54 : static int ns_current_ns_fd;
55 : static int ns_default_ns_fd;
56 :
57 : static int ns_debug;
58 :
59 : struct ns_map_nsid {
60 : RB_ENTRY(ns_map_nsid) id_entry;
61 : ns_id_t ns_id_external;
62 : ns_id_t ns_id;
63 : };
64 :
65 0 : static inline int ns_map_compare(const struct ns_map_nsid *a,
66 : const struct ns_map_nsid *b)
67 : {
68 0 : return (a->ns_id - b->ns_id);
69 : }
70 :
71 : RB_HEAD(ns_map_nsid_head, ns_map_nsid);
72 2 : RB_PROTOTYPE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
73 0 : RB_GENERATE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare);
74 : static struct ns_map_nsid_head ns_map_nsid_list =
75 : RB_INITIALIZER(&ns_map_nsid_list);
76 :
77 : static ns_id_t ns_id_external_numbering;
78 :
79 :
80 : #ifndef CLONE_NEWNET
81 : #define CLONE_NEWNET 0x40000000
82 : /* New network namespace (lo, device, names sockets, etc) */
83 : #endif
84 :
85 : #ifndef HAVE_SETNS
86 : static inline int setns(int fd, int nstype)
87 : {
88 : #ifdef __NR_setns
89 : return syscall(__NR_setns, fd, nstype);
90 : #else
91 : errno = EINVAL;
92 : return -1;
93 : #endif
94 : }
95 : #endif /* !HAVE_SETNS */
96 :
97 : #ifdef HAVE_NETNS
98 : static int have_netns_enabled = -1;
99 : #endif /* HAVE_NETNS */
100 :
101 17 : static int have_netns(void)
102 : {
103 : #ifdef HAVE_NETNS
104 17 : if (have_netns_enabled < 0) {
105 3 : int fd = open(NS_DEFAULT_NAME, O_RDONLY);
106 :
107 3 : if (fd < 0)
108 0 : have_netns_enabled = 0;
109 : else {
110 3 : have_netns_enabled = 1;
111 3 : close(fd);
112 : }
113 : }
114 17 : return have_netns_enabled;
115 : #else
116 : return 0;
117 : #endif
118 : }
119 :
120 : /* Holding NS hooks */
121 : static struct ns_master {
122 : int (*ns_new_hook)(struct ns *ns);
123 : int (*ns_delete_hook)(struct ns *ns);
124 : int (*ns_enable_hook)(struct ns *ns);
125 : int (*ns_disable_hook)(struct ns *ns);
126 : } ns_master = {
127 : 0,
128 : };
129 :
130 : static int ns_is_enabled(struct ns *ns);
131 :
132 10 : static inline int ns_compare(const struct ns *a, const struct ns *b)
133 : {
134 10 : return (a->ns_id - b->ns_id);
135 : }
136 :
137 : /* Look up a NS by identifier. */
138 11 : static struct ns *ns_lookup_internal(ns_id_t ns_id)
139 : {
140 11 : struct ns ns;
141 :
142 11 : ns.ns_id = ns_id;
143 22 : return RB_FIND(ns_head, &ns_tree, &ns);
144 : }
145 :
146 : /* Look up a NS by name */
147 0 : static struct ns *ns_lookup_name_internal(const char *name)
148 : {
149 0 : struct ns *ns = NULL;
150 :
151 0 : RB_FOREACH (ns, ns_head, &ns_tree) {
152 0 : if (ns->name != NULL) {
153 0 : if (strcmp(name, ns->name) == 0)
154 0 : return ns;
155 : }
156 : }
157 : return NULL;
158 : }
159 :
160 1 : static struct ns *ns_get_created_internal(struct ns *ns, char *name,
161 : ns_id_t ns_id)
162 : {
163 1 : int created = 0;
164 : /*
165 : * Initialize interfaces.
166 : */
167 1 : if (!ns && !name && ns_id != NS_UNKNOWN)
168 1 : ns = ns_lookup_internal(ns_id);
169 1 : if (!ns && name)
170 0 : ns = ns_lookup_name_internal(name);
171 1 : if (!ns) {
172 1 : ns = XCALLOC(MTYPE_NS, sizeof(struct ns));
173 1 : ns->ns_id = ns_id;
174 1 : if (name)
175 0 : ns->name = XSTRDUP(MTYPE_NS_NAME, name);
176 1 : ns->fd = -1;
177 1 : RB_INSERT(ns_head, &ns_tree, ns);
178 1 : created = 1;
179 : }
180 1 : if (ns_id != ns->ns_id) {
181 0 : RB_REMOVE(ns_head, &ns_tree, ns);
182 0 : ns->ns_id = ns_id;
183 0 : RB_INSERT(ns_head, &ns_tree, ns);
184 : }
185 1 : if (!created)
186 : return ns;
187 1 : if (ns_debug) {
188 0 : if (ns->ns_id != NS_UNKNOWN)
189 0 : zlog_info("NS %u is created.", ns->ns_id);
190 : else
191 0 : zlog_info("NS %s is created.", ns->name);
192 : }
193 1 : if (ns_master.ns_new_hook)
194 0 : (*ns_master.ns_new_hook)(ns);
195 : return ns;
196 : }
197 :
198 : /*
199 : * Enable a NS - that is, let the NS be ready to use.
200 : * The NS_ENABLE_HOOK callback will be called to inform
201 : * that they can allocate resources in this NS.
202 : *
203 : * RETURN: 1 - enabled successfully; otherwise, 0.
204 : */
205 1 : static int ns_enable_internal(struct ns *ns, void (*func)(ns_id_t, void *))
206 : {
207 1 : if (!ns_is_enabled(ns)) {
208 0 : if (have_netns()) {
209 0 : ns->fd = open(ns->name, O_RDONLY);
210 : } else {
211 0 : ns->fd = -2;
212 : /* Remember ns_enable_hook has been called */
213 0 : errno = -ENOTSUP;
214 : }
215 :
216 0 : if (!ns_is_enabled(ns)) {
217 0 : flog_err_sys(EC_LIB_SYSTEM_CALL,
218 : "Can not enable NS %u: %s!", ns->ns_id,
219 : safe_strerror(errno));
220 0 : return 0;
221 : }
222 :
223 : /* Non default NS. leave */
224 0 : if (ns->ns_id == NS_UNKNOWN) {
225 0 : flog_err(EC_LIB_NS,
226 : "Can not enable NS %s %u: Invalid NSID",
227 : ns->name, ns->ns_id);
228 0 : return 0;
229 : }
230 0 : if (func)
231 0 : func(ns->ns_id, (void *)ns->vrf_ctxt);
232 0 : if (ns_debug) {
233 0 : if (have_netns())
234 0 : zlog_info("NS %u is associated with NETNS %s.",
235 : ns->ns_id, ns->name);
236 0 : zlog_info("NS %u is enabled.", ns->ns_id);
237 : }
238 : /* zebra first receives NS enable event,
239 : * then VRF enable event
240 : */
241 0 : if (ns_master.ns_enable_hook)
242 0 : (*ns_master.ns_enable_hook)(ns);
243 : }
244 :
245 : return 1;
246 : }
247 :
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 : */
253 7 : static int ns_is_enabled(struct ns *ns)
254 : {
255 7 : if (have_netns())
256 7 : return ns && ns->fd >= 0;
257 : else
258 0 : return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT;
259 : }
260 :
261 : /*
262 : * Disable a NS - that is, let the NS be unusable.
263 : * The NS_DELETE_HOOK callback will be called to inform
264 : * that they must release the resources in the NS.
265 : */
266 1 : static void ns_disable_internal(struct ns *ns)
267 : {
268 1 : if (ns_is_enabled(ns)) {
269 1 : if (ns_debug)
270 0 : zlog_info("NS %u is to be disabled.", ns->ns_id);
271 :
272 1 : if (ns_master.ns_disable_hook)
273 0 : (*ns_master.ns_disable_hook)(ns);
274 :
275 1 : if (have_netns())
276 1 : close(ns->fd);
277 :
278 1 : ns->fd = -1;
279 : }
280 1 : }
281 :
282 : /* VRF list existence check by name. */
283 1 : static struct ns_map_nsid *ns_map_nsid_lookup_by_nsid(ns_id_t ns_id)
284 : {
285 1 : struct ns_map_nsid ns_map;
286 :
287 1 : ns_map.ns_id = ns_id;
288 2 : return RB_FIND(ns_map_nsid_head, &ns_map_nsid_list, &ns_map);
289 : }
290 :
291 1 : ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool map)
292 : {
293 1 : struct ns_map_nsid *ns_map;
294 1 : vrf_id_t ns_id_external;
295 :
296 1 : ns_map = ns_map_nsid_lookup_by_nsid(ns_id);
297 1 : if (ns_map && !map) {
298 0 : ns_id_external = ns_map->ns_id_external;
299 0 : RB_REMOVE(ns_map_nsid_head, &ns_map_nsid_list, ns_map);
300 0 : return ns_id_external;
301 : }
302 1 : if (ns_map)
303 0 : return ns_map->ns_id_external;
304 1 : ns_map = XCALLOC(MTYPE_NS, sizeof(struct ns_map_nsid));
305 : /* increase vrf_id
306 : * default vrf is the first one : 0
307 : */
308 1 : ns_map->ns_id_external = ns_id_external_numbering++;
309 1 : ns_map->ns_id = ns_id;
310 1 : RB_INSERT(ns_map_nsid_head, &ns_map_nsid_list, ns_map);
311 1 : return ns_map->ns_id_external;
312 : }
313 :
314 0 : struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id)
315 : {
316 0 : return ns_get_created_internal(ns, name, ns_id);
317 : }
318 :
319 0 : int ns_have_netns(void)
320 : {
321 0 : return have_netns();
322 : }
323 :
324 : /* Delete a NS. This is called in ns_terminate(). */
325 1 : void ns_delete(struct ns *ns)
326 : {
327 1 : if (ns_debug)
328 0 : zlog_info("NS %u is to be deleted.", ns->ns_id);
329 :
330 1 : ns_disable(ns);
331 :
332 1 : if (ns_master.ns_delete_hook)
333 0 : (*ns_master.ns_delete_hook)(ns);
334 :
335 : /*
336 : * I'm not entirely sure if the vrf->iflist
337 : * needs to be moved into here or not.
338 : */
339 : // if_terminate (&ns->iflist);
340 :
341 1 : RB_REMOVE(ns_head, &ns_tree, ns);
342 1 : XFREE(MTYPE_NS_NAME, ns->name);
343 :
344 1 : XFREE(MTYPE_NS, ns);
345 1 : }
346 :
347 : /* Look up the data pointer of the specified VRF. */
348 0 : void *ns_info_lookup(ns_id_t ns_id)
349 : {
350 0 : struct ns *ns = ns_lookup_internal(ns_id);
351 :
352 0 : return ns ? ns->info : NULL;
353 : }
354 :
355 : /* Look up a NS by name */
356 0 : struct ns *ns_lookup_name(const char *name)
357 : {
358 0 : return ns_lookup_name_internal(name);
359 : }
360 :
361 1 : int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *))
362 : {
363 1 : return ns_enable_internal(ns, func);
364 : }
365 :
366 1 : void ns_disable(struct ns *ns)
367 : {
368 1 : ns_disable_internal(ns);
369 1 : }
370 :
371 10 : struct ns *ns_lookup(ns_id_t ns_id)
372 : {
373 10 : return ns_lookup_internal(ns_id);
374 : }
375 :
376 2 : void ns_walk_func(int (*func)(struct ns *,
377 : void *param_in,
378 : void **param_out),
379 : void *param_in,
380 : void **param_out)
381 : {
382 2 : struct ns *ns = NULL;
383 2 : int ret;
384 :
385 6 : RB_FOREACH (ns, ns_head, &ns_tree) {
386 2 : ret = func(ns, param_in, param_out);
387 2 : if (ret == NS_WALK_STOP)
388 : return;
389 : }
390 : }
391 :
392 0 : const char *ns_get_name(struct ns *ns)
393 : {
394 0 : if (!ns)
395 : return NULL;
396 0 : return ns->name;
397 : }
398 :
399 : /* Add a NS hook. Please add hooks before calling ns_init(). */
400 0 : void ns_add_hook(int type, int (*func)(struct ns *))
401 : {
402 0 : switch (type) {
403 0 : case NS_NEW_HOOK:
404 0 : ns_master.ns_new_hook = func;
405 0 : break;
406 0 : case NS_DELETE_HOOK:
407 0 : ns_master.ns_delete_hook = func;
408 0 : break;
409 0 : case NS_ENABLE_HOOK:
410 0 : ns_master.ns_enable_hook = func;
411 0 : break;
412 0 : case NS_DISABLE_HOOK:
413 0 : ns_master.ns_disable_hook = func;
414 0 : break;
415 : default:
416 : break;
417 : }
418 0 : }
419 :
420 : /*
421 : * NS realization with NETNS
422 : */
423 :
424 0 : char *ns_netns_pathname(struct vty *vty, const char *name)
425 : {
426 0 : static char pathname[PATH_MAX];
427 0 : char *result;
428 0 : char *check_base;
429 :
430 0 : if (name[0] == '/') /* absolute pathname */
431 0 : result = realpath(name, pathname);
432 : else {
433 : /* relevant pathname */
434 0 : char tmp_name[PATH_MAX];
435 :
436 0 : snprintf(tmp_name, sizeof(tmp_name), "%s/%s", NS_RUN_DIR, name);
437 0 : result = realpath(tmp_name, pathname);
438 : }
439 :
440 0 : if (!result) {
441 0 : if (vty)
442 0 : vty_out(vty, "Invalid pathname for %s: %s\n",
443 : pathname,
444 0 : safe_strerror(errno));
445 : else
446 0 : flog_warn(EC_LIB_LINUX_NS,
447 : "Invalid pathname for %s: %s", pathname,
448 : safe_strerror(errno));
449 0 : return NULL;
450 : }
451 0 : check_base = basename(pathname);
452 0 : if (check_base != NULL && strlen(check_base) + 1 > NS_NAMSIZ) {
453 0 : if (vty)
454 0 : vty_out(vty, "NS name (%s) invalid: too long (>%d)\n",
455 : check_base, NS_NAMSIZ - 1);
456 : else
457 0 : flog_warn(EC_LIB_LINUX_NS,
458 : "NS name (%s) invalid: too long (>%d)",
459 : check_base, NS_NAMSIZ - 1);
460 0 : return NULL;
461 : }
462 : return pathname;
463 : }
464 :
465 4 : void ns_init(void)
466 : {
467 4 : static int ns_initialised;
468 :
469 4 : ns_debug = 0;
470 : /* silently return as initialisation done */
471 4 : if (ns_initialised == 1)
472 : return;
473 3 : errno = 0;
474 3 : if (have_netns())
475 3 : ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
476 : else {
477 0 : ns_default_ns_fd = -1;
478 0 : default_ns = NULL;
479 : }
480 3 : ns_current_ns_fd = -1;
481 3 : ns_initialised = 1;
482 : }
483 :
484 : /* Initialize NS module. */
485 1 : void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns)
486 : {
487 1 : int fd;
488 :
489 1 : ns_init();
490 1 : default_ns = ns_get_created_internal(NULL, NULL, default_ns_id);
491 1 : if (!default_ns) {
492 0 : flog_err(EC_LIB_NS, "%s: failed to create the default NS!",
493 : __func__);
494 0 : exit(1);
495 : }
496 1 : if (have_netns()) {
497 1 : fd = open(NS_DEFAULT_NAME, O_RDONLY);
498 1 : default_ns->fd = fd;
499 : }
500 1 : default_ns->internal_ns_id = internal_ns;
501 :
502 : /* Set the default NS name. */
503 1 : default_ns->name = XSTRDUP(MTYPE_NS_NAME, NS_DEFAULT_NAME);
504 1 : if (ns_debug)
505 0 : zlog_info("%s: default NSID is %u", __func__,
506 : default_ns->ns_id);
507 :
508 : /* Enable the default NS. */
509 1 : if (!ns_enable(default_ns, NULL)) {
510 0 : flog_err(EC_LIB_NS, "%s: failed to enable the default NS!",
511 : __func__);
512 0 : exit(1);
513 : }
514 1 : }
515 :
516 : /* Terminate NS module. */
517 1 : void ns_terminate(void)
518 : {
519 1 : struct ns *ns;
520 :
521 2 : while (!RB_EMPTY(ns_head, &ns_tree)) {
522 1 : ns = RB_ROOT(ns_head, &ns_tree);
523 :
524 1 : ns_delete(ns);
525 : }
526 1 : }
527 :
528 0 : int ns_switch_to_netns(const char *name)
529 : {
530 0 : int ret;
531 0 : int fd;
532 :
533 0 : if (name == NULL)
534 : return -1;
535 0 : if (ns_default_ns_fd == -1)
536 : return -1;
537 0 : fd = open(name, O_RDONLY);
538 0 : if (fd == -1) {
539 0 : errno = EINVAL;
540 0 : return -1;
541 : }
542 0 : ret = setns(fd, CLONE_NEWNET);
543 0 : ns_current_ns_fd = fd;
544 0 : close(fd);
545 0 : return ret;
546 : }
547 :
548 : /* returns 1 if switch() was not called before
549 : * return status of setns() otherwise
550 : */
551 6 : int ns_switchback_to_initial(void)
552 : {
553 6 : if (ns_current_ns_fd != -1 && ns_default_ns_fd != -1) {
554 0 : int ret;
555 :
556 0 : ret = setns(ns_default_ns_fd, CLONE_NEWNET);
557 0 : ns_current_ns_fd = -1;
558 0 : return ret;
559 : }
560 : /* silently ignore if setns() is not called */
561 : return 1;
562 : }
563 :
564 : /* Create a socket for the NS. */
565 5 : int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
566 : {
567 5 : struct ns *ns = ns_lookup(ns_id);
568 5 : int ret;
569 :
570 5 : if (!ns || !ns_is_enabled(ns)) {
571 0 : errno = EINVAL;
572 0 : return -1;
573 : }
574 5 : if (have_netns()) {
575 5 : ret = (ns_id != NS_DEFAULT) ? setns(ns->fd, CLONE_NEWNET) : 0;
576 0 : if (ret >= 0) {
577 5 : ret = socket(domain, type, protocol);
578 5 : if (ns_id != NS_DEFAULT) {
579 0 : setns(ns_lookup(NS_DEFAULT)->fd, CLONE_NEWNET);
580 0 : ns_current_ns_fd = ns_id;
581 : }
582 : }
583 : } else
584 0 : ret = socket(domain, type, protocol);
585 :
586 : return ret;
587 : }
588 :
589 : /* if relative link_nsid matches default netns,
590 : * then return default absolute netns value
591 : * otherwise, return NS_UNKNOWN
592 : */
593 4 : ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid)
594 : {
595 4 : struct ns *ns;
596 :
597 4 : ns = ns_lookup(ns_id_reference);
598 4 : if (!ns)
599 : return NS_UNKNOWN;
600 :
601 4 : if (ns->relative_default_ns != link_nsid)
602 : return NS_UNKNOWN;
603 :
604 4 : ns = ns_get_default();
605 4 : assert(ns);
606 4 : return ns->ns_id;
607 : }
608 :
609 5 : struct ns *ns_get_default(void)
610 : {
611 5 : return default_ns;
612 : }
|