]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_upstream.c
Merge remote-tracking branch 'origin/stable/3.0'
[mirror_frr.git] / pimd / pim_upstream.c
index b29e71a334c7736521931ed5e0ddb53685eeb0a2..1e31a3aba1e3459e200548632607ca833ee0200e 100644 (file)
@@ -53,6 +53,7 @@
 #include "pim_msdp.h"
 #include "pim_jp_agg.h"
 #include "pim_nht.h"
+#include "pim_ssm.h"
 
 struct hash *pim_upstream_hash = NULL;
 struct list *pim_upstream_list = NULL;
@@ -154,20 +155,20 @@ static void upstream_channel_oil_detach(struct pim_upstream *up)
   }
 }
 
-void
+struct pim_upstream *
 pim_upstream_del(struct pim_upstream *up, const char *name)
 {
   bool notify_msdp = false;
   struct prefix nht_p;
 
   if (PIM_DEBUG_TRACE)
-    zlog_debug ("%s(%s): Delete %s ref count: %d",
-               __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count);
+    zlog_debug ("%s(%s): Delete %s ref count: %d, flags: %d (Pre decrement)",
+               __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count, up->flags);
 
   --up->ref_count;
 
   if (up->ref_count >= 1)
-    return;
+    return up;
 
   THREAD_OFF(up->t_ka_timer);
   THREAD_OFF(up->t_rs_timer);
@@ -184,6 +185,7 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
   }
 
   join_timer_stop(up);
+  pim_jp_agg_upstream_verification (up, false);
   up->rpf.source_nexthop.interface = NULL;
 
   if (up->sg.src.s_addr != INADDR_ANY) {
@@ -196,9 +198,24 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
   upstream_channel_oil_detach(up);
 
   if (up->sources)
-    list_delete (up->sources);
+    {
+      struct listnode *node, *nnode;
+      struct pim_upstream *child;
+      for (ALL_LIST_ELEMENTS (up->sources, node, nnode, child))
+       {
+         if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags))
+           {
+             PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
+             pim_upstream_del(child, __PRETTY_FUNCTION__);
+           }
+       }
+
+      list_delete (up->sources);
+    }
   up->sources = NULL;
 
+  list_delete (up->ifchannels);
+
   /*
     notice that listnode_delete() can't be moved
     into pim_upstream_free() because the later is
@@ -225,12 +242,14 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
     {
       char buf[PREFIX2STR_BUFFER];
       prefix2str (&nht_p, buf, sizeof (buf));
-      zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ",
-                __PRETTY_FUNCTION__, up->sg_str, buf);
+      zlog_debug ("%s: Deregister upstream %s addr %s with Zebra",
+                  __PRETTY_FUNCTION__, up->sg_str, buf);
     }
   pim_delete_tracked_nexthop (&nht_p, up, NULL);
 
   pim_upstream_free (up);
+
+  return NULL;
 }
 
 void
@@ -285,13 +304,15 @@ static void join_timer_stop(struct pim_upstream *up)
 {
   struct pim_neighbor *nbr;
 
+  THREAD_OFF (up->t_join_timer);
+
   nbr = pim_neighbor_find (up->rpf.source_nexthop.interface,
                            up->rpf.rpf_addr.u.prefix4);
 
   if (nbr)
     pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
 
-  THREAD_OFF (up->t_join_timer);
+  pim_jp_agg_upstream_verification (up, false);
 }
 
 void
@@ -321,6 +342,7 @@ join_timer_start(struct pim_upstream *up)
                       on_join_timer,
                       up, qpim_t_periodic);
     }
+  pim_jp_agg_upstream_verification (up, true);
 }
 
 /*
@@ -332,13 +354,6 @@ join_timer_start(struct pim_upstream *up)
  */
 void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old)
 {
-  struct pim_neighbor *nbr;
-
-  nbr = pim_neighbor_find (old->source_nexthop.interface,
-                           old->rpf_addr.u.prefix4);
-  if (nbr)
-    pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
-
   //THREAD_OFF(up->t_join_timer);
   join_timer_start(up);
 }
