]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pim-msdp: part-3: use SA cache for setting up SPTs
authoranuradhak <anuradhak@cumulusnetworks.com>
Tue, 8 Nov 2016 18:34:31 +0000 (10:34 -0800)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 22 Dec 2016 01:26:15 +0000 (20:26 -0500)
1. Added a new MSDP source reference flag for creating (S,G) entries
based on the SA-cache. The RFC recommends treating as SA like rxing
a (S, G) join (which is a bit different then treating like a traffic
stream).
2. SA-SPT is only setup if we are RP for the group and a corresponding
(*,G) exists with a non-empty OIL.
3. When an SA is moved we need to let the SPT live if it is active (this
change will come in a subsequent CL).

Testing done:
1. SA first; SPT setup whenever (*, G) comes around.
2. (*, G) first. As soon as SA is added SPT is setup.
3. (*, G) del with valid SA entries around.

Ticket: CM-13306

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
pimd/pim_cmd.c
pimd/pim_msdp.c
pimd/pim_msdp.h
pimd/pim_msdp_packet.c
pimd/pim_register.c
pimd/pim_rp.c
pimd/pim_upstream.c
pimd/pim_upstream.h

index 5b5bf8235d1b6b3a3672aa89077937d51e519822..03856bdfcf19a6c8a823b370ec7012fb50294be9 100644 (file)
@@ -1603,6 +1603,10 @@ json_object_pim_upstream_add (json_object *json, struct pim_upstream *up)
 
   if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
     json_object_boolean_true_add(json, "sourceStream");
+
+  /* XXX: need to print ths flag in the plain text display as well */
+  if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
+    json_object_boolean_true_add(json, "sourceMsdp");
 }
 
 static void pim_show_upstream(struct vty *vty, u_char uj)
@@ -5294,13 +5298,14 @@ ip_msdp_show_sa(struct vty *vty, u_char uj)
   char grp_str[INET_ADDRSTRLEN];
   char rp_str[INET_ADDRSTRLEN];
   char timebuf[PIM_MSDP_UPTIME_STRLEN];
+  char spt_str[2];
   int64_t now;
 
   if (uj) {
     // XXX: blah
     return;
   } else {
-    vty_out(vty, "Source                     Group               RP    Uptime%s", VTY_NEWLINE);
+    vty_out(vty, "Source                     Group               RP  SPT    Uptime%s", VTY_NEWLINE);
     for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
       now = pim_time_monotonic_sec();
       pim_time_uptime(timebuf, sizeof(timebuf), now - sa->uptime);
@@ -5308,11 +5313,17 @@ ip_msdp_show_sa(struct vty *vty, u_char uj)
       pim_inet4_dump("<grp?>", sa->sg.grp, grp_str, sizeof(grp_str));
       if (sa->flags & PIM_MSDP_SAF_LOCAL) {
         strcpy(rp_str, "local");
+        strcpy(spt_str, "-");
       } else {
         pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
+        if (sa->up) {
+          strcpy(spt_str, "y");
+        } else {
+          strcpy(spt_str, "n");
+        }
       }
-      vty_out(vty, "%-15s  %15s  %15s  %8s%s",
-          src_str, grp_str, rp_str, timebuf, VTY_NEWLINE);
+      vty_out(vty, "%-15s  %15s  %15s  %3s  %8s%s",
+          src_str, grp_str, rp_str, spt_str, timebuf, VTY_NEWLINE);
     }
   }
 }
index d8237469c879db7e47dbe8ece92d6c1125505b26..8e933222c6e9430ab122ec991d06288b97635d59 100644 (file)
@@ -82,6 +82,7 @@ pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa, const char *timer_str)
 static int
 pim_msdp_sa_adv_timer_cb(struct thread *t)
 {
+  msdp->sa_adv_timer = NULL;
   if (PIM_DEBUG_MSDP_INTERNAL) {
     zlog_debug("MSDP SA advertisment timer expired");
   }
@@ -107,6 +108,7 @@ pim_msdp_sa_state_timer_cb(struct thread *t)
   struct pim_msdp_sa *sa;
 
   sa = THREAD_ARG(t);
+  sa->sa_state_timer = NULL;
 
   if (PIM_DEBUG_MSDP_EVENTS) {
     pim_msdp_sa_timer_expiry_log(sa, "state");
@@ -125,6 +127,134 @@ pim_msdp_sa_state_timer_setup(struct pim_msdp_sa *sa, bool start)
   }
 }
 
