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