@@ -426,18 +441,10 @@ static void forward_on(struct pim_upstream *up)
 {
   struct listnode      *chnode;
   struct listnode      *chnextnode;
-  struct pim_interface *pim_ifp;
-  struct pim_ifchannel *ch;
+  struct pim_ifchannel *ch = NULL;
 
   /* scan (S,G) state */
-  for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
-    pim_ifp = ch->interface->info;
-    if (!pim_ifp)
-      continue;
-
-    if (ch->upstream != up)
-      continue;
-
+  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
     if (pim_macro_chisin_oiflist(ch))
       pim_forward_start(ch);
 
@@ -448,17 +455,10 @@ static void forward_off(struct pim_upstream *up)
 {
   struct listnode      *chnode;
   struct listnode      *chnextnode;
-  struct pim_interface *pim_ifp;
   struct pim_ifchannel *ch;
 
   /* scan per-interface (S,G) state */
-  for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
-    pim_ifp = ch->interface->info;
-    if (!pim_ifp)
-      continue;
-
-    if (ch->upstream != up)
-      continue;
+  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
 
     pim_forward_stop(ch);
 
@@ -468,7 +468,15 @@ static void forward_off(struct pim_upstream *up)
 static int
 pim_upstream_could_register (struct pim_upstream *up)
 {
-  struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
+  struct pim_interface *pim_ifp = NULL;
+
+  if (up->rpf.source_nexthop.interface)
+    pim_ifp = up->rpf.source_nexthop.interface->info;
+  else
+    {
+      if (PIM_DEBUG_TRACE)
+        zlog_debug ("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str);
+    }
 
   if (pim_ifp && PIM_I_am_DR (pim_ifp) &&
       pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
@@ -477,6 +485,51 @@ pim_upstream_could_register (struct pim_upstream *up)
   return 0;
 }
 
+/* Source registration is supressed for SSM groups. When the SSM range changes
+ * we re-revaluate register setup for existing upstream entries */
+void
+pim_upstream_register_reevaluate (void)
+{
+  struct listnode *upnode;
+  struct pim_upstream *up;
+
+  for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, upnode, up))
+    {
+      /* If FHR is set CouldRegister is True. Also check if the flow
+       * is actually active; if it is not kat setup will trigger source
+       * registration whenever the flow becomes active. */
+      if (!PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) || !up->t_ka_timer)
+        continue;
+
+      if (pim_is_grp_ssm (up->sg.grp))
+        {
+          /* clear the register state  for SSM groups */
+          if (up->reg_state != PIM_REG_NOINFO)
+            {
+              if (PIM_DEBUG_PIM_EVENTS)
+                zlog_debug ("Clear register for %s as G is now SSM",
+                            up->sg_str);
+              /* remove regiface from the OIL if it is there*/
+              pim_channel_del_oif (up->channel_oil, pim_regiface,
+                                   PIM_OIF_FLAG_PROTO_PIM);
+              up->reg_state = PIM_REG_NOINFO;
+            }
+        }
+      else
+        {
+          /* register ASM sources with the RP */
+          if (up->reg_state == PIM_REG_NOINFO)
+            {
+              if (PIM_DEBUG_PIM_EVENTS)
+                zlog_debug ("Register %s as G is now ASM", up->sg_str);
+              pim_channel_add_oif (up->channel_oil, pim_regiface,
+                                   PIM_OIF_FLAG_PROTO_PIM);
+              up->reg_state = PIM_REG_JOIN;
+            }
+        }
+    }
+}
+
 void
 pim_upstream_switch(struct pim_upstream *up,
                    enum pim_upstream_state new_state)
@@ -508,9 +561,8 @@ pim_upstream_switch(struct pim_upstream *up,
             PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
             if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
               {
-                up->reg_state = PIM_REG_JOIN;
                 pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
-               pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+                pim_register_join (up);
               }
          }
        else
@@ -616,15 +668,25 @@ pim_upstream_new (struct prefix_sg *sg,
   up->rpf.rpf_addr.family                         = AF_INET;
   up->rpf.rpf_addr.u.prefix4.s_addr               = PIM_NET_INADDR_ANY;
 
+  up->ifchannels                 = list_new();
+  up->ifchannels->cmp            = (int (*)(void *, void *))pim_ifchannel_compare;
+
   if (up->sg.src.s_addr != INADDR_ANY)
     wheel_add_item (pim_upstream_sg_wheel, up);
 
   rpf_result = pim_rpf_update(up, NULL, 1);
   if (rpf_result == PIM_RPF_FAILURE) {
+    struct prefix nht_p;
+
     if (PIM_DEBUG_TRACE)
       zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
                   up->sg_str);
 
+    nht_p.family = AF_INET;
+    nht_p.prefixlen = IPV4_MAX_BITLEN;
+    nht_p.u.prefix4 = up->upstream_addr;
+    pim_delete_tracked_nexthop (&nht_p, up, NULL);
+
     if (up->parent)
       {
        listnode_delete (up->parent->sources, up);
@@ -643,10 +705,12 @@ pim_upstream_new (struct prefix_sg *sg,
     return NULL;
   }
 
-  pim_ifp = up->rpf.source_nexthop.interface->info;
-  if (pim_ifp)
-    up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
-
+  if (up->rpf.source_nexthop.interface)
+    {
+      pim_ifp = up->rpf.source_nexthop.interface->info;
+      if (pim_ifp)
+        up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
+    }
   listnode_add_sort(pim_upstream_list, up);
 
   if (PIM_DEBUG_TRACE)
@@ -692,7 +756,8 @@ pim_upstream_find_or_add(struct prefix_sg *sg,
   return up;
 }
 
-static void pim_upstream_ref(struct pim_upstream *up, int flags)
+void
+pim_upstream_ref(struct pim_upstream *up, int flags)
 {
   up->flags |= flags;
   ++up->ref_count;
@@ -716,10 +781,14 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
   if (PIM_DEBUG_TRACE)
     {
       if (up)
-       zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
+        {
+          char buf[PREFIX2STR_BUFFER];
+          prefix2str (&up->rpf.rpf_addr, buf, sizeof (buf));
+         zlog_debug("%s(%s): %s, iif %s found: %d: ref_count: %d",
                   __PRETTY_FUNCTION__, name,
-                  up->sg_str, found,
+                  up->sg_str, buf, found,
                   up->ref_count);
+        }
       else
        zlog_debug("%s(%s): (%s) failure to create",
                   __PRETTY_FUNCTION__, name,
@@ -729,28 +798,34 @@ struct pim_upstream *pim_upstream_add(struct prefix_sg *sg,
   return up;
 }
 
+/*
+ * Passed in up must be the upstream for ch.  starch is NULL if no
+ * information
+ */
 int
 pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
-                                             struct pim_ifchannel *ch)
+                                              struct pim_ifchannel *ch,
+                                              struct pim_ifchannel *starch)
 {
-  struct pim_upstream *parent = up->parent;
-
-  if (ch->upstream == up)
+  if (ch)
     {
-      if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
-       return 1;
-
       if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
-       return 0;
+        return 0;
+
+      if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
+        return 1;
     }
 
   /*
    * joins (*,G)
    */
-  if (parent && ch->upstream == parent)
+  if (starch)
     {
-      if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
-       return 1;
+      if (PIM_IF_FLAG_TEST_S_G_RPT (starch->upstream->flags))
+        return 0;
+
+      if (!pim_macro_ch_lost_assert (starch) && pim_macro_chisin_joins_or_include (starch))
+        return 1;
     }
 
   return 0;
@@ -781,20 +856,28 @@ pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
  */
 int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
 {
-  struct listnode      *chnode;
-  struct listnode      *chnextnode;
-  struct pim_interface *pim_ifp;
-  struct pim_ifchannel *ch;
+  struct interface     *ifp;
+  struct listnode      *node;
+  struct pim_ifchannel *ch, *starch;
+  struct pim_upstream  *starup = up->parent;
   int                  ret = 0;
 
-  /* scan per-interface (S,G) state */
-  for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
     {
-      pim_ifp = ch->interface->info;
-      if (!pim_ifp)
-       continue;
+      if (!ifp->info)
+        continue;
+
+      ch = pim_ifchannel_find (ifp, &up->sg);
 
-      ret += pim_upstream_evaluate_join_desired_interface (up, ch);
+      if (starup)
+        starch = pim_ifchannel_find (ifp, &starup->sg);
+      else
+        starch = NULL;
+
+      if (!ch && !starch)
+        continue;
+
+      ret += pim_upstream_evaluate_join_desired_interface (up, ch, starch);
     } /* scan iface channel list */
 
   return ret; /* false */
@@ -881,18 +964,9 @@ void pim_upstream_rpf_interface_changed(struct pim_upstream *up,
   struct listnode      *chnode;
   struct listnode      *chnextnode;
   struct pim_ifchannel *ch;
-  struct pim_interface *pim_ifp;
 
   /* search all ifchannels */
-  for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
-
-    pim_ifp = ch->interface->info;
-    if (!pim_ifp)
-      continue;
-
-    if (ch->upstream != up)
-      continue;
-
+  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
     if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
       if (
          /* RPF_interface(S) was NOT I */
@@ -913,18 +987,10 @@ void pim_upstream_update_could_assert(struct pim_upstream *up)
 {
   struct listnode      *chnode;
   struct listnode      *chnextnode;
-  struct pim_interface *pim_ifp;
   struct pim_ifchannel *ch;
 
   /* scan per-interface (S,G) state */
-  for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
-    pim_ifp = ch->interface->info;
-    if (!pim_ifp)
-      continue;
-
-    if (ch->upstream != up)
-      continue;
-
+  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
     pim_ifchannel_update_could_assert(ch);
   } /* scan iface channel list */
 }
@@ -933,18 +999,10 @@ void pim_upstream_update_my_assert_metric(struct pim_upstream *up)
 {
   struct listnode      *chnode;
   struct listnode      *chnextnode;
-  struct pim_interface *pim_ifp;
   struct pim_ifchannel *ch;
 
   /* scan per-interface (S,G) state */
-  for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
-    pim_ifp = ch->interface->info;
-    if (!pim_ifp)
-      continue;
-
-    if (ch->upstream != up)
-      continue;
-
+  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
     pim_ifchannel_update_my_assert_metric(ch);
 
   } /* scan iface channel list */
@@ -958,14 +1016,11 @@ static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
   struct pim_ifchannel *ch;
 
   /* scan per-interface (S,G) state */
-  for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
+  for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
     pim_ifp = ch->interface->info;
     if (!pim_ifp)
       continue;
 
-    if (ch->upstream != up)
-      continue;
-
     pim_ifchannel_update_assert_tracking_desired(ch);
 
   } /* scan iface channel list */
@@ -1001,10 +1056,8 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up)
       zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
 
     PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
-    if (up->reg_state == PIM_REG_NOINFO) {
-      pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
-      up->reg_state = PIM_REG_JOIN;
-    }
+    if (up->reg_state == PIM_REG_NOINFO)
+      pim_register_join (up);
   }
 }
 
@@ -1023,26 +1076,31 @@ pim_upstream_keep_alive_timer (struct thread *t)
   up->t_ka_timer = NULL;
 
   if (I_am_RP (up->sg.grp))
-  {
-    pim_br_clear_pmbr (&up->sg);
-    /*
-     * We need to do more here :)
-     * But this is the start.
-     */
-  }
+    {
+      pim_br_clear_pmbr (&up->sg);
+      /*
+       * We need to do more here :)
+       * But this is the start.
+       */
+    }
 
   /* source is no longer active - pull the SA from MSDP's cache */
   pim_msdp_sa_local_del(&up->sg);
 
   /* if entry was created because of activity we need to deref it */
   if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
-  {
-    pim_upstream_fhr_kat_expiry(up);
-    if (PIM_DEBUG_TRACE)
-      zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
-    PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
-    pim_upstream_del(up, __PRETTY_FUNCTION__);
-  }
+    {
+      pim_upstream_fhr_kat_expiry(up);
+      if (PIM_DEBUG_TRACE)
+       zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
+      PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
+      pim_upstream_del(up, __PRETTY_FUNCTION__);
+    }
+  else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
+    {
+      PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
+      pim_upstream_del(up, __PRETTY_FUNCTION__);
+    }
 
   return 0;
 }
@@ -1132,11 +1190,10 @@ pim_upstream_is_sg_rpt (struct pim_upstream *up)
   struct listnode *chnode;
   struct pim_ifchannel *ch;
 
-  for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch))
+  for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch))
     {
-      if ((ch->upstream == up) &&
-         (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)))
-       return 1;
+      if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
+        return 1;
     }
 
   return 0;
