]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Create ns.c
authorDonald Sharp <sharpd@cumulusnetwroks.com>
Sun, 4 Sep 2016 00:45:35 +0000 (20:45 -0400)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 9 Sep 2016 16:15:13 +0000 (12:15 -0400)
Create the ns.c files from the original vrf.c code
to allow us to create the 'logical-router' command
to work within namespaces.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
lib/Makefile.am
lib/memtypes.c
lib/ns.c [new file with mode: 0644]
lib/ns.h [new file with mode: 0644]

index ada31a0d21fb46d58e4723364e7747fc58a02f0e..5a970c881da219d53902ea0acb624851bb511c6a 100644 (file)
@@ -14,7 +14,7 @@ libzebra_la_SOURCES = \
        filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
        zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
        sigevent.c pqueue.c jhash.c memtypes.c workqueue.c nexthop.c json.c \
-       ptm_lib.c csv.c bfd.c vrf.c systemd.c
+       ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c
 
 BUILT_SOURCES = memtypes.h route_types.h gitversion.h
 
@@ -30,7 +30,7 @@ pkginclude_HEADERS = \
        plist.h zclient.h sockopt.h smux.h md5.h if_rmap.h keychain.h \
        privs.h sigevent.h pqueue.h jhash.h zassert.h memtypes.h \
        workqueue.h route_types.h libospf.h nexthop.h json.h \
-       ptm_lib.h csv.h bfd.h vrf.h systemd.h bitfield.h
+       ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h
 
 noinst_HEADERS = \
        plist_int.h
index 56d4faead5ae34dec1712dde7e3ca3f23b527b04..510312f336b6053fec87beffa0c194dbeab57686 100644 (file)
@@ -77,6 +77,9 @@ struct memory_list memory_list_lib[] =
   { MTYPE_VRF,                 "VRF"                           },
   { MTYPE_VRF_NAME,            "VRF name"                      },
   { MTYPE_VRF_BITMAP,          "VRF bit-map"                   },
+  { MTYPE_NS,                   "Logical-Router"                },
+  { MTYPE_NS_NAME,              "Logical-Router Name"           },
+  { MTYPE_NS_BITMAP,            "Logical-Router bit-map"        },
   { MTYPE_IF_LINK_PARAMS,      "Informational Link Parameters" },
   { -1, NULL },
 };
