static void scan_upstream_rpf_cache() { struct listnode *up_node; struct listnode *up_nextnode; struct pim_upstream *up; for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { struct in_addr old_rpf_addr; enum pim_rpf_result rpf_result; rpf_result = pim_rpf_update(up, &old_rpf_addr); if (rpf_result == PIM_RPF_FAILURE) continue; if (rpf_result == PIM_RPF_CHANGED) { if (up->join_state == PIM_UPSTREAM_JOINED) { /* RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages Transitions from Joined State RPF'(S,G) changes not due to an Assert The upstream (S,G) state machine remains in Joined state. Send Join(S,G) to the new upstream neighbor, which is the new value of RPF'(S,G). Send Prune(S,G) to the old upstream neighbor, which is the old value of RPF'(S,G). Set the Join Timer (JT) to expire after t_periodic seconds. */ /* send Prune(S,G) to the old upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, old_rpf_addr, up->source_addr, up->group_addr, 0 /* prune */); /* send Join(S,G) to the current upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 1 /* join */); pim_upstream_join_timer_restart(up); } /* up->join_state == PIM_UPSTREAM_JOINED */ /* FIXME can join_desired actually be changed by pim_rpf_update() returning PIM_RPF_CHANGED ? */ pim_upstream_update_join_desired(up); } /* PIM_RPF_CHANGED */ } /* for (qpim_upstream_list) */ }
static void send_join(struct pim_upstream *up) { zassert(up->join_state == PIM_UPSTREAM_JOINED); if (PIM_DEBUG_PIM_TRACE) { if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) { char src_str[100]; char grp_str[100]; char rpf_str[100]; pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("<rpf?>", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s", __PRETTY_FUNCTION__, src_str, grp_str, rpf_str); /* warning only */ } } /* send Join(S,G) to the current upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 1 /* join */); }
static void pim_upstream_switch(struct pim_upstream *up, enum pim_upstream_state new_state) { enum pim_upstream_state old_state = up->join_state; zassert(old_state != new_state); up->join_state = new_state; up->state_transition = pim_time_monotonic_sec(); if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("<src?>", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("<grp?>", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)", __PRETTY_FUNCTION__, ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"), src_str, grp_str); } pim_upstream_update_assert_tracking_desired(up); if (new_state == PIM_UPSTREAM_JOINED) { forward_on(up); send_join(up); join_timer_start(up); } else { forward_off(up); pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 0 /* prune */); zassert(up->t_join_timer); THREAD_OFF(up->t_join_timer); } }