ospf6d: add SNMP support for ospfv3*LsdbTable

This includes:
 - ospfv3AsLsdbTable
 - ospfv3AreaLsdbTable
 - ospfv3LinkLsdbTable
diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c
index 1880fc0..ce49331 100644
--- a/ospf6d/ospf6_snmp.c
+++ b/ospf6d/ospf6_snmp.c
@@ -90,26 +90,20 @@
 #define OSPFv3AREASTUBMETRICTYPE        15
 #define OSPFv3AREATEENABLED             16
 
-/* OSPFv3 MIB AS Lsdb Table values: ospfv3AsLsdbTable */
-#define OSPFv3ASLSDBSEQUENCE             4
-#define OSPFv3ASLSDBAGE                  5
-#define OSPFv3ASLSDBCHECKSUM             6
-#define OSPFv3ASLSDBADVERTISEMENT        7
-#define OSPFv3ASLSDBTYPEKNOWN            8
+/* OSPFv3 MIB * Lsdb Table values: ospfv3*LsdbTable */
+#define OSPFv3WWLSDBSEQUENCE             1
+#define OSPFv3WWLSDBAGE                  2
+#define OSPFv3WWLSDBCHECKSUM             3
+#define OSPFv3WWLSDBADVERTISEMENT        4
+#define OSPFv3WWLSDBTYPEKNOWN            5
 
-/* OSPFv3 MIB Area Lsdb Table values: ospfv3AreaLsdbTable */
-#define OSPFv3AREALSDBSEQUENCE           5
-#define OSPFv3AREALSDBAGE                6
-#define OSPFv3AREALSDBCHECKSUM           7
-#define OSPFv3AREALSDBADVERTISEMENT      8
-#define OSPFv3AREALSDBTYPEKNOWN          9
-
-/* OSPFv3 MIB Link Lsdb Table values: ospfv3LinkLsdbTable */
-#define OSPFv3LINKLSDBSEQUENCE           6
-#define OSPFv3LINKLSDBAGE                7
-#define OSPFv3LINKLSDBCHECKSUM           8
-#define OSPFv3LINKLSDBADVERTISEMENT      9
-#define OSPFv3LINKLSDBTYPEKNOWN         10
+/* Three first bits are to identify column */
+#define OSPFv3WWCOLUMN 0x7
+/* Then we use other bits to identify table */
+#define OSPFv3WWASTABLE   (1 << 3)
+#define OSPFv3WWAREATABLE (1 << 4)
+#define OSPFv3WWLINKTABLE (1 << 5)
+#define OSPFv3WWVIRTLINKTABLE (1 << 6)
 
 /* OSPFv3 MIB Host Table values: ospfv3HostTable */
 #define OSPFv3HOSTMETRIC                 3
@@ -192,13 +186,6 @@
 #define OSPFv3AREAAGGREGATEEFFECT     7
 #define OSPFv3AREAAGGREGATEROUTETAG   8
 
-/* OSPFv3 MIB Virtual Link Lsdb Table values: ospfv3VirtLinkLsdbTable */
-#define OSPFv3VIRTLINKLSDBSEQUENCE       6
-#define OSPFv3VIRTLINKLSDBAGE            7
-#define OSPFv3VIRTLINKLSDBCHECKSUM       8
-#define OSPFv3VIRTLINKLSDBADVERTISEMENT  9
-#define OSPFv3VIRTLINKLSDBTYPEKNOWN     10
-
 /* SYNTAX Status from OSPF-MIB. */
 #define OSPF_STATUS_ENABLED  1
 #define OSPF_STATUS_DISABLED 2
@@ -223,8 +210,8 @@
 				   int, size_t *, WriteMethod **);
 static u_char *ospfv3AreaEntry (struct variable *, oid *, size_t *,
 				int, size_t *, WriteMethod **);
