]>
git.proxmox.com Git - mirror_frr.git/blob - lib/netns_linux.c
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
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 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 #define CLONE_NEWNET 0x40000000
61 /* New network namespace (lo, device, names sockets, etc) */
65 static inline int setns(int fd
, int nstype
)
68 return syscall(__NR_setns
, fd
, nstype
);
74 #endif /* !HAVE_SETNS */
77 static int have_netns_enabled
= -1;
78 #endif /* HAVE_NETNS */
80 /* default NS ID value used when VRF backend is not NETNS */
81 #define NS_DEFAULT_INTERNAL 0
83 static int have_netns(void)
86 if (have_netns_enabled
< 0) {
87 int fd
= open(NS_DEFAULT_NAME
, O_RDONLY
);
90 have_netns_enabled
= 0;
92 have_netns_enabled
= 1;
96 return have_netns_enabled
;
102 /* Holding NS hooks */
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
);
112 static int ns_is_enabled(struct ns
*ns
);
114 static inline int ns_compare(const struct ns
*a
, const struct ns
*b
)
116 return (a
->ns_id
- b
->ns_id
);
119 /* Look up a NS by identifier. */
120 static struct ns
*ns_lookup_internal(ns_id_t ns_id
)
125 return RB_FIND(ns_head
, &ns_tree
, &ns
);
128 /* Look up a NS by name */
129 static struct ns
*ns_lookup_name_internal(const char *name
)
131 struct ns
*ns
= NULL
;
133 RB_FOREACH (ns
, ns_head
, &ns_tree
) {
134 if (ns
->name
!= NULL
) {
135 if (strcmp(name
, ns
->name
) == 0)
142 static struct ns
*ns_get_created_internal(struct ns
*ns
, char *name
,
147 * Initialize interfaces.
149 if (!ns
&& !name
&& ns_id
!= NS_UNKNOWN
)
150 ns
= ns_lookup_internal(ns_id
);
152 ns
= ns_lookup_name_internal(name
);
154 ns
= XCALLOC(MTYPE_NS
, sizeof(struct ns
));
157 ns
->name
= XSTRDUP(MTYPE_NS_NAME
, name
);
159 RB_INSERT(ns_head
, &ns_tree
, ns
);
162 if (ns_id
!= ns
->ns_id
) {
163 RB_REMOVE(ns_head
, &ns_tree
, ns
);
165 RB_INSERT(ns_head
, &ns_tree
, ns
);
170 if (ns
->ns_id
!= NS_UNKNOWN
)
171 zlog_info("NS %u is created.", ns
->ns_id
);
173 zlog_info("NS %s is created.", ns
->name
);
175 if (ns_master
.ns_new_hook
)
176 (*ns_master
.ns_new_hook
) (ns
);
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.
185 * RETURN: 1 - enabled successfully; otherwise, 0.
187 static int ns_enable_internal(struct ns
*ns
, void (*func
)(ns_id_t
, void *))
189 if (!ns_is_enabled(ns
)) {
191 ns
->fd
= open(ns
->name
, O_RDONLY
);
194 /* Remember ns_enable_hook has been called */
198 if (!ns_is_enabled(ns
)) {
199 zlog_err("Can not enable NS %u: %s!", ns
->ns_id
,
200 safe_strerror(errno
));
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
);
211 func(ns
->ns_id
, (void *)ns
->vrf_ctxt
);
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
);
218 /* zebra first receives NS enable event,
219 * then VRF enable event
221 if (ns_master
.ns_enable_hook
)
222 (*ns_master
.ns_enable_hook
)(ns
);
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.
233 static int ns_is_enabled(struct ns
*ns
)
236 return ns
&& ns
->fd
>= 0;
238 return ns
&& ns
->fd
== -2 && ns
->ns_id
== NS_DEFAULT
;
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.
246 static void ns_disable_internal(struct ns
*ns
)
248 if (ns_is_enabled(ns
)) {
250 zlog_info("NS %u is to be disabled.",
253 if (ns_master
.ns_disable_hook
)
254 (*ns_master
.ns_disable_hook
)(ns
);
263 struct ns
*ns_get_created(struct ns
*ns
, char *name
, ns_id_t ns_id
)
265 return ns_get_created_internal(ns
, name
, ns_id
);
268 int ns_have_netns(void)
273 /* Delete a NS. This is called in ns_terminate(). */
274 void ns_delete(struct ns
*ns
)
277 zlog_info("NS %u is to be deleted.", ns
->ns_id
);
281 if (ns_master
.ns_delete_hook
)
282 (*ns_master
.ns_delete_hook
)(ns
);
285 * I'm not entirely sure if the vrf->iflist
286 * needs to be moved into here or not.
288 // if_terminate (&ns->iflist);
290 RB_REMOVE(ns_head
, &ns_tree
, ns
);
292 XFREE(MTYPE_NS_NAME
, ns
->name
);
297 /* Look up the data pointer of the specified VRF. */
299 ns_info_lookup(ns_id_t ns_id
)
301 struct ns
*ns
= ns_lookup_internal(ns_id
);
303 return ns
? ns
->info
: NULL
;
306 /* Look up a NS by name */
307 struct ns
*ns_lookup_name(const char *name
)
309 return ns_lookup_name_internal(name
);
312 int ns_enable(struct ns
*ns
, void (*func
)(ns_id_t
, void *))
314 return ns_enable_internal(ns
, func
);
317 void ns_disable(struct ns
*ns
)
319 return ns_disable_internal(ns
);
322 struct ns
*ns_lookup(ns_id_t ns_id
)
324 return ns_lookup_internal(ns_id
);
327 void ns_walk_func(int (*func
)(struct ns
*))
329 struct ns
*ns
= NULL
;
331 RB_FOREACH (ns
, ns_head
, &ns_tree
)
335 const char *ns_get_name(struct ns
*ns
)
342 /* Add a NS hook. Please add hooks before calling ns_init(). */
343 void ns_add_hook(int type
, int (*func
)(struct ns
*))
347 ns_master
.ns_new_hook
= func
;
350 ns_master
.ns_delete_hook
= func
;
353 ns_master
.ns_enable_hook
= func
;
355 case NS_DISABLE_HOOK
:
356 ns_master
.ns_disable_hook
= func
;
364 * NS realization with NETNS
367 char *ns_netns_pathname(struct vty
*vty
, const char *name
)
369 static char pathname
[PATH_MAX
];
373 if (name
[0] == '/') /* absolute pathname */
374 result
= realpath(name
, pathname
);
376 /* relevant pathname */
377 char tmp_name
[PATH_MAX
];
379 snprintf(tmp_name
, PATH_MAX
, "%s/%s", NS_RUN_DIR
, name
);
380 result
= realpath(tmp_name
, pathname
);
385 vty_out(vty
, "Invalid pathname: %s\n",
386 safe_strerror(errno
));
388 zlog_warn("Invalid pathname: %s",
389 safe_strerror(errno
));
392 check_base
= basename(pathname
);
393 if (check_base
!= NULL
&& strlen(check_base
) + 1 > NS_NAMSIZ
) {
395 vty_out(vty
, "NS name (%s) invalid: too long (>%d)\n",
396 check_base
, NS_NAMSIZ
-1);
398 zlog_warn("NS name (%s) invalid: too long (>%d)",
399 check_base
, NS_NAMSIZ
-1);
407 static int ns_initialised
;
410 /* silently return as initialisation done */
411 if (ns_initialised
== 1)
415 if (have_netns_enabled
< 0)
416 ns_default_ns_fd
= open(NS_DEFAULT_NAME
, O_RDONLY
);
418 ns_default_ns_fd
= -1;
420 ns_default_ns_fd
= -1;
422 #endif /* HAVE_NETNS */
423 if (ns_default_ns_fd
== -1)
424 zlog_err("NS initialisation failure (%s)",
425 safe_strerror(errno
));
426 ns_current_ns_fd
= -1;
430 /* Initialize NS module. */
431 void ns_init_management(ns_id_t default_ns_id
)
436 default_ns
= ns_get_created_internal(NULL
, NULL
, default_ns_id
);
438 zlog_err("%s: failed to create the default NS!",
443 fd
= open(NS_DEFAULT_NAME
, O_RDONLY
);
446 /* Set the default NS name. */
447 default_ns
->name
= XSTRDUP(MTYPE_NS_NAME
, NS_DEFAULT_NAME
);
449 zlog_info("%s: default NSID is %u",
450 __func__
, default_ns
->ns_id
);
452 /* Enable the default NS. */
453 if (!ns_enable(default_ns
, NULL
)) {
454 zlog_err("%s: failed to enable the default NS!",
460 /* Terminate NS module. */
461 void ns_terminate(void)
465 while (!RB_EMPTY(ns_head
, &ns_tree
)) {
466 ns
= RB_ROOT(ns_head
, &ns_tree
);
472 int ns_switch_to_netns(const char *name
)
479 if (ns_default_ns_fd
== -1)
481 fd
= open(name
, O_RDONLY
);
486 ret
= setns(fd
, CLONE_NEWNET
);
487 ns_current_ns_fd
= fd
;
492 /* returns 1 if switch() was not called before
493 * return status of setns() otherwise
495 int ns_switchback_to_initial(void)
497 if (ns_current_ns_fd
!= -1 && ns_default_ns_fd
!= -1) {
500 ret
= setns(ns_default_ns_fd
, CLONE_NEWNET
);
501 ns_current_ns_fd
= -1;
504 /* silently ignore if setns() is not called */
508 /* Create a socket for the NS. */
509 int ns_socket(int domain
, int type
, int protocol
, ns_id_t ns_id
)
511 struct ns
*ns
= ns_lookup(ns_id
);
514 if (!ns
|| !ns_is_enabled(ns
)) {
519 ret
= (ns_id
!= NS_DEFAULT
) ? setns(ns
->fd
, CLONE_NEWNET
) : 0;
521 ret
= socket(domain
, type
, protocol
);
522 if (ns_id
!= NS_DEFAULT
) {
523 setns(ns_lookup(NS_DEFAULT
)->fd
, CLONE_NEWNET
);
524 ns_current_ns_fd
= ns_id
;
528 ret
= socket(domain
, type
, protocol
);
533 ns_id_t
ns_get_default_id(void)
536 return default_ns
->ns_id
;