zebra: maintain the router-id per VRF

A router may need different identifier among the VRFs. So move the
maintenance of router-id per VRF.

* rib.h:

  Move the previous global variables in router-id.c into the
  "struct zebra_vrf":
  - struct list _rid_all_sorted_list/*rid_all_sorted_list
  - struct list _rid_lo_sorted_list/*rid_lo_sorted_list
  - struct prefix rid_user_assigned

* router-id.c/router-id.h:

  A new parameter "vrf_id" is added to all the router-id APIs.
  Their operations are done only within the specified VRF.

  A new command "router-id A.B.C.D vrf N" is added to allow
  manual router-id for any VRF.

  The old router_id_init() function is splitted into two:
  - router_id_cmd_init(): it only installs the commands
  - router_id_init(): this new one initializes the variables for
                      a specified VRF

* zebra_rib.c: Add new functions zebra_vrf_get/lookup() called
               from router-id.c.

* main.c: Replace router_id_init() with router_id_cmd_init() and
          call the new router_id_init() in zebra_vrf_new().

Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Vincent JARDIN <vincent.jardin@6wind.com>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/zebra/main.c b/zebra/main.c
index a690c9a..c7e3b68 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -215,6 +215,7 @@
     {
       zvrf = zebra_vrf_alloc (vrf_id);
       *info = (void *)zvrf;
+      router_id_init (zvrf);
     }
 
   return 0;
@@ -348,7 +349,7 @@
   rib_init ();
   zebra_if_init ();
   zebra_debug_init ();
-  router_id_init();
+  router_id_cmd_init ();
   zebra_vty_init ();
   access_list_init ();
   prefix_list_init ();
diff --git a/zebra/rib.h b/zebra/rib.h
index dcb307e..06aa353 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -23,6 +23,7 @@
 #ifndef _ZEBRA_RIB_H
 #define _ZEBRA_RIB_H
 
+#include "linklist.h"
 #include "prefix.h"
 #include "table.h"
 #include "queue.h"
@@ -351,6 +352,15 @@
 
   /* Static route configuration.  */
   struct route_table *stable[AFI_MAX][SAFI_MAX];
+
+  /* 2nd pointer type used primarily to quell a warning on
+   * ALL_LIST_ELEMENTS_RO
+   */
+  struct list _rid_all_sorted_list;
+  struct list _rid_lo_sorted_list;
+  struct list *rid_all_sorted_list;
+  struct list *rid_lo_sorted_list;
+  struct prefix rid_user_assigned;
 };
 
 /*
diff --git a/zebra/router-id.c b/zebra/router-id.c
index bfafc27..a4eb73a 100644
--- a/zebra/router-id.c
+++ b/zebra/router-id.c
@@ -36,20 +36,12 @@
 #include "log.h"
 #include "table.h"
 #include "rib.h"
+#include "vrf.h"
 
 #include "zebra/zserv.h"
 #include "zebra/router-id.h"
 #include "zebra/redistribute.h"
 
-/* 2nd pointer type used primarily to quell a warning on 
- * ALL_LIST_ELEMENTS_RO
- */
-static struct list _rid_all_sorted_list;
-static struct list _rid_lo_sorted_list;
-static struct list *rid_all_sorted_list = &_rid_all_sorted_list;
-static struct list *rid_lo_sorted_list = &_rid_lo_sorted_list;
-static struct prefix rid_user_assigned;
-
 /* master zebra server structure */
 extern struct zebra_t zebrad;
 
@@ -80,44 +72,55 @@
 }
 
 void
-router_id_get (struct prefix *p)
+router_id_get (struct prefix *p, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct connected *c;
+  struct zebra_vrf *zvrf = vrf_info_get (vrf_id);
 
   p->u.prefix4.s_addr = 0;
   p->family = AF_INET;
   p->prefixlen = 32;
 
-  if (rid_user_assigned.u.prefix4.s_addr)
-    p->u.prefix4.s_addr = rid_user_assigned.u.prefix4.s_addr;
-  else if (!list_isempty (rid_lo_sorted_list))
+  if (zvrf->rid_user_assigned.u.prefix4.s_addr)
+    p->u.prefix4.s_addr = zvrf->rid_user_assigned.u.prefix4.s_addr;
+  else if (!list_isempty (zvrf->rid_lo_sorted_list))
     {
-      node = listtail (rid_lo_sorted_list);
+      node = listtail (zvrf->rid_lo_sorted_list);
       c = listgetdata (node);
       p->u.prefix4.s_addr = c->address->u.prefix4.s_addr;
     }
-  else if (!list_isempty (rid_all_sorted_list))
+  else if (!list_isempty (zvrf->rid_all_sorted_list))
     {
-      node = listtail (rid_all_sorted_list);
+      node = listtail (zvrf->rid_all_sorted_list);
       c = listgetdata (node);
       p->u.prefix4.s_addr = c->address->u.prefix4.s_addr;
     }
 }
 
 static void