@@ -1355,31 +1412,48 @@ pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_regist
 int
 pim_upstream_inherited_olist_decide (struct pim_upstream *up)
 {
-  struct pim_interface *pim_ifp;
-  struct listnode *chnextnode;
-  struct pim_ifchannel *ch;
-  struct listnode *chnode;
+  struct interface *ifp;
+  struct pim_interface *pim_ifp = NULL;
+  struct pim_ifchannel *ch, *starch;
+  struct listnode *node;
+  struct pim_upstream *starup = up->parent;
   int output_intf = 0;
 
-  pim_ifp = up->rpf.source_nexthop.interface->info;
+  if (up->rpf.source_nexthop.interface)
+    pim_ifp = up->rpf.source_nexthop.interface->info;
+  else
+    {
+      if (PIM_DEBUG_TRACE)
+        zlog_debug ("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str);
+    }
   if (pim_ifp && !up->channel_oil)
     up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
 
-  for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
+  for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
     {
-      pim_ifp = ch->interface->info;
-      if (!pim_ifp)
-       continue;
+      if (!ifp->info)
+        continue;
 
-      if (pim_upstream_evaluate_join_desired_interface (up, ch))
-       {
+      ch = pim_ifchannel_find (ifp, &up->sg);
+
+      if (starup)
+        starch = pim_ifchannel_find (ifp, &starup->sg);
+      else
+        starch = NULL;
+
+      if (!ch && !starch)
+        continue;
+
+      if (pim_upstream_evaluate_join_desired_interface (up, ch, starch))
+        {
           int flag = PIM_OIF_FLAG_PROTO_PIM;
 
-          if (ch->sg.src.s_addr == INADDR_ANY && ch->upstream != up)
+          if (!ch)
             flag = PIM_OIF_FLAG_PROTO_STAR;
-          pim_channel_add_oif (up->channel_oil, ch->interface, flag);
-         output_intf++;
-       }
+
+          pim_channel_add_oif (up->channel_oil, ifp, flag);
+          output_intf++;
+        }
     }
 
   return output_intf;
@@ -1573,28 +1647,108 @@ pim_upstream_sg_running (void *arg)
       return;
     }
 
-  if (pim_upstream_kat_start_ok(up)) {
-    /* Add a source reference to the stream if
-     * one doesn't already exist */
-    if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+  if (pim_upstream_kat_start_ok(up))
     {
-      if (PIM_DEBUG_TRACE)
-        zlog_debug ("source reference created on kat restart %s", up->sg_str);
+      /* Add a source reference to the stream if
+       * one doesn't already exist */
+      if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+       {
+         if (PIM_DEBUG_TRACE)
+           zlog_debug ("source reference created on kat restart %s", up->sg_str);
 
-      pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
-      PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
-      pim_upstream_fhr_kat_start(up);
+         pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
+         PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
+         pim_upstream_fhr_kat_start(up);
+       }
+      pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
     }
+  else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
     pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
-  }
 
   if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
-  {
-    pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
-  }
+    {
+      pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
+    }
   return;
 }
 