+static void
+pim_msdp_sa_upstream_del(struct pim_msdp_sa *sa)
+{
+  struct pim_upstream *up = sa->up;
+  if (!up) {
+    return;
+  }
+
+  sa->up = NULL;
+  /* XXX: we can't pull the plug on an active flow even if the SA entry is
+   * removed. so ideally we want to start the kat in parallel and let the
+   * entry age out; but running the kat has fatal consequences. need to
+   * check with Donald on the best way to go abt this */
+  if (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags)) {
+    PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(up->flags);
+    pim_upstream_del(up, __PRETTY_FUNCTION__);
+  }
+
+  if (PIM_DEBUG_MSDP_EVENTS) {
+    char key_str[PIM_MSDP_SA_KEY_STRLEN];
+    pim_msdp_sa_key_dump(sa, key_str, sizeof(key_str), true);
+    zlog_debug("%s de-referenced SPT", key_str);
+  }
+}
+
+static bool
+pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, struct pim_upstream *xg_up)
+{
+  if (sa->flags & PIM_MSDP_SAF_LOCAL) {
+    /* if there is a local reference we should NEVER use it for setting up
+     * SPTs otherwise we will get stuck in a simple circular deadlock */
+    return false;
+  }
+
+  if (!(sa->flags & PIM_MSDP_SAF_PEER)) {
+    /* SA should have been rxed from a peer */
+    return false;
+  }
+  /* check if we are RP */
+  if (!I_am_RP(sa->sg.grp)) {
+    return false;
+  }
+
+  /* check if we have a (*, G) with a non-empty immediate OIL */
+  if (!xg_up) {
+    struct prefix_sg sg;
+
+    memset(&sg, 0, sizeof(sg));
+    sg.grp = sa->sg.grp;
+
+    xg_up = pim_upstream_find(&sg);
+  }
+  if (!xg_up || (xg_up->join_state != PIM_UPSTREAM_JOINED)) {
+    /* join desired will be true for such (*, G) entries so we will
+     * just look at join_state and let the PIM state machine do the rest of
+     * the magic */
+    return false;
+  }
+
+  return true;
+}
+
+/* Upstream add evaluation needs to happen everytime -
+ * 1. Peer reference is added or removed.
+ * 2. Local reference is added or removed.
+ * 3. The RP for a group changes.
+ * 4. joinDesired for the associated (*, G) changes
+ * 5. associated (*, G) is removed - this seems like a bit redundant
+ *    (considering #4); but just in case an entry gets nuked without
+ *    upstream state transition
+ *    */
+static void
+pim_msdp_sa_upstream_update(struct pim_msdp_sa *sa,
+                            struct pim_upstream *xg_up, const char *ctx)
+{
+  struct pim_upstream *up;
+  char key_str[PIM_MSDP_SA_KEY_STRLEN];
+
+  if (PIM_DEBUG_MSDP_EVENTS || PIM_DEBUG_MSDP_INTERNAL) {
+    pim_msdp_sa_key_dump(sa, key_str, sizeof(key_str), true);
+  }
+
+  if (PIM_DEBUG_MSDP_INTERNAL) {
+      zlog_debug("%s upstream update on %s", key_str, ctx);
+  }
+
+  if (!pim_msdp_sa_upstream_add_ok(sa, xg_up)) {
+    pim_msdp_sa_upstream_del(sa);
+    return;
+  }
+
+  if (sa->up) {
+    /* nothing to do */
+    return;
+  }
+
+  up = pim_upstream_find(&sa->sg);
+  if (up && (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags))) {
+    /* somehow we lost track of the upstream ptr? best log it */
+    sa->up = up;
+    if (PIM_DEBUG_MSDP_EVENTS) {
+      zlog_debug("%s SPT reference missing", key_str);
+    }
+    return;
+  }
+
+  /* RFC3618: "RP triggers a (S, G) join event towards the data source
+   * as if a JP message was rxed addressed to the RP itself." */
+  up = pim_upstream_add(&sa->sg, NULL /* iif */,
+                        PIM_UPSTREAM_FLAG_MASK_SRC_MSDP,
+                        __PRETTY_FUNCTION__);
+
+  sa->up = up;
+  if (up) {
+    /* update inherited oil */
+    pim_upstream_inherited_olist(up);
+    /* should we also start the kat in parallel? we will need it when the
+     * SA ages out */
+    if (PIM_DEBUG_MSDP_EVENTS) {
+      zlog_debug("%s referenced SPT", key_str);
+    }
+  } else {
+    if (PIM_DEBUG_MSDP_EVENTS) {
+      zlog_debug("%s SPT reference failed", key_str);
+    }
+  }
+}
+
 /* release all mem associated with a sa */
 static void
 pim_msdp_sa_free(struct pim_msdp_sa *sa)