-router_id_set (struct prefix *p)
+router_id_set (struct prefix *p, vrf_id_t vrf_id)
 {
   struct prefix p2;
   struct listnode *node;
   struct zserv *client;
+  struct zebra_vrf *zvrf;
 
-  rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr;
+  if (p->u.prefix4.s_addr == 0) /* unset */
+    {
+      zvrf = vrf_info_lookup (vrf_id);
+      if (! zvrf)
+        return;
+    }
+  else /* set */
+    zvrf = vrf_info_get (vrf_id);
 
-  router_id_get (&p2);
+  zvrf->rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr;
+
+  router_id_get (&p2, vrf_id);
 
   for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
-    zsend_router_id_update (client, &p2);
+    zsend_router_id_update (client, &p2, vrf_id);
 }
 
 void
@@ -128,28 +131,29 @@
   struct prefix before;
   struct prefix after;
   struct zserv *client;
+  struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id);
 
   if (router_id_bad_address (ifc))
     return;
 
-  router_id_get (&before);
+  router_id_get (&before, zvrf->vrf_id);
 
   if (!strncmp (ifc->ifp->name, "lo", 2)
       || !strncmp (ifc->ifp->name, "dummy", 5))
-    l = rid_lo_sorted_list;
+    l = zvrf->rid_lo_sorted_list;
   else
-    l = rid_all_sorted_list;
+    l = zvrf->rid_all_sorted_list;
   
   if (!router_id_find_node (l, ifc))
     listnode_add_sort (l, ifc);
 
-  router_id_get (&after);
+  router_id_get (&after, zvrf->vrf_id);
 
   if (prefix_same (&before, &after))
     return;
 
   for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
-    zsend_router_id_update (client, &after);
+    zsend_router_id_update (client, &after, zvrf->vrf_id);
 }
 
 void
@@ -161,36 +165,51 @@
   struct prefix before;
   struct listnode *node;
   struct zserv *client;
+  struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id);
 
   if (router_id_bad_address (ifc))
     return;
 
-  router_id_get (&before);
+  router_id_get (&before, zvrf->vrf_id);
 
   if (!strncmp (ifc->ifp->name, "lo", 2)
       || !strncmp (ifc->ifp->name, "dummy", 5))
-    l = rid_lo_sorted_list;
+    l = zvrf->rid_lo_sorted_list;
   else
-    l = rid_all_sorted_list;
+    l = zvrf->rid_all_sorted_list;
 
   if ((c = router_id_find_node (l, ifc)))
     listnode_delete (l, c);
 
-  router_id_get (&after);
+  router_id_get (&after, zvrf->vrf_id);
 
   if (prefix_same (&before, &after))
     return;
 
   for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
-    zsend_router_id_update (client, &after);
+    zsend_router_id_update (client, &after, zvrf->vrf_id);
 }
 
 void
 router_id_write (struct vty *vty)
 {
-  if (rid_user_assigned.u.prefix4.s_addr)
-    vty_out (vty, "router-id %s%s", inet_ntoa (rid_user_assigned.u.prefix4),
-	     VTY_NEWLINE);
+  struct zebra_vrf *zvrf;
+  vrf_iter_t iter;
+
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    if ((zvrf = vrf_iter2info (iter)) != NULL)
+      if (zvrf->rid_user_assigned.u.prefix4.s_addr)
+        {
+          if (zvrf->vrf_id == VRF_DEFAULT)
+            vty_out (vty, "router-id %s%s",
+                     inet_ntoa (zvrf->rid_user_assigned.u.prefix4),
+                     VTY_NEWLINE);
+          else
+            vty_out (vty, "router-id %s vrf %u%s",
+                     inet_ntoa (zvrf->rid_user_assigned.u.prefix4),
+                     zvrf->vrf_id,
+                     VTY_NEWLINE);
+        }
 }
 
 DEFUN (router_id,
@@ -200,6 +219,7 @@
        "IP address to use for router-id\n")
 {
   struct prefix rid;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
   rid.u.prefix4.s_addr = inet_addr (argv[0]);
   if (!rid.u.prefix4.s_addr)
@@ -208,11 +228,21 @@
   rid.prefixlen = 32;
   rid.family = AF_INET;
 
-  router_id_set (&rid);
+  if (argc > 1)
+    VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+
+  router_id_set (&rid, vrf_id);
 
   return CMD_SUCCESS;
 }
 
