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