@@ -137,8 +267,6 @@ pim_msdp_sa_new(struct prefix_sg *sg, struct in_addr rp)
 {
   struct pim_msdp_sa *sa;
 
-  pim_msdp_enable();
-
   sa = XCALLOC(MTYPE_PIM_MSDP_SA, sizeof(*sa));
   if (!sa) {
     zlog_err("%s: PIM XCALLOC(%zu) failure",
@@ -194,6 +322,10 @@ pim_msdp_sa_add(struct prefix_sg *sg, struct in_addr rp)
 static void
 pim_msdp_sa_del(struct pim_msdp_sa * sa)
 {
+  /* this is somewhat redundant - still want to be careful not to leave
+   * stale upstream references */
+  pim_msdp_sa_upstream_del(sa);
+
   /* stop timers */
   pim_msdp_sa_state_timer_setup(sa, false /* start */);
 
@@ -243,6 +375,7 @@ pim_msdp_sa_deref(struct pim_msdp_sa *sa, enum pim_msdp_sa_flags flags)
   }
 
   sa->flags &= ~flags;
+  pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "sa-deref");
   if (!(sa->flags & PIM_MSDP_SAF_REF)) {
     pim_msdp_sa_del(sa);
   }
@@ -275,6 +408,10 @@ pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg,
     sa->peer = mp->peer;
     /* start/re-start the state timer to prevent cache expiry */
     pim_msdp_sa_state_timer_setup(sa, true /* start */);
+    /* We re-evaluate SA "SPT-trigger" everytime we hear abt it from a
+     * peer. XXX: If this becomes too much of a periodic overhead we
+     * can make it event based */
+    pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "peer-ref");
   } else {
     if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
       sa->flags |= PIM_MSDP_SAF_LOCAL;
@@ -282,8 +419,9 @@ pim_msdp_sa_ref(struct pim_msdp_peer *mp, struct prefix_sg *sg,
       if (PIM_DEBUG_MSDP_EVENTS) {
         zlog_debug("%s added locally", key_str);
       }
-      /* send an immeidate SA update to peers */
+      /* send an immediate SA update to peers */
       pim_msdp_pkt_sa_tx_one(sa);
+      pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "local-ref");
     }
     sa->flags &= ~PIM_MSDP_SAF_STALE;
   }
@@ -338,28 +476,100 @@ pim_msdp_sa_local_setup(void)
   }
 }
 
