lib: move the interface list into "struct vrf"

An interface belongs to a specific VRF. So move the interface list
into the "struct vrf".

* vrf.c/vrf.h:
  - add a new member "struct list *iflist" to the the "struct vrf";
  - call if_init() in vrf_new();
  - call if_terminate() in vrf_delete();
  - add utilities to access the interface list and VRF ID in the
    specified VRF.

* if.c/if.h:
  - the global "iflist" now only exists for the default VRF;
  - the global "if_master" is initialized on the definition;
  - in if_create(), the interface is added into the list in the
    specified VRF; if the VRF does not exist, create one;
  - add parameters to if_init()/if_terminate() so that the
    interface list in the VRF can be initialized/destroyed;
  - in if_dump_all() scan the interfaces in all the VRFs;
  - add a command "show address vrf N" to show addresses in a
    specified VRF;
  - add a command "show address vrf all" to show addresses in all
    VRFs;
  - new APIs ifxxx_vrf() are added to access an interface in a
    specified VRF.

The old interface APIs (the global variable "iflist" and the API
functions) are not changed to keep the backward compatibility.
The new APIs are used in the daemons which support multiple VRFs
(till now only zebra).

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/lib/if.c b/lib/if.c
index f17e508..30da8a9 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -27,6 +27,7 @@
 #include "vector.h"
 #include "vty.h"
 #include "command.h"
+#include "vrf.h"
 #include "if.h"
 #include "sockunion.h"
 #include "prefix.h"
@@ -36,7 +37,7 @@
 #include "str.h"
 #include "log.h"
 
-/* Master list of interfaces. */
+/* List of interfaces in only the default VRF */
 struct list *iflist;
 
 /* One for each program.  This structure is needed to store hooks. */
@@ -44,7 +45,7 @@
 {
   int (*if_new_hook) (struct interface *);
   int (*if_delete_hook) (struct interface *);
-} if_master;
+} if_master = {0,};
 
 /* Compare interface names, returning an integer greater than, equal to, or
  * less than 0, (following the strcmp convention), according to the
@@ -113,9 +114,10 @@
 
 /* Create new interface structure. */
 struct interface *
-if_create (const char *name, int namelen)
+if_create_vrf (const char *name, int namelen, vrf_id_t vrf_id)
 {
   struct interface *ifp;
+  struct list *intf_list = vrf_iflist_get (vrf_id);
 
   ifp = XCALLOC (MTYPE_IF, sizeof (struct interface));
   ifp->ifindex = IFINDEX_INTERNAL;
@@ -124,11 +126,12 @@
   assert (namelen <= INTERFACE_NAMSIZ);	/* Need space for '\0' at end. */
   strncpy (ifp->name, name, namelen);
   ifp->name[namelen] = '\0';
-  if (if_lookup_by_name(ifp->name) == NULL)
-    listnode_add_sort (iflist, ifp);
+  ifp->vrf_id = vrf_id;
+  if (if_lookup_by_name_vrf (ifp->name, vrf_id) == NULL)
+    listnode_add_sort (intf_list, ifp);
   else
     zlog_err("if_create(%s): corruption detected -- interface with this "
-	     "name exists already!", ifp->name);
+             "name exists already in VRF %u!", ifp->name, vrf_id);
   ifp->connected = list_new ();
   ifp->connected->del = (void (*) (void *)) connected_free;
 
@@ -138,6 +141,12 @@
   return ifp;
 }
 
+struct interface *
+if_create (const char *name, int namelen)
+{
+  return if_create_vrf (name, namelen, VRF_DEFAULT);
+}
+
 /* Delete interface structure. */
 void
 if_delete_retain (struct interface *ifp)
@@ -153,7 +162,7 @@
 void
 if_delete (struct interface *ifp)
 {
-  listnode_delete (iflist, ifp);
+  listnode_delete (vrf_iflist (ifp->vrf_id), ifp);
 
   if_delete_retain(ifp);
 
@@ -180,12 +189,12 @@
 
 /* Interface existance check by index. */
 struct interface *
-if_lookup_by_index (unsigned int index)
+if_lookup_by_index_vrf (unsigned int index, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
 
-  for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       if (ifp->ifindex == index)
 	return ifp;
@@ -193,33 +202,51 @@
   return NULL;
 }
 
+struct interface *
+if_lookup_by_index (unsigned int index)
+{
+  return if_lookup_by_index_vrf (index, VRF_DEFAULT);
+}
+
 const char *
-ifindex2ifname (unsigned int index)
+ifindex2ifname_vrf (unsigned int index, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_index(index)) != NULL) ?
+  return ((ifp = if_lookup_by_index_vrf (index, vrf_id)) != NULL) ?
   	 ifp->name : "unknown";
 }
 
