3 * Copyright (C) 2014 6WIND S.A.
5 * This file is part of GNU Zebra.
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.
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.
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
41 #include "lib_errors.h"
43 DEFINE_MTYPE_STATIC(LIB
, NS
, "NetNS Context");
44 DEFINE_MTYPE_STATIC(LIB
, NS_NAME
, "NetNS Name");
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
);
49 RB_GENERATE(ns_head
, ns
, entry
, ns_compare
)
51 static struct ns_head ns_tree
= RB_INITIALIZER(&ns_tree
);
53 static struct ns
*default_ns
;
54 static int ns_current_ns_fd
;
55 static int ns_default_ns_fd
;
60 RB_ENTRY(ns_map_nsid
) id_entry
;
61 ns_id_t ns_id_external
;
65 static inline int ns_map_compare(const struct ns_map_nsid
*a
,
66 const struct ns_map_nsid
*b
)
68 return (a
->ns_id
- b
->ns_id
);
71 RB_HEAD(ns_map_nsid_head
, ns_map_nsid
);
72 RB_PROTOTYPE(ns_map_nsid_head
, ns_map_nsid
, id_entry
, ns_map_compare
);
73 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
);
77 static ns_id_t ns_id_external_numbering
;
81 #define CLONE_NEWNET 0x40000000
82 /* New network namespace (lo, device, names sockets, etc) */
86 static inline int setns(int fd
, int nstype
)
89 return syscall(__NR_setns
, fd
, nstype
);
95 #endif /* !HAVE_SETNS */
98 static int have_netns_enabled
= -1;
99 #endif /* HAVE_NETNS */
101 static int have_netns(void)
104 if (have_netns_enabled
< 0) {
105 int fd
= open(NS_DEFAULT_NAME
, O_RDONLY
);
108 have_netns_enabled
= 0;
110 have_netns_enabled
= 1;
114 return have_netns_enabled
;
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
);
130 static int ns_is_enabled(struct ns
*ns
);
132 static inline int ns_compare(const struct ns
*a
, const struct ns
*b
)
134 return (a
->ns_id
- b
->ns_id
);
137 /* Look up a NS by identifier. */
138 static struct ns
*ns_lookup_internal(ns_id_t ns_id
)
143 return RB_FIND(ns_head
, &ns_tree
, &ns
);
146 /* Look up a NS by name */
147 static struct ns
*ns_lookup_name_internal(const char *name
)
149 struct ns
*ns
= NULL
;
151 RB_FOREACH (ns
, ns_head
, &ns_tree
) {
152 if (ns
->name
!= NULL
) {
153 if (strcmp(name
, ns
->name
) == 0)
160 static struct ns
*ns_get_created_internal(struct ns
*ns
, char *name
,
165 * Initialize interfaces.
167 if (!ns
&& !name
&& ns_id
!= NS_UNKNOWN
)
168 ns
= ns_lookup_internal(ns_id
);
170 ns
= ns_lookup_name_internal(name
);
172 ns
= XCALLOC(MTYPE_NS
, sizeof(struct ns
));
175 ns
->name
= XSTRDUP(MTYPE_NS_NAME
, name
);
177 RB_INSERT(ns_head
, &ns_tree
, ns
);
180 if (ns_id
!= ns
->ns_id
) {
181 RB_REMOVE(ns_head
, &ns_tree
, ns
);
183 RB_INSERT(ns_head
, &ns_tree
, ns
);
188 if (ns
->ns_id
!= NS_UNKNOWN
)
189 zlog_info("NS %u is created.", ns
->ns_id
);
191 zlog_info("NS %s is created.", ns
->name
);
193 if (ns_master
.ns_new_hook
)
194 (*ns_master
.ns_new_hook
)(ns
);
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.
203 * RETURN: 1 - enabled successfully; otherwise, 0.
205 static int ns_enable_internal(struct ns
*ns
, void (*func
)(ns_id_t
, void *))
207 if (!ns_is_enabled(ns
)) {
209 ns
->fd
= open(ns
->name
, O_RDONLY
);
212 /* Remember ns_enable_hook has been called */
216 if (!ns_is_enabled(ns
)) {
217 flog_err_sys(EC_LIB_SYSTEM_CALL
,
218 "Can not enable NS %u: %s!", ns
->ns_id
,
219 safe_strerror(errno
));
223 /* Non default NS. leave */
224 if (ns
->ns_id
== NS_UNKNOWN
) {
226 "Can not enable NS %s %u: Invalid NSID",
227 ns
->name
, ns
->ns_id
);
231 func(ns
->ns_id
, (void *)ns
->vrf_ctxt
);
234 zlog_info("NS %u is associated with NETNS %s.",
235 ns
->ns_id
, ns
->name
);
236 zlog_info("NS %u is enabled.", ns
->ns_id
);
238 /* zebra first receives NS enable event,
239 * then VRF enable event
241 if (ns_master
.ns_enable_hook
)
242 (*ns_master
.ns_enable_hook
)(ns
);
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.
253 static int ns_is_enabled(struct ns
*ns
)
256 return ns
&& ns
->fd
>= 0;
258 return ns
&& ns
->fd
== -2 && ns
->ns_id
== NS_DEFAULT
;
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.
266 static void ns_disable_internal(struct ns
*ns
)
268 if (ns_is_enabled(ns
)) {
270 zlog_info("NS %u is to be disabled.", ns
->ns_id
);
272 if (ns_master
.ns_disable_hook
)
273 (*ns_master
.ns_disable_hook
)(ns
);
282 /* VRF list existence check by name. */
283 static struct ns_map_nsid
*ns_map_nsid_lookup_by_nsid(ns_id_t ns_id
)
285 struct ns_map_nsid ns_map
;
287 ns_map
.ns_id
= ns_id
;
288 return RB_FIND(ns_map_nsid_head
, &ns_map_nsid_list
, &ns_map
);
291 ns_id_t
ns_map_nsid_with_external(ns_id_t ns_id
, bool map
)
293 struct ns_map_nsid
*ns_map
;
294 vrf_id_t ns_id_external
;
296 ns_map
= ns_map_nsid_lookup_by_nsid(ns_id
);
297 if (ns_map
&& !map
) {
298 ns_id_external
= ns_map
->ns_id_external
;
299 RB_REMOVE(ns_map_nsid_head
, &ns_map_nsid_list
, ns_map
);
300 return ns_id_external
;
303 return ns_map
->ns_id_external
;
304 ns_map
= XCALLOC(MTYPE_NS
, sizeof(struct ns_map_nsid
));
306 * default vrf is the first one : 0
308 ns_map
->ns_id_external
= ns_id_external_numbering
++;
309 ns_map
->ns_id
= ns_id
;
310 RB_INSERT(ns_map_nsid_head
, &ns_map_nsid_list
, ns_map
);
311 return ns_map
->ns_id_external
;
314 struct ns
*ns_get_created(struct ns
*ns
, char *name
, ns_id_t ns_id
)
316 return ns_get_created_internal(ns
, name
, ns_id
);
319 int ns_have_netns(void)
324 /* Delete a NS. This is called in ns_terminate(). */
325 void ns_delete(struct ns
*ns
)
328 zlog_info("NS %u is to be deleted.", ns
->ns_id
);
332 if (ns_master
.ns_delete_hook
)
333 (*ns_master
.ns_delete_hook
)(ns
);
336 * I'm not entirely sure if the vrf->iflist
337 * needs to be moved into here or not.
339 // if_terminate (&ns->iflist);
341 RB_REMOVE(ns_head
, &ns_tree
, ns
);
342 XFREE(MTYPE_NS_NAME
, ns
->name
);
347 /* Look up the data pointer of the specified VRF. */
348 void *ns_info_lookup(ns_id_t ns_id
)
350 struct ns
*ns
= ns_lookup_internal(ns_id
);
352 return ns
? ns
->info
: NULL
;
355 /* Look up a NS by name */
356 struct ns
*ns_lookup_name(const char *name
)
358 return ns_lookup_name_internal(name
);
361 int ns_enable(struct ns
*ns
, void (*func
)(ns_id_t
, void *))
363 return ns_enable_internal(ns
, func
);
366 void ns_disable(struct ns
*ns
)
368 ns_disable_internal(ns
);
371 struct ns
*ns_lookup(ns_id_t ns_id
)
373 return ns_lookup_internal(ns_id
);
376 void ns_walk_func(int (*func
)(struct ns
*,
382 struct ns
*ns
= NULL
;
385 RB_FOREACH (ns
, ns_head
, &ns_tree
) {
386 ret
= func(ns
, param_in
, param_out
);
387 if (ret
== NS_WALK_STOP
)
392 const char *ns_get_name(struct ns
*ns
)
399 /* Add a NS hook. Please add hooks before calling ns_init(). */
400 void ns_add_hook(int type
, int (*func
)(struct ns
*))
404 ns_master
.ns_new_hook
= func
;
407 ns_master
.ns_delete_hook
= func
;
410 ns_master
.ns_enable_hook
= func
;
412 case NS_DISABLE_HOOK
:
413 ns_master
.ns_disable_hook
= func
;
421 * NS realization with NETNS
424 char *ns_netns_pathname(struct vty
*vty
, const char *name
)
426 static char pathname
[PATH_MAX
];
430 if (name
[0] == '/') /* absolute pathname */
431 result
= realpath(name
, pathname
);
433 /* relevant pathname */
434 char tmp_name
[PATH_MAX
];
436 snprintf(tmp_name
, sizeof(tmp_name
), "%s/%s", NS_RUN_DIR
, name
);
437 result
= realpath(tmp_name
, pathname
);
442 vty_out(vty
, "Invalid pathname for %s: %s\n",
444 safe_strerror(errno
));
446 flog_warn(EC_LIB_LINUX_NS
,
447 "Invalid pathname for %s: %s", pathname
,
448 safe_strerror(errno
));
451 check_base
= basename(pathname
);
452 if (check_base
!= NULL
&& strlen(check_base
) + 1 > NS_NAMSIZ
) {
454 vty_out(vty
, "NS name (%s) invalid: too long (>%d)\n",
455 check_base
, NS_NAMSIZ
- 1);
457 flog_warn(EC_LIB_LINUX_NS
,
458 "NS name (%s) invalid: too long (>%d)",
459 check_base
, NS_NAMSIZ
- 1);
467 static int ns_initialised
;
470 /* silently return as initialisation done */
471 if (ns_initialised
== 1)
475 ns_default_ns_fd
= open(NS_DEFAULT_NAME
, O_RDONLY
);
477 ns_default_ns_fd
= -1;
480 ns_current_ns_fd
= -1;
484 /* Initialize NS module. */
485 void ns_init_management(ns_id_t default_ns_id
, ns_id_t internal_ns
)
490 default_ns
= ns_get_created_internal(NULL
, NULL
, default_ns_id
);
492 flog_err(EC_LIB_NS
, "%s: failed to create the default NS!",
497 fd
= open(NS_DEFAULT_NAME
, O_RDONLY
);
500 default_ns
->internal_ns_id
= internal_ns
;
502 /* Set the default NS name. */
503 default_ns
->name
= XSTRDUP(MTYPE_NS_NAME
, NS_DEFAULT_NAME
);
505 zlog_info("%s: default NSID is %u", __func__
,
508 /* Enable the default NS. */
509 if (!ns_enable(default_ns
, NULL
)) {
510 flog_err(EC_LIB_NS
, "%s: failed to enable the default NS!",
516 /* Terminate NS module. */
517 void ns_terminate(void)
521 while (!RB_EMPTY(ns_head
, &ns_tree
)) {
522 ns
= RB_ROOT(ns_head
, &ns_tree
);
528 int ns_switch_to_netns(const char *name
)
535 if (ns_default_ns_fd
== -1)
537 fd
= open(name
, O_RDONLY
);
542 ret
= setns(fd
, CLONE_NEWNET
);
543 ns_current_ns_fd
= fd
;
548 /* returns 1 if switch() was not called before
549 * return status of setns() otherwise
551 int ns_switchback_to_initial(void)
553 if (ns_current_ns_fd
!= -1 && ns_default_ns_fd
!= -1) {
556 ret
= setns(ns_default_ns_fd
, CLONE_NEWNET
);
557 ns_current_ns_fd
= -1;
560 /* silently ignore if setns() is not called */
564 /* Create a socket for the NS. */
565 int ns_socket(int domain
, int type
, int protocol
, ns_id_t ns_id
)
567 struct ns
*ns
= ns_lookup(ns_id
);
570 if (!ns
|| !ns_is_enabled(ns
)) {
575 ret
= (ns_id
!= NS_DEFAULT
) ? setns(ns
->fd
, CLONE_NEWNET
) : 0;
577 ret
= socket(domain
, type
, protocol
);
578 if (ns_id
!= NS_DEFAULT
) {
579 setns(ns_lookup(NS_DEFAULT
)->fd
, CLONE_NEWNET
);
580 ns_current_ns_fd
= ns_id
;
584 ret
= socket(domain
, type
, protocol
);
589 /* if relative link_nsid matches default netns,
590 * then return default absolute netns value
591 * otherwise, return NS_UNKNOWN
593 ns_id_t
ns_id_get_absolute(ns_id_t ns_id_reference
, ns_id_t link_nsid
)
597 ns
= ns_lookup(ns_id_reference
);
601 if (ns
->relative_default_ns
!= link_nsid
)
604 ns
= ns_get_default();
609 struct ns
*ns_get_default(void)