struct ns_head ns_tree = RB_INITIALIZER(&ns_tree);
+static int ns_current_ns_fd;
+static int ns_default_ns_fd;
+
#ifndef CLONE_NEWNET
#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */
#endif
return CMD_SUCCESS;
}
+void ns_init(void)
+{
+#ifdef HAVE_NETNS
+ if (have_netns_enabled < 0) {
+ ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
+ return;
+ }
+#endif /* HAVE_NETNS */
+ ns_default_ns_fd = -1;
+}
+
/* Initialize NS module. */
void ns_init_zebra(void)
{
struct ns *default_ns;
+ ns_init();
/* The default NS always exists. */
default_ns = ns_get(NS_DEFAULT);
+ ns_current_ns_fd = -1;
if (!default_ns) {
zlog_err("ns_init: failed to create the default NS!");
exit(1);
}
}
+int ns_switch_to_netns(const char *name)
+{
+ int ret;
+ int fd;
+
+ if (name == NULL)
+ return -1;
+ fd = open(name, O_RDONLY);
+ if (fd == -1) {
+ errno = ENOSYS;
+ return -1;
+ }
+ ret = setns(fd, CLONE_NEWNET);
+ ns_current_ns_fd = fd;
+ close(fd);
+ return ret;
+}
+
+/* returns 1 if switch() was not called before
+ * return status of setns() otherwise
+ */
+int ns_switchback_to_initial(void)
+{
+ if (ns_current_ns_fd != -1) {
+ int ret;
+
+ ret = setns(ns_default_ns_fd, CLONE_NEWNET);
+ ns_current_ns_fd = -1;
+ return ret;
+ }
+ /* silently ignore if setns() is not called */
+ return 1;
+}
+
/* Create a socket for the NS. */
int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
{
ret = (ns_id != NS_DEFAULT) ? setns(ns->fd, CLONE_NEWNET) : 0;
if (ret >= 0) {
ret = socket(domain, type, protocol);
- if (ns_id != NS_DEFAULT)
+ if (ns_id != NS_DEFAULT) {
setns(ns_lookup(NS_DEFAULT)->fd, CLONE_NEWNET);
+ ns_current_ns_fd = ns_id;
+ }
}
} else
ret = socket(domain, type, protocol);
/*
* NS initializer/destructor
*/
+extern void ns_init(void);
extern void ns_init_zebra(void);
extern void ns_terminate(void);
extern void ns_walk_func(int (*func)(struct ns *));
extern const char *ns_get_name(struct ns *ns);
+/* API that can be used by all daemons */
+extern int ns_switchback_to_initial(void);
+extern int ns_switch_to_netns(const char *netns_name);
+extern void ns_init(void);
+
#endif /*_ZEBRA_NS_H*/
return strcmp(a->name, b->name);
}
+int vrf_switch_to_netns(vrf_id_t vrf_id)
+{
+ char *name;
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+ /* VRF has no NETNS backend. silently ignore */
+ if (!vrf || vrf->data.l.netns_name[0] == '\0')
+ return 0;
+ /* VRF is default VRF. silently ignore */
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return 0;
+ name = ns_netns_pathname(NULL, vrf->data.l.netns_name);
+ if (debug_vrf)
+ zlog_debug("VRF_SWITCH: %s(%u)", name, vrf->vrf_id);
+ return ns_switch_to_netns(name);
+}
+
+int vrf_switchback_to_initial(void)
+{
+ int ret = ns_switchback_to_initial();
+
+ if (ret == 0 && debug_vrf)
+ zlog_debug("VRF_SWITCHBACK");
+ return ret;
+}
+
/* return 1 if vrf can be enabled */
int vrf_update_vrf_id(vrf_id_t vrf_id, struct vrf *vrf)
{
return CMD_SUCCESS;
}
+int vrf_is_mapped_on_netns(vrf_id_t vrf_id)
+{
+ struct vrf *vrf = vrf_lookup_by_id(vrf_id);
+
+ if (!vrf || vrf->data.l.netns_name[0] == '\0')
+ return 0;
+ if (vrf->vrf_id == VRF_DEFAULT)
+ return 0;
+ return 1;
+}
+
/* vrf CLI commands */
DEFUN_NOSH (vrf,
vrf_cmd,
const char *name,
struct vrf **vrf);
+/* VRF is mapped on netns or not ? */
+int vrf_is_mapped_on_netns(vrf_id_t vrf_id);
+
+/* VRF switch from NETNS */
+extern int vrf_switch_to_netns(vrf_id_t vrf_id);
+extern int vrf_switchback_to_initial(void);
+
/* used by NS when vrf backend is NS.
* Notify a change in the VRF ID of the VRF
*/