+const char *
+ifindex2ifname (unsigned int index)
+{
+  return ifindex2ifname_vrf (index, VRF_DEFAULT);
+}
+
+unsigned int
+ifname2ifindex_vrf (const char *name, vrf_id_t vrf_id)
+{
+  struct interface *ifp;
+
+  return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp->ifindex
+                                                   : IFINDEX_INTERNAL;
+}
+
 unsigned int
 ifname2ifindex (const char *name)
 {
-  struct interface *ifp;
-
-  return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp->ifindex
-                                                   : IFINDEX_INTERNAL;
+  return ifname2ifindex_vrf (name, VRF_DEFAULT);
 }
 
 /* Interface existance check by interface name. */
 struct interface *
-if_lookup_by_name (const char *name)
+if_lookup_by_name_vrf (const char *name, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
   
   if (name)
-    for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+    for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
       {
         if (strcmp(name, ifp->name) == 0)
           return ifp;
@@ -228,7 +255,13 @@
 }
 
 struct interface *
-if_lookup_by_name_len(const char *name, size_t namelen)
+if_lookup_by_name (const char *name)
+{
+  return if_lookup_by_name_vrf (name, VRF_DEFAULT);
+}
+
+struct interface *
+if_lookup_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct interface *ifp;
@@ -236,7 +269,7 @@
   if (namelen > INTERFACE_NAMSIZ)
     return NULL;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       if (!memcmp(name, ifp->name, namelen) && (ifp->name[namelen] == '\0'))
 	return ifp;
@@ -244,9 +277,15 @@
   return NULL;
 }
 
+struct interface *
+if_lookup_by_name_len(const char *name, size_t namelen)
+{
+  return if_lookup_by_name_len_vrf (name, namelen, VRF_DEFAULT);
+}
+
 /* Lookup interface by IPv4 address. */
 struct interface *
-if_lookup_exact_address (struct in_addr src)
+if_lookup_exact_address_vrf (struct in_addr src, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct listnode *cnode;
@@ -254,7 +293,7 @@
   struct prefix *p;
   struct connected *c;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
 	{
@@ -270,9 +309,15 @@
   return NULL;
 }
 
+struct interface *
+if_lookup_exact_address (struct in_addr src)
+{
+  return if_lookup_exact_address_vrf (src, VRF_DEFAULT);
+}
+
 /* Lookup interface by IPv4 address. */
 struct interface *
-if_lookup_address (struct in_addr src)
+if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct prefix addr;
@@ -288,7 +333,7 @@
 
   match = NULL;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
 	{
@@ -304,16 +349,22 @@
   return match;
 }
 
+struct interface *
+if_lookup_address (struct in_addr src)
+{
+  return if_lookup_address_vrf (src, VRF_DEFAULT);
+}
+
 /* Lookup interface by prefix */
 struct interface *
-if_lookup_prefix (struct prefix *prefix)
+if_lookup_prefix_vrf (struct prefix *prefix, vrf_id_t vrf_id)
 {
   struct listnode *node;
   struct listnode *cnode;
   struct interface *ifp;
   struct connected *c;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
         {
@@ -326,24 +377,42 @@
   return NULL;
 }
 
+struct interface *
+if_lookup_prefix (struct prefix *prefix)
+{
+  return if_lookup_prefix_vrf (prefix, VRF_DEFAULT);
+}
+
 /* Get interface by name if given name interface doesn't exist create
    one. */
 struct interface *
-if_get_by_name (const char *name)
+if_get_by_name_vrf (const char *name, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_name(name)) != NULL) ? ifp :
-	 if_create(name, strlen(name));
+  return ((ifp = if_lookup_by_name_vrf (name, vrf_id)) != NULL) ? ifp :
+         if_create_vrf (name, strlen(name), vrf_id);
 }
 
 struct interface *
-if_get_by_name_len(const char *name, size_t namelen)
+if_get_by_name (const char *name)
+{
+  return if_get_by_name_vrf (name, VRF_DEFAULT);
+}
+
+struct interface *
+if_get_by_name_len_vrf (const char *name, size_t namelen, vrf_id_t vrf_id)
 {
   struct interface *ifp;
 
-  return ((ifp = if_lookup_by_name_len(name, namelen)) != NULL) ? ifp :
-	 if_create(name, namelen);
+  return ((ifp = if_lookup_by_name_len_vrf (name, namelen, vrf_id)) != NULL) ? \
+         ifp : if_create_vrf (name, namelen, vrf_id);
+}
+
+struct interface *
+if_get_by_name_len (const char *name, size_t namelen)
+{
+  return if_get_by_name_len_vrf (name, namelen, VRF_DEFAULT);
 }
 
 /* Does interface up ? */