-static u_char *ospfv3AreaLsdbEntry (struct variable *, oid *, size_t *,
-				    int, size_t *, WriteMethod **);
+static u_char *ospfv3WwLsdbEntry (struct variable *, oid *, size_t *,
+				  int, size_t *, WriteMethod **);
 static u_char *ospfv3NbrEntry (struct variable *, oid *, size_t *,
 			       int, size_t *, WriteMethod **);
 static u_char *ospfv3IfEntry (struct variable *, oid *, size_t *,
@@ -316,18 +303,42 @@
   {OSPFv3AREATEENABLED,         INTEGER, RWRITE, ospfv3AreaEntry,
    4, {1, 2, 1, 16}},
 
+  /* OSPFv3 AS LSDB */
+  {OSPFv3WWLSDBSEQUENCE | OSPFv3WWASTABLE,      INTEGER,   RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 3, 1, 4}},
+  {OSPFv3WWLSDBAGE | OSPFv3WWASTABLE,           UNSIGNED,  RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 3, 1, 5}},
+  {OSPFv3WWLSDBCHECKSUM | OSPFv3WWASTABLE,      INTEGER,   RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 3, 1, 6}},
+  {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWASTABLE, STRING,    RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 3, 1, 7}},
+  {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWASTABLE,     INTEGER,   RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 3, 1, 8}},
+
   /* OSPFv3 Area LSDB */
-  {OSPFv3AREALSDBSEQUENCE,      INTEGER,   RONLY,  ospfv3AreaLsdbEntry,
+  {OSPFv3WWLSDBSEQUENCE | OSPFv3WWAREATABLE,      INTEGER,   RONLY,  ospfv3WwLsdbEntry,
    4, {1, 4, 1, 5}},
-  {OSPFv3AREALSDBAGE,          UNSIGNED,   RONLY,  ospfv3AreaLsdbEntry,
+  {OSPFv3WWLSDBAGE | OSPFv3WWAREATABLE,           UNSIGNED,  RONLY,  ospfv3WwLsdbEntry,
    4, {1, 4, 1, 6}},
-  {OSPFv3AREALSDBCHECKSUM,      INTEGER,   RONLY,  ospfv3AreaLsdbEntry,
+  {OSPFv3WWLSDBCHECKSUM | OSPFv3WWAREATABLE,      INTEGER,   RONLY,  ospfv3WwLsdbEntry,
    4, {1, 4, 1, 7}},
-  {OSPFv3AREALSDBADVERTISEMENT, STRING,    RONLY,  ospfv3AreaLsdbEntry,
+  {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWAREATABLE, STRING,    RONLY,  ospfv3WwLsdbEntry,
    4, {1, 4, 1, 8}},
-  {OSPFv3AREALSDBTYPEKNOWN,     INTEGER,   RONLY,  ospfv3AreaLsdbEntry,
+  {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWAREATABLE,     INTEGER,   RONLY,  ospfv3WwLsdbEntry,
    4, {1, 4, 1, 9}},
 
+  /* OSPFv3 Link LSDB */
+  {OSPFv3WWLSDBSEQUENCE | OSPFv3WWLINKTABLE,      INTEGER,   RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 5, 1, 6}},
+  {OSPFv3WWLSDBAGE | OSPFv3WWLINKTABLE,           UNSIGNED,  RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 5, 1, 7}},
+  {OSPFv3WWLSDBCHECKSUM | OSPFv3WWLINKTABLE,      INTEGER,   RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 5, 1, 8}},
+  {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWLINKTABLE, STRING,    RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 5, 1, 9}},
+  {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWLINKTABLE,     INTEGER,   RONLY,  ospfv3WwLsdbEntry,
+   4, {1, 5, 1, 10}},
+
   /* OSPFv3 interfaces */
   {OSPFv3IFAREAID,             UNSIGNED, RONLY, ospfv3IfEntry,
    4, {1, 7, 1, 3}},
@@ -596,12 +607,18 @@
   return NULL;
 }
 
+static int
+if_icmp_func (struct interface *ifp1, struct interface *ifp2)
+{
+  return (ifp1->ifindex - ifp2->ifindex);
+}
+
 static u_char *
