]> git.puffer.fish Git - mirror/frr.git/commitdiff
pimd: Add ability for ifchannel *,G to know their S,G's
authorDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 7 Nov 2016 19:33:54 +0000 (14:33 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 22 Dec 2016 01:26:14 +0000 (20:26 -0500)
Add the ability for pim ifchannels *,G's to know their
corresponding S,G's.  This will facilitate handling
S,G,rpt state information better.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_ifchannel.c
pimd/pim_ifchannel.h

index ecba4dd1b215b4a1a1ca121ff6ed4c5eb9b1022b..b83e8c17852c65d72bf482a576ff70c243af18b0 100644 (file)
@@ -46,41 +46,6 @@ struct list *pim_ifchannel_list = NULL;
 
 static void pim_if_igmp_join_del_all(struct interface *ifp);
 
-static int
-pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
-{
-  struct pim_interface *pim_ifp1;
-  struct pim_interface *pim_ifp2;
-
-  if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr))
-    return -1;
-
-  if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr))
-    return 1;
-
-  if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr))
-    return -1;
-
-  if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr))
-    return 1;
-
-  pim_ifp1 = ch1->interface->info;
-  pim_ifp2 = ch2->interface->info;
-  if (ntohl(pim_ifp1->primary_address.s_addr) < ntohl(pim_ifp2->primary_address.s_addr))
-    return -1;
-
-  if (ntohl(pim_ifp1->primary_address.s_addr) > ntohl(pim_ifp2->primary_address.s_addr))
-    return 1;
-
-  if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index)
-    return -1;
-
-  if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index)
-    return 1;
-
-  return 0;
-}
-
 void
 pim_if_init (void)
 {
index 9e8b177947c17aca572b34200d5ee33033e2a031..b1759c0da9f5c48aa6b534e23fccc2b59ac62a27 100644 (file)
@@ -174,4 +174,5 @@ void pim_if_update_assert_tracking_desired(struct interface *ifp);
 void pim_if_create_pimreg(void);
 
 int pim_if_connected_to_source (struct interface *ifp, struct in_addr src);
+
 #endif /* PIM_IFACE_H */
index 32e079831080c74bc09989f3d06aaaea2dbd0f4a..835ea424c55ca181033be8074b42b7fd9ec381e0 100644 (file)
 #include "pim_oil.h"
 #include "pim_upstream.h"
 
+int
+pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
+{
+  struct pim_interface *pim_ifp1;
+  struct pim_interface *pim_ifp2;
+
+  if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr))
+    return -1;
+
+  if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr))
+    return 1;
+
+  if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr))
+    return -1;
+
+  if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr))
+    return 1;
+
+  pim_ifp1 = ch1->interface->info;
+  pim_ifp2 = ch2->interface->info;
+  if (ntohl(pim_ifp1->primary_address.s_addr) < ntohl(pim_ifp2->primary_address.s_addr))
+    return -1;
+
+  if (ntohl(pim_ifp1->primary_address.s_addr) > ntohl(pim_ifp2->primary_address.s_addr))
+    return 1;
+
+  if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index)
+    return -1;
+
+  if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index)
+    return 1;
+
+  return 0;
+}
+
 /*
  * A (*,G) or a (*,*) is going away
  * remove the parent pointer from
 static void
 pim_ifchannel_remove_children (struct pim_ifchannel *ch)
 {
-  struct pim_interface *pim_ifp = ch->interface->info;
-  struct listnode *ch_node;
   struct pim_ifchannel *child;
 
-  // Basic sanity, (*,*) not currently supported
-  if ((ch->sg.src.s_addr == INADDR_ANY) &&
-      (ch->sg.grp.s_addr == INADDR_ANY))
-    return;
-
-  // Basic sanity (S,G) have no children
-  if ((ch->sg.src.s_addr != INADDR_ANY) &&
-      (ch->sg.grp.s_addr != INADDR_ANY))
+  if (!ch->sources)
     return;
 
-  for (ALL_LIST_ELEMENTS_RO (pim_ifp->pim_ifchannel_list, ch_node, child))
+  while (!list_isempty (ch->sources))
     {
-      if (child->parent == ch)
-       child->parent = NULL;
+      child = listnode_head (ch->sources);
+      child->parent = NULL;
+      listnode_delete (ch->sources, child);
     }
 }
 
@@ -96,16 +123,15 @@ pim_ifchannel_find_new_children (struct pim_ifchannel *ch)
       if ((ch->sg.grp.s_addr != INADDR_ANY) &&
          (child->sg.grp.s_addr == ch->sg.grp.s_addr) &&
          (child != ch))
-       child->parent = ch;
+       {
+         child->parent = ch;
+         listnode_add_sort (ch->sources, child);
+       }
     }
 }
 
 void pim_ifchannel_free(struct pim_ifchannel *ch)
 {
-  zassert(!ch->t_ifjoin_expiry_timer);
-  zassert(!ch->t_ifjoin_prune_pending_timer);
-  zassert(!ch->t_ifassert_timer);
-
   XFREE(MTYPE_PIM_IFCHANNEL, ch);
 }
 
@@ -114,7 +140,6 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
   struct pim_interface *pim_ifp;
 
   pim_ifp = ch->interface->info;
-  zassert(pim_ifp);
 
   /*
    * When this channel is removed
@@ -123,6 +148,9 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
    */
   pim_ifchannel_remove_children (ch);
 