@@ -470,11 +539,15 @@
 void
 if_dump_all (void)
 {
+  struct list *intf_list;
   struct listnode *node;
   void *p;
+  vrf_iter_t iter;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, p))
-    if_dump (p);
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    if ((intf_list = vrf_iter2iflist (iter)) != NULL)
+      for (ALL_LIST_ELEMENTS_RO (intf_list, node, p))
+        if_dump (p);
 }
 
 DEFUN (interface_desc, 
@@ -534,12 +607,12 @@
  *     - no idea, just get the name in its entirety.
  */
 static struct interface *
-if_sunwzebra_get (const char *name, size_t nlen)
+if_sunwzebra_get (const char *name, size_t nlen, vrf_id_t vrf_id)
 {
   struct interface *ifp;
   size_t seppos = 0;
 
-  if ( (ifp = if_lookup_by_name_len(name, nlen)) != NULL)
+  if ( (ifp = if_lookup_by_name_len_vrf (name, nlen, vrf_id)) != NULL)
     return ifp;
   
   /* hunt the primary interface name... */
@@ -548,9 +621,9 @@
   
   /* Wont catch seperator as last char, e.g. 'foo0:' but thats invalid */
   if (seppos < nlen)
-    return if_get_by_name_len (name, seppos);
+    return if_get_by_name_len_vrf (name, seppos, vrf_id);
   else
-    return if_get_by_name_len (name, nlen);
+    return if_get_by_name_len_vrf (name, nlen, vrf_id);
 }
 #endif /* SUNOS_5 */
 
@@ -562,6 +635,7 @@
 {
   struct interface *ifp;
   size_t sl;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
   if ((sl = strlen(argv[0])) > INTERFACE_NAMSIZ)
     {
@@ -572,9 +646,9 @@
     }
 
 #ifdef SUNOS_5
-  ifp = if_sunwzebra_get (argv[0], sl);
+  ifp = if_sunwzebra_get (argv[0], sl, vrf_id);
 #else
-  ifp = if_get_by_name_len(argv[0], sl);
+  ifp = if_get_by_name_len_vrf (argv[0], sl, vrf_id);
 #endif /* SUNOS_5 */
 
   vty->index = ifp;
@@ -592,8 +666,9 @@
 {
   // deleting interface
   struct interface *ifp;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
-  ifp = if_lookup_by_name (argv[0]);
+  ifp = if_lookup_by_name_vrf (argv[0], vrf_id);
 
   if (ifp == NULL)
     {
@@ -625,8 +700,12 @@
   struct interface *ifp;
   struct connected *ifc;
   struct prefix *p;
+  vrf_id_t vrf_id = VRF_DEFAULT;
 
-  for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+  if (argc > 0)
+    VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
     {
       for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc))
 	{
@@ -640,6 +719,52 @@
   return CMD_SUCCESS;
 }
 
+ALIAS (show_address,
+       show_address_vrf_cmd,
+       "show address " VRF_CMD_STR,
+       SHOW_STR
+       "address\n"
+       VRF_CMD_HELP_STR)
+
+DEFUN (show_address_vrf_all,
+       show_address_vrf_all_cmd,
+       "show address " VRF_ALL_CMD_STR,
+       SHOW_STR
+       "address\n"
+       VRF_ALL_CMD_HELP_STR)
+{
+  struct list *intf_list;
+  struct listnode *node;
+  struct listnode *node2;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+  vrf_iter_t iter;
+
+  for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+    {
+      intf_list = vrf_iter2iflist (iter);
+      if (!intf_list || !listcount (intf_list))
+        continue;
+
+      vty_out (vty, "%sVRF %u%s%s", VTY_NEWLINE, vrf_iter2id (iter),
+               VTY_NEWLINE, VTY_NEWLINE);
+
+      for (ALL_LIST_ELEMENTS_RO (intf_list, node, ifp))
+        {
+          for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc))
+            {
+              p = ifc->address;
+
+              if (p->family == AF_INET)
+                vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen,
+                         VTY_NEWLINE);
+            }
+        }
+    }
+  return CMD_SUCCESS;
+}
+
 /* Allocate connected structure. */
 struct connected *
 connected_new (void)
@@ -886,35 +1011,36 @@
 
 /* Initialize interface list. */
 void
-if_init (void)
+if_init (vrf_id_t vrf_id, struct list **intf_list)
 {
-  iflist = list_new ();
+  *intf_list = list_new ();
 #if 0
   ifaddr_ipv4_table = route_table_init ();
 #endif /* ifaddr_ipv4_table */
 
-  if (iflist) {
-    iflist->cmp = (int (*)(void *, void *))if_cmp_func;
-    return;
-  }
+  (*intf_list)->cmp = (int (*)(void *, void *))if_cmp_func;
 
-  memset (&if_master, 0, sizeof if_master);
+  if (vrf_id == VRF_DEFAULT)
+    iflist = *intf_list;
 }
 
 void
-if_terminate (void)
+if_terminate (vrf_id_t vrf_id, struct list **intf_list)
 {
   for (;;)
     {
       struct interface *ifp;
 
-      ifp = listnode_head (iflist);
+      ifp = listnode_head (*intf_list);
       if (ifp == NULL)
 	break;
 
       if_delete (ifp);
     }
 
-  list_delete (iflist);
-  iflist = NULL;
+  list_delete (*intf_list);
+  *intf_list = NULL;
+
+  if (vrf_id == VRF_DEFAULT)
+    iflist = NULL;
 }