-/* whenever the RP changes we need to re-evaluate the "local"
- * SA-cache */
-/* XXX: need to call this from thr right places. also needs more testing */
+/* whenever the RP changes we need to re-evaluate the "local" SA-cache */
+/* XXX: needs to be tested */
 void
 pim_msdp_i_am_rp_changed(void)
 {
   struct listnode *sanode;
   struct pim_msdp_sa *sa;
 
+  if (!(msdp->flags & PIM_MSDPF_ENABLE)) {
+    /* if the feature is not enabled do nothing */
+    return;
+  }
+
+  if (PIM_DEBUG_MSDP_INTERNAL) {
+      zlog_debug("MSDP i_am_rp changed"); 
+  }
+
   /* mark all local entries as stale */
   for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
-    sa->flags |= PIM_MSDP_SAF_STALE;
+    if (sa->flags & PIM_MSDP_SAF_LOCAL) {
+      sa->flags |= PIM_MSDP_SAF_STALE;
+    }
   }
 
   /* re-setup local SA entries */
   pim_msdp_sa_local_setup();
 
-  /* purge stale SA entries */
   for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+    /* purge stale SA entries */
     if (sa->flags & PIM_MSDP_SAF_STALE) {
+      /* clear the stale flag; the entry may be kept even after
+       * "local-deref" */
+      sa->flags &= ~PIM_MSDP_SAF_STALE;
       pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL);
     }
+    /* also check if we can still influence SPT */
+    pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "rp-change");
+  }
+}
+
+/* We track the join state of (*, G) entries. If G has sources in the SA-cache
+ * we need to setup or teardown SPT when the JoinDesired status changes for
+ * (*, G) */
+void
+pim_msdp_up_join_state_changed(struct pim_upstream *xg_up)
+{
+  struct listnode *sanode;
+  struct pim_msdp_sa *sa;
+
+  if (PIM_DEBUG_MSDP_INTERNAL) {
+      zlog_debug("MSDP join state changed for %s", pim_str_sg_dump(&xg_up->sg)); 
+  }
+
+  /* If this is not really an XG entry just move on */
+  if ((xg_up->sg.src.s_addr != INADDR_ANY) ||
+      (xg_up->sg.grp.s_addr == INADDR_ANY)) {
+    return;
+  }
+
+  /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
+   * walking */
+  for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+    if (sa->sg.grp.s_addr != xg_up->sg.grp.s_addr) {
+      continue;
+    }
+    pim_msdp_sa_upstream_update(sa, xg_up, "up-jp-change");
+  }
+}
+
+/* XXX: Need to maintain SAs per-group to avoid all this unnecessary
+ * walking */
+void
+pim_msdp_up_xg_del(struct prefix_sg *sg)
+{
+  struct listnode *sanode;
+  struct pim_msdp_sa *sa;
+
+  if (PIM_DEBUG_MSDP_INTERNAL) {
+      zlog_debug("MSDP %s del", pim_str_sg_dump(sg)); 
+  }
+
+  /* If this is not really an XG entry just move on */
+  if ((sg->src.s_addr != INADDR_ANY) ||
+      (sg->grp.s_addr == INADDR_ANY)) {
+    return;
+  }
+
+  /* XXX: Need to maintain SAs per-group to avoid all this unnecessary
+   * walking */
+  for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+    if (sa->sg.grp.s_addr != sg->grp.s_addr) {
+      continue;
+    }
+    pim_msdp_sa_upstream_update(sa, NULL /* xg */, "up-jp-change");
   }
 }
 
@@ -536,6 +746,12 @@ pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state)
     }
   }
 
+  if (PIM_DEBUG_MSDP_INTERNAL) {
+    char key_str[PIM_MSDP_PEER_KEY_STRLEN];
+
+    pim_msdp_peer_key_dump(mp, key_str, sizeof(key_str), false);
+    zlog_debug("%s pim_msdp_peer_stop_tcp_conn", key_str);
+  }
   /* stop read and write threads */
   PIM_MSDP_PEER_READ_OFF(mp);
   PIM_MSDP_PEER_WRITE_OFF(mp);
@@ -594,6 +810,7 @@ pim_msdp_peer_hold_timer_cb(struct thread *t)
   struct pim_msdp_peer *mp;
 
   mp = THREAD_ARG(t);
