]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: copy logical-router-command under vrf subnode
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 6 Dec 2017 11:03:59 +0000 (12:03 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 27 Feb 2018 10:11:24 +0000 (11:11 +0100)
a vty command is added:
in addition to this command ( kept for future usage):
- [no] logical-router-id <ID> netns <NETNSNAME>
a new command is being placed under vrf subnode
- vrf <NAME>
   [no] netns <NETNSNAME>
  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 <philippe.guibert@6wind.com>
lib/ns.c
lib/ns.h
lib/vrf.c
lib/vrf.h
zebra/zebra_ns.c
zebra/zebra_ns.h
zebra/zebra_vrf.c

index e3a1d9d0dc3e497fc6061760b1fdbbf039dc9fa1..25136d0a1e898afc2acad10f49e74c63e18535a8 100644 (file)
--- a/lib/ns.c
+++ b/lib/ns.c
 
 #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);
        }
 }
 
index 79b4cab04d03c8bb5e3b2d187f2ca2c0faf43b5f..fab3e193689397020a28e42324b22150d7e8237f 100644 (file)
--- 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*/
index c300a87a3683e8d2ee530357f270a4d5be17636f..56c8bdbabefade0386131a170976a6cd9ca0a513 100644 (file)
--- 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();
 }
index f1dc450194696bdbb7cf3ba01add1e08d7dd1436..40e6ab6cd6ebf06b07bc586daea3b07a199a4e97 100644 (file)
--- 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);
index 1715881f7e87c177f0f06e2b10dec308cd682a0a..80847518a7e50eeb4ca99d6adf26d613d775f0d5 100644 (file)
@@ -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;
+}
index 765f2c6893d959b611df6c4c0236f08a31dbefca..99e4984164e6b8e385f6a812ff1942d643bab45c 100644 (file)
@@ -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
index 6eec2c18c4d4148f552b4949298b1bf442a46906..a3596a4263351f1a404c4e4fccfbcf3193bb5ca1 100644 (file)
@@ -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");
                }