-ospfv3AreaLsdbEntry (struct variable *v, oid *name, size_t *length,
+ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length,
                      int exact, size_t *var_len, WriteMethod **write_method)
 {
   struct ospf6_lsa *lsa = NULL;
-  u_int32_t area_id, id, adv_router;
+  u_int32_t ifindex, area_id, id, instid, adv_router;
   u_int16_t type;
   int len;
   oid *offset;
@@ -609,12 +626,15 @@
   char a[16], b[16], c[16];
   struct ospf6_area *oa;
   struct listnode *node;
+  struct interface *iif;
+  struct ospf6_interface *oi = NULL;
+  struct list *ifslist;
 
   if (smux_header_table(v, name, length, exact, var_len, write_method)
       == MATCH_FAILED)
     return NULL;
 
-  area_id = type = id = adv_router = 0;
+  instid = ifindex = area_id = type = id = adv_router = 0;
 
   /* Check OSPFv3 instance. */
   if (ospf6 == NULL)
@@ -624,17 +644,38 @@
   offset = name + v->namelen;
   offsetlen = *length - v->namelen;
 
-#define OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET 4
-
-  if (exact && offsetlen != OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET)
+  if (exact && (v->magic & OSPFv3WWASTABLE) && offsetlen != 3)
+    return NULL;
+  if (exact && (v->magic & OSPFv3WWAREATABLE) && offsetlen != 4)
+    return NULL;
+  if (exact && (v->magic & OSPFv3WWLINKTABLE) && offsetlen != 5)
     return NULL;
 
-  /* Parse area-id */
-  len = (offsetlen < 1 ? 0 : 1);
-  if (len)
-    area_id = htonl (*offset);
-  offset += len;
-  offsetlen -= len;
+  if (v->magic & OSPFv3WWLINKTABLE)
+    {
+      /* Parse ifindex */
+      len = (offsetlen < 1 ? 0 : 1);
+      if (len)
+        ifindex = *offset;
+      offset += len;
+      offsetlen -= len;
+
+      /* Parse instance ID */
+      len = (offsetlen < 1 ? 0 : 1);
+      if (len)
+        instid = *offset;
+      offset += len;
+      offsetlen -= len;
+    }
+  else if (v->magic & OSPFv3WWAREATABLE)
+    {
+      /* Parse area-id */
+      len = (offsetlen < 1 ? 0 : 1);
+      if (len)
+        area_id = htonl (*offset);
+      offset += len;
+      offsetlen -= len;
+    }
 
   /* Parse type */
   len = (offsetlen < 1 ? 0 : 1);
@@ -657,52 +698,102 @@
   offset += len;
   offsetlen -= len;
 
-  inet_ntop (AF_INET, &area_id, a, sizeof (a));
-  inet_ntop (AF_INET, &adv_router, b, sizeof (b));
-  inet_ntop (AF_INET, &id, c, sizeof (c));
-  zlog_debug ("SNMP access by lsdb: area=%s exact=%d length=%lu magic=%d"
-	      " type=%#x adv_router=%s id=%s",
-	      a, exact, (u_long)*length, v->magic, ntohs (type), b, c);
-
   if (exact)
     {
-      oa = ospf6_area_lookup (area_id, ospf6);
-      lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb);
+      if (v->magic & OSPFv3WWASTABLE)
+        {
+          lsa = ospf6_lsdb_lookup (type, id, adv_router, ospf6->lsdb);
+        }
+      else if (v->magic & OSPFv3WWAREATABLE)
+        {
+          oa = ospf6_area_lookup (area_id, ospf6);
+          lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb);
+        }
+      else if (v->magic & OSPFv3WWLINKTABLE)
+        {
+          oi = ospf6_interface_lookup_by_ifindex (ifindex);
+          if (oi->instance_id != instid) return NULL;
+          lsa = ospf6_lsdb_lookup (type, id, adv_router, oi->lsdb);
+        }
     }
   else
     {
-      for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
-        {
-          if (lsa)
-            continue;
-          if (oa->area_id < area_id)
-            continue;
+      if (v->magic & OSPFv3WWASTABLE)
+	{
+	  if (ospf6->lsdb->count)
+	    lsa = ospf6_lsdb_lookup_next (type, id, adv_router,
+					  ospf6->lsdb);
+	}
+      else if (v->magic & OSPFv3WWAREATABLE)
+	for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa))
+          {
+            if (oa->area_id < area_id)
+              continue;
 
-          lsa = ospf6_lsdb_lookup_next (type, id, adv_router,
-                                        oa->lsdb);
-          if (! lsa)
+            if (oa->lsdb->count)
+              lsa = ospf6_lsdb_lookup_next (type, id, adv_router,
+                                            oa->lsdb);
+            if (lsa) break;
+            type = 0;
+            id = 0;
+            adv_router = 0;
+          }
+      else if (v->magic & OSPFv3WWLINKTABLE)
+        {
+          /* We build a sorted list of interfaces */
+          ifslist = list_new ();
+          if (!ifslist) return NULL;
+          ifslist->cmp = (int (*)(void *, void *))if_icmp_func;
+          for (ALL_LIST_ELEMENTS_RO (iflist, node, iif))
+            listnode_add_sort (ifslist, iif);
+          
+          for (ALL_LIST_ELEMENTS_RO (ifslist, node, iif))
             {
+              if (!iif->ifindex) continue;
+              oi = ospf6_interface_lookup_by_ifindex (iif->ifindex);
+              if (!oi) continue;
+              if (iif->ifindex < ifindex) continue;
+              if (oi->instance_id < instid) continue;
+              
+              if (oi->lsdb->count)
+                lsa = ospf6_lsdb_lookup_next (type, id, adv_router,
+                                            oi->lsdb);
+              if (lsa) break;
               type = 0;
-	      id = 0;
-	      adv_router = 0;
+              id = 0;
+              adv_router = 0;
+              oi = NULL;
             }
+
+          list_delete_all_node (ifslist);
         }
     }
 
   if (! lsa)
