From b95c18833a36bcf03b7a72c110be24873a65420d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 6 Dec 2017 12:03:59 +0100 Subject: [PATCH] zebra: copy logical-router-command under vrf subnode a vty command is added: in addition to this command ( kept for future usage): - [no] logical-router-id netns a new command is being placed under vrf subnode - vrf [no] netns exit This command permits to map a VRF with a Netnamespace. The commit only handles the relationship between vrf and ns structures. It adds 2 attributes to vrf structure: - one defines the kind of vrf ( mapped under netns or vrf from kernel) - the other is the opaque pointer to ns The show running-config is handled by zebra daemon. Signed-off-by: Philippe Guibert --- lib/ns.c | 184 ++++++++++++++++++++++++++++++++++++++-------- lib/ns.h | 4 + lib/vrf.c | 2 + lib/vrf.h | 3 + zebra/zebra_ns.c | 8 ++ zebra/zebra_ns.h | 1 + zebra/zebra_vrf.c | 1 + 7 files changed, 173 insertions(+), 30 deletions(-) diff --git a/lib/ns.c b/lib/ns.c index e3a1d9d0dc..25136d0a1e 100644 --- a/lib/ns.c +++ b/lib/ns.c @@ -35,12 +35,14 @@ #include "command.h" #include "vty.h" +#include "vrf.h" -DEFINE_MTYPE_STATIC(LIB, NS, "Logical-Router") -DEFINE_MTYPE_STATIC(LIB, NS_NAME, "Logical-Router Name") +DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context") +DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name") static __inline int ns_compare(const struct ns *, const struct ns *); static struct ns *ns_lookup(ns_id_t); +static struct ns *ns_lookup_name(const char *); RB_GENERATE(ns_head, ns, entry, ns_compare) @@ -105,12 +107,31 @@ struct ns_master { static int ns_is_enabled(struct ns *ns); static int ns_enable(struct ns *ns); static void ns_disable(struct ns *ns); +static void ns_get_created(struct ns *ns); static __inline int ns_compare(const struct ns *a, const struct ns *b) { return (a->ns_id - b->ns_id); } +static void ns_get_created(struct ns *ns) +{ + /* + * Initialize interfaces. + * + * I'm not sure if this belongs here or in + * the vrf code. + */ + // if_init (&ns->iflist); + + if (ns->ns_id != NS_UNKNOWN) + zlog_info("NS %u is created.", ns->ns_id); + else + zlog_info("NS %s is created.", ns->name); + if (ns_master.ns_new_hook) + (*ns_master.ns_new_hook)(ns->ns_id, &ns->info); +} + /* Get a NS. If not found, create one. */ static struct ns *ns_get(ns_id_t ns_id) { @@ -124,20 +145,27 @@ static struct ns *ns_get(ns_id_t ns_id) ns->ns_id = ns_id; ns->fd = -1; RB_INSERT(ns_head, &ns_tree, ns); + ns_get_created(ns); + return ns; +} - /* - * Initialize interfaces. - * - * I'm not sure if this belongs here or in - * the vrf code. - */ - // if_init (&ns->iflist); +/* Get a NS. If not found, create one. */ +static struct ns *ns_get_by_name(char *ns_name) +{ + struct ns *ns; - zlog_info("NS %u is created.", ns_id); + ns = ns_lookup_name(ns_name); + if (ns) + return (ns); - if (ns_master.ns_new_hook) - (*ns_master.ns_new_hook)(ns_id, &ns->info); + ns = XCALLOC(MTYPE_NS, sizeof(struct ns)); + ns->ns_id = NS_UNKNOWN; + ns->name = XSTRDUP(MTYPE_NS_NAME, ns_name); + ns->fd = -1; + RB_INSERT(ns_head, &ns_tree, ns); + /* ns_id not initialised */ + ns_get_created(ns); return ns; } @@ -172,6 +200,20 @@ static struct ns *ns_lookup(ns_id_t ns_id) return (RB_FIND(ns_head, &ns_tree, &ns)); } +/* Look up a NS by name */ +static struct ns *ns_lookup_name(const char *name) +{ + struct ns *ns = NULL; + + RB_FOREACH(ns, ns_head, &ns_tree) { + if (ns->name != NULL) { + if (strcmp(name, ns->name) == 0) + return ns; + } + } + return NULL; +} + /* * Check whether the NS is enabled - that is, whether the NS * is ready to allocate resources. Currently there's only one @@ -289,8 +331,8 @@ static char *ns_netns_pathname(struct vty *vty, const char *name) return pathname; } -DEFUN_NOSH (ns_netns, - ns_netns_cmd, +DEFUN_NOSH (ns_logicalrouter, + ns_logicalrouter_cmd, "logical-router (1-65535) ns NAME", "Enable a logical-router\n" "Specify the logical-router indentifier\n" @@ -299,7 +341,7 @@ DEFUN_NOSH (ns_netns, { int idx_number = 1; int idx_name = 3; - ns_id_t ns_id = NS_DEFAULT; + ns_id_t ns_id; struct ns *ns = NULL; char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg); @@ -327,8 +369,11 @@ DEFUN_NOSH (ns_netns, return CMD_SUCCESS; } -DEFUN (no_ns_netns, - no_ns_netns_cmd, +static struct cmd_node logicalrouter_node = {NS_NODE, "", /* NS node has no interface. */ + 1}; + +DEFUN (no_ns_logicalrouter, + no_ns_logicalrouter_cmd, "no logical-router (1-65535) ns NAME", NO_STR "Enable a Logical-Router\n" @@ -338,7 +383,7 @@ DEFUN (no_ns_netns, { int idx_number = 2; int idx_name = 4; - ns_id_t ns_id = NS_DEFAULT; + ns_id_t ns_id; struct ns *ns = NULL; char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg); @@ -368,30 +413,99 @@ DEFUN (no_ns_netns, return CMD_SUCCESS; } -/* NS node. */ -static struct cmd_node ns_node = {NS_NODE, "", /* NS node has no interface. */ - 1}; +DEFUN_NOSH (ns_netns, + ns_netns_cmd, + "netns NAME", + "Attach VRF to a Namespace\n" + "The file name in " NS_RUN_DIR ", or a full pathname\n") +{ + int idx_name = 1; + struct ns *ns = NULL; + char *pathname = ns_netns_pathname(vty, argv[idx_name]->arg); + + VTY_DECLVAR_CONTEXT(vrf, vrf); + + if (!pathname) + return CMD_WARNING_CONFIG_FAILED; + + if (!vrf) + return CMD_WARNING_CONFIG_FAILED; + if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) { + vty_out(vty, "VRF %u is already configured with VRF %s\n", + vrf->vrf_id, vrf->name); + return CMD_WARNING_CONFIG_FAILED; + } + if (vrf->ns_ctxt != NULL) { + ns = (struct ns *) vrf->ns_ctxt; + if (ns && 0 != strcmp(ns->name, pathname)) { + vty_out(vty, "VRF %u is already configured" + " with NETNS %s\n", + vrf->vrf_id, ns->name); + return CMD_WARNING_CONFIG_FAILED; + } + } + ns = ns_lookup_name(pathname); + if (ns && ns->vrf_ctxt) { + struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt; + + vty_out(vty, "NS %s is already configured" + " with VRF %u(%s)\n", + ns->name, vrf2->vrf_id, vrf2->name); + return CMD_WARNING_CONFIG_FAILED; + } else if (!ns) + ns = ns_get_by_name(pathname); -/* NS configuration write function. */ -static int ns_config_write(struct vty *vty) + if (!ns_enable(ns)) { + vty_out(vty, "Can not associate NS %u with NETNS %s\n", + ns->ns_id, ns->name); + return CMD_WARNING_CONFIG_FAILED; + } + + vrf->ns_ctxt = (void *)ns; + ns->vrf_ctxt = (void *)vrf; + return CMD_SUCCESS; +} + +static int ns_logicalrouter_config_write(struct vty *vty) { struct ns *ns; int write = 0; - if (vrf_is_backend_netns()) - return 0; RB_FOREACH(ns, ns_head, &ns_tree) { if (ns->ns_id == NS_DEFAULT || ns->name == NULL) continue; - vty_out(vty, "logical-router %u netns %s\n", ns->ns_id, ns->name); write = 1; } - return write; } +DEFUN (no_ns_netns, + no_ns_netns_cmd, + "no netns [NAME]", + NO_STR + "Detach VRF from a Namespace\n" + "The file name in " NS_RUN_DIR ", or a full pathname\n") +{ + struct ns *ns = NULL; + + VTY_DECLVAR_CONTEXT(vrf, vrf); + + if (!vrf->ns_ctxt) { + vty_out(vty, "VRF %s(%u) is not configured with NetNS\n", + vrf->name, vrf->vrf_id); + return CMD_WARNING_CONFIG_FAILED; + } + + ns = (struct ns *)vrf->ns_ctxt; + + ns->vrf_ctxt = NULL; + ns_delete(ns); + vrf->ns_ctxt = NULL; + return CMD_SUCCESS; +} + /* Initialize NS module. */ void ns_init(void) { @@ -415,9 +529,19 @@ void ns_init(void) if (have_netns() && !vrf_is_backend_netns()) { /* Install NS commands. */ - install_node(&ns_node, ns_config_write); - install_element(CONFIG_NODE, &ns_netns_cmd); - install_element(CONFIG_NODE, &no_ns_netns_cmd); + install_node(&logicalrouter_node, + ns_logicalrouter_config_write); + install_element(CONFIG_NODE, &ns_logicalrouter_cmd); + install_element(CONFIG_NODE, &no_ns_logicalrouter_cmd); + } +} + +void ns_cmd_init(void) +{ + if (have_netns()) { + /* Install NS commands. */ + install_element(VRF_NODE, &ns_netns_cmd); + install_element(VRF_NODE, &no_ns_netns_cmd); } } diff --git a/lib/ns.h b/lib/ns.h index 79b4cab04d..fab3e19368 100644 --- a/lib/ns.h +++ b/lib/ns.h @@ -49,6 +49,9 @@ struct ns { /* Master list of interfaces belonging to this NS */ struct list *iflist; + /* Back Pointer to VRF */ + void *vrf_ctxt; + /* User data */ void *info; }; @@ -89,5 +92,6 @@ extern void ns_terminate(void); /* Create a socket serving for the given NS */ extern int ns_socket(int, int, int, ns_id_t); +extern void ns_cmd_init(void); #endif /*_ZEBRA_NS_H*/ diff --git a/lib/vrf.c b/lib/vrf.c index c300a87a36..56c8bdbabe 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -29,6 +29,7 @@ #include "log.h" #include "memory.h" #include "command.h" +#include "ns.h" DEFINE_MTYPE_STATIC(LIB, VRF, "VRF") DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map") @@ -574,4 +575,5 @@ void vrf_cmd_init(int (*writefunc)(struct vty *vty)) install_element(CONFIG_NODE, &no_vrf_cmd); install_node(&vrf_node, writefunc); install_default(VRF_NODE); + ns_cmd_init(); } diff --git a/lib/vrf.h b/lib/vrf.h index f1dc450194..40e6ab6cd6 100644 --- a/lib/vrf.h +++ b/lib/vrf.h @@ -88,6 +88,9 @@ struct vrf { /* The table_id from the kernel */ struct vrf_data data; + /* Back pointer to namespace context */ + void *ns_ctxt; + QOBJ_FIELDS }; RB_HEAD(vrf_id_head, vrf); diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 1715881f7e..80847518a7 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -1,6 +1,7 @@ /* zebra NS Routines * Copyright (C) 2016 Cumulus Networks, Inc. * Donald Sharp + * Copyright (C) 2017/2018 6WIND * * This file is part of Quagga. * @@ -177,3 +178,10 @@ int zebra_ns_init(void) return 0; } + +int zebra_ns_config_write(struct vty *vty, struct ns *ns) +{ + if (ns && ns->name != NULL) + vty_out(vty, " netns %s\n", ns->name); + return 0; +} diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 765f2c6893..99e4984164 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -82,4 +82,5 @@ extern struct route_table *zebra_ns_find_table(struct zebra_ns *zns, extern struct route_table *zebra_ns_get_table(struct zebra_ns *zns, struct zebra_vrf *zvrf, uint32_t tableid, afi_t afi); +int zebra_ns_config_write(struct vty *vty, struct ns *ns); #endif diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index 6eec2c18c4..a3596a4263 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -563,6 +563,7 @@ static int vrf_config_write(struct vty *vty) zvrf->l3vni, is_l3vni_for_prefix_routes_only(zvrf->l3vni) ? " prefix-routes-only" :""); + zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt); vty_out(vty, "!\n"); } -- 2.39.5