]> git.proxmox.com Git - mirror_frr.git/blob - lib/ns.c
ae0a24668eef566dbcf920581dca01486c186358
[mirror_frr.git] / lib / ns.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
18 * along with GNU Zebra; see the file COPYING. If not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23 #include <zebra.h>
24
25 #ifdef HAVE_NETNS
26 #undef _GNU_SOURCE
27 #define _GNU_SOURCE
28
29 #include <sched.h>
30 #endif
31
32 #include "if.h"
33 #include "ns.h"
34 #include "log.h"
35 #include "memory.h"
36
37 #include "command.h"
38 #include "vty.h"
39
40 DEFINE_MTYPE_STATIC(LIB, NS, "Logical-Router")
41 DEFINE_MTYPE_STATIC(LIB, NS_NAME, "Logical-Router Name")
42
43 static __inline int ns_compare (struct ns *, struct ns *);
44 static struct ns *ns_lookup (ns_id_t);
45
46 RB_GENERATE (ns_head, ns, entry, ns_compare)
47
48 struct ns_head ns_tree = RB_INITIALIZER (&ns_tree);
49
50 #ifndef CLONE_NEWNET
51 #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
52 #endif
53
54 #ifndef HAVE_SETNS
55 static inline int setns(int fd, int nstype)
56 {
57 #ifdef __NR_setns
58 return syscall(__NR_setns, fd, nstype);
59 #else
60 errno = ENOSYS;
61 return -1;
62 #endif
63 }
64 #endif /* HAVE_SETNS */
65
66 #ifdef HAVE_NETNS
67
68 #define NS_DEFAULT_NAME "/proc/self/ns/net"
69 static int have_netns_enabled = -1;
70
71 #else /* !HAVE_NETNS */
72
73 #define NS_DEFAULT_NAME "Default-logical-router"
74
75 #endif /* HAVE_NETNS */
76
77 static int have_netns(void)
78 {
79 #ifdef HAVE_NETNS
80 if (have_netns_enabled < 0)
81 {
82 int fd = open (NS_DEFAULT_NAME, O_RDONLY);
83
84 if (fd < 0)
85 have_netns_enabled = 0;
86 else
87 {
88 have_netns_enabled = 1;
89 close(fd);
90 }
91 }
92 return have_netns_enabled;
93 #else
94 return 0;
95 #endif
96 }
97
98 /* Holding NS hooks */
99 struct ns_master
100 {
101 int (*ns_new_hook) (ns_id_t, void **);
102 int (*ns_delete_hook) (ns_id_t, void **);
103 int (*ns_enable_hook) (ns_id_t, void **);
104 int (*ns_disable_hook) (ns_id_t, void **);
105 } ns_master = {0,};
106
107 static int ns_is_enabled (struct ns *ns);
108 static int ns_enable (struct ns *ns);
109 static void ns_disable (struct ns *ns);
110
111 static __inline int
112 ns_compare(struct ns *a, struct ns *b)
113 {
114 return (a->ns_id - b->ns_id);
115 }
116
117 /* Get a NS. If not found, create one. */
118 static struct ns *
119 ns_get (ns_id_t ns_id)
120 {
121 struct ns *ns;
122
123 ns = ns_lookup (ns_id);
124 if (ns)
125 return (ns);
126
127 ns = XCALLOC (MTYPE_NS, sizeof (struct ns));
128 ns->ns_id = ns_id;
129 ns->fd = -1;
130 RB_INSERT (ns_head, &ns_tree, ns);
131
132 /*
133 * Initialize interfaces.
134 *
135 * I'm not sure if this belongs here or in
136 * the vrf code.
137 */
138 // if_init (&ns->iflist);
139
140 zlog_info ("NS %u is created.", ns_id);
141
142 if (ns_master.ns_new_hook)
143 (*ns_master.ns_new_hook) (ns_id, &ns->info);
144
145 return ns;
146 }
147
148 /* Delete a NS. This is called in ns_terminate(). */
149 static void
150 ns_delete (struct ns *ns)
151 {
152 zlog_info ("NS %u is to be deleted.", ns->ns_id);
153
154 ns_disable (ns);
155
156 if (ns_master.ns_delete_hook)
157 (*ns_master.ns_delete_hook) (ns->ns_id, &ns->info);
158
159 /*
160 * I'm not entirely sure if the vrf->iflist
161 * needs to be moved into here or not.
162 */
163 //if_terminate (&ns->iflist);
164
165 RB_REMOVE (ns_head, &ns_tree, ns);
166 if (ns->name)
167 XFREE (MTYPE_NS_NAME, ns->name);
168
169 XFREE (MTYPE_NS, ns);
170 }
171
172 /* Look up a NS by identifier. */
173 static struct ns *
174 ns_lookup (ns_id_t ns_id)
175 {
176 struct ns ns;
177 ns.ns_id = ns_id;
178 return (RB_FIND (ns_head, &ns_tree, &ns));
179 }
180
181 /*
182 * Check whether the NS is enabled - that is, whether the NS
183 * is ready to allocate resources. Currently there's only one
184 * type of resource: socket.
185 */
186 static int
187 ns_is_enabled (struct ns *ns)
188 {
189 if (have_netns())
190 return ns && ns->fd >= 0;
191 else
192 return ns && ns->fd == -2 && ns->ns_id == NS_DEFAULT;
193 }
194
195 /*
196 * Enable a NS - that is, let the NS be ready to use.
197 * The NS_ENABLE_HOOK callback will be called to inform
198 * that they can allocate resources in this NS.
199 *
200 * RETURN: 1 - enabled successfully; otherwise, 0.
201 */
202 static int
203 ns_enable (struct ns *ns)
204 {
205
206 if (!ns_is_enabled (ns))
207 {
208 if (have_netns()) {
209 ns->fd = open (ns->name, O_RDONLY);
210 } else {
211 ns->fd = -2; /* Remember that ns_enable_hook has been called */
212 errno = -ENOTSUP;
213 }
214
215 if (!ns_is_enabled (ns))
216 {
217 zlog_err ("Can not enable NS %u: %s!",
218 ns->ns_id, safe_strerror (errno));
219 return 0;
220 }
221
222 if (have_netns())
223 zlog_info ("NS %u is associated with NETNS %s.",
224 ns->ns_id, ns->name);
225
226 zlog_info ("NS %u is enabled.", ns->ns_id);
227 if (ns_master.ns_enable_hook)
228 (*ns_master.ns_enable_hook) (ns->ns_id, &ns->info);
229 }
230
231 return 1;
232 }
233
234 /*
235 * Disable a NS - that is, let the NS be unusable.
236 * The NS_DELETE_HOOK callback will be called to inform
237 * that they must release the resources in the NS.
238 */
239 static void
240 ns_disable (struct ns *ns)
241 {
242 if (ns_is_enabled (ns))
243 {
244 zlog_info ("NS %u is to be disabled.", ns->ns_id);
245
246 if (ns_master.ns_disable_hook)
247 (*ns_master.ns_disable_hook) (ns->ns_id, &ns->info);
248
249 if (have_netns())
250 close (ns->fd);
251
252 ns->fd = -1;
253 }
254 }
255
256
257 /* Add a NS hook. Please add hooks before calling ns_init(). */
258 void
259 ns_add_hook (int type, int (*func)(ns_id_t, void **))
260 {
261 switch (type) {
262 case NS_NEW_HOOK:
263 ns_master.ns_new_hook = func;
264 break;
265 case NS_DELETE_HOOK:
266 ns_master.ns_delete_hook = func;
267 break;
268 case NS_ENABLE_HOOK:
269 ns_master.ns_enable_hook = func;
270 break;
271 case NS_DISABLE_HOOK:
272 ns_master.ns_disable_hook = func;
273 break;
274 default:
275 break;
276 }
277 }
278
279 /*
280 * NS realization with NETNS
281 */
282
283 static char *
284 ns_netns_pathname (struct vty *vty, const char *name)
285 {
286 static char pathname[PATH_MAX];
287 char *result;
288
289 if (name[0] == '/') /* absolute pathname */
290 result = realpath (name, pathname);
291 else /* relevant pathname */
292 {
293 char tmp_name[PATH_MAX];
294 snprintf (tmp_name, PATH_MAX, "%s/%s", NS_RUN_DIR, name);
295 result = realpath (tmp_name, pathname);
296 }
297
298 if (! result)
299 {
300 vty_out (vty, "Invalid pathname: %s%s", safe_strerror (errno),
301 VTY_NEWLINE);
302 return NULL;
303 }
304 return pathname;
305 }
306
307 DEFUN_NOSH (ns_netns,
308 ns_netns_cmd,
309 "logical-router (1-65535) ns NAME",
310 "Enable a logical-router\n"
311 "Specify the logical-router indentifier\n"
312 "The Name Space\n"
313 "The file name in " NS_RUN_DIR ", or a full pathname\n")
314 {
315 int idx_number = 1;
316 int idx_name = 3;
317 ns_id_t ns_id = NS_DEFAULT;
318 struct ns *ns = NULL;
319 char *pathname = ns_netns_pathname (vty, argv[idx_name]->arg);
320
321 if (!pathname)
322 return CMD_WARNING;
323
324 VTY_GET_INTEGER ("NS ID", ns_id, argv[idx_number]->arg);
325 ns = ns_get (ns_id);
326
327 if (ns->name && strcmp (ns->name, pathname) != 0)
328 {
329 vty_out (vty, "NS %u is already configured with NETNS %s%s",
330 ns->ns_id, ns->name, VTY_NEWLINE);
331 return CMD_WARNING;
332 }
333
334 if (!ns->name)
335 ns->name = XSTRDUP (MTYPE_NS_NAME, pathname);
336
337 if (!ns_enable (ns))
338 {
339 vty_out (vty, "Can not associate NS %u with NETNS %s%s",
340 ns->ns_id, ns->name, VTY_NEWLINE);
341 return CMD_WARNING;
342 }
343
344 return CMD_SUCCESS;
345 }
346
347 DEFUN (no_ns_netns,
348 no_ns_netns_cmd,
349 "no logical-router (1-65535) ns NAME",
350 NO_STR
351 "Enable a Logical-Router\n"
352 "Specify the Logical-Router identifier\n"
353 "The Name Space\n"
354 "The file name in " NS_RUN_DIR ", or a full pathname\n")
355 {
356 int idx_number = 2;
357 int idx_name = 4;
358 ns_id_t ns_id = NS_DEFAULT;
359 struct ns *ns = NULL;
360 char *pathname = ns_netns_pathname (vty, argv[idx_name]->arg);
361
362 if (!pathname)
363 return CMD_WARNING;
364
365 VTY_GET_INTEGER ("NS ID", ns_id, argv[idx_number]->arg);
366 ns = ns_lookup (ns_id);
367
368 if (!ns)
369 {
370 vty_out (vty, "NS %u is not found%s", ns_id, VTY_NEWLINE);
371 return CMD_SUCCESS;
372 }
373
374 if (ns->name && strcmp (ns->name, pathname) != 0)
375 {
376 vty_out (vty, "Incorrect NETNS file name%s", VTY_NEWLINE);
377 return CMD_WARNING;
378 }
379
380 ns_disable (ns);
381
382 if (ns->name)
383 {
384 XFREE (MTYPE_NS_NAME, ns->name);
385 ns->name = NULL;
386 }
387
388 return CMD_SUCCESS;
389 }
390
391 /* NS node. */
392 static struct cmd_node ns_node =
393 {
394 NS_NODE,
395 "", /* NS node has no interface. */
396 1
397 };
398
399 /* NS configuration write function. */
400 static int
401 ns_config_write (struct vty *vty)
402 {
403 struct ns *ns;
404 int write = 0;
405
406 RB_FOREACH (ns, ns_head, &ns_tree) {
407 if (ns->ns_id == NS_DEFAULT || ns->name == NULL)
408 continue;
409
410 vty_out (vty, "logical-router %u netns %s%s", ns->ns_id, ns->name,
411 VTY_NEWLINE);
412 write = 1;
413 }
414
415 return write;
416 }
417
418 /* Initialize NS module. */
419 void
420 ns_init (void)
421 {
422 struct ns *default_ns;
423
424 /* The default NS always exists. */
425 default_ns = ns_get (NS_DEFAULT);
426 if (!default_ns)
427 {
428 zlog_err ("ns_init: failed to create the default NS!");
429 exit (1);
430 }
431
432 /* Set the default NS name. */
433 default_ns->name = XSTRDUP (MTYPE_NS_NAME, NS_DEFAULT_NAME);
434
435 /* Enable the default NS. */
436 if (!ns_enable (default_ns))
437 {
438 zlog_err ("ns_init: failed to enable the default NS!");
439 exit (1);
440 }
441
442 if (have_netns())
443 {
444 /* Install NS commands. */
445 install_node (&ns_node, ns_config_write);
446 install_element (CONFIG_NODE, &ns_netns_cmd);
447 install_element (CONFIG_NODE, &no_ns_netns_cmd);
448 }
449 }
450
451 /* Terminate NS module. */
452 void
453 ns_terminate (void)
454 {
455 struct ns *ns;
456
457 while ((ns = RB_ROOT (&ns_tree)) != NULL)
458 ns_delete (ns);
459 }
460
461 /* Create a socket for the NS. */
462 int
463 ns_socket (int domain, int type, int protocol, ns_id_t ns_id)
464 {
465 struct ns *ns = ns_lookup (ns_id);
466 int ret = -1;
467
468 if (!ns_is_enabled (ns))
469 {
470 errno = ENOSYS;
471 return -1;
472 }
473
474 if (have_netns())
475 {
476 ret = (ns_id != NS_DEFAULT) ? setns (ns->fd, CLONE_NEWNET) : 0;
477 if (ret >= 0)
478 {
479 ret = socket (domain, type, protocol);
480 if (ns_id != NS_DEFAULT)
481 setns (ns_lookup (NS_DEFAULT)->fd, CLONE_NEWNET);
482 }
483 }
484 else
485 ret = socket (domain, type, protocol);
486
487 return ret;
488 }