+void
+pim_upstream_add_lhr_star_pimreg (void)
+{
+  struct pim_upstream *up;
+  struct listnode *node;
+
+  for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+    {
+      if (up->sg.src.s_addr != INADDR_ANY)
+        continue;
+
+      if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+        continue;
+
+      pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+    }
+}
+
+void
+pim_upstream_spt_prefix_list_update (struct prefix_list *pl)
+{
+  const char *pname = prefix_list_name (pl);
+
+  if (pimg->spt.plist && strcmp (pimg->spt.plist, pname) == 0)
+    {
+      pim_upstream_remove_lhr_star_pimreg (pname);
+    }
+}
+
+/*
+ * nlist -> The new prefix list
+ *
+ * Per Group Application of pimreg to the OIL
+ * If the prefix list tells us DENY then
+ * we need to Switchover to SPT immediate
+ * so add the pimreg.
+ * If the prefix list tells us to ACCEPT than
+ * we need to Never do the SPT so remove
+ * the interface
+ *
+ */
+void
+pim_upstream_remove_lhr_star_pimreg (const char *nlist)
+{
+  struct pim_upstream *up;
+  struct listnode *node;
+  struct prefix_list *np;
+  struct prefix g;
+  enum prefix_list_type apply_new;
+
+  np = prefix_list_lookup (AFI_IP, nlist);
+
+  g.family = AF_INET;
+  g.prefixlen = IPV4_MAX_PREFIXLEN;
+
+  for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+    {
+      if (up->sg.src.s_addr != INADDR_ANY)
+        continue;
+
+      if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+        continue;
+
+      if (!nlist)
+        {
+          pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+          continue;
+        }
+      g.u.prefix4 = up->sg.grp;
+      apply_new = prefix_list_apply (np, &g);
+      if (apply_new == PREFIX_DENY)
+        pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+      else
+        pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+    }
+}
+
 void
 pim_upstream_init (void)
 {