]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_ifchannel.c
Merge pull request #5767 from ton31337/fix/replace_s_addr_0_to_INADDR_ANY
[mirror_frr.git] / pimd / pim_ifchannel.c
index 3fb3da8f4450a274ebe9ddcc760e6da5d1238c67..d9c9bb37dd2048171c25b8ce883ca1a7cb6cec2b 100644 (file)
@@ -133,7 +133,7 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
        if (ch->upstream->channel_oil) {
                uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
                if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
-                       mask = PIM_OIF_FLAG_PROTO_IGMP;
+                       mask |= PIM_OIF_FLAG_PROTO_IGMP;
 
                /*
                 * A S,G RPT channel can have an empty oil, we also
@@ -142,13 +142,16 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
                 * being inherited.  So let's figure out what
                 * needs to be done here
                 */
-               if (pim_upstream_evaluate_join_desired_interface(
-                           ch->upstream, ch, ch->parent))
+               if ((ch->sg.src.s_addr != INADDR_ANY) &&
+                               pim_upstream_evaluate_join_desired_interface(
+                                       ch->upstream, ch, ch->parent))
                        pim_channel_add_oif(ch->upstream->channel_oil,
-                                           ch->interface, mask);
-               else
-                       pim_channel_del_oif(ch->upstream->channel_oil,
-                                           ch->interface, mask);
+                                       ch->interface,
+                                       PIM_OIF_FLAG_PROTO_STAR,
+                                       __func__);
+
+               pim_channel_del_oif(ch->upstream->channel_oil,
+                                       ch->interface, mask, __func__);
                /*
                 * Do we have any S,G's that are inheriting?
                 * Nuke from on high too.
@@ -159,9 +162,10 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
 
                        for (ALL_LIST_ELEMENTS_RO(ch->upstream->sources,
                                                  up_node, child))
-                               pim_channel_del_oif(child->channel_oil,
-                                                   ch->interface,
-                                                   PIM_OIF_FLAG_PROTO_STAR);
+                               pim_channel_del_inherited_oif(
+                                               child->channel_oil,
+                                               ch->interface,
+                                               __func__);
                }
        }
 
@@ -177,9 +181,7 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
 
        listnode_delete(ch->upstream->ifchannels, ch);
 
-       if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
-               pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
-       }
+       pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
 
        /* upstream is common across ifchannels, check if upstream's
           ifchannel list is empty before deleting upstream_del
@@ -189,11 +191,13 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
                pim_upstream_del(pim_ifp->pim, ch->upstream,
                        __PRETTY_FUNCTION__);
 
-       else
-               zlog_warn("%s: Avoiding deletion of upstream with ref_count %d "
-                       "from ifchannel(%s): %s", __PRETTY_FUNCTION__,
-                       ch->upstream->ref_count, ch->interface->name,
-                       ch->sg_str);
+       else {
+               if (PIM_DEBUG_PIM_TRACE)
+                       zlog_debug("%s: Avoiding deletion of upstream with ref_count %d "
+                                  "from ifchannel(%s): %s", __PRETTY_FUNCTION__,
+                                  ch->upstream->ref_count, ch->interface->name,
+                                  ch->sg_str);
+       }
 
        ch->upstream = NULL;
 
@@ -227,6 +231,8 @@ void pim_ifchannel_delete_all(struct interface *ifp)
        while (!RB_EMPTY(pim_ifchannel_rb, &pim_ifp->ifchannel_rb)) {
                ch = RB_ROOT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
 
+               pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__,
+                               ch, PIM_IFJOIN_NOINFO);
                pim_ifchannel_delete(ch);
        }
 }
@@ -244,6 +250,7 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
 {
        enum pim_ifjoin_state old_state = ch->ifjoin_state;
        struct pim_interface *pim_ifp = ch->interface->info;
+       struct pim_ifchannel *child_ch;
 
        if (PIM_DEBUG_PIM_EVENTS)
                zlog_debug(
@@ -287,28 +294,18 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                                        if (!c_oil)
                                                continue;
 
-                                       if (!pim_upstream_evaluate_join_desired(
-                                                   pim_ifp->pim, child)) {
-                                               pim_channel_del_oif(
-                                                       c_oil, ch->interface,
-                                                       PIM_OIF_FLAG_PROTO_STAR);
-                                               pim_upstream_update_join_desired(
-                                                       pim_ifp->pim, child);
-                                       }
-
                                        /*
                                         * If the S,G has no if channel and the
                                         * c_oil still
                                         * has output here then the *,G was
                                         * supplying the implied
                                         * if channel.  So remove it.
-                                        * I think this is dead code now. is it?
                                         */
                                        if (c_oil->oil.mfcc_ttls
                                                    [pim_ifp->mroute_vif_index])
-                                               pim_channel_del_oif(
+                                               pim_channel_del_inherited_oif(
                                                        c_oil, ch->interface,
-                                                       PIM_OIF_FLAG_PROTO_STAR);
+                                                       __func__);
                                }
                        }
                        if (ch->ifjoin_state == PIM_IFJOIN_JOIN) {
@@ -322,12 +319,19 @@ void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
                                                        child->sg_str,
                                                        up->sg_str);
 
-                                       if (pim_upstream_evaluate_join_desired(
-                                                   pim_ifp->pim, child)) {
+                                       /* check if the channel can be
+                                        * inherited into the SG's OIL
+                                        */
+                                       child_ch = pim_ifchannel_find(
+                                                       ch->interface,
+                                                       &child->sg);
+                                       if (pim_upstream_eval_inherit_if(
+                                                   child, child_ch, ch)) {
                                                pim_channel_add_oif(
                                                        child->channel_oil,
                                                        ch->interface,
-                                                       PIM_OIF_FLAG_PROTO_STAR);
+                                                       PIM_OIF_FLAG_PROTO_STAR,
+                                                       __func__);
                                                pim_upstream_update_join_desired(
                                                        pim_ifp->pim, child);
                                        }
@@ -576,7 +580,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
        ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
        ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch);
 
-       ch->ifassert_winner.s_addr = 0;
+       ch->ifassert_winner.s_addr = INADDR_ANY;
 
        /* Assert state */
        ch->t_ifassert_timer = NULL;
@@ -613,7 +617,7 @@ static int on_ifjoin_expiry_timer(struct thread *t)
 
        ch = THREAD_ARG(t);
 
-       if (PIM_DEBUG_TRACE)
+       if (PIM_DEBUG_PIM_TRACE)
                zlog_debug("%s: ifchannel %s expiry timer", __PRETTY_FUNCTION__,
                           ch->sg_str);
 
@@ -632,7 +636,7 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
 
        ch = THREAD_ARG(t);
 
-       if (PIM_DEBUG_TRACE)
+       if (PIM_DEBUG_PIM_TRACE)
                zlog_debug(
                        "%s: IFCHANNEL%s %s Prune Pending Timer Popped",
                        __PRETTY_FUNCTION__, pim_str_sg_dump(&ch->sg),
@@ -777,6 +781,28 @@ static int nonlocal_upstream(int is_join, struct interface *recv_ifp,
        return 1; /* non-local */
 }
 
+static void pim_ifchannel_ifjoin_handler(struct pim_ifchannel *ch,
+               struct pim_interface *pim_ifp)
+{
+       pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
+                       PIM_IFJOIN_JOIN);
+       PIM_IF_FLAG_UNSET_S_G_RPT(ch->flags);
+       /* check if the interface qualifies as an immediate
+        * OIF
+        */
+       if (pim_upstream_evaluate_join_desired_interface(
+                               ch->upstream, ch,
+                               NULL /*starch*/)) {
+               pim_channel_add_oif(ch->upstream->channel_oil,
+                               ch->interface,
+                               PIM_OIF_FLAG_PROTO_PIM,
+                               __func__);
+               pim_upstream_update_join_desired(pim_ifp->pim,
+                               ch->upstream);
+       }
+}
+
+
 void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
                            struct in_addr upstream, struct prefix_sg *sg,
                            uint8_t source_flags, uint16_t holdtime)
@@ -791,8 +817,6 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
 
        ch = pim_ifchannel_add(ifp, sg, source_flags,
                               PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
-       if (!ch)
-               return;
 
        /*
          RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
@@ -886,25 +910,8 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
                if (source_flags & PIM_ENCODE_RPT_BIT)
                        pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
                                                    PIM_IFJOIN_NOINFO);
-               else {
-                       /*
-                        * We have received a S,G join and we are in
-                        * S,G RPT Prune state.  Which means we need
-                        * to transition to Join state and setup
-                        * state as appropriate.
-                        */
-                       pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
-                                                   PIM_IFJOIN_JOIN);
-                       PIM_IF_FLAG_UNSET_S_G_RPT(ch->flags);
-                       if (pim_upstream_evaluate_join_desired(pim_ifp->pim,
-                                                              ch->upstream)) {
-                               pim_channel_add_oif(ch->upstream->channel_oil,
-                                                   ch->interface,
-                                                   PIM_OIF_FLAG_PROTO_PIM);
-                               pim_upstream_update_join_desired(pim_ifp->pim,
-                                                                ch->upstream);
-                       }
-               }
+               else
+                       pim_ifchannel_ifjoin_handler(ch, pim_ifp);
                break;
        case PIM_IFJOIN_PRUNE_PENDING:
                THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
@@ -912,9 +919,9 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
                        THREAD_OFF(ch->t_ifjoin_expiry_timer);
                        pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
                                                    PIM_IFJOIN_NOINFO);
-               } else
-                       pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
-                                                   PIM_IFJOIN_JOIN);
+               } else {
+                       pim_ifchannel_ifjoin_handler(ch, pim_ifp);
+               }
                break;
        case PIM_IFJOIN_PRUNE_TMP:
                break;
@@ -943,7 +950,7 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream,
 
        ch = pim_ifchannel_find(ifp, sg);
        if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT)) {
-               if (PIM_DEBUG_TRACE)
+               if (PIM_DEBUG_PIM_TRACE)
                        zlog_debug(
                                "%s: Received prune with no relevant ifchannel %s%s state: %d",
                                __PRETTY_FUNCTION__, ifp->name,
@@ -953,8 +960,6 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream,
 
        ch = pim_ifchannel_add(ifp, sg, source_flags,
                               PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
-       if (!ch)
-               return;
 
        pim_ifp = ifp->info;
 
@@ -1082,13 +1087,6 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
        }
 
        ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
-       if (!ch) {
-               if (PIM_DEBUG_EVENTS)
-                       zlog_debug("%s:%s Unable to add ifchannel",
-                                  __PRETTY_FUNCTION__,
-                                  pim_str_sg_dump(sg));
-               return 0;
-       }
 
        ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
 
@@ -1110,9 +1108,9 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
                        if (pim_upstream_evaluate_join_desired_interface(
                                    child, ch, starch)) {
                                pim_channel_add_oif(child->channel_oil, ifp,
-                                                   PIM_OIF_FLAG_PROTO_STAR);
-                               pim_upstream_switch(pim, child,
-                                                   PIM_UPSTREAM_JOINED);
+                                                   PIM_OIF_FLAG_PROTO_STAR,
+                                                       __func__);
+                               pim_upstream_update_join_desired(pim, child);
                        }
                }
 
@@ -1129,12 +1127,14 @@ int pim_ifchannel_local_membership_add(struct interface *ifp,
                                    == PREFIX_DENY) {
                                        pim_channel_add_oif(
                                                up->channel_oil, pim->regiface,
-                                               PIM_OIF_FLAG_PROTO_IGMP);
+                                               PIM_OIF_FLAG_PROTO_IGMP,
+                                               __func__);
                                }
                        }
                } else
                        pim_channel_add_oif(up->channel_oil, pim->regiface,
-                                           PIM_OIF_FLAG_PROTO_IGMP);
+                                       PIM_OIF_FLAG_PROTO_IGMP,
+                                       __func__);
        }
 
        return 1;
@@ -1179,22 +1179,19 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
                                           child->sg_str);
 
                        ch = pim_ifchannel_find(ifp, &child->sg);
-                       if (c_oil
-                           && !pim_upstream_evaluate_join_desired_interface(
-                                      child, ch, starch))
-                               pim_channel_del_oif(c_oil, ifp,
-                                                   PIM_OIF_FLAG_PROTO_STAR);
-
                        /*
                         * If the S,G has no if channel and the c_oil still
                         * has output here then the *,G was supplying the
                         * implied
                         * if channel.  So remove it.
                         */
-                       if (!chchannel && c_oil
-                           && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
-                               pim_channel_del_oif(c_oil, ifp,
-                                                   PIM_OIF_FLAG_PROTO_STAR);
+                       if (!pim_upstream_evaluate_join_desired_interface(
+                               child, ch, starch) ||
+                               (!chchannel &&
+                                c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])) {
+                               pim_channel_del_inherited_oif(c_oil, ifp,
+                                               __func__);
+                       }
 
                        /* Child node removal/ref count-- will happen as part of
                         * parent' delete_no_info */
@@ -1225,10 +1222,10 @@ void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
        }
 
        if (new_couldassert) {
-               /* CouldAssert(S,G,I) switched from FALSE to TRUE */
+               /* CouldAssert(S,G,I) switched from false to true */
                PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags);
        } else {
-               /* CouldAssert(S,G,I) switched from TRUE to FALSE */
+               /* CouldAssert(S,G,I) switched from true to false */
                PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags);
 
                if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) {
@@ -1308,10 +1305,10 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch)
        }
 
        if (new_atd) {
-               /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */
+               /* AssertTrackingDesired(S,G,I) switched from false to true */
                PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags);
        } else {
-               /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */
+               /* AssertTrackingDesired(S,G,I) switched from true to false */
                PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
 
                if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
@@ -1413,12 +1410,10 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
                                child->upstream))) {
                                pim_channel_add_oif(
                                        child->upstream->channel_oil,
-                                       ch->interface, PIM_OIF_FLAG_PROTO_STAR);
-                               pim_upstream_switch(pim, child->upstream,
-                                                   PIM_UPSTREAM_JOINED);
-                               pim_jp_agg_single_upstream_send(
-                                       &child->upstream->rpf, child->upstream,
-                                       true);
+                                       ch->interface, PIM_OIF_FLAG_PROTO_STAR,
+                                       __func__);
+                               pim_upstream_update_join_desired(pim,
+                                               child->upstream);
                        }
                        send_upstream_starg = true;