+  if (ch->sources)
+    list_delete (ch->sources);
+
   if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
     pim_upstream_update_join_desired(ch->upstream);
   }
@@ -134,6 +162,11 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
   THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
   THREAD_OFF(ch->t_ifassert_timer);
 
+  if (ch->parent)
+    {
+      listnode_delete (ch->parent->sources, ch);
+      ch->parent = NULL;
+    }
   /*
     notice that listnode_delete() can't be moved
     into pim_ifchannel_free() because the later is
@@ -346,29 +379,24 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
  * if we have it.
  */
 static struct pim_ifchannel *
-pim_ifchannel_find_parent (struct interface *ifp,
-                          struct prefix_sg *sg)
+pim_ifchannel_find_parent (struct pim_ifchannel *ch)
 {
-  struct prefix_sg parent_sg = *sg;
-
-  // (*,*) || (S,*)
-  if (((sg->src.s_addr == INADDR_ANY) &&
-       (sg->grp.s_addr == INADDR_ANY)) ||
-      ((sg->src.s_addr != INADDR_ANY) &&
-       (sg->grp.s_addr == INADDR_ANY)))
-    return NULL;
+  struct prefix_sg parent_sg = ch->sg;
+  struct pim_ifchannel *parent = NULL;
 
   // (S,G)
-  if ((sg->src.s_addr != INADDR_ANY) &&
-      (sg->grp.s_addr != INADDR_ANY))
+  if ((parent_sg.src.s_addr != INADDR_ANY) &&
+      (parent_sg.grp.s_addr != INADDR_ANY))
     {
       parent_sg.src.s_addr = INADDR_ANY;
-      return pim_ifchannel_find (ifp, &parent_sg);
+      parent = pim_ifchannel_find (ch->interface, &parent_sg);
+
+      if (parent)
+       listnode_add (parent->sources, ch);
+      return parent;
     }
 
-  // (*,G) -- Not going to find anything currently
-  parent_sg.grp.s_addr = INADDR_ANY;
-  return pim_ifchannel_find (ifp, &parent_sg);
+  return NULL;
 }
 
 struct pim_ifchannel *
@@ -384,7 +412,6 @@ pim_ifchannel_add(struct interface *ifp,
     return ch;
 
   pim_ifp = ifp->info;
-  zassert(pim_ifp);
 
   up = pim_upstream_add(sg, NULL, flags, __PRETTY_FUNCTION__);
   if (!up) {
@@ -399,7 +426,8 @@ pim_ifchannel_add(struct interface *ifp,
     zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=%s on interface %s",
              __PRETTY_FUNCTION__,
              pim_str_sg_dump (sg), ifp->name);
-    
+
+    pim_upstream_del (up, __PRETTY_FUNCTION__);
     return NULL;
   }
 
@@ -407,7 +435,15 @@ pim_ifchannel_add(struct interface *ifp,
   ch->upstream                     = up;
   ch->interface                    = ifp;
   ch->sg                           = *sg;
-  ch->parent                       = pim_ifchannel_find_parent (ifp, sg);
+  ch->parent                       = pim_ifchannel_find_parent (ch);
+  if (ch->sg.src.s_addr == INADDR_ANY)
+    {
+      ch->sources = list_new ();
+      ch->sources->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
+    }
+  else
+    ch->sources = NULL;
+
   pim_ifchannel_find_new_children (ch);
   ch->local_ifmembership           = PIM_IFMEMBERSHIP_NOINFO;
 
index e98abfcf30c5c6ffb4b210622ea8c85b1f86784a..7791e6d950275321e3604e43ea7e595c6738fad8 100644 (file)
@@ -76,6 +76,7 @@ struct pim_assert_metric {
 */
 struct pim_ifchannel {
   struct pim_ifchannel     *parent;
+  struct list              *sources;
   struct prefix_sg          sg;
   struct interface         *interface;   /* backpointer to interface */
   uint32_t                  flags;
@@ -141,4 +142,6 @@ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch);
 void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch);
 
 void pim_ifchannel_scan_forward_start (struct interface *new_ifp);
+
+int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2);
 #endif /* PIM_IFCHANNEL_H */