diff --git a/lib/netns_linux.c b/lib/netns_linux.c index 3d61cecc03..c215b4151b 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -59,6 +59,26 @@ static int ns_default_ns_fd; static int ns_debug; +struct ns_map_nsid { + RB_ENTRY(ns_map_nsid) id_entry; + ns_id_t ns_id_external; + ns_id_t ns_id; +}; + +static __inline int ns_map_compare(const struct ns_map_nsid *a, + const struct ns_map_nsid *b) +{ + return (a->ns_id - b->ns_id); +} + +RB_HEAD(ns_map_nsid_head, ns_map_nsid); +RB_PROTOTYPE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare); +RB_GENERATE(ns_map_nsid_head, ns_map_nsid, id_entry, ns_map_compare); +struct ns_map_nsid_head ns_map_nsid_list = RB_INITIALIZER(&ns_map_nsid_list); + +static ns_id_t ns_id_external_numbering; + + #ifndef CLONE_NEWNET #define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ @@ -262,6 +282,38 @@ static void ns_disable_internal(struct ns *ns) } } +/* VRF list existance check by name. */ +static struct ns_map_nsid *ns_map_nsid_lookup_by_nsid(ns_id_t ns_id) +{ + struct ns_map_nsid ns_map; + + ns_map.ns_id = ns_id; + return (RB_FIND(ns_map_nsid_head, &ns_map_nsid_list, &ns_map)); +} + +ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool maporunmap) +{ + struct ns_map_nsid *ns_map; + vrf_id_t ns_id_external; + + ns_map = ns_map_nsid_lookup_by_nsid(ns_id); + if (ns_map && !maporunmap) { + ns_id_external = ns_map->ns_id_external; + RB_REMOVE(ns_map_nsid_head, &ns_map_nsid_list, ns_map); + return ns_id_external; + } + if (ns_map) + return ns_map->ns_id_external; + ns_map = XCALLOC(MTYPE_NS, sizeof(struct ns_map_nsid)); + /* increase vrf_id + * default vrf is the first one : 0 + */ + ns_map->ns_id_external = ns_id_external_numbering++; + ns_map->ns_id = ns_id; + RB_INSERT(ns_map_nsid_head, &ns_map_nsid_list, ns_map); + return ns_map->ns_id_external; +} + struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id) { return ns_get_created_internal(ns, name, ns_id); @@ -430,7 +482,7 @@ void ns_init(void) } /* Initialize NS module. */ -void ns_init_management(ns_id_t default_ns_id) +void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns) { int fd; @@ -444,6 +496,8 @@ void ns_init_management(ns_id_t default_ns_id) fd = open(NS_DEFAULT_NAME, O_RDONLY); default_ns->fd = fd; } + default_ns->internal_ns_id = internal_ns; + /* Set the default NS name. */ default_ns->name = XSTRDUP(MTYPE_NS_NAME, NS_DEFAULT_NAME); if (ns_debug) diff --git a/lib/netns_other.c b/lib/netns_other.c index 2402dd17d6..4c7be05fab 100644 --- a/lib/netns_other.c +++ b/lib/netns_other.c @@ -153,6 +153,11 @@ int ns_enable(struct ns *ns, int (*func)(ns_id_t, void *)) return 0; } +ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool maporunmap) +{ + return NS_UNKNOWN; +} + struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id) { return NULL; diff --git a/lib/ns.h b/lib/ns.h index fac91a40da..ba857b630e 100644 --- a/lib/ns.h +++ b/lib/ns.h @@ -46,6 +46,9 @@ struct ns { /* Identifier, same as the vector index */ ns_id_t ns_id; + /* Identifier, mapped on the NSID value */ + ns_id_t internal_ns_id; + /* Name */ char *name; @@ -100,7 +103,7 @@ extern void ns_terminate(void); /* API to initialize NETNS managerment * parameter is the default ns_id */ -extern void ns_init_management(ns_id_t ns_id); +extern void ns_init_management(ns_id_t ns_id, ns_id_t internal_ns_idx); /* @@ -133,6 +136,11 @@ extern int ns_have_netns(void); /* API to get context information of a NS */ extern void *ns_info_lookup(ns_id_t ns_id); +/* API to map internal ns id value with + * user friendly ns id external value + */ +extern ns_id_t ns_map_nsid_with_external(ns_id_t ns_id, bool maporunmap); + /* * NS init routine * should be called from backendx diff --git a/lib/vrf.c b/lib/vrf.c index 8593cf289f..b493f832f3 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -539,7 +539,8 @@ void vrf_configure_backend(int vrf_backend_netns) vrf_backend = vrf_backend_netns; } -int vrf_handler_create(struct vty *vty, const char *vrfname, struct vrf **vrf) +int vrf_handler_create(struct vty *vty, const char *vrfname, + struct vrf **vrf) { struct vrf *vrfp; @@ -566,7 +567,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname, struct vrf **vrf) } int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, - ns_id_t ns_id) + ns_id_t ns_id, ns_id_t internal_ns_id) { struct ns *ns = NULL; @@ -613,6 +614,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, return CMD_WARNING_CONFIG_FAILED; } ns = ns_get_created(ns, pathname, ns_id); + ns->internal_ns_id = internal_ns_id; ns->vrf_ctxt = (void *)vrf; vrf->ns_ctxt = (void *)ns; /* update VRF netns NAME */ @@ -718,7 +720,8 @@ DEFUN_NOSH (vrf_netns, vrf_daemon_privs->change(ZPRIVS_RAISE)) zlog_err("%s: Can't raise privileges", __func__); - ret = vrf_netns_handler_create(vty, vrf, pathname, NS_UNKNOWN); + ret = vrf_netns_handler_create(vty, vrf, pathname, + NS_UNKNOWN, NS_UNKNOWN); if (vrf_daemon_privs && vrf_daemon_privs->change(ZPRIVS_LOWER)) @@ -827,6 +830,9 @@ vrf_id_t vrf_get_default_id(void) if (vrf) return vrf->vrf_id; + /* backend netns is only known by zebra + * for other daemons, we return VRF_DEFAULT_INTERNAL + */ if (vrf_is_backend_netns()) return ns_get_default_id(); else diff --git a/lib/vrf.h b/lib/vrf.h index 85a5309279..8aa0fc2215 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -272,7 +272,8 @@ extern int vrf_handler_create(struct vty *vty, const char *name, * should be called from zebra only */ extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, - char *pathname, ns_id_t ns_id); + char *pathname, ns_id_t ext_ns_id, + ns_id_t ns_id); /* used internally to enable or disable VRF. * Notify a change in the VRF ID of the VRF diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index f9beb32ac4..30f850597c 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -70,7 +70,7 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name) char *netnspath = ns_netns_pathname(NULL, name); struct vrf *vrf; int ret; - ns_id_t ns_id; + ns_id_t ns_id, ns_id_external; if (netnspath == NULL) return; @@ -80,8 +80,9 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name) ns_id = zebra_ns_id_get(netnspath); if (zserv_privs.change(ZPRIVS_LOWER)) zlog_err("Can't lower privileges"); + ns_id_external = ns_map_nsid_with_external(ns_id, true); /* if VRF with NS ID already present */ - vrf = vrf_lookup_by_id((vrf_id_t)ns_id); + vrf = vrf_lookup_by_id((vrf_id_t)ns_id_external); if (vrf) { zlog_warn( "NS notify : same NSID used by VRF %s. Ignore NS %s creation", @@ -90,15 +91,18 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name) } if (vrf_handler_create(NULL, name, &vrf) != CMD_SUCCESS) { zlog_warn("NS notify : failed to create VRF %s", name); + ns_map_nsid_with_external(ns_id, false); return; } if (zserv_privs.change(ZPRIVS_RAISE)) zlog_err("Can't raise privileges"); - ret = vrf_netns_handler_create(NULL, vrf, netnspath, ns_id); + ret = vrf_netns_handler_create(NULL, vrf, netnspath, + ns_id_external, ns_id); if (zserv_privs.change(ZPRIVS_LOWER)) zlog_err("Can't lower privileges"); if (ret != CMD_SUCCESS) { zlog_warn("NS notify : failed to create NS %s", netnspath); + ns_map_nsid_with_external(ns_id, false); return; } zlog_info("NS notify : created VRF %s NS %s", name, netnspath); diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 7393f767af..52cf4351bc 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -274,6 +274,7 @@ int zebra_ns_disable(ns_id_t ns_id, void **info) int zebra_ns_init(void) { ns_id_t ns_id; + ns_id_t ns_id_external; dzns = zebra_ns_alloc(); @@ -282,8 +283,8 @@ int zebra_ns_init(void) ns_id = zebra_ns_id_get_default(); if (zserv_privs.change(ZPRIVS_LOWER)) zlog_err("Can't lower privileges"); - - ns_init_management(ns_id); + ns_id_external = ns_map_nsid_with_external(ns_id, true); + ns_init_management(ns_id_external, ns_id); logicalrouter_init(logicalrouter_config_write); @@ -295,7 +296,7 @@ int zebra_ns_init(void) zebra_vrf_init(); /* Default NS is activated */ - zebra_ns_enable(ns_id, (void **)&dzns); + zebra_ns_enable(ns_id_external, (void **)&dzns); if (vrf_is_backend_netns()) { ns_add_hook(NS_NEW_HOOK, zebra_ns_new);