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
39 DEFINE_MTYPE_STATIC(LIB
, NS
, "Logical-Router")
40 DEFINE_MTYPE_STATIC(LIB
, NS_NAME
, "Logical-Router Name")
42 static __inline
int ns_compare(const struct ns
*, const struct ns
*);
43 static struct ns
*ns_lookup(ns_id_t
);
45 RB_GENERATE(ns_head
, ns
, entry
, ns_compare
)
47 struct ns_head ns_tree
= RB_INITIALIZER(&ns_tree
);
50 #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
54 static inline int setns(int fd
, int nstype
)
57 return syscall(__NR_setns
, fd
, nstype
);
63 #endif /* HAVE_SETNS */
67 #define NS_DEFAULT_NAME "/proc/self/ns/net"
68 static int have_netns_enabled
= -1;
70 #else /* !HAVE_NETNS */
72 #define NS_DEFAULT_NAME "Default-logical-router"
74 #endif /* HAVE_NETNS */
76 static int have_netns(void)
79 if (have_netns_enabled
< 0) {
80 int fd
= open(NS_DEFAULT_NAME
, O_RDONLY
);
83 have_netns_enabled
= 0;
85 have_netns_enabled
= 1;
89 return have_netns_enabled
;
95 /* Holding NS hooks */
97 int (*ns_new_hook
)(ns_id_t
, void **);
98 int (*ns_delete_hook
)(ns_id_t
, void **);
99 int (*ns_enable_hook
)(ns_id_t
, void **);
100 int (*ns_disable_hook
)(ns_id_t
, void **);
105 static int ns_is_enabled(struct ns
*ns
);
106 static int ns_enable(struct ns
*ns
);
107 static void ns_disable(struct ns
*ns
);
109 static __inline
int ns_compare(const struct ns
*a
, const struct ns
*b
)
111 return (a
->ns_id
- b
->ns_id
);
114 /* Get a NS. If not found, create one. */
115 static struct ns
*ns_get(ns_id_t ns_id
)
119 ns
= ns_lookup(ns_id
);
123 ns
= XCALLOC(MTYPE_NS
, sizeof(struct ns
));
126 RB_INSERT(ns_head
, &ns_tree
, ns
);
129 * Initialize interfaces.
131 * I'm not sure if this belongs here or in
134 // if_init (&ns->iflist);
136 zlog_info("NS %u is created.", ns_id
);
138 if (ns_master
.ns_new_hook
)
139 (*ns_master
.ns_new_hook
)(ns_id
, &ns
->info
);
144 /* Delete a NS. This is called in ns_terminate(). */
145 static void ns_delete(struct ns
*ns
)
147 zlog_info("NS %u is to be deleted.", ns
->ns_id
);
151 if (ns_master
.ns_delete_hook
)
152 (*ns_master
.ns_delete_hook
)(ns
->ns_id
, &ns
->info
);
155 * I'm not entirely sure if the vrf->iflist
156 * needs to be moved into here or not.
158 // if_terminate (&ns->iflist);
160 RB_REMOVE(ns_head
, &ns_tree
, ns
);
162 XFREE(MTYPE_NS_NAME
, ns
->name
);
167 /* Look up a NS by identifier. */
168 static struct ns
*ns_lookup(ns_id_t ns_id
)
172 return (RB_FIND(ns_head
, &ns_tree
, &ns
));
176 * Check whether the NS is enabled - that is, whether the NS
177 * is ready to allocate resources. Currently there's only one
178 * type of resource: socket.
180 static int ns_is_enabled(struct ns
*ns
)
183 return ns
&& ns
->fd
>= 0;
185 return ns
&& ns
->fd
== -2 && ns
->ns_id
== NS_DEFAULT
;
189 * Enable a NS - that is, let the NS be ready to use.
190 * The NS_ENABLE_HOOK callback will be called to inform
191 * that they can allocate resources in this NS.
193 * RETURN: 1 - enabled successfully; otherwise, 0.
195 static int ns_enable(struct ns
*ns
)
198 if (!ns_is_enabled(ns
)) {
200 ns
->fd
= open(ns
->name
, O_RDONLY
);
202 ns
->fd
= -2; /* Remember that ns_enable_hook has been
207 if (!ns_is_enabled(ns
)) {
208 zlog_err("Can not enable NS %u: %s!", ns
->ns_id
,
209 safe_strerror(errno
));
214 zlog_info("NS %u is associated with NETNS %s.",
215 ns
->ns_id
, ns
->name
);
217 zlog_info("NS %u is enabled.", ns
->ns_id
);
218 if (ns_master
.ns_enable_hook
)
219 (*ns_master
.ns_enable_hook
)(ns
->ns_id
, &ns
->info
);
226 * Disable a NS - that is, let the NS be unusable.
227 * The NS_DELETE_HOOK callback will be called to inform
228 * that they must release the resources in the NS.
230 static void ns_disable(struct ns
*ns
)
232 if (ns_is_enabled(ns
)) {
233 zlog_info("NS %u is to be disabled.", ns
->ns_id
);
235 if (ns_master
.ns_disable_hook
)
236 (*ns_master
.ns_disable_hook
)(ns
->ns_id
, &ns
->info
);
246 /* Add a NS hook. Please add hooks before calling ns_init(). */
247 void ns_add_hook(int type
, int (*func
)(ns_id_t
, void **))
251 ns_master
.ns_new_hook
= func
;
254 ns_master
.ns_delete_hook
= func
;
257 ns_master
.ns_enable_hook
= func
;
259 case NS_DISABLE_HOOK
:
260 ns_master
.ns_disable_hook
= func
;
268 * NS realization with NETNS
271 static char *ns_netns_pathname(struct vty
*vty
, const char *name
)
273 static char pathname
[PATH_MAX
];
276 if (name
[0] == '/') /* absolute pathname */
277 result
= realpath(name
, pathname
);
278 else /* relevant pathname */
280 char tmp_name
[PATH_MAX
];
281 snprintf(tmp_name
, PATH_MAX
, "%s/%s", NS_RUN_DIR
, name
);
282 result
= realpath(tmp_name
, pathname
);
286 vty_out(vty
, "Invalid pathname: %s\n", safe_strerror(errno
));
292 DEFUN_NOSH (ns_netns
,
294 "logical-router (1-65535) ns NAME",
295 "Enable a logical-router\n"
296 "Specify the logical-router indentifier\n"
298 "The file name in " NS_RUN_DIR
", or a full pathname\n")
302 ns_id_t ns_id
= NS_DEFAULT
;
303 struct ns
*ns
= NULL
;
304 char *pathname
= ns_netns_pathname(vty
, argv
[idx_name
]->arg
);
307 return CMD_WARNING_CONFIG_FAILED
;
309 ns_id
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
312 if (ns
->name
&& strcmp(ns
->name
, pathname
) != 0) {
313 vty_out(vty
, "NS %u is already configured with NETNS %s\n",
314 ns
->ns_id
, ns
->name
);
315 return CMD_WARNING_CONFIG_FAILED
;
319 ns
->name
= XSTRDUP(MTYPE_NS_NAME
, pathname
);
321 if (!ns_enable(ns
)) {
322 vty_out(vty
, "Can not associate NS %u with NETNS %s\n",
323 ns
->ns_id
, ns
->name
);
324 return CMD_WARNING_CONFIG_FAILED
;
332 "no logical-router (1-65535) ns NAME",
334 "Enable a Logical-Router\n"
335 "Specify the Logical-Router identifier\n"
337 "The file name in " NS_RUN_DIR
", or a full pathname\n")
341 ns_id_t ns_id
= NS_DEFAULT
;
342 struct ns
*ns
= NULL
;
343 char *pathname
= ns_netns_pathname(vty
, argv
[idx_name
]->arg
);
346 return CMD_WARNING_CONFIG_FAILED
;
348 ns_id
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
349 ns
= ns_lookup(ns_id
);
352 vty_out(vty
, "NS %u is not found\n", ns_id
);
356 if (ns
->name
&& strcmp(ns
->name
, pathname
) != 0) {
357 vty_out(vty
, "Incorrect NETNS file name\n");
358 return CMD_WARNING_CONFIG_FAILED
;
364 XFREE(MTYPE_NS_NAME
, ns
->name
);
372 static struct cmd_node ns_node
= {NS_NODE
, "", /* NS node has no interface. */
375 /* NS configuration write function. */
376 static int ns_config_write(struct vty
*vty
)
381 RB_FOREACH(ns
, ns_head
, &ns_tree
)
383 if (ns
->ns_id
== NS_DEFAULT
|| ns
->name
== NULL
)
386 vty_out(vty
, "logical-router %u netns %s\n", ns
->ns_id
,
394 /* Initialize NS module. */
397 struct ns
*default_ns
;
399 /* The default NS always exists. */
400 default_ns
= ns_get(NS_DEFAULT
);
402 zlog_err("ns_init: failed to create the default NS!");
406 /* Set the default NS name. */
407 default_ns
->name
= XSTRDUP(MTYPE_NS_NAME
, NS_DEFAULT_NAME
);
409 /* Enable the default NS. */
410 if (!ns_enable(default_ns
)) {
411 zlog_err("ns_init: failed to enable the default NS!");
416 /* Install NS commands. */
417 install_node(&ns_node
, ns_config_write
);
418 install_element(CONFIG_NODE
, &ns_netns_cmd
);
419 install_element(CONFIG_NODE
, &no_ns_netns_cmd
);
423 /* Terminate NS module. */
424 void ns_terminate(void)
428 while ((ns
= RB_ROOT(ns_head
, &ns_tree
)) != NULL
)
432 /* Create a socket for the NS. */
433 int ns_socket(int domain
, int type
, int protocol
, ns_id_t ns_id
)
435 struct ns
*ns
= ns_lookup(ns_id
);
438 if (!ns_is_enabled(ns
)) {
444 ret
= (ns_id
!= NS_DEFAULT
) ? setns(ns
->fd
, CLONE_NEWNET
) : 0;
446 ret
= socket(domain
, type
, protocol
);
447 if (ns_id
!= NS_DEFAULT
)
448 setns(ns_lookup(NS_DEFAULT
)->fd
, CLONE_NEWNET
);
451 ret
= socket(domain
, type
, protocol
);