]>
git.proxmox.com Git - mirror_frr.git/blob - lib/ns.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
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.
40 DEFINE_MTYPE_STATIC(LIB
, NS
, "Logical-Router")
41 DEFINE_MTYPE_STATIC(LIB
, NS_NAME
, "Logical-Router Name")
43 static __inline
int ns_compare (struct ns
*, struct ns
*);
44 static struct ns
*ns_lookup (ns_id_t
);
46 RB_GENERATE (ns_head
, ns
, entry
, ns_compare
)
48 struct ns_head ns_tree
= RB_INITIALIZER (&ns_tree
);
51 #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
55 static inline int setns(int fd
, int nstype
)
58 return syscall(__NR_setns
, fd
, nstype
);
64 #endif /* HAVE_SETNS */
68 #define NS_DEFAULT_NAME "/proc/self/ns/net"
69 static int have_netns_enabled
= -1;
71 #else /* !HAVE_NETNS */
73 #define NS_DEFAULT_NAME "Default-logical-router"
75 #endif /* HAVE_NETNS */
77 static int have_netns(void)
80 if (have_netns_enabled
< 0)
82 int fd
= open (NS_DEFAULT_NAME
, O_RDONLY
);
85 have_netns_enabled
= 0;
88 have_netns_enabled
= 1;
92 return have_netns_enabled
;
98 /* Holding NS hooks */
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 **);
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
);
112 ns_compare(struct ns
*a
, struct ns
*b
)
114 return (a
->ns_id
- b
->ns_id
);
117 /* Get a NS. If not found, create one. */
119 ns_get (ns_id_t ns_id
)
123 ns
= ns_lookup (ns_id
);
127 ns
= XCALLOC (MTYPE_NS
, sizeof (struct ns
));
130 RB_INSERT (ns_head
, &ns_tree
, ns
);
133 * Initialize interfaces.
135 * I'm not sure if this belongs here or in
138 // if_init (&ns->iflist);
140 zlog_info ("NS %u is created.", ns_id
);
142 if (ns_master
.ns_new_hook
)
143 (*ns_master
.ns_new_hook
) (ns_id
, &ns
->info
);
148 /* Delete a NS. This is called in ns_terminate(). */
150 ns_delete (struct ns
*ns
)
152 zlog_info ("NS %u is to be deleted.", ns
->ns_id
);
156 if (ns_master
.ns_delete_hook
)
157 (*ns_master
.ns_delete_hook
) (ns
->ns_id
, &ns
->info
);
160 * I'm not entirely sure if the vrf->iflist
161 * needs to be moved into here or not.
163 //if_terminate (&ns->iflist);
165 RB_REMOVE (ns_head
, &ns_tree
, ns
);
167 XFREE (MTYPE_NS_NAME
, ns
->name
);
169 XFREE (MTYPE_NS
, ns
);
172 /* Look up a NS by identifier. */
174 ns_lookup (ns_id_t ns_id
)
178 return (RB_FIND (ns_head
, &ns_tree
, &ns
));
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.
187 ns_is_enabled (struct ns
*ns
)
190 return ns
&& ns
->fd
>= 0;
192 return ns
&& ns
->fd
== -2 && ns
->ns_id
== NS_DEFAULT
;
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.
200 * RETURN: 1 - enabled successfully; otherwise, 0.
203 ns_enable (struct ns
*ns
)
206 if (!ns_is_enabled (ns
))
209 ns
->fd
= open (ns
->name
, O_RDONLY
);
211 ns
->fd
= -2; /* Remember that ns_enable_hook has been called */
215 if (!ns_is_enabled (ns
))
217 zlog_err ("Can not enable NS %u: %s!",
218 ns
->ns_id
, safe_strerror (errno
));
223 zlog_info ("NS %u is associated with NETNS %s.",
224 ns
->ns_id
, ns
->name
);
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
);
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.
240 ns_disable (struct ns
*ns
)
242 if (ns_is_enabled (ns
))
244 zlog_info ("NS %u is to be disabled.", ns
->ns_id
);
246 if (ns_master
.ns_disable_hook
)
247 (*ns_master
.ns_disable_hook
) (ns
->ns_id
, &ns
->info
);
257 /* Add a NS hook. Please add hooks before calling ns_init(). */
259 ns_add_hook (int type
, int (*func
)(ns_id_t
, void **))
263 ns_master
.ns_new_hook
= func
;
266 ns_master
.ns_delete_hook
= func
;
269 ns_master
.ns_enable_hook
= func
;
271 case NS_DISABLE_HOOK
:
272 ns_master
.ns_disable_hook
= func
;
280 * NS realization with NETNS
284 ns_netns_pathname (struct vty
*vty
, const char *name
)
286 static char pathname
[PATH_MAX
];
289 if (name
[0] == '/') /* absolute pathname */
290 result
= realpath (name
, pathname
);
291 else /* relevant pathname */
293 char tmp_name
[PATH_MAX
];
294 snprintf (tmp_name
, PATH_MAX
, "%s/%s", NS_RUN_DIR
, name
);
295 result
= realpath (tmp_name
, pathname
);
300 vty_out (vty
, "Invalid pathname: %s%s", safe_strerror (errno
),
307 DEFUN_NOSH (ns_netns
,
309 "logical-router (1-65535) ns NAME",
310 "Enable a logical-router\n"
311 "Specify the logical-router indentifier\n"
313 "The file name in " NS_RUN_DIR
", or a full pathname\n")
317 ns_id_t ns_id
= NS_DEFAULT
;
318 struct ns
*ns
= NULL
;
319 char *pathname
= ns_netns_pathname (vty
, argv
[idx_name
]->arg
);
324 VTY_GET_INTEGER ("NS ID", ns_id
, argv
[idx_number
]->arg
);
327 if (ns
->name
&& strcmp (ns
->name
, pathname
) != 0)
329 vty_out (vty
, "NS %u is already configured with NETNS %s%s",
330 ns
->ns_id
, ns
->name
, VTY_NEWLINE
);
335 ns
->name
= XSTRDUP (MTYPE_NS_NAME
, pathname
);
339 vty_out (vty
, "Can not associate NS %u with NETNS %s%s",
340 ns
->ns_id
, ns
->name
, VTY_NEWLINE
);
349 "no logical-router (1-65535) ns NAME",
351 "Enable a Logical-Router\n"
352 "Specify the Logical-Router identifier\n"
354 "The file name in " NS_RUN_DIR
", or a full pathname\n")
358 ns_id_t ns_id
= NS_DEFAULT
;
359 struct ns
*ns
= NULL
;
360 char *pathname
= ns_netns_pathname (vty
, argv
[idx_name
]->arg
);
365 VTY_GET_INTEGER ("NS ID", ns_id
, argv
[idx_number
]->arg
);
366 ns
= ns_lookup (ns_id
);
370 vty_out (vty
, "NS %u is not found%s", ns_id
, VTY_NEWLINE
);
374 if (ns
->name
&& strcmp (ns
->name
, pathname
) != 0)
376 vty_out (vty
, "Incorrect NETNS file name%s", VTY_NEWLINE
);
384 XFREE (MTYPE_NS_NAME
, ns
->name
);
392 static struct cmd_node ns_node
=
395 "", /* NS node has no interface. */
399 /* NS configuration write function. */
401 ns_config_write (struct vty
*vty
)
406 RB_FOREACH (ns
, ns_head
, &ns_tree
) {
407 if (ns
->ns_id
== NS_DEFAULT
|| ns
->name
== NULL
)
410 vty_out (vty
, "logical-router %u netns %s%s", ns
->ns_id
, ns
->name
,
418 /* Initialize NS module. */
422 struct ns
*default_ns
;
424 /* The default NS always exists. */
425 default_ns
= ns_get (NS_DEFAULT
);
428 zlog_err ("ns_init: failed to create the default NS!");
432 /* Set the default NS name. */
433 default_ns
->name
= XSTRDUP (MTYPE_NS_NAME
, NS_DEFAULT_NAME
);
435 /* Enable the default NS. */
436 if (!ns_enable (default_ns
))
438 zlog_err ("ns_init: failed to enable the default NS!");
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
);
451 /* Terminate NS module. */
457 while ((ns
= RB_ROOT (&ns_tree
)) != NULL
)
461 /* Create a socket for the NS. */
463 ns_socket (int domain
, int type
, int protocol
, ns_id_t ns_id
)
465 struct ns
*ns
= ns_lookup (ns_id
);
468 if (!ns_is_enabled (ns
))
476 ret
= (ns_id
!= NS_DEFAULT
) ? setns (ns
->fd
, CLONE_NEWNET
) : 0;
479 ret
= socket (domain
, type
, protocol
);
480 if (ns_id
!= NS_DEFAULT
)
481 setns (ns_lookup (NS_DEFAULT
)->fd
, CLONE_NEWNET
);
485 ret
= socket (domain
, type
, protocol
);