+ALIAS (router_id,
+       router_id_vrf_cmd,
+       "router-id A.B.C.D " VRF_CMD_STR,
+       "Manually set the router-id\n"
+       "IP address to use for router-id\n"
+       VRF_CMD_HELP_STR)
+
 DEFUN (no_router_id,
        no_router_id_cmd,
        "no router-id",
@@ -220,16 +250,27 @@
        "Remove the manually configured router-id\n")
 {
   struct prefix rid;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
   rid.u.prefix4.s_addr = 0;
   rid.prefixlen = 0;
   rid.family = AF_INET;
 
-  router_id_set (&rid);
+  if (argc > 0)
+    VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+
+  router_id_set (&rid, vrf_id);
 
   return CMD_SUCCESS;
 }
 
+ALIAS (no_router_id,
+       no_router_id_vrf_cmd,
+       "no router-id " VRF_CMD_STR,
+       NO_STR
+       "Remove the manually configured router-id\n"
+       VRF_CMD_HELP_STR)
+
 static int
 router_id_cmp (void *a, void *b)
 {
@@ -240,18 +281,27 @@
 }
 
 void
-router_id_init (void)
+router_id_cmd_init (void)
 {
   install_element (CONFIG_NODE, &router_id_cmd);
   install_element (CONFIG_NODE, &no_router_id_cmd);
+  install_element (CONFIG_NODE, &router_id_vrf_cmd);
+  install_element (CONFIG_NODE, &no_router_id_vrf_cmd);
+}
 
-  memset (rid_all_sorted_list, 0, sizeof (*rid_all_sorted_list));
-  memset (rid_lo_sorted_list, 0, sizeof (*rid_lo_sorted_list));
-  memset (&rid_user_assigned, 0, sizeof (rid_user_assigned));
+void
+router_id_init (struct zebra_vrf *zvrf)
+{
+  zvrf->rid_all_sorted_list = &zvrf->_rid_all_sorted_list;
+  zvrf->rid_lo_sorted_list = &zvrf->_rid_lo_sorted_list;
 
-  rid_all_sorted_list->cmp = router_id_cmp;
-  rid_lo_sorted_list->cmp = router_id_cmp;
+  memset (zvrf->rid_all_sorted_list, 0, sizeof (zvrf->_rid_all_sorted_list));
+  memset (zvrf->rid_lo_sorted_list, 0, sizeof (zvrf->_rid_lo_sorted_list));
+  memset (&zvrf->rid_user_assigned, 0, sizeof (zvrf->rid_user_assigned));
 
-  rid_user_assigned.family = AF_INET;
-  rid_user_assigned.prefixlen = 32;
+  zvrf->rid_all_sorted_list->cmp = router_id_cmp;
+  zvrf->rid_lo_sorted_list->cmp = router_id_cmp;
+
+  zvrf->rid_user_assigned.family = AF_INET;
+  zvrf->rid_user_assigned.prefixlen = 32;
 }
diff --git a/zebra/router-id.h b/zebra/router-id.h
index be12bf5..46d300e 100644
--- a/zebra/router-id.h
+++ b/zebra/router-id.h
@@ -33,8 +33,9 @@
 
 extern void router_id_add_address(struct connected *);
 extern void router_id_del_address(struct connected *);
-extern void router_id_init(void);
+extern void router_id_init(struct zebra_vrf *);
+extern void router_id_cmd_init(void);
 extern void router_id_write(struct vty *);
-extern void router_id_get(struct prefix *);
+extern void router_id_get(struct prefix *, vrf_id_t);
 
 #endif
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 85f448c..e17bb72 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -735,7 +735,8 @@
 
 /* Router-id is updated. Send ZEBRA_ROUTER_ID_ADD to client. */
 int
-zsend_router_id_update (struct zserv *client, struct prefix *p)
+zsend_router_id_update (struct zserv *client, struct prefix *p,
+    vrf_id_t vrf_id)
 {
   struct stream *s;
   int blen;
@@ -1181,9 +1182,9 @@
   /* Router-id information is needed. */
   client->ridinfo = 1;
 
-  router_id_get (&p);
+  router_id_get (&p, VRF_DEFAULT);
 
-  return zsend_router_id_update (client,&p);
+  return zsend_router_id_update (client, &p, VRF_DEFAULT);
 }
 
 /* Unregister zebra server router-id information. */
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 5e8bcca..eaa164b 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -106,7 +106,8 @@
 extern int zsend_interface_update (int, struct zserv *, struct interface *);
 extern int zsend_route_multipath (int, struct zserv *, struct prefix *, 
                                   struct rib *);
-extern int zsend_router_id_update(struct zserv *, struct prefix *);
+extern int zsend_router_id_update (struct zserv *, struct prefix *,
+                                   vrf_id_t);
 
 extern pid_t pid;