diff --git a/lib/ns.c b/lib/ns.c
new file mode 100644 (file)
index 0000000..daaffc6
--- /dev/null
+++ b/lib/ns.c
@@ -0,0 +1,503 @@
+/*
+ * NS functions.
+ * Copyright (C) 2014 6WIND S.A.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "ns.h"
+#include "prefix.h"
+#include "table.h"
+#include "log.h"
+#include "memory.h"
+
+#define NS_DEFAULT_NAME    "Default-logical-router"
+
+struct ns
+{
+  /* Identifier, same as the vector index */
+  ns_id_t ns_id;
+  /* Name */
+  char *name;
+
+  /* Master list of interfaces belonging to this NS */
+  struct list *iflist;
+
+  /* User data */
+  void *info;
+};
+
+/* Holding NS hooks  */
+struct ns_master
+{
+  int (*ns_new_hook) (ns_id_t, void **);
+  int (*ns_delete_hook) (ns_id_t, void **);
+  int (*ns_enable_hook) (ns_id_t, void **);
+  int (*ns_disable_hook) (ns_id_t, void **);
+} ns_master = {0,};
+
+/* NS table */
+struct route_table *ns_table = NULL;
+
+static int ns_is_enabled (struct ns *ns);
+static int ns_enable (struct ns *ns);
+static void ns_disable (struct ns *ns);
+
+
+/* Build the table key */
+static void
+ns_build_key (ns_id_t ns_id, struct prefix *p)
+{
+  p->family = AF_INET;
+  p->prefixlen = IPV4_MAX_BITLEN;
+  p->u.prefix4.s_addr = ns_id;
+}
+
+/* Get a NS. If not found, create one. */
+static struct ns *
+ns_get (ns_id_t ns_id)
+{
+  struct prefix p;
+  struct route_node *rn;
+  struct ns *ns;
+
+  ns_build_key (ns_id, &p);
+  rn = route_node_get (ns_table, &p);
+  if (rn->info)
+    {
+      ns = (struct ns *)rn->info;
+      route_unlock_node (rn); /* get */
+      return ns;
+    }
+
+  ns = XCALLOC (MTYPE_NS, sizeof (struct ns));
+  ns->ns_id = ns_id;
+  rn->info = ns;
+
+  /*
+   * Initialize interfaces.
+   *
+   * I'm not sure if this belongs here or in
+   * the vrf code.
+   */
+  // if_init (&ns->iflist);
+
+  zlog_info ("NS %u is created.", ns_id);
+
+  if (ns_master.ns_new_hook)
+    (*ns_master.ns_new_hook) (ns_id, &ns->info);
+
+  return ns;
+}
+
+/* Delete a NS. This is called in ns_terminate(). */
+static void
+ns_delete (struct ns *ns)
+{
+  zlog_info ("NS %u is to be deleted.", ns->ns_id);
+
+  if (ns_is_enabled (ns))
+    ns_disable (ns);
+
+  if (ns_master.ns_delete_hook)
+    (*ns_master.ns_delete_hook) (ns->ns_id, &ns->info);
+
+  /*
+   * I'm not entirely sure if the vrf->iflist
+   * needs to be moved into here or not.
+   */
+  //if_terminate (&ns->iflist);
+
+  if (ns->name)
+    XFREE (MTYPE_NS_NAME, ns->name);
+
+  XFREE (MTYPE_NS, ns);
+}
+
+/* Look up a NS by identifier. */
+static struct ns *
+ns_lookup (ns_id_t ns_id)
+{
+  struct prefix p;
+  struct route_node *rn;
+  struct ns *ns = NULL;
+
+  ns_build_key (ns_id, &p);
+  rn = route_node_lookup (ns_table, &p);
+  if (rn)
+    {
+      ns = (struct ns *)rn->info;
+      route_unlock_node (rn); /* lookup */
+    }
+  return ns;
+}
+
+/*
+ * Check whether the NS is enabled - that is, whether the NS
+ * is ready to allocate resources. Currently there's only one
+ * type of resource: socket.
+ */
+static int
+ns_is_enabled (struct ns *ns)
+{
+  return ns && ns->ns_id == NS_DEFAULT;
+}
+
+/*
+ * Enable a NS - that is, let the NS be ready to use.
+ * The NS_ENABLE_HOOK callback will be called to inform
+ * that they can allocate resources in this NS.
+ *
+ * RETURN: 1 - enabled successfully; otherwise, 0.
+ */
+static int
+ns_enable (struct ns *ns)
+{
+  /* Till now, only the default NS can be enabled. */
+  if (ns->ns_id == NS_DEFAULT)
+    {
+      zlog_info ("NS %u is enabled.", ns->ns_id);
+
+      if (ns_master.ns_enable_hook)
+        (*ns_master.ns_enable_hook) (ns->ns_id, &ns->info);
+
+      return 1;
+    }
+
+  return 0;
+}
+
+/*
+ * Disable a NS - that is, let the NS be unusable.
+ * The NS_DELETE_HOOK callback will be called to inform
+ * that they must release the resources in the NS.
+ */
+static void
+ns_disable (struct ns *ns)
+{
+  if (ns_is_enabled (ns))
+    {
+      zlog_info ("NS %u is to be disabled.", ns->ns_id);
+
+      /* Till now, nothing to be done for the default NS. */
+
+      if (ns_master.ns_disable_hook)
+        (*ns_master.ns_disable_hook) (ns->ns_id, &ns->info);
+    }
+}
+
+
+/* Add a NS hook. Please add hooks before calling ns_init(). */
+void
+ns_add_hook (int type, int (*func)(ns_id_t, void **))
+{
+  switch (type) {
+  case NS_NEW_HOOK:
+    ns_master.ns_new_hook = func;
+    break;
+  case NS_DELETE_HOOK:
+    ns_master.ns_delete_hook = func;
+    break;
+  case NS_ENABLE_HOOK:
+    ns_master.ns_enable_hook = func;
+    break;
+  case NS_DISABLE_HOOK:
+    ns_master.ns_disable_hook = func;
+    break;
+  default:
+    break;
+  }
+}
+
+/* Return the iterator of the first NS. */
+ns_iter_t
+ns_first (void)
+{
+  struct route_node *rn;
+
+  for (rn = route_top (ns_table); rn; rn = route_next (rn))
+    if (rn->info)
+      {
+        route_unlock_node (rn); /* top/next */
+        return (ns_iter_t)rn;
+      }
+  return NS_ITER_INVALID;
+}
+
+/* Return the next NS iterator to the given iterator. */
+ns_iter_t
+ns_next (ns_iter_t iter)
+{
+  struct route_node *rn = NULL;
+
+  /* Lock it first because route_next() will unlock it. */
+  if (iter != NS_ITER_INVALID)
+    rn = route_next (route_lock_node ((struct route_node *)iter));
+
+  for (; rn; rn = route_next (rn))
+    if (rn->info)
+      {
+        route_unlock_node (rn); /* next */
+        return (ns_iter_t)rn;
+      }
+  return NS_ITER_INVALID;
+}
+
+/* Return the NS iterator of the given NS ID. If it does not exist,
+ * the iterator of the next existing NS is returned. */
+ns_iter_t
+ns_iterator (ns_id_t ns_id)
+{
+  struct prefix p;
+  struct route_node *rn;
+
+  ns_build_key (ns_id, &p);
+  rn = route_node_get (ns_table, &p);
+  if (rn->info)
+    {
+      /* OK, the NS exists. */
+      route_unlock_node (rn); /* get */
+      return (ns_iter_t)rn;
+    }
+
+  /* Find the next NS. */
+  for (rn = route_next (rn); rn; rn = route_next (rn))
+    if (rn->info)
+      {
+        route_unlock_node (rn); /* next */
+        return (ns_iter_t)rn;
+      }
+
+  return NS_ITER_INVALID;
+}
+
+/* Obtain the NS ID from the given NS iterator. */
+ns_id_t
+ns_iter2id (ns_iter_t iter)
+{
+  struct route_node *rn = (struct route_node *) iter;
+  return (rn && rn->info) ? ((struct ns *)rn->info)->ns_id : NS_DEFAULT;
+}
+
+/* Obtain the data pointer from the given NS iterator. */
+void *
+ns_iter2info (ns_iter_t iter)
+{
+  struct route_node *rn = (struct route_node *) iter;
+  return (rn && rn->info) ? ((struct ns *)rn->info)->info : NULL;
+}
+
+/* Obtain the interface list from the given NS iterator. */
+struct list *
+ns_iter2iflist (ns_iter_t iter)
+{
+  struct route_node *rn = (struct route_node *) iter;
+  return (rn && rn->info) ? ((struct ns *)rn->info)->iflist : NULL;
+}
+
+/* Get the data pointer of the specified NS. If not found, create one. */
+void *
+ns_info_get (ns_id_t ns_id)
+{
+  struct ns *ns = ns_get (ns_id);
+  return ns->info;
+}
+
+/* Look up the data pointer of the specified NS. */
+void *
+ns_info_lookup (ns_id_t ns_id)
+{
+  struct ns *ns = ns_lookup (ns_id);
+  return ns ? ns->info : NULL;
+}
+
+/* Look up the interface list in a NS. */
+struct list *
+ns_iflist (ns_id_t ns_id)
+{
+   struct ns * ns = ns_lookup (ns_id);
+   return ns ? ns->iflist : NULL;
+}
+
+/* Get the interface list of the specified NS. Create one if not find. */
+struct list *
+ns_iflist_get (ns_id_t ns_id)
+{
+   struct ns * ns = ns_get (ns_id);
+   return ns->iflist;
+}
+
+/*
+ * NS bit-map
+ */
+
+#define NS_BITMAP_NUM_OF_GROUPS            8
+#define NS_BITMAP_NUM_OF_BITS_IN_GROUP \
+    (UINT16_MAX / NS_BITMAP_NUM_OF_GROUPS)
+#define NS_BITMAP_NUM_OF_BYTES_IN_GROUP \
+    (NS_BITMAP_NUM_OF_BITS_IN_GROUP / CHAR_BIT + 1) /* +1 for ensure */
+
+#define NS_BITMAP_GROUP(_id) \
+    ((_id) / NS_BITMAP_NUM_OF_BITS_IN_GROUP)
+#define NS_BITMAP_BIT_OFFSET(_id) \
+    ((_id) % NS_BITMAP_NUM_OF_BITS_IN_GROUP)
+
+#define NS_BITMAP_INDEX_IN_GROUP(_bit_offset) \
+    ((_bit_offset) / CHAR_BIT)
+#define NS_BITMAP_FLAG(_bit_offset) \
+    (((u_char)1) << ((_bit_offset) % CHAR_BIT))
+
+struct ns_bitmap
+{
+  u_char *groups[NS_BITMAP_NUM_OF_GROUPS];
+};
+
+ns_bitmap_t
+ns_bitmap_init (void)
+{
+  return (ns_bitmap_t) XCALLOC (MTYPE_NS_BITMAP, sizeof (struct ns_bitmap));
+}
+
+void
+ns_bitmap_free (ns_bitmap_t bmap)
+{
+  struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+  int i;
+
+  if (bmap == NS_BITMAP_NULL)
+    return;
+
+  for (i = 0; i < NS_BITMAP_NUM_OF_GROUPS; i++)
+    if (bm->groups[i])
+      XFREE (MTYPE_NS_BITMAP, bm->groups[i]);
+
+  XFREE (MTYPE_NS_BITMAP, bm);
+}
+
+void
+ns_bitmap_set (ns_bitmap_t bmap, ns_id_t ns_id)
+{
+  struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+  u_char group = NS_BITMAP_GROUP (ns_id);
+  u_char offset = NS_BITMAP_BIT_OFFSET (ns_id);
+
+  if (bmap == NS_BITMAP_NULL)
+    return;
+
+  if (bm->groups[group] == NULL)
+    bm->groups[group] = XCALLOC (MTYPE_NS_BITMAP,
+                                 NS_BITMAP_NUM_OF_BYTES_IN_GROUP);
+
+  SET_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)],
+            NS_BITMAP_FLAG (offset));
+}
+
+void
+ns_bitmap_unset (ns_bitmap_t bmap, ns_id_t ns_id)
+{
+  struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+  u_char group = NS_BITMAP_GROUP (ns_id);
+  u_char offset = NS_BITMAP_BIT_OFFSET (ns_id);
+
+  if (bmap == NS_BITMAP_NULL || bm->groups[group] == NULL)
+    return;
+
+  UNSET_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)],
+              NS_BITMAP_FLAG (offset));
+}
+
+int
+ns_bitmap_check (ns_bitmap_t bmap, ns_id_t ns_id)
+{
+  struct ns_bitmap *bm = (struct ns_bitmap *) bmap;
+  u_char group = NS_BITMAP_GROUP (ns_id);
+  u_char offset = NS_BITMAP_BIT_OFFSET (ns_id);
+
+  if (bmap == NS_BITMAP_NULL || bm->groups[group] == NULL)
+    return 0;
+
+  return CHECK_FLAG (bm->groups[group][NS_BITMAP_INDEX_IN_GROUP (offset)],
+                     NS_BITMAP_FLAG (offset)) ? 1 : 0;
+}
+
+/* Initialize NS module. */
+void
+ns_init (void)
+{
+  struct ns *default_ns;
+
+  /* Allocate NS table.  */
+  ns_table = route_table_init ();
+
+  /* The default NS always exists. */
+  default_ns = ns_get (NS_DEFAULT);
+  if (!default_ns)
+    {
+      zlog_err ("ns_init: failed to create the default NS!");
+      exit (1);
+    }
+
+  /* Set the default NS name. */
+  default_ns->name = XSTRDUP (MTYPE_NS_NAME, NS_DEFAULT_NAME);
+
+  /* Enable the default NS. */
+  if (!ns_enable (default_ns))
+    {
+      zlog_err ("ns_init: failed to enable the default NS!");
+      exit (1);
+    }
+}
+
+/* Terminate NS module. */
+void
+ns_terminate (void)
+{
+  struct route_node *rn;
+  struct ns *ns;
+
+  for (rn = route_top (ns_table); rn; rn = route_next (rn))
+    if ((ns = rn->info) != NULL)
+      ns_delete (ns);
+
+  route_table_finish (ns_table);
+  ns_table = NULL;
+}
+
+/* Create a socket for the NS. */
+int
+ns_socket (int domain, int type, int protocol, ns_id_t ns_id)
+{
+  int ret = -1;
+
+  if (!ns_is_enabled (ns_lookup (ns_id)))
+    {
+      errno = ENOSYS;
+      return -1;
+    }
+
+  if (ns_id == NS_DEFAULT)
+    ret = socket (domain, type, protocol);
+  else
+    errno = ENOSYS;
+
+  return ret;
+}
+
diff --git a/lib/ns.h b/lib/ns.h
new file mode 100644 (file)
index 0000000..81e2456
--- /dev/null
+++ b/lib/ns.h
@@ -0,0 +1,142 @@
+/*
+ * NS related header.
+ * Copyright (C) 2014 6WIND S.A.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ZEBRA_NS_H
+#define _ZEBRA_NS_H
+
+#include "linklist.h"
+
+typedef u_int16_t ns_id_t;
+
+/* The default NS ID */
+#define NS_DEFAULT 0
+
+/*
+ * The command strings
+ */
+
+#define NS_CMD_STR         "logical-router <0-65535>"
+#define NS_CMD_HELP_STR    "Specify the Logical-Router\nThe Logical-Router ID\n"
+
+#define NS_ALL_CMD_STR         "logical-router all"
+#define NS_ALL_CMD_HELP_STR    "Specify the logical-router\nAll logical-router's\n"
+
+/*
+ * NS hooks
+ */
+
+#define NS_NEW_HOOK        0   /* a new logical-router is just created */
+#define NS_DELETE_HOOK     1   /* a logical-router is to be deleted */
+#define NS_ENABLE_HOOK     2   /* a logical-router is ready to use */
+#define NS_DISABLE_HOOK    3   /* a logical-router is to be unusable */
+
+/*
+ * Add a specific hook ns module.
+ * @param1: hook type
+ * @param2: the callback function
+ *          - param 1: the NS ID
+ *          - param 2: the address of the user data pointer (the user data
+ *                     can be stored in or freed from there)
+ */
+extern void ns_add_hook (int, int (*)(ns_id_t, void **));
+
+/*
+ * NS iteration
+ */
+
+typedef void *              ns_iter_t;
+#define NS_ITER_INVALID    NULL    /* invalid value of the iterator */
+
+/*
+ * NS iteration utilities. Example for the usage:
+ *
+ *   ns_iter_t iter = ns_first();
+ *   for (; iter != NS_ITER_INVALID; iter = ns_next (iter))
+ *
+ * or
+ *
+ *   ns_iter_t iter = ns_iterator (<a given NS ID>);
+ *   for (; iter != NS_ITER_INVALID; iter = ns_next (iter))
+ */
+
+/* Return the iterator of the first NS. */
+extern ns_iter_t ns_first (void);
+/* Return the next NS iterator to the given iterator. */
+extern ns_iter_t ns_next (ns_iter_t);
+/* Return the NS iterator of the given NS ID. If it does not exist,
+ * the iterator of the next existing NS is returned. */
+extern ns_iter_t ns_iterator (ns_id_t);
+
+/*
+ * NS iterator to properties
+ */
+extern ns_id_t ns_iter2id (ns_iter_t);
+extern void *ns_iter2info (ns_iter_t);
+extern struct list *ns_iter2iflist (ns_iter_t);
+
+/*
+ * Utilities to obtain the user data
+ */
+
+/* Get the data pointer of the specified NS. If not found, create one. */
+extern void *ns_info_get (ns_id_t);
+/* Look up the data pointer of the specified NS. */
+extern void *ns_info_lookup (ns_id_t);
+
+/*
+ * Utilities to obtain the interface list
+ */
+
+/* Look up the interface list of the specified NS. */
+extern struct list *ns_iflist (ns_id_t);
+/* Get the interface list of the specified NS. Create one if not find. */
+extern struct list *ns_iflist_get (ns_id_t);
+
+/*
+ * NS bit-map: maintaining flags, one bit per NS ID
+ */
+
+typedef void *              ns_bitmap_t;
+#define NS_BITMAP_NULL     NULL
+
+extern ns_bitmap_t ns_bitmap_init (void);
+extern void ns_bitmap_free (ns_bitmap_t);
+extern void ns_bitmap_set (ns_bitmap_t, ns_id_t);
+extern void ns_bitmap_unset (ns_bitmap_t, ns_id_t);
+extern int ns_bitmap_check (ns_bitmap_t, ns_id_t);
+
+/*
+ * NS initializer/destructor
+ */
+/* Please add hooks before calling ns_init(). */
+extern void ns_init (void);
+extern void ns_terminate (void);
+
+/*
+ * NS utilities
+ */
+
+/* Create a socket serving for the given NS */
+extern int ns_socket (int, int, int, ns_id_t);
+
+#endif /*_ZEBRA_NS_H*/
+