+  mp->hold_timer = NULL;
 
   if (PIM_DEBUG_MSDP_EVENTS) {
     pim_msdp_peer_timer_expiry_log(mp, "hold");
@@ -627,6 +844,7 @@ pim_msdp_peer_ka_timer_cb(struct thread *t)
   struct pim_msdp_peer *mp;
 
   mp = THREAD_ARG(t);
+  mp->ka_timer = NULL;
 
   if (PIM_DEBUG_MSDP_EVENTS) {
     pim_msdp_peer_timer_expiry_log(mp, "ka");
@@ -636,7 +854,6 @@ pim_msdp_peer_ka_timer_cb(struct thread *t)
   pim_msdp_peer_ka_timer_setup(mp, true /* start */);
   return 0;
 }
-/* XXX: reset this anytime a message is sent to the peer */
 static void
 pim_msdp_peer_ka_timer_setup(struct pim_msdp_peer *mp, bool start)
 {
@@ -690,6 +907,7 @@ pim_msdp_peer_cr_timer_cb(struct thread *t)
   struct pim_msdp_peer *mp;
 
   mp = THREAD_ARG(t);
+  mp->cr_timer = NULL;
 
   if (PIM_DEBUG_MSDP_EVENTS) {
     pim_msdp_peer_timer_expiry_log(mp, "connect-retry");
index 2af453f689a5ad4e12f4d3114fea10e750b3a0d8..5e13b33b5bde3390e318def2a837117063479eeb 100644 (file)
@@ -81,6 +81,8 @@ struct pim_msdp_sa {
 #define PIM_MSDP_SA_HOLD_TIME ((3*60)+30)
   struct thread *sa_state_timer;  // 5.6
   int64_t uptime;
+
+  struct pim_upstream *up;
 };
 
 enum pim_msdp_peer_flags {
@@ -193,4 +195,6 @@ void pim_msdp_sa_local_add(struct prefix_sg *sg);
 void pim_msdp_sa_local_del(struct prefix_sg *sg);
 void pim_msdp_i_am_rp_changed(void);
 bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp);
+void pim_msdp_up_join_state_changed(struct pim_upstream *xg_up);
+void pim_msdp_up_xg_del(struct prefix_sg *sg);
 #endif
index d6b476571444217f7e79ffc918bb46ae05236a3b..bc6156325fa85eab15fe36efe6de25140579aa71 100644 (file)
@@ -150,14 +150,17 @@ pim_msdp_write(struct thread *thread)
   struct stream *s;
   int num;
   enum pim_msdp_tlv type;
+  int work_cnt = 0;
+  char key_str[PIM_MSDP_PEER_KEY_STRLEN];
 
   mp = THREAD_ARG(thread);
   mp->t_write = NULL;
 
   if (PIM_DEBUG_MSDP_INTERNAL) {
-    char key_str[PIM_MSDP_PEER_KEY_STRLEN];
-
     pim_msdp_peer_key_dump(mp, key_str, sizeof(key_str), false);
+  }
+
+  if (PIM_DEBUG_MSDP_INTERNAL) {
     zlog_debug("%s pim_msdp_write", key_str);
   }
   if (mp->fd < 0) {
@@ -176,7 +179,7 @@ pim_msdp_write(struct thread *thread)
     return 0;
   }
 
-  sockopt_cork (mp->fd, 1);
+  sockopt_cork(mp->fd, 1);
 
   /* Nonblocking write until TCP output buffer is full  */
   do
@@ -190,8 +193,12 @@ pim_msdp_write(struct thread *thread)
     num = write(mp->fd, STREAM_PNT(s), writenum);
     if (num < 0) {
       /* write failed either retry needed or error */
-      if (ERRNO_IO_RETRY(errno))
+      if (ERRNO_IO_RETRY(errno)) {
+        if (PIM_DEBUG_MSDP_INTERNAL) {
+          zlog_debug("%s pim_msdp_write io retry", key_str);
+        }
         break;
+      }
 
       /* XXX:revisit; reset TCP connection */
       pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed");
@@ -202,9 +209,6 @@ pim_msdp_write(struct thread *thread)
       /* Partial write */
       stream_forward_getp(s, num);
       if (PIM_DEBUG_MSDP_INTERNAL) {
-        char key_str[PIM_MSDP_PEER_KEY_STRLEN];
-
-        pim_msdp_peer_key_dump(mp, key_str, sizeof(key_str), false);
         zlog_debug("%s pim_msdp_partial_write", key_str);
       }
       break;
@@ -230,12 +234,17 @@ pim_msdp_write(struct thread *thread)
     /* packet sent delete it. */
     pim_msdp_pkt_delete(mp);
 
+    ++work_cnt;
     /* XXX - may need to pause if we have done too much work in this
      * loop */
   } while ((s = stream_fifo_head(mp->obuf)) != NULL);
   pim_msdp_write_proceed_actions(mp);
 
-  sockopt_cork (mp->fd, 0);
+  sockopt_cork(mp->fd, 0);
+
+  if (PIM_DEBUG_MSDP_INTERNAL) {
+    zlog_debug("%s pim_msdp_write wrote %d packets", key_str, work_cnt);
+  }
 
   return 0;
 }
index e012115e3788f5f5aeda407884b685bb85718d94..3058df1af4f61186bb22934b60bd9175a445d950 100644 (file)
@@ -352,6 +352,7 @@ pim_register_recv (struct interface *ifp,
               {
                 zlog_debug ("Received Register(%s), for which I have no path back", pim_str_sg_dump (&upstream->sg));
               }
+            pim_upstream_unset_created_by_upstream(upstream);
             pim_upstream_del (upstream, __PRETTY_FUNCTION__);
             return 1;
           }
index 817837afbf0279d941efe48ce8e7a250e4b7b2ef..1bd48798c65458860431612cda888305e0b68b43 100644 (file)
@@ -40,6 +40,7 @@
 #include "pim_sock.h"
 #include "pim_memory.h"
 #include "pim_iface.h"
+#include "pim_msdp.h"
 
 struct rp_info
 {
@@ -226,6 +227,7 @@ pim_rp_find_match_group (struct prefix *group)
 static void
 pim_rp_refresh_group_to_rp_mapping()
 {
+  pim_msdp_i_am_rp_changed();
 }
 
 void
@@ -509,6 +511,7 @@ pim_rp_check_rp (struct in_addr old, struct in_addr new)
 {
   struct listnode *node;
   struct rp_info *rp_info;
+  bool i_am_rp_changed = false;
 
   if (qpim_rp_list == NULL)
     return;
@@ -529,14 +532,24 @@ pim_rp_check_rp (struct in_addr old, struct in_addr new)
 
       if (new.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
         {
-         rp_info->i_am_rp = 1;
+          if (!rp_info->i_am_rp) {
+            i_am_rp_changed = true;
+          }
+          rp_info->i_am_rp = 1;
         }
 
       if (old.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
         {
+          if (rp_info->i_am_rp) {
+            i_am_rp_changed = true;
+          }
           rp_info->i_am_rp = 0;
         }
     }
+
+    if (i_am_rp_changed) {
+      pim_msdp_i_am_rp_changed();
+    }
 }
 
 /*
index 2596f8c6e1b57149ad857ac3745c13b067e5d79a..2abf0b296f0296945668b888618336f6a1d29727 100644 (file)
@@ -119,7 +119,7 @@ pim_upstream_set_created_by_upstream(struct pim_upstream *up)
   pim_msdp_sa_local_add(&up->sg);
 }
 
-static void
+void
 pim_upstream_unset_created_by_upstream(struct pim_upstream *up)
 {
   PIM_UPSTREAM_FLAG_UNSET_CREATED_BY_UPSTREAM(up->flags);
@@ -169,6 +169,8 @@ static void upstream_channel_oil_detach(struct pim_upstream *up)
 void
 pim_upstream_del(struct pim_upstream *up, const char *name)
 {
+  bool notify_msdp = false;
+
   if (PIM_DEBUG_PIM_TRACE)
     {
       zlog_debug ("%s: Delete (%s) ref count: %d",
@@ -187,10 +189,20 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
   THREAD_OFF(up->t_ka_timer);
   THREAD_OFF(up->t_rs_timer);
 
+  if (up->join_state == PIM_UPSTREAM_JOINED) {
+    pim_joinprune_send (up->rpf.source_nexthop.interface,
+                      up->rpf.rpf_addr.u.prefix4,
+                      up, 0);
+    if (up->sg.src.s_addr == INADDR_ANY) {
+        /* if a (*, G) entry in the joined state is being deleted we
+         * need to notify MSDP */
+        notify_msdp = true;
+    }
+  }
+
   if (up->sg.src.s_addr != INADDR_ANY)
     wheel_remove_item (pim_upstream_sg_wheel, up);
 
-  pim_msdp_sa_local_del(&up->sg);
   pim_upstream_remove_children (up);
   pim_mroute_del (up->channel_oil);
   upstream_channel_oil_detach(up);
@@ -212,6 +224,9 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
   listnode_delete (pim_upstream_list, up);
   hash_release (pim_upstream_hash, up);
 
+  if (notify_msdp) {
+    pim_msdp_up_xg_del(&up->sg);
+  }
   pim_upstream_free(up);
 }
 
@@ -465,6 +480,7 @@ pim_upstream_switch(struct pim_upstream *up,
       {
         int old_fhr = PIM_UPSTREAM_FLAG_TEST_FHR(up->flags);
         forward_on(up);
+        pim_msdp_up_join_state_changed(up);
        if (pim_upstream_could_register (up))
          {
             PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
@@ -487,6 +503,8 @@ pim_upstream_switch(struct pim_upstream *up,
   }
   else {
     forward_off(up);
+    if (old_state == PIM_UPSTREAM_JOINED)
+      pim_msdp_up_join_state_changed(up);
     pim_joinprune_send(up->rpf.source_nexthop.interface,
                       up->rpf.rpf_addr.u.prefix4,
                       up,
@@ -925,9 +943,6 @@ pim_upstream_keep_alive_timer (struct thread *t)
       pim_mroute_del (up->channel_oil);
       THREAD_OFF (up->t_ka_timer);
       THREAD_OFF (up->t_rs_timer);
-      THREAD_OFF (up->t_join_timer);
-      pim_joinprune_send (up->rpf.source_nexthop.interface, up->rpf.rpf_addr.u.prefix4,
-                          up, 0);
       PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM (up->flags);
       if (PIM_UPSTREAM_FLAG_TEST_CREATED_BY_UPSTREAM(up->flags))
        {
index 7f8c0c99cb10bb3d7e08999c5698bb7081fb4d29..a073125021c5de8e7b9e9c05b4b35066189e40c7 100644 (file)
@@ -34,6 +34,7 @@
 #define PIM_UPSTREAM_FLAG_MASK_SRC_PIM                 (1 << 4)
 #define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM              (1 << 5)
 #define PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM     (1 << 6)
+#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP                (1 << 7)
 
 #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -42,6 +43,7 @@
 #define PIM_UPSTREAM_FLAG_TEST_SRC_PIM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
 #define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
 #define PIM_UPSTREAM_FLAG_TEST_CREATED_BY_UPSTREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
 
 #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -50,6 +52,7 @@
 #define PIM_UPSTREAM_FLAG_SET_SRC_PIM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
 #define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
 #define PIM_UPSTREAM_FLAG_SET_CREATED_BY_UPSTREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM)
+#define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
 
 #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
 #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -58,6 +61,7 @@
 #define PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_PIM)
 #define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
 #define PIM_UPSTREAM_FLAG_UNSET_CREATED_BY_UPSTREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_CREATED_BY_UPSTREAM)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
 
 enum pim_upstream_state {
   PIM_UPSTREAM_NOTJOINED,
@@ -164,4 +168,5 @@ void pim_upstream_find_new_rpf (void);
 void pim_upstream_init (void);
 void pim_upstream_terminate (void);
 void pim_upstream_set_created_by_upstream(struct pim_upstream *up);
+void pim_upstream_unset_created_by_upstream(struct pim_upstream *up);
 #endif /* PIM_UPSTREAM_H */