-    {
-      zlog_debug ("SNMP respond: No LSA to return");
       return NULL;
+
+  /* Add indexes */
+  if (v->magic & OSPFv3WWASTABLE)
+    {
+      *length = v->namelen + 3;
+      offset = name + v->namelen;
     }
-  oa = OSPF6_AREA (lsa->lsdb->data);
-
-  zlog_debug ("SNMP respond: area: %s lsa: %s", oa->name, lsa->name);
-
-  /* Add Index (AreaId, Type, RouterId, Lsid) */
-  *length = v->namelen + OSPFV3_AREA_LSDB_ENTRY_EXACT_OFFSET;
-  offset = name + v->namelen;
-  *offset = ntohl (oa->area_id);
-  offset++;
+  else if (v->magic & OSPFv3WWAREATABLE)
+    {
+      *length = v->namelen + 4;
+      offset = name + v->namelen;
+      *offset = ntohl (oa->area_id);
+      offset++;
+    }
+  else if (v->magic & OSPFv3WWLINKTABLE)
+    {
+      *length = v->namelen + 5;
+      offset = name + v->namelen;
+      *offset = oi->interface->ifindex;
+      offset++;
+      *offset = oi->instance_id;
+      offset++;
+    }
   *offset = ntohs (lsa->header->type);
   offset++;
   *offset = ntohl (lsa->header->adv_router);
@@ -711,23 +802,23 @@
   offset++;
 
   /* Return the current value of the variable */
-  switch (v->magic)
+  switch (v->magic & OSPFv3WWCOLUMN)
     {
-    case OSPFv3AREALSDBSEQUENCE:
+    case OSPFv3WWLSDBSEQUENCE:
       return SNMP_INTEGER (ntohl (lsa->header->seqnum));
       break;
-    case OSPFv3AREALSDBAGE:
+    case OSPFv3WWLSDBAGE:
       ospf6_lsa_age_current (lsa);
       return SNMP_INTEGER (ntohs (lsa->header->age));
       break;
-    case OSPFv3AREALSDBCHECKSUM:
+    case OSPFv3WWLSDBCHECKSUM:
       return SNMP_INTEGER (ntohs (lsa->header->checksum));
       break;
-    case OSPFv3AREALSDBADVERTISEMENT:
+    case OSPFv3WWLSDBADVERTISEMENT:
       *var_len = ntohs (lsa->header->length);
       return (u_char *) lsa->header;
       break;
-    case OSPFv3AREALSDBTYPEKNOWN:
+    case OSPFv3WWLSDBTYPEKNOWN:
       return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ?
                            SNMP_TRUE : SNMP_FALSE);
       break;
@@ -735,12 +826,6 @@
   return NULL;
 }
 
-static int
-if_icmp_func (struct interface *ifp1, struct interface *ifp2)
-{
-  return (ifp1->ifindex - ifp2->ifindex);
-}
-
 static u_char *
 ospfv3IfEntry (struct variable *v, oid *name, size_t *length,
 		int exact, size_t *var_len, WriteMethod **write_method)