diff options
Diffstat (limited to 'pimd/pim_upstream.c')
| -rw-r--r-- | pimd/pim_upstream.c | 2540 |
1 files changed, 1246 insertions, 1294 deletions
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index af9c3913a5..5b8cb59295 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -11,7 +11,7 @@ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, @@ -60,35 +60,33 @@ struct list *pim_upstream_list = NULL; struct timer_wheel *pim_upstream_sg_wheel = NULL; static void join_timer_stop(struct pim_upstream *up); -static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up); +static void +pim_upstream_update_assert_tracking_desired(struct pim_upstream *up); /* * A (*,G) or a (*,*) is going away * remove the parent pointer from * those pointing at us */ -static void -pim_upstream_remove_children (struct pim_upstream *up) +static void pim_upstream_remove_children(struct pim_upstream *up) { - struct pim_upstream *child; - - if (!up->sources) - return; - - while (!list_isempty (up->sources)) - { - child = listnode_head (up->sources); - listnode_delete (up->sources, child); - if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) - { - PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags); - child = pim_upstream_del(child, __PRETTY_FUNCTION__); - } - if (child) - child->parent = NULL; - } - list_delete(up->sources); - up->sources = NULL; + struct pim_upstream *child; + + if (!up->sources) + return; + + while (!list_isempty(up->sources)) { + child = listnode_head(up->sources); + listnode_delete(up->sources, child); + if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags)) { + PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags); + child = pim_upstream_del(child, __PRETTY_FUNCTION__); + } + if (child) + child->parent = NULL; + } + list_delete(up->sources); + up->sources = NULL; } /* @@ -96,30 +94,27 @@ pim_upstream_remove_children (struct pim_upstream *up) * Find the children that would point * at us. */ -static void -pim_upstream_find_new_children (struct pim_upstream *up) +static void pim_upstream_find_new_children(struct pim_upstream *up) { - struct pim_upstream *child; - struct listnode *ch_node; - - if ((up->sg.src.s_addr != INADDR_ANY) && - (up->sg.grp.s_addr != INADDR_ANY)) - return; - - if ((up->sg.src.s_addr == INADDR_ANY) && - (up->sg.grp.s_addr == INADDR_ANY)) - return; - - for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, ch_node, child)) - { - if ((up->sg.grp.s_addr != INADDR_ANY) && - (child->sg.grp.s_addr == up->sg.grp.s_addr) && - (child != up)) - { - child->parent = up; - listnode_add_sort (up->sources, child); + struct pim_upstream *child; + struct listnode *ch_node; + + if ((up->sg.src.s_addr != INADDR_ANY) + && (up->sg.grp.s_addr != INADDR_ANY)) + return; + + if ((up->sg.src.s_addr == INADDR_ANY) + && (up->sg.grp.s_addr == INADDR_ANY)) + return; + + for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, ch_node, child)) { + if ((up->sg.grp.s_addr != INADDR_ANY) + && (child->sg.grp.s_addr == up->sg.grp.s_addr) + && (child != up)) { + child->parent = up; + listnode_add_sort(up->sources, child); + } } - } } /* @@ -127,221 +122,213 @@ pim_upstream_find_new_children (struct pim_upstream *up) * If we have a (S,G), find the (*,G) * If we have a (*,G), find the (*,*) */ -static struct pim_upstream * -pim_upstream_find_parent (struct pim_upstream *child) +static struct pim_upstream *pim_upstream_find_parent(struct pim_upstream *child) { - struct prefix_sg any = child->sg; - struct pim_upstream *up = NULL; + struct prefix_sg any = child->sg; + struct pim_upstream *up = NULL; - // (S,G) - if ((child->sg.src.s_addr != INADDR_ANY) && - (child->sg.grp.s_addr != INADDR_ANY)) - { - any.src.s_addr = INADDR_ANY; - up = pim_upstream_find (&any); + // (S,G) + if ((child->sg.src.s_addr != INADDR_ANY) + && (child->sg.grp.s_addr != INADDR_ANY)) { + any.src.s_addr = INADDR_ANY; + up = pim_upstream_find(&any); - if (up) - listnode_add (up->sources, child); + if (up) + listnode_add(up->sources, child); - return up; - } + return up; + } - return NULL; + return NULL; } void pim_upstream_free(struct pim_upstream *up) { - XFREE(MTYPE_PIM_UPSTREAM, up); - up = NULL; + XFREE(MTYPE_PIM_UPSTREAM, up); + up = NULL; } static void upstream_channel_oil_detach(struct pim_upstream *up) { - if (up->channel_oil) - { - /* Detaching from channel_oil, channel_oil may exist post del, - but upstream would not keep reference of it - */ - pim_channel_oil_del(up->channel_oil); - up->channel_oil = NULL; - } + if (up->channel_oil) { + /* Detaching from channel_oil, channel_oil may exist post del, + but upstream would not keep reference of it + */ + pim_channel_oil_del(up->channel_oil); + up->channel_oil = NULL; + } } -struct pim_upstream * -pim_upstream_del(struct pim_upstream *up, const char *name) +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 , flags: %d c_oil ref count %d (Pre decrement)", - __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count, up->flags, - up->channel_oil->oil_ref_count); - - --up->ref_count; - - if (up->ref_count >= 1) - return up; - - THREAD_OFF(up->t_ka_timer); - THREAD_OFF(up->t_rs_timer); - THREAD_OFF(up->t_msdp_reg_timer); - - if (up->join_state == PIM_UPSTREAM_JOINED) { - pim_jp_agg_single_upstream_send (&up->rpf, 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; - } - } - - 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) { - wheel_remove_item (pim_upstream_sg_wheel, up); - notify_msdp = true; - } - - pim_upstream_remove_children (up); - if (up->sources) - list_delete (up->sources); - up->sources = NULL; - pim_mroute_del (up->channel_oil, __PRETTY_FUNCTION__); - upstream_channel_oil_detach(up); - - list_delete (up->ifchannels); - up->ifchannels = NULL; - - /* - notice that listnode_delete() can't be moved - into pim_upstream_free() because the later is - called by list_delete_all_node() - */ - if (up->parent && up->parent->sources) - listnode_delete (up->parent->sources, up); - up->parent = NULL; - - listnode_delete (pim_upstream_list, up); - hash_release (pim_upstream_hash, up); - - if (notify_msdp) - { - pim_msdp_up_del (&up->sg); - } - - /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = up->upstream_addr; - if (PIM_DEBUG_TRACE) - { - char buf[PREFIX2STR_BUFFER]; - prefix2str (&nht_p, buf, sizeof (buf)); - zlog_debug ("%s: Deregister upstream %s addr %s with Zebra NHT", - __PRETTY_FUNCTION__, up->sg_str, buf); - } - pim_delete_tracked_nexthop (&nht_p, up, NULL); - - pim_upstream_free (up); - - return NULL; + bool notify_msdp = false; + struct prefix nht_p; + + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s(%s): Delete %s ref count: %d , flags: %d c_oil ref count %d (Pre decrement)", + __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count, + up->flags, up->channel_oil->oil_ref_count); + + --up->ref_count; + + if (up->ref_count >= 1) + return up; + + THREAD_OFF(up->t_ka_timer); + THREAD_OFF(up->t_rs_timer); + THREAD_OFF(up->t_msdp_reg_timer); + + if (up->join_state == PIM_UPSTREAM_JOINED) { + pim_jp_agg_single_upstream_send(&up->rpf, 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; + } + } + + 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) { + wheel_remove_item(pim_upstream_sg_wheel, up); + notify_msdp = true; + } + + pim_upstream_remove_children(up); + if (up->sources) + list_delete(up->sources); + up->sources = NULL; + pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + upstream_channel_oil_detach(up); + + list_delete(up->ifchannels); + up->ifchannels = NULL; + + /* + notice that listnode_delete() can't be moved + into pim_upstream_free() because the later is + called by list_delete_all_node() + */ + if (up->parent && up->parent->sources) + listnode_delete(up->parent->sources, up); + up->parent = NULL; + + listnode_delete(pim_upstream_list, up); + hash_release(pim_upstream_hash, up); + + if (notify_msdp) { + pim_msdp_up_del(&up->sg); + } + + /* Deregister addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = up->upstream_addr; + if (PIM_DEBUG_TRACE) { + char buf[PREFIX2STR_BUFFER]; + prefix2str(&nht_p, buf, sizeof(buf)); + zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", + __PRETTY_FUNCTION__, up->sg_str, buf); + } + pim_delete_tracked_nexthop(&nht_p, up, NULL); + + pim_upstream_free(up); + + return NULL; } -void -pim_upstream_send_join (struct pim_upstream *up) +void pim_upstream_send_join(struct pim_upstream *up) { - if (PIM_DEBUG_TRACE) { - char rpf_str[PREFIX_STRLEN]; - pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); - zlog_debug ("%s: RPF'%s=%s(%s) for Interface %s", __PRETTY_FUNCTION__, - up->sg_str, rpf_str, pim_upstream_state2str (up->join_state), - up->rpf.source_nexthop.interface->name); - if (pim_rpf_addr_is_inaddr_any(&up->rpf)) { - zlog_debug("%s: can't send join upstream: RPF'%s=%s", - __PRETTY_FUNCTION__, - up->sg_str, rpf_str); - /* warning only */ - } - } - - /* send Join(S,G) to the current upstream neighbor */ - pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */); + if (PIM_DEBUG_TRACE) { + char rpf_str[PREFIX_STRLEN]; + pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, + sizeof(rpf_str)); + zlog_debug("%s: RPF'%s=%s(%s) for Interface %s", + __PRETTY_FUNCTION__, up->sg_str, rpf_str, + pim_upstream_state2str(up->join_state), + up->rpf.source_nexthop.interface->name); + if (pim_rpf_addr_is_inaddr_any(&up->rpf)) { + zlog_debug("%s: can't send join upstream: RPF'%s=%s", + __PRETTY_FUNCTION__, up->sg_str, rpf_str); + /* warning only */ + } + } + + /* send Join(S,G) to the current upstream neighbor */ + pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */); } static int on_join_timer(struct thread *t) { - struct pim_upstream *up; + struct pim_upstream *up; - up = THREAD_ARG(t); + up = THREAD_ARG(t); - up->t_join_timer = NULL; + up->t_join_timer = NULL; - /* - * In the case of a HFR we will not ahve anyone to send this to. - */ - if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) - return 0; + /* + * In the case of a HFR we will not ahve anyone to send this to. + */ + if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) + return 0; - /* - * Don't send the join if the outgoing interface is a loopback - * But since this might change leave the join timer running - */ - if (up->rpf.source_nexthop.interface && - !if_is_loopback (up->rpf.source_nexthop.interface)) - pim_upstream_send_join (up); + /* + * Don't send the join if the outgoing interface is a loopback + * But since this might change leave the join timer running + */ + if (up->rpf.source_nexthop + .interface && !if_is_loopback(up->rpf.source_nexthop.interface)) + pim_upstream_send_join(up); - join_timer_start(up); + join_timer_start(up); - return 0; + return 0; } static void join_timer_stop(struct pim_upstream *up) { - struct pim_neighbor *nbr; + struct pim_neighbor *nbr; - THREAD_OFF (up->t_join_timer); + THREAD_OFF(up->t_join_timer); - nbr = pim_neighbor_find (up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + 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); + if (nbr) + pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); - pim_jp_agg_upstream_verification (up, false); + pim_jp_agg_upstream_verification(up, false); } -void -join_timer_start(struct pim_upstream *up) +void join_timer_start(struct pim_upstream *up) { - struct pim_neighbor *nbr = NULL; - - if (up->rpf.source_nexthop.interface) - { - nbr = pim_neighbor_find (up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); - - if (PIM_DEBUG_PIM_EVENTS) { - zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s", - __PRETTY_FUNCTION__, - qpim_t_periodic, - up->sg_str); - } - } - - if (nbr) - pim_jp_agg_add_group (nbr->upstream_jp_agg, up, 1); - else - { - THREAD_OFF (up->t_join_timer); - THREAD_TIMER_ON(master, up->t_join_timer, - on_join_timer, - up, qpim_t_periodic); - } - pim_jp_agg_upstream_verification (up, true); + struct pim_neighbor *nbr = NULL; + + if (up->rpf.source_nexthop.interface) { + nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, + up->rpf.rpf_addr.u.prefix4); + + if (PIM_DEBUG_PIM_EVENTS) { + zlog_debug( + "%s: starting %d sec timer for upstream (S,G)=%s", + __PRETTY_FUNCTION__, qpim_t_periodic, + up->sg_str); + } + } + + if (nbr) + pim_jp_agg_add_group(nbr->upstream_jp_agg, up, 1); + else { + THREAD_OFF(up->t_join_timer); + THREAD_TIMER_ON(master, up->t_join_timer, on_join_timer, up, + qpim_t_periodic); + } + pim_jp_agg_upstream_verification(up, true); } /* @@ -351,502 +338,488 @@ join_timer_start(struct pim_upstream *up) * As such we need to remove from the old list and * add to the new list. */ -void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old) +void pim_upstream_join_timer_restart(struct pim_upstream *up, + struct pim_rpf *old) { - //THREAD_OFF(up->t_join_timer); - join_timer_start(up); + // THREAD_OFF(up->t_join_timer); + join_timer_start(up); } static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up, int interval_msec) { - if (PIM_DEBUG_PIM_EVENTS) { - zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s", - __PRETTY_FUNCTION__, - interval_msec, - up->sg_str); - } - - THREAD_OFF(up->t_join_timer); - THREAD_TIMER_MSEC_ON(master, up->t_join_timer, - on_join_timer, - up, interval_msec); + if (PIM_DEBUG_PIM_EVENTS) { + zlog_debug("%s: restarting %d msec timer for upstream (S,G)=%s", + __PRETTY_FUNCTION__, interval_msec, up->sg_str); + } + + THREAD_OFF(up->t_join_timer); + THREAD_TIMER_MSEC_ON(master, up->t_join_timer, on_join_timer, up, + interval_msec); } void pim_upstream_join_suppress(struct pim_upstream *up, - struct in_addr rpf_addr, - int holdtime) + struct in_addr rpf_addr, int holdtime) { - long t_joinsuppress_msec; - long join_timer_remain_msec; - - t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), - 1000 * holdtime); - - join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); - - if (PIM_DEBUG_TRACE) { - char rpf_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str)); - zlog_debug("%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec", - __FILE__, __PRETTY_FUNCTION__, - up->sg_str, - rpf_str, - join_timer_remain_msec, t_joinsuppress_msec); - } - - if (join_timer_remain_msec < t_joinsuppress_msec) { - if (PIM_DEBUG_TRACE) { - zlog_debug("%s %s: suppressing Join(S,G)=%s for %ld msec", - __FILE__, __PRETTY_FUNCTION__, - up->sg_str, t_joinsuppress_msec); - } - - pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec); - } + long t_joinsuppress_msec; + long join_timer_remain_msec; + + t_joinsuppress_msec = + MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), + 1000 * holdtime); + + join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); + + if (PIM_DEBUG_TRACE) { + char rpf_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str)); + zlog_debug( + "%s %s: detected Join%s to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec", + __FILE__, __PRETTY_FUNCTION__, up->sg_str, rpf_str, + join_timer_remain_msec, t_joinsuppress_msec); + } + + if (join_timer_remain_msec < t_joinsuppress_msec) { + if (PIM_DEBUG_TRACE) { + zlog_debug( + "%s %s: suppressing Join(S,G)=%s for %ld msec", + __FILE__, __PRETTY_FUNCTION__, up->sg_str, + t_joinsuppress_msec); + } + + pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec); + } } void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, - struct pim_upstream *up) + struct pim_upstream *up) { - long join_timer_remain_msec; - int t_override_msec; - - join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); - t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface); - - if (PIM_DEBUG_TRACE) { - char rpf_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str, sizeof(rpf_str)); - zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec", - debug_label, - up->sg_str, rpf_str, - join_timer_remain_msec, t_override_msec); - } - - if (join_timer_remain_msec > t_override_msec) { - if (PIM_DEBUG_TRACE) { - zlog_debug("%s: decreasing (S,G)=%s join timer to t_override=%d msec", - debug_label, - up->sg_str, - t_override_msec); - } - - pim_upstream_join_timer_restart_msec(up, t_override_msec); - } + long join_timer_remain_msec; + int t_override_msec; + + join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); + t_override_msec = + pim_if_t_override_msec(up->rpf.source_nexthop.interface); + + if (PIM_DEBUG_TRACE) { + char rpf_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str, + sizeof(rpf_str)); + zlog_debug( + "%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec", + debug_label, up->sg_str, rpf_str, + join_timer_remain_msec, t_override_msec); + } + + if (join_timer_remain_msec > t_override_msec) { + if (PIM_DEBUG_TRACE) { + zlog_debug( + "%s: decreasing (S,G)=%s join timer to t_override=%d msec", + debug_label, up->sg_str, t_override_msec); + } + + pim_upstream_join_timer_restart_msec(up, t_override_msec); + } } static void forward_on(struct pim_upstream *up) { - struct listnode *chnode; - struct listnode *chnextnode; - struct pim_ifchannel *ch = NULL; + struct listnode *chnode; + struct listnode *chnextnode; + struct pim_ifchannel *ch = NULL; - /* scan (S,G) state */ - for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { - if (pim_macro_chisin_oiflist(ch)) - pim_forward_start(ch); + /* scan (S,G) state */ + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { + if (pim_macro_chisin_oiflist(ch)) + pim_forward_start(ch); - } /* scan iface channel list */ + } /* scan iface channel list */ } static void forward_off(struct pim_upstream *up) { - struct listnode *chnode; - struct listnode *chnextnode; - struct pim_ifchannel *ch; + struct listnode *chnode; + struct listnode *chnextnode; + struct pim_ifchannel *ch; - /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { - pim_forward_stop(ch); + pim_forward_stop(ch); - } /* scan iface channel list */ + } /* scan iface channel list */ } -static int -pim_upstream_could_register (struct pim_upstream *up) +static int pim_upstream_could_register(struct pim_upstream *up) { - 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); - } + 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)) - return 1; + if (pim_ifp && PIM_I_am_DR(pim_ifp) + && pim_if_connected_to_source(up->rpf.source_nexthop.interface, + up->sg.src)) + return 1; - return 0; + 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) +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; - } - } - } + 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) +void pim_upstream_switch(struct pim_upstream *up, + enum pim_upstream_state new_state) { - enum pim_upstream_state old_state = up->join_state; - - if (PIM_DEBUG_PIM_EVENTS) - { - zlog_debug ("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s", - __PRETTY_FUNCTION__, - up->sg_str, - pim_upstream_state2str (up->join_state), - pim_upstream_state2str (new_state)); - } - - up->join_state = new_state; - if (old_state != new_state) - up->state_transition = pim_time_monotonic_sec(); - - pim_upstream_update_assert_tracking_desired(up); - - if (new_state == PIM_UPSTREAM_JOINED) { - if (old_state != PIM_UPSTREAM_JOINED) - { - 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); - if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) - { - pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); - pim_register_join (up); - } - } - else - { - pim_upstream_send_join (up); - join_timer_start (up); - } - } - else - { - forward_on (up); - } - } - else { - - forward_off(up); - if (old_state == PIM_UPSTREAM_JOINED) - pim_msdp_up_join_state_changed(up); - - /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards RP. - If I am RP for G then send S,G prune to its IIF. */ - if (pim_upstream_is_sg_rpt(up) && up->parent && !I_am_RP(up->sg.grp)) - { - if (PIM_DEBUG_PIM_TRACE_DETAIL) - zlog_debug ("%s: *,G IIF %s S,G IIF %s ", __PRETTY_FUNCTION__, - up->parent->rpf.source_nexthop.interface->name, - up->rpf.source_nexthop.interface->name); - pim_jp_agg_single_upstream_send(&up->parent->rpf, up->parent, 1 /* (W,G) Join */); - } - else - pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */); - join_timer_stop(up); - } + enum pim_upstream_state old_state = up->join_state; + + if (PIM_DEBUG_PIM_EVENTS) { + zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s", + __PRETTY_FUNCTION__, up->sg_str, + pim_upstream_state2str(up->join_state), + pim_upstream_state2str(new_state)); + } + + up->join_state = new_state; + if (old_state != new_state) + up->state_transition = pim_time_monotonic_sec(); + + pim_upstream_update_assert_tracking_desired(up); + + if (new_state == PIM_UPSTREAM_JOINED) { + if (old_state != PIM_UPSTREAM_JOINED) { + 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); + if (!old_fhr + && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM( + up->flags)) { + pim_upstream_keep_alive_timer_start( + up, qpim_keep_alive_time); + pim_register_join(up); + } + } else { + pim_upstream_send_join(up); + join_timer_start(up); + } + } else { + forward_on(up); + } + } else { + + forward_off(up); + if (old_state == PIM_UPSTREAM_JOINED) + pim_msdp_up_join_state_changed(up); + + /* IHR, Trigger SGRpt on *,G IIF to prune S,G from RPT towards + RP. + If I am RP for G then send S,G prune to its IIF. */ + if (pim_upstream_is_sg_rpt(up) && up->parent + && !I_am_RP(up->sg.grp)) { + if (PIM_DEBUG_PIM_TRACE_DETAIL) + zlog_debug( + "%s: *,G IIF %s S,G IIF %s ", + __PRETTY_FUNCTION__, + up->parent->rpf.source_nexthop + .interface->name, + up->rpf.source_nexthop.interface->name); + pim_jp_agg_single_upstream_send(&up->parent->rpf, + up->parent, + 1 /* (W,G) Join */); + } else + pim_jp_agg_single_upstream_send(&up->rpf, up, + 0 /* prune */); + join_timer_stop(up); + } } -int -pim_upstream_compare (void *arg1, void *arg2) +int pim_upstream_compare(void *arg1, void *arg2) { - const struct pim_upstream *up1 = (const struct pim_upstream *)arg1; - const struct pim_upstream *up2 = (const struct pim_upstream *)arg2; + const struct pim_upstream *up1 = (const struct pim_upstream *)arg1; + const struct pim_upstream *up2 = (const struct pim_upstream *)arg2; - if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr)) - return -1; + if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr)) + return -1; - if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr)) - return 1; + if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr)) + return 1; - if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr)) - return -1; + if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr)) + return -1; - if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr)) - return 1; + if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr)) + return 1; - return 0; + return 0; } static struct pim_upstream * -pim_upstream_new (struct prefix_sg *sg, - struct interface *incoming, - int flags) +pim_upstream_new(struct prefix_sg *sg, struct interface *incoming, int flags) { - enum pim_rpf_result rpf_result; - struct pim_interface *pim_ifp; - struct pim_upstream *up; - - up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); - if (!up) - { - zlog_err("%s: PIM XCALLOC(%zu) failure", - __PRETTY_FUNCTION__, sizeof(*up)); - return NULL; - } - - up->sg = *sg; - pim_str_sg_set (sg, up->sg_str); - up = hash_get (pim_upstream_hash, up, hash_alloc_intern); - if (!pim_rp_set_upstream_addr (&up->upstream_addr, sg->src, sg->grp)) - { - if (PIM_DEBUG_TRACE) - zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); - - hash_release (pim_upstream_hash, up); - XFREE (MTYPE_PIM_UPSTREAM, up); - return NULL; - } - - up->parent = pim_upstream_find_parent (up); - if (up->sg.src.s_addr == INADDR_ANY) - { - up->sources = list_new (); - up->sources->cmp = pim_upstream_compare; - } - else - up->sources = NULL; - - pim_upstream_find_new_children (up); - up->flags = flags; - up->ref_count = 1; - up->t_join_timer = NULL; - up->t_ka_timer = NULL; - up->t_rs_timer = NULL; - up->t_msdp_reg_timer = NULL; - up->join_state = PIM_UPSTREAM_NOTJOINED; - up->reg_state = PIM_REG_NOINFO; - up->state_transition = pim_time_monotonic_sec(); - up->channel_oil = NULL; - up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; - - up->rpf.source_nexthop.interface = NULL; - up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET; - up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY; - up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference; - up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric; - 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); - up->parent = NULL; - } - - if (up->sg.src.s_addr != INADDR_ANY) - wheel_remove_item (pim_upstream_sg_wheel, up); - - pim_upstream_remove_children (up); - if (up->sources) - list_delete (up->sources); - - hash_release (pim_upstream_hash, up); - XFREE(MTYPE_PIM_UPSTREAM, up); - return NULL; - } - - 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) - { - zlog_debug ("%s: Created Upstream %s upstream_addr %s ref count %d increment", - __PRETTY_FUNCTION__, up->sg_str, - inet_ntoa (up->upstream_addr), up->ref_count); - } - - return up; + enum pim_rpf_result rpf_result; + struct pim_interface *pim_ifp; + struct pim_upstream *up; + + up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); + if (!up) { + zlog_err("%s: PIM XCALLOC(%zu) failure", __PRETTY_FUNCTION__, + sizeof(*up)); + return NULL; + } + + up->sg = *sg; + pim_str_sg_set(sg, up->sg_str); + up = hash_get(pim_upstream_hash, up, hash_alloc_intern); + if (!pim_rp_set_upstream_addr(&up->upstream_addr, sg->src, sg->grp)) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: Received a (*,G) with no RP configured", + __PRETTY_FUNCTION__); + + hash_release(pim_upstream_hash, up); + XFREE(MTYPE_PIM_UPSTREAM, up); + return NULL; + } + + up->parent = pim_upstream_find_parent(up); + if (up->sg.src.s_addr == INADDR_ANY) { + up->sources = list_new(); + up->sources->cmp = pim_upstream_compare; + } else + up->sources = NULL; + + pim_upstream_find_new_children(up); + up->flags = flags; + up->ref_count = 1; + up->t_join_timer = NULL; + up->t_ka_timer = NULL; + up->t_rs_timer = NULL; + up->t_msdp_reg_timer = NULL; + up->join_state = PIM_UPSTREAM_NOTJOINED; + up->reg_state = PIM_REG_NOINFO; + up->state_transition = pim_time_monotonic_sec(); + up->channel_oil = NULL; + up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; + + up->rpf.source_nexthop.interface = NULL; + up->rpf.source_nexthop.mrib_nexthop_addr.family = AF_INET; + up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = + PIM_NET_INADDR_ANY; + up->rpf.source_nexthop.mrib_metric_preference = + qpim_infinite_assert_metric.metric_preference; + up->rpf.source_nexthop.mrib_route_metric = + qpim_infinite_assert_metric.route_metric; + 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); + up->parent = NULL; + } + + if (up->sg.src.s_addr != INADDR_ANY) + wheel_remove_item(pim_upstream_sg_wheel, up); + + pim_upstream_remove_children(up); + if (up->sources) + list_delete(up->sources); + + hash_release(pim_upstream_hash, up); + XFREE(MTYPE_PIM_UPSTREAM, up); + return NULL; + } + + 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) { + zlog_debug( + "%s: Created Upstream %s upstream_addr %s ref count %d increment", + __PRETTY_FUNCTION__, up->sg_str, + inet_ntoa(up->upstream_addr), up->ref_count); + } + + return up; } struct pim_upstream *pim_upstream_find(struct prefix_sg *sg) { - struct pim_upstream lookup; - struct pim_upstream *up = NULL; + struct pim_upstream lookup; + struct pim_upstream *up = NULL; - lookup.sg = *sg; - up = hash_lookup (pim_upstream_hash, &lookup); - return up; + lookup.sg = *sg; + up = hash_lookup(pim_upstream_hash, &lookup); + return up; } -struct pim_upstream * -pim_upstream_find_or_add(struct prefix_sg *sg, - struct interface *incoming, - int flags, const char *name) +struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, + struct interface *incoming, + int flags, const char *name) { - struct pim_upstream *up; - - up = pim_upstream_find(sg); - - if (up) - { - if (!(up->flags & flags)) - { - up->flags |= flags; - up->ref_count++; - if (PIM_DEBUG_TRACE) - zlog_debug ("%s(%s): upstream %s ref count %d increment", - __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count); - } - } - else - up = pim_upstream_add (sg, incoming, flags, name); - - return up; + struct pim_upstream *up; + + up = pim_upstream_find(sg); + + if (up) { + if (!(up->flags & flags)) { + up->flags |= flags; + up->ref_count++; + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s(%s): upstream %s ref count %d increment", + __PRETTY_FUNCTION__, name, up->sg_str, + up->ref_count); + } + } else + up = pim_upstream_add(sg, incoming, flags, name); + + return up; } -void -pim_upstream_ref(struct pim_upstream *up, int flags, const char *name) +void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name) { - up->flags |= flags; - ++up->ref_count; - if (PIM_DEBUG_TRACE) - zlog_debug ("%s(%s): upstream %s ref count %d increment", - __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count); + up->flags |= flags; + ++up->ref_count; + if (PIM_DEBUG_TRACE) + zlog_debug("%s(%s): upstream %s ref count %d increment", + __PRETTY_FUNCTION__, name, up->sg_str, + up->ref_count); } struct pim_upstream *pim_upstream_add(struct prefix_sg *sg, - struct interface *incoming, - int flags, const char *name) + struct interface *incoming, int flags, + const char *name) { - struct pim_upstream *up = NULL; - int found = 0; - up = pim_upstream_find(sg); - if (up) { - pim_upstream_ref(up, flags, name); - found = 1; - } - else { - up = pim_upstream_new(sg, incoming, flags); - } - - if (PIM_DEBUG_TRACE) - { - if (up) - { - char buf[PREFIX2STR_BUFFER]; - prefix2str (&up->rpf.rpf_addr, buf, sizeof (buf)); - zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d", + struct pim_upstream *up = NULL; + int found = 0; + up = pim_upstream_find(sg); + if (up) { + pim_upstream_ref(up, flags, name); + found = 1; + } else { + up = pim_upstream_new(sg, incoming, flags); + } + + if (PIM_DEBUG_TRACE) { + if (up) { + char buf[PREFIX2STR_BUFFER]; + prefix2str(&up->rpf.rpf_addr, buf, sizeof(buf)); + zlog_debug("%s(%s): %s, iif %s (%s) found: %d: ref_count: %d", __PRETTY_FUNCTION__, name, up->sg_str, buf, up->rpf.source_nexthop.interface ? up->rpf.source_nexthop.interface->name : "NIL" , found, up->ref_count); - } - else - zlog_debug("%s(%s): (%s) failure to create", - __PRETTY_FUNCTION__, name, - pim_str_sg_dump (sg)); - } + } else + zlog_debug("%s(%s): (%s) failure to create", + __PRETTY_FUNCTION__, name, + pim_str_sg_dump(sg)); + } - return up; + 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 *starch) +int pim_upstream_evaluate_join_desired_interface(struct pim_upstream *up, + struct pim_ifchannel *ch, + struct pim_ifchannel *starch) { - if (ch) - { - if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) - return 0; - - if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch)) - return 1; - } - - /* - * joins (*,G) - */ - if (starch) - { - 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; + if (ch) { + if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) + return 0; + + if (!pim_macro_ch_lost_assert(ch) + && pim_macro_chisin_joins_or_include(ch)) + return 1; + } + + /* + * joins (*,G) + */ + if (starch) { + 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; } /* @@ -864,7 +837,7 @@ pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up, pim_ifp->pim_dr_addr ch->ifassert_winner_metric ch->ifassert_winner - ch->local_ifmembership + ch->local_ifmembership ch->ifjoin_state ch->upstream->rpf.source_nexthop.mrib_metric_preference ch->upstream->rpf.source_nexthop.mrib_route_metric @@ -874,31 +847,31 @@ pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up, */ int pim_upstream_evaluate_join_desired(struct pim_upstream *up) { - struct interface *ifp; - struct listnode *node; - struct pim_ifchannel *ch, *starch; - struct pim_upstream *starup = up->parent; - int ret = 0; + struct interface *ifp; + struct listnode *node; + struct pim_ifchannel *ch, *starch; + struct pim_upstream *starup = up->parent; + int ret = 0; - for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) - { - if (!ifp->info) - continue; + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + if (!ifp->info) + continue; - ch = pim_ifchannel_find (ifp, &up->sg); + ch = pim_ifchannel_find(ifp, &up->sg); - if (starup) - starch = pim_ifchannel_find (ifp, &starup->sg); - else - starch = NULL; + if (starup) + starch = pim_ifchannel_find(ifp, &starup->sg); + else + starch = NULL; - if (!ch && !starch) - continue; + if (!ch && !starch) + continue; - ret += pim_upstream_evaluate_join_desired_interface (up, ch, starch); - } /* scan iface channel list */ + ret += pim_upstream_evaluate_join_desired_interface(up, ch, + starch); + } /* scan iface channel list */ - return ret; /* false */ + return ret; /* false */ } /* @@ -906,28 +879,28 @@ int pim_upstream_evaluate_join_desired(struct pim_upstream *up) */ void pim_upstream_update_join_desired(struct pim_upstream *up) { - int was_join_desired; /* boolean */ - int is_join_desired; /* boolean */ - - was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags); - - is_join_desired = pim_upstream_evaluate_join_desired(up); - if (is_join_desired) - PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags); - else - PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); - - /* switched from false to true */ - if (is_join_desired && !was_join_desired) { - pim_upstream_switch(up, PIM_UPSTREAM_JOINED); - return; - } - - /* switched from true to false */ - if (!is_join_desired && was_join_desired) { - pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED); - return; - } + int was_join_desired; /* boolean */ + int is_join_desired; /* boolean */ + + was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags); + + is_join_desired = pim_upstream_evaluate_join_desired(up); + if (is_join_desired) + PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags); + else + PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); + + /* switched from false to true */ + if (is_join_desired && !was_join_desired) { + pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + return; + } + + /* switched from true to false */ + if (!is_join_desired && was_join_desired) { + pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED); + return; + } } /* @@ -941,110 +914,110 @@ void pim_upstream_update_join_desired(struct pim_upstream *up) */ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr) { - struct listnode *up_node; - struct listnode *up_nextnode; - struct pim_upstream *up; - - /* - * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr - */ - for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { - - if (PIM_DEBUG_TRACE) { - char neigh_str[INET_ADDRSTRLEN]; - char rpf_addr_str[PREFIX_STRLEN]; - pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, sizeof(neigh_str)); - pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); - zlog_debug("%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s", - __PRETTY_FUNCTION__, - neigh_str, up->sg_str, - up->join_state == PIM_UPSTREAM_JOINED, - rpf_addr_str); - } - - /* consider only (S,G) upstream in Joined state */ - if (up->join_state != PIM_UPSTREAM_JOINED) - continue; - - /* match RPF'(S,G)=neigh_addr */ - if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr) - continue; - - pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change", - up); - } + struct listnode *up_node; + struct listnode *up_nextnode; + struct pim_upstream *up; + + /* + * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr + */ + for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { + + if (PIM_DEBUG_TRACE) { + char neigh_str[INET_ADDRSTRLEN]; + char rpf_addr_str[PREFIX_STRLEN]; + pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, + sizeof(neigh_str)); + pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_addr_str, + sizeof(rpf_addr_str)); + zlog_debug( + "%s: matching neigh=%s against upstream (S,G)=%s joined=%d rpf_addr=%s", + __PRETTY_FUNCTION__, neigh_str, up->sg_str, + up->join_state == PIM_UPSTREAM_JOINED, + rpf_addr_str); + } + + /* consider only (S,G) upstream in Joined state */ + if (up->join_state != PIM_UPSTREAM_JOINED) + continue; + + /* match RPF'(S,G)=neigh_addr */ + if (up->rpf.rpf_addr.u.prefix4.s_addr != neigh_addr.s_addr) + continue; + + pim_upstream_join_timer_decrease_to_t_override( + "RPF'(S,G) GenID change", up); + } } void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct interface *old_rpf_ifp) { - struct listnode *chnode; - struct listnode *chnextnode; - struct pim_ifchannel *ch; - - /* search all ifchannels */ - 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 */ - (old_rpf_ifp == ch->interface) - && - /* RPF_interface(S) stopped being I */ - (ch->upstream->rpf.source_nexthop.interface != ch->interface) - ) { - assert_action_a5(ch); - } - } /* PIM_IFASSERT_I_AM_LOSER */ - - pim_ifchannel_update_assert_tracking_desired(ch); - } + struct listnode *chnode; + struct listnode *chnextnode; + struct pim_ifchannel *ch; + + /* search all ifchannels */ + 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 */ + (old_rpf_ifp == ch->interface) && + /* RPF_interface(S) stopped being I */ + (ch->upstream->rpf.source_nexthop + .interface != ch->interface)) { + assert_action_a5(ch); + } + } /* PIM_IFASSERT_I_AM_LOSER */ + + pim_ifchannel_update_assert_tracking_desired(ch); + } } void pim_upstream_update_could_assert(struct pim_upstream *up) { - struct listnode *chnode; - struct listnode *chnextnode; - struct pim_ifchannel *ch; - - /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { - pim_ifchannel_update_could_assert(ch); - } /* scan iface channel list */ + struct listnode *chnode; + struct listnode *chnextnode; + struct pim_ifchannel *ch; + + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { + pim_ifchannel_update_could_assert(ch); + } /* scan iface channel list */ } void pim_upstream_update_my_assert_metric(struct pim_upstream *up) { - struct listnode *chnode; - struct listnode *chnextnode; - struct pim_ifchannel *ch; + struct listnode *chnode; + struct listnode *chnextnode; + struct pim_ifchannel *ch; - /* scan per-interface (S,G) state */ - for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { - pim_ifchannel_update_my_assert_metric(ch); + /* scan per-interface (S,G) state */ + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { + pim_ifchannel_update_my_assert_metric(ch); - } /* scan iface channel list */ + } /* scan iface channel list */ } static void pim_upstream_update_assert_tracking_desired(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(up->ifchannels, chnode, chnextnode, ch)) - { - if (!ch->interface) - continue; - pim_ifp = ch->interface->info; - if (!pim_ifp) - continue; - - pim_ifchannel_update_assert_tracking_desired(ch); - - } /* scan iface channel list */ + 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(up->ifchannels, chnode, chnextnode, ch)) { + if (!ch->interface) + continue; + pim_ifp = ch->interface->info; + if (!pim_ifp) + continue; + + pim_ifchannel_update_assert_tracking_desired(ch); + + } /* scan iface channel list */ } /* When kat is stopped CouldRegister goes to false so we need to @@ -1052,19 +1025,21 @@ static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up) * from the OIL */ static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up) { - if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) - return; - - if (PIM_DEBUG_TRACE) - zlog_debug ("kat expired on %s; clear fhr reg state", up->sg_str); - - /* stop reg-stop timer */ - THREAD_OFF(up->t_rs_timer); - /* remove regiface from the OIL if it is there*/ - pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); - /* clear the register state */ - up->reg_state = PIM_REG_NOINFO; - PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags); + if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) + return; + + if (PIM_DEBUG_TRACE) + zlog_debug("kat expired on %s; clear fhr reg state", + up->sg_str); + + /* stop reg-stop timer */ + THREAD_OFF(up->t_rs_timer); + /* remove regiface from the OIL if it is there*/ + pim_channel_del_oif(up->channel_oil, pim_regiface, + PIM_OIF_FLAG_PROTO_PIM); + /* clear the register state */ + up->reg_state = PIM_REG_NOINFO; + PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags); } /* When kat is started CouldRegister can go to true. And if it does we @@ -1072,14 +1047,16 @@ static void pim_upstream_fhr_kat_expiry(struct pim_upstream *up) * to the OIL */ static void pim_upstream_fhr_kat_start(struct pim_upstream *up) { - if (pim_upstream_could_register(up)) { - if (PIM_DEBUG_TRACE) - 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_register_join (up); - } + if (pim_upstream_could_register(up)) { + if (PIM_DEBUG_TRACE) + 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_register_join(up); + } } /* @@ -1088,84 +1065,76 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up) * KAT expiry indicates that flow is inactive. If the flow was created or * maintained by activity now is the time to deref it. */ -static int -pim_upstream_keep_alive_timer (struct thread *t) +static int pim_upstream_keep_alive_timer(struct thread *t) { - struct pim_upstream *up; - - up = THREAD_ARG(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. - */ - } - - /* 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__); - } - 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; + struct pim_upstream *up; + + up = THREAD_ARG(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. + */ + } + + /* 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__); + } 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; } -void -pim_upstream_keep_alive_timer_start (struct pim_upstream *up, - uint32_t time) +void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time) { - if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { - if (PIM_DEBUG_TRACE) - zlog_debug ("kat start on %s with no stream reference", up->sg_str); - } - THREAD_OFF (up->t_ka_timer); - THREAD_TIMER_ON (master, - up->t_ka_timer, - pim_upstream_keep_alive_timer, - up, time); - - /* any time keepalive is started against a SG we will have to - * re-evaluate our active source database */ - pim_msdp_sa_local_update(up); + if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { + if (PIM_DEBUG_TRACE) + zlog_debug("kat start on %s with no stream reference", + up->sg_str); + } + THREAD_OFF(up->t_ka_timer); + THREAD_TIMER_ON(master, up->t_ka_timer, pim_upstream_keep_alive_timer, + up, time); + + /* any time keepalive is started against a SG we will have to + * re-evaluate our active source database */ + pim_msdp_sa_local_update(up); } /* MSDP on RP needs to know if a source is registerable to this RP */ -static int -pim_upstream_msdp_reg_timer(struct thread *t) +static int pim_upstream_msdp_reg_timer(struct thread *t) { - struct pim_upstream *up; + struct pim_upstream *up; - up = THREAD_ARG(t); - up->t_msdp_reg_timer = NULL; + up = THREAD_ARG(t); + up->t_msdp_reg_timer = NULL; - /* source is no longer active - pull the SA from MSDP's cache */ - pim_msdp_sa_local_del(&up->sg); - return 1; + /* source is no longer active - pull the SA from MSDP's cache */ + pim_msdp_sa_local_del(&up->sg); + return 1; } -void -pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) +void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) { - THREAD_OFF(up->t_msdp_reg_timer); - THREAD_TIMER_ON(master, up->t_msdp_reg_timer, - pim_upstream_msdp_reg_timer, up, PIM_MSDP_REG_RXED_PERIOD); + THREAD_OFF(up->t_msdp_reg_timer); + THREAD_TIMER_ON(master, up->t_msdp_reg_timer, + pim_upstream_msdp_reg_timer, up, + PIM_MSDP_REG_RXED_PERIOD); - pim_msdp_sa_local_update(up); + pim_msdp_sa_local_update(up); } /* @@ -1196,28 +1165,25 @@ pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) * SwitchToSptDesired(S,G) return true once a single packet has been * received for the source and group. */ -int -pim_upstream_switch_to_spt_desired (struct prefix_sg *sg) +int pim_upstream_switch_to_spt_desired(struct prefix_sg *sg) { - if (I_am_RP (sg->grp)) - return 1; + if (I_am_RP(sg->grp)) + return 1; - return 0; + return 0; } -int -pim_upstream_is_sg_rpt (struct pim_upstream *up) +int pim_upstream_is_sg_rpt(struct pim_upstream *up) { - struct listnode *chnode; - struct pim_ifchannel *ch; + struct listnode *chnode; + struct pim_ifchannel *ch; - for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) - { - if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) - return 1; - } + for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch)) { + if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) + return 1; + } - return 0; + return 0; } /* * After receiving a packet set SPTbit: @@ -1235,248 +1201,243 @@ pim_upstream_is_sg_rpt (struct pim_upstream *up) * } * } */ -void -pim_upstream_set_sptbit (struct pim_upstream *up, struct interface *incoming) +void pim_upstream_set_sptbit(struct pim_upstream *up, + struct interface *incoming) { - struct pim_upstream *starup = up->parent; - - // iif == RPF_interfvace(S) - if (up->rpf.source_nexthop.interface != incoming) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: Incoming Interface: %s is different than RPF_interface(S) %s", - __PRETTY_FUNCTION__, incoming->name, up->rpf.source_nexthop.interface->name); - return; - } - - // AND JoinDesired(S,G) == TRUE - // FIXME - - // DirectlyConnected(S) == TRUE - if (pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src)) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: %s is directly connected to the source", __PRETTY_FUNCTION__, - up->sg_str); - up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; - return; - } - - // OR RPF_interface(S) != RPF_interface(RP(G)) - if (!starup || up->rpf.source_nexthop.interface != starup->rpf.source_nexthop.interface) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: %s RPF_interface(S) != RPF_interface(RP(G))", - __PRETTY_FUNCTION__, up->sg_str); - up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; - return; - } - - // OR inherited_olist(S,G,rpt) == NULL - if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up)) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__, - up->sg_str); - up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; - return; - } - - // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND - // ( RPF'(S,G) != NULL ) ) - if (up->parent && pim_rpf_is_same (&up->rpf, &up->parent->rpf)) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__, - up->sg_str); - up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; - return; - } - - return; + struct pim_upstream *starup = up->parent; + + // iif == RPF_interfvace(S) + if (up->rpf.source_nexthop.interface != incoming) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Incoming Interface: %s is different than RPF_interface(S) %s", + __PRETTY_FUNCTION__, incoming->name, + up->rpf.source_nexthop.interface->name); + return; + } + + // AND JoinDesired(S,G) == TRUE + // FIXME + + // DirectlyConnected(S) == TRUE + if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, + up->sg.src)) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: %s is directly connected to the source", + __PRETTY_FUNCTION__, up->sg_str); + up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; + return; + } + + // OR RPF_interface(S) != RPF_interface(RP(G)) + if (!starup + || up->rpf.source_nexthop + .interface != starup->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: %s RPF_interface(S) != RPF_interface(RP(G))", + __PRETTY_FUNCTION__, up->sg_str); + up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; + return; + } + + // OR inherited_olist(S,G,rpt) == NULL + if (pim_upstream_is_sg_rpt(up) + && pim_upstream_empty_inherited_olist(up)) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL", + __PRETTY_FUNCTION__, up->sg_str); + up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; + return; + } + + // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND + // ( RPF'(S,G) != NULL ) ) + if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)", + __PRETTY_FUNCTION__, up->sg_str); + up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; + return; + } + + return; } -const char * -pim_upstream_state2str (enum pim_upstream_state join_state) +const char *pim_upstream_state2str(enum pim_upstream_state join_state) { - switch (join_state) - { - case PIM_UPSTREAM_NOTJOINED: - return "NotJoined"; - break; - case PIM_UPSTREAM_JOINED: - return "Joined"; - break; - } - return "Unknown"; + switch (join_state) { + case PIM_UPSTREAM_NOTJOINED: + return "NotJoined"; + break; + case PIM_UPSTREAM_JOINED: + return "Joined"; + break; + } + return "Unknown"; } -const char * -pim_reg_state2str (enum pim_reg_state reg_state, char *state_str) +const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str) { - switch (reg_state) - { - case PIM_REG_NOINFO: - strcpy (state_str, "RegNoInfo"); - break; - case PIM_REG_JOIN: - strcpy (state_str, "RegJoined"); - break; - case PIM_REG_JOIN_PENDING: - strcpy (state_str, "RegJoinPend"); - break; - case PIM_REG_PRUNE: - strcpy (state_str, "RegPrune"); - break; - default: - strcpy (state_str, "RegUnknown"); - } - return state_str; + switch (reg_state) { + case PIM_REG_NOINFO: + strcpy(state_str, "RegNoInfo"); + break; + case PIM_REG_JOIN: + strcpy(state_str, "RegJoined"); + break; + case PIM_REG_JOIN_PENDING: + strcpy(state_str, "RegJoinPend"); + break; + case PIM_REG_PRUNE: + strcpy(state_str, "RegPrune"); + break; + default: + strcpy(state_str, "RegUnknown"); + } + return state_str; } -static int -pim_upstream_register_stop_timer (struct thread *t) +static int pim_upstream_register_stop_timer(struct thread *t) { - struct pim_interface *pim_ifp; - struct pim_upstream *up; - struct pim_rpf *rpg; - struct ip ip_hdr; - up = THREAD_ARG (t); - - up->t_rs_timer = NULL; - - if (PIM_DEBUG_TRACE) - { - char state_str[PIM_REG_STATE_STR_LEN]; - zlog_debug ("%s: (S,G)=%s upstream register stop timer %s", - __PRETTY_FUNCTION__, up->sg_str, - pim_reg_state2str(up->reg_state, state_str)); - } - - switch (up->reg_state) - { - case PIM_REG_JOIN_PENDING: - up->reg_state = PIM_REG_JOIN; - pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); - break; - case PIM_REG_JOIN: - break; - case PIM_REG_PRUNE: - pim_ifp = up->rpf.source_nexthop.interface->info; - if (!pim_ifp) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: Interface: %s is not configured for pim", - __PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name); - return 0; - } - up->reg_state = PIM_REG_JOIN_PENDING; - pim_upstream_start_register_stop_timer (up, 1); - - if (((up->channel_oil->cc.lastused/100) > PIM_KEEPALIVE_PERIOD) && - (I_am_RP (up->sg.grp))) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__); - return 0; + struct pim_interface *pim_ifp; + struct pim_upstream *up; + struct pim_rpf *rpg; + struct ip ip_hdr; + up = THREAD_ARG(t); + + up->t_rs_timer = NULL; + + if (PIM_DEBUG_TRACE) { + char state_str[PIM_REG_STATE_STR_LEN]; + zlog_debug("%s: (S,G)=%s upstream register stop timer %s", + __PRETTY_FUNCTION__, up->sg_str, + pim_reg_state2str(up->reg_state, state_str)); } - rpg = RP (up->sg.grp); - memset (&ip_hdr, 0, sizeof (struct ip)); - ip_hdr.ip_p = PIM_IP_PROTO_PIM; - ip_hdr.ip_hl = 5; - ip_hdr.ip_v = 4; - ip_hdr.ip_src = up->sg.src; - ip_hdr.ip_dst = up->sg.grp; - ip_hdr.ip_len = htons (20); - // checksum is broken - pim_register_send ((uint8_t *)&ip_hdr, sizeof (struct ip), - pim_ifp->primary_address, rpg, 1, up); - break; - default: - break; - } - - return 0; + + switch (up->reg_state) { + case PIM_REG_JOIN_PENDING: + up->reg_state = PIM_REG_JOIN; + pim_channel_add_oif(up->channel_oil, pim_regiface, + PIM_OIF_FLAG_PROTO_PIM); + break; + case PIM_REG_JOIN: + break; + case PIM_REG_PRUNE: + pim_ifp = up->rpf.source_nexthop.interface->info; + if (!pim_ifp) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Interface: %s is not configured for pim", + __PRETTY_FUNCTION__, + up->rpf.source_nexthop.interface->name); + return 0; + } + up->reg_state = PIM_REG_JOIN_PENDING; + pim_upstream_start_register_stop_timer(up, 1); + + if (((up->channel_oil->cc.lastused / 100) + > PIM_KEEPALIVE_PERIOD) + && (I_am_RP(up->sg.grp))) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", + __PRETTY_FUNCTION__); + return 0; + } + rpg = RP(up->sg.grp); + memset(&ip_hdr, 0, sizeof(struct ip)); + ip_hdr.ip_p = PIM_IP_PROTO_PIM; + ip_hdr.ip_hl = 5; + ip_hdr.ip_v = 4; + ip_hdr.ip_src = up->sg.src; + ip_hdr.ip_dst = up->sg.grp; + ip_hdr.ip_len = htons(20); + // checksum is broken + pim_register_send((uint8_t *)&ip_hdr, sizeof(struct ip), + pim_ifp->primary_address, rpg, 1, up); + break; + default: + break; + } + + return 0; } -void -pim_upstream_start_register_stop_timer (struct pim_upstream *up, int null_register) +void pim_upstream_start_register_stop_timer(struct pim_upstream *up, + int null_register) { - uint32_t time; - - if (up->t_rs_timer) - { - THREAD_TIMER_OFF (up->t_rs_timer); - up->t_rs_timer = NULL; - } - - if (!null_register) - { - uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD); - uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD); - time = lower + (random () % (upper - lower + 1)) - PIM_REGISTER_PROBE_PERIOD; - } - else - time = PIM_REGISTER_PROBE_PERIOD; - - if (PIM_DEBUG_TRACE) - { - zlog_debug ("%s: (S,G)=%s Starting upstream register stop timer %d", - __PRETTY_FUNCTION__, up->sg_str, time); - } - THREAD_TIMER_ON (master, up->t_rs_timer, - pim_upstream_register_stop_timer, - up, time); + uint32_t time; + + if (up->t_rs_timer) { + THREAD_TIMER_OFF(up->t_rs_timer); + up->t_rs_timer = NULL; + } + + if (!null_register) { + uint32_t lower = (0.5 * PIM_REGISTER_SUPPRESSION_PERIOD); + uint32_t upper = (1.5 * PIM_REGISTER_SUPPRESSION_PERIOD); + time = lower + (random() % (upper - lower + 1)) + - PIM_REGISTER_PROBE_PERIOD; + } else + time = PIM_REGISTER_PROBE_PERIOD; + + if (PIM_DEBUG_TRACE) { + zlog_debug( + "%s: (S,G)=%s Starting upstream register stop timer %d", + __PRETTY_FUNCTION__, up->sg_str, time); + } + THREAD_TIMER_ON(master, up->t_rs_timer, + pim_upstream_register_stop_timer, up, time); } -int -pim_upstream_inherited_olist_decide (struct pim_upstream *up) +int pim_upstream_inherited_olist_decide(struct pim_upstream *up) { - 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; - - 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_RO (vrf_iflist (VRF_DEFAULT), node, ifp)) - { - if (!ifp->info) - continue; - - 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) - flag = PIM_OIF_FLAG_PROTO_STAR; - - pim_channel_add_oif (up->channel_oil, ifp, flag); - output_intf++; - } - } - - return output_intf; + 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; + + 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_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + if (!ifp->info) + continue; + + 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) + flag = PIM_OIF_FLAG_PROTO_STAR; + + pim_channel_add_oif(up->channel_oil, ifp, flag); + output_intf++; + } + } + + return output_intf; } /* @@ -1495,29 +1456,27 @@ pim_upstream_inherited_olist_decide (struct pim_upstream *up) * return 1 if there are any output interfaces * return 0 if there are not any output interfaces */ -int -pim_upstream_inherited_olist (struct pim_upstream *up) +int pim_upstream_inherited_olist(struct pim_upstream *up) { - int output_intf = pim_upstream_inherited_olist_decide (up); - - /* - * If we have output_intf switch state to Join and work like normal - * If we don't have an output_intf that means we are probably a - * switch on a stick so turn on forwarding to just accept the - * incoming packets so we don't bother the other stuff! - */ - if (output_intf) - pim_upstream_switch (up, PIM_UPSTREAM_JOINED); - else - forward_on (up); - - return output_intf; + int output_intf = pim_upstream_inherited_olist_decide(up); + + /* + * If we have output_intf switch state to Join and work like normal + * If we don't have an output_intf that means we are probably a + * switch on a stick so turn on forwarding to just accept the + * incoming packets so we don't bother the other stuff! + */ + if (output_intf) + pim_upstream_switch(up, PIM_UPSTREAM_JOINED); + else + forward_on(up); + + return output_intf; } -int -pim_upstream_empty_inherited_olist (struct pim_upstream *up) +int pim_upstream_empty_inherited_olist(struct pim_upstream *up) { - return pim_channel_oil_empty (up->channel_oil); + return pim_channel_oil_empty(up->channel_oil); } /* @@ -1526,58 +1485,54 @@ pim_upstream_empty_inherited_olist (struct pim_upstream *up) * set and see if the new neighbor allows * the join to be sent */ -void -pim_upstream_find_new_rpf (void) +void pim_upstream_find_new_rpf(void) { - struct listnode *up_node; - struct listnode *up_nextnode; - struct pim_upstream *up; - - /* - * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr - */ - for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) - { - if (pim_rpf_addr_is_inaddr_any(&up->rpf)) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("Upstream %s without a path to send join, checking", - up->sg_str); - pim_rpf_update (up, NULL, 1); + struct listnode *up_node; + struct listnode *up_nextnode; + struct pim_upstream *up; + + /* + * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr + */ + for (ALL_LIST_ELEMENTS(pim_upstream_list, up_node, up_nextnode, up)) { + if (pim_rpf_addr_is_inaddr_any(&up->rpf)) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "Upstream %s without a path to send join, checking", + up->sg_str); + pim_rpf_update(up, NULL, 1); + } } - } } -static unsigned int -pim_upstream_hash_key (void *arg) +static unsigned int pim_upstream_hash_key(void *arg) { - struct pim_upstream *up = (struct pim_upstream *)arg; + struct pim_upstream *up = (struct pim_upstream *)arg; - return jhash_2words (up->sg.src.s_addr, up->sg.grp.s_addr, 0); + return jhash_2words(up->sg.src.s_addr, up->sg.grp.s_addr, 0); } -void pim_upstream_terminate (void) +void pim_upstream_terminate(void) { - if (pim_upstream_list) - list_delete (pim_upstream_list); - pim_upstream_list = NULL; + if (pim_upstream_list) + list_delete(pim_upstream_list); + pim_upstream_list = NULL; - if (pim_upstream_hash) - hash_free (pim_upstream_hash); - pim_upstream_hash = NULL; + if (pim_upstream_hash) + hash_free(pim_upstream_hash); + pim_upstream_hash = NULL; } -static int -pim_upstream_equal (const void *arg1, const void *arg2) +static int pim_upstream_equal(const void *arg1, const void *arg2) { - const struct pim_upstream *up1 = (const struct pim_upstream *)arg1; - const struct pim_upstream *up2 = (const struct pim_upstream *)arg2; + const struct pim_upstream *up1 = (const struct pim_upstream *)arg1; + const struct pim_upstream *up2 = (const struct pim_upstream *)arg2; - if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) && - (up1->sg.src.s_addr == up2->sg.src.s_addr)) - return 1; + if ((up1->sg.grp.s_addr == up2->sg.grp.s_addr) + && (up1->sg.src.s_addr == up2->sg.src.s_addr)) + return 1; - return 0; + return 0; } /* rfc4601:section-4.2:"Data Packet Forwarding Rules" defines @@ -1596,129 +1551,128 @@ pim_upstream_equal (const void *arg1, const void *arg2) */ static bool pim_upstream_kat_start_ok(struct pim_upstream *up) { - /* "iif == RPF_interface(S)" check has to be done by the kernel or hw - * so we will skip that here */ - if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, - up->sg.src)) { - return true; - } - - if ((up->join_state == PIM_UPSTREAM_JOINED) && - !pim_upstream_empty_inherited_olist(up)) { - /* XXX: I have added this RP check just for 3.2 and it's a digression from - * what rfc-4601 says. Till now we were only running KAT on FHR and RP and - * there is some angst around making the change to run it all routers that - * maintain the (S, G) state. This is tracked via CM-13601 and MUST be - * removed to handle spt turn-arounds correctly in a 3-tier clos */ - if (I_am_RP (up->sg.grp)) - return true; - } - - return false; + /* "iif == RPF_interface(S)" check has to be done by the kernel or hw + * so we will skip that here */ + if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, + up->sg.src)) { + return true; + } + + if ((up->join_state == PIM_UPSTREAM_JOINED) + && !pim_upstream_empty_inherited_olist(up)) { + /* XXX: I have added this RP check just for 3.2 and it's a + * digression from + * what rfc-4601 says. Till now we were only running KAT on FHR + * and RP and + * there is some angst around making the change to run it all + * routers that + * maintain the (S, G) state. This is tracked via CM-13601 and + * MUST be + * removed to handle spt turn-arounds correctly in a 3-tier clos + */ + if (I_am_RP(up->sg.grp)) + return true; + } + + return false; } /* * Code to check and see if we've received packets on a S,G mroute * and if so to set the SPT bit appropriately */ -static void -pim_upstream_sg_running (void *arg) +static void pim_upstream_sg_running(void *arg) { - struct pim_upstream *up = (struct pim_upstream *)arg; - - // No packet can have arrived here if this is the case - if (!up->channel_oil || !up->channel_oil->installed) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: %s is not installed in mroute", - __PRETTY_FUNCTION__, up->sg_str); - return; - } - - /* - * This is a bit of a hack - * We've noted that we should rescan but - * we've missed the window for doing so in - * pim_zebra.c for some reason. I am - * only doing this at this point in time - * to get us up and working for the moment - */ - if (up->channel_oil->oil_inherited_rescan) - { - if (PIM_DEBUG_TRACE) - zlog_debug ("%s: Handling unscanned inherited_olist for %s", __PRETTY_FUNCTION__, up->sg_str); - pim_upstream_inherited_olist_decide (up); - up->channel_oil->oil_inherited_rescan = 0; - } - pim_mroute_update_counters (up->channel_oil); - - // Have we seen packets? - if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) && - (up->channel_oil->cc.lastused/100 > 30)) - { - if (PIM_DEBUG_TRACE) - { - zlog_debug ("%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)", - __PRETTY_FUNCTION__, up->sg_str, - up->channel_oil->cc.oldpktcnt, - up->channel_oil->cc.pktcnt, - up->channel_oil->cc.lastused/100); + struct pim_upstream *up = (struct pim_upstream *)arg; + + // No packet can have arrived here if this is the case + if (!up->channel_oil || !up->channel_oil->installed) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: %s is not installed in mroute", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + + /* + * This is a bit of a hack + * We've noted that we should rescan but + * we've missed the window for doing so in + * pim_zebra.c for some reason. I am + * only doing this at this point in time + * to get us up and working for the moment + */ + if (up->channel_oil->oil_inherited_rescan) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Handling unscanned inherited_olist for %s", + __PRETTY_FUNCTION__, up->sg_str); + pim_upstream_inherited_olist_decide(up); + up->channel_oil->oil_inherited_rescan = 0; + } + pim_mroute_update_counters(up->channel_oil); + + // Have we seen packets? + if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) + && (up->channel_oil->cc.lastused / 100 > 30)) { + if (PIM_DEBUG_TRACE) { + zlog_debug( + "%s: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)", + __PRETTY_FUNCTION__, up->sg_str, + up->channel_oil->cc.oldpktcnt, + up->channel_oil->cc.pktcnt, + up->channel_oil->cc.lastused / 100); + } + return; } - 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_DEBUG_TRACE) - zlog_debug ("source reference created on kat restart %s", up->sg_str); - - pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, __PRETTY_FUNCTION__); - PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); - pim_upstream_fhr_kat_start(up); + + 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_DEBUG_TRACE) + zlog_debug( + "source reference created on kat restart %s", + up->sg_str); + + pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, + __PRETTY_FUNCTION__); + 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_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); - } - return; + return; } -void -pim_upstream_add_lhr_star_pimreg (void) +void pim_upstream_add_lhr_star_pimreg(void) { - struct pim_upstream *up; - struct listnode *node; + 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; + 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 (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) + continue; - pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP); - } + 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) +void pim_upstream_spt_prefix_list_update(struct prefix_list *pl) { - const char *pname = prefix_list_name (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); - } + if (pimg->spt.plist && strcmp(pimg->spt.plist, pname) == 0) { + pim_upstream_remove_lhr_star_pimreg(pname); + } } /* @@ -1733,53 +1687,51 @@ pim_upstream_spt_prefix_list_update (struct prefix_list *pl) * the interface * */ -void -pim_upstream_remove_lhr_star_pimreg (const char *nlist) +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); - } + 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) +void pim_upstream_init(void) { - pim_upstream_sg_wheel = wheel_init (master, 31000, 100, - pim_upstream_hash_key, - pim_upstream_sg_running); - pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key, - pim_upstream_equal); - - pim_upstream_list = list_new (); - pim_upstream_list->del = (void (*)(void *)) pim_upstream_free; - pim_upstream_list->cmp = pim_upstream_compare; - + pim_upstream_sg_wheel = + wheel_init(master, 31000, 100, pim_upstream_hash_key, + pim_upstream_sg_running); + pim_upstream_hash = hash_create_size(8192, pim_upstream_hash_key, + pim_upstream_equal); + + pim_upstream_list = list_new(); + pim_upstream_list->del = (void (*)(void *))pim_upstream_free; + pim_upstream_list->cmp = pim_upstream_compare; } |
