diff options
Diffstat (limited to 'pimd')
| -rw-r--r-- | pimd/pim_cmd.c | 155 | ||||
| -rw-r--r-- | pimd/pim_ifchannel.c | 2 | ||||
| -rw-r--r-- | pimd/pim_igmp_mtrace.c | 7 | ||||
| -rw-r--r-- | pimd/pim_join.c | 6 | ||||
| -rw-r--r-- | pimd/pim_jp_agg.c | 14 | ||||
| -rw-r--r-- | pimd/pim_mroute.c | 16 | ||||
| -rw-r--r-- | pimd/pim_nht.c | 57 | ||||
| -rw-r--r-- | pimd/pim_nht.h | 1 | ||||
| -rw-r--r-- | pimd/pim_oil.c | 58 | ||||
| -rw-r--r-- | pimd/pim_oil.h | 20 | ||||
| -rw-r--r-- | pimd/pim_register.c | 12 | ||||
| -rw-r--r-- | pimd/pim_rp.c | 202 | ||||
| -rw-r--r-- | pimd/pim_rp.h | 8 | ||||
| -rw-r--r-- | pimd/pim_rpf.c | 33 | ||||
| -rw-r--r-- | pimd/pim_rpf.h | 3 | ||||
| -rw-r--r-- | pimd/pim_upstream.c | 189 | ||||
| -rw-r--r-- | pimd/pim_upstream.h | 24 | ||||
| -rw-r--r-- | pimd/pim_zebra.c | 365 | ||||
| -rw-r--r-- | pimd/pim_zlookup.c | 2 | ||||
| -rw-r--r-- | pimd/pimd.c | 4 |
20 files changed, 780 insertions, 398 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index f521704f1b..70b3ae10e5 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -198,7 +198,7 @@ static void pim_show_assert_helper(struct vty *vty, pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation); pim_time_timer_to_mmss(timer, sizeof(timer), ch->t_ifassert_timer); - vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n", + vty_out(vty, "%-16s %-15s %-15s %-15s %-6s %-15s %-8s %-5s\n", ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, pim_ifchannel_ifassert_name(ch->ifassert_state), winner_str, uptime, timer); @@ -214,7 +214,7 @@ static void pim_show_assert(struct pim_instance *pim, struct vty *vty) now = pim_time_monotonic_sec(); vty_out(vty, - "Interface Address Source Group State Winner Uptime Timer\n"); + "Interface Address Source Group State Winner Uptime Timer\n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; @@ -239,7 +239,7 @@ static void pim_show_assert_internal_helper(struct vty *vty, pim_inet4_dump("<ch_src?>", ch->sg.src, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); - vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n", + vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-3s %-3s %-4s\n", ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no", pim_macro_ch_could_assert_eval(ch) ? "yes" : "no", @@ -261,7 +261,7 @@ static void pim_show_assert_internal(struct pim_instance *pim, struct vty *vty) "eATD: Evaluate AssertTrackingDesired\n\n"); vty_out(vty, - "Interface Address Source Group CA eCA ATD eATD\n"); + "Interface Address Source Group CA eCA ATD eATD\n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; if (!pim_ifp) @@ -292,7 +292,7 @@ static void pim_show_assert_metric_helper(struct vty *vty, pim_inet4_dump("<ch_grp?>", ch->sg.grp, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("<addr?>", am.ip_address, addr_str, sizeof(addr_str)); - vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s\n", + vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %4u %6u %-15s\n", ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, am.rpt_bit_flag ? "yes" : "no", am.metric_preference, am.route_metric, addr_str); @@ -305,7 +305,7 @@ static void pim_show_assert_metric(struct pim_instance *pim, struct vty *vty) struct interface *ifp; vty_out(vty, - "Interface Address Source Group RPT Pref Metric Address \n"); + "Interface Address Source Group RPT Pref Metric Address \n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; @@ -349,7 +349,7 @@ static void pim_show_assert_winner_metric_helper(struct vty *vty, else snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric); - vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n", + vty_out(vty, "%-16s %-15s %-15s %-15s %-3s %-4s %-6s %-15s\n", ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str, metr_str, addr_str); } @@ -362,7 +362,7 @@ static void pim_show_assert_winner_metric(struct pim_instance *pim, struct interface *ifp; vty_out(vty, - "Interface Address Source Group RPT Pref Metric Address \n"); + "Interface Address Source Group RPT Pref Metric Address \n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; @@ -462,7 +462,7 @@ static void pim_show_membership(struct pim_instance *pim, struct vty *vty, json, JSON_C_TO_STRING_PRETTY)); } else { vty_out(vty, - "Interface Address Source Group Membership\n"); + "Interface Address Source Group Membership\n"); /* * Example of the json data we are traversing @@ -499,7 +499,7 @@ static void pim_show_membership(struct pim_instance *pim, struct vty *vty, type = json_object_get_type(if_field_val); if (type == json_type_object) { - vty_out(vty, "%-9s ", key); + vty_out(vty, "%-16s ", key); json_object_object_get_ex( val, "address", &json_tmp); @@ -566,7 +566,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, json = json_object_new_object(); else vty_out(vty, - "Interface State Address V Querier Query Timer Uptime\n"); + "Interface State Address V Querier Query Timer Uptime\n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; @@ -614,7 +614,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, } } else { vty_out(vty, - "%-9s %5s %15s %d %7s %11s %8s\n", + "%-16s %5s %15s %d %7s %11s %8s\n", ifp->name, if_is_up(ifp) ? (igmp->mtrace_only ? "mtrc" @@ -854,7 +854,7 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty) now = pim_time_monotonic_sec(); vty_out(vty, - "Interface Address Source Group Socket Uptime \n"); + "Interface Address Source Group Socket Uptime \n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; @@ -888,7 +888,7 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty) pim_inet4_dump("<src?>", ij->source_addr, source_str, sizeof(source_str)); - vty_out(vty, "%-9s %-15s %-15s %-15s %6d %8s\n", + vty_out(vty, "%-16s %-15s %-15s %-15s %6d %8s\n", ifp->name, pri_addr_str, source_str, group_str, ij->sock_fd, uptime); } /* for (pim_ifp->igmp_join_list) */ @@ -1191,7 +1191,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim, vty_out(vty, "Designated Router\n"); vty_out(vty, "-----------------\n"); vty_out(vty, "Address : %s\n", dr_str); - vty_out(vty, "Priority : %d(%d)\n", + vty_out(vty, "Priority : %u(%d)\n", pim_ifp->pim_dr_priority, pim_ifp->pim_dr_num_nondrpri_neighbors); vty_out(vty, "Uptime : %s\n", dr_uptime); @@ -1421,11 +1421,11 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, json, JSON_C_TO_STRING_PRETTY)); } else { vty_out(vty, - "Interface State Address PIM Nbrs PIM DR FHR IfChannels\n"); + "Interface State Address PIM Nbrs PIM DR FHR IfChannels\n"); json_object_object_foreach(json, key, val) { - vty_out(vty, "%-9s ", key); + vty_out(vty, "%-16s ", key); json_object_object_get_ex(val, "state", &json_tmp); vty_out(vty, "%5s ", json_object_get_string(json_tmp)); @@ -1474,12 +1474,13 @@ static void pim_show_interface_traffic(struct pim_instance *pim, json = json_object_new_object(); else { vty_out(vty, "\n"); - vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s\n", - "Interface", " HELLO", " JOIN", " PRUNE", - " REGISTER", " REGISTER-STOP", " ASSERT"); - vty_out(vty, "%-10s%-18s%-17s%-17s%-17s%-17s%-17s\n", "", - " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx", - " Rx/Tx", " Rx/Tx"); + vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n", + "Interface", " HELLO", " JOIN", + " PRUNE", " REGISTER", "REGISTER-STOP", + " ASSERT"); + vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n", "", + " Rx/Tx", " Rx/Tx", " Rx/Tx", + " Rx/Tx", " Rx/Tx", " Rx/Tx"); vty_out(vty, "---------------------------------------------------------------------------------------------------------------\n"); } @@ -1519,7 +1520,7 @@ static void pim_show_interface_traffic(struct pim_instance *pim, json_object_object_add(json, ifp->name, json_row); } else { vty_out(vty, - "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n", + "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n", ifp->name, pim_ifp->pim_ifstat_hello_recv, pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv, @@ -1555,14 +1556,14 @@ static void pim_show_interface_traffic_single(struct pim_instance *pim, json = json_object_new_object(); else { vty_out(vty, "\n"); - vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s\n", + vty_out(vty, "%-16s%-17s%-17s%-17s%-17s%-17s%-17s\n", "Interface", " HELLO", " JOIN", " PRUNE", " REGISTER", " REGISTER-STOP", " ASSERT"); - vty_out(vty, "%-10s%-18s%-17s%-17s%-17s%-17s%-17s\n", "", + vty_out(vty, "%-14s%-18s%-17s%-17s%-17s%-17s%-17s\n", "", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx"); vty_out(vty, - "---------------------------------------------------------------------------------------------------------------\n"); + "---------------------------------------------------------------------------------------------------------------------\n"); } FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -1605,7 +1606,7 @@ static void pim_show_interface_traffic_single(struct pim_instance *pim, json_object_object_add(json, ifp->name, json_row); } else { vty_out(vty, - "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n", + "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u \n", ifp->name, pim_ifp->pim_ifstat_hello_recv, pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv, @@ -1687,7 +1688,7 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp, } else json_object_object_add(json_grp, ch_src_str, json_row); } else { - vty_out(vty, "%-9s %-15s %-15s %-15s %-10s %8s %-6s %5s\n", + vty_out(vty, "%-16s %-15s %-15s %-15s %-10s %8s %-6s %5s\n", ch->interface->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags), @@ -1709,7 +1710,7 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty, bool uj) json = json_object_new_object(); else vty_out(vty, - "Interface Address Source Group State Uptime Expire Prune\n"); + "Interface Address Source Group State Uptime Expire Prune\n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; @@ -1957,7 +1958,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty, vty_out(vty, "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G)"); vty_out(vty, - "\nInstalled Source Group IIF OIL\n"); + "\nInstalled Source Group IIF OIL\n"); } for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) { @@ -2040,9 +2041,8 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty, c_oil->cc.wrong_if); } } else { - vty_out(vty, "%-9d %-15s %-15s %-7s ", - c_oil->installed, src_str, grp_str, - in_ifname); + vty_out(vty, "%-9d %-15s %-15s %-16s ", + c_oil->installed, src_str, grp_str, in_ifname); } for (oif_vif_index = 0; oif_vif_index < MAXVIFS; @@ -2159,7 +2159,7 @@ static void pim_show_neighbors(struct pim_instance *pim, struct vty *vty, json = json_object_new_object(); } else { vty_out(vty, - "Interface Neighbor Uptime Holdtime DR Pri\n"); + "Interface Neighbor Uptime Holdtime DR Pri\n"); } FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -2201,7 +2201,7 @@ static void pim_show_neighbors(struct pim_instance *pim, struct vty *vty, neigh_src_str, json_row); } else { - vty_out(vty, "%-9s %15s %8s %8s %6d\n", + vty_out(vty, "%-16s %15s %8s %8s %6d\n", ifp->name, neigh_src_str, uptime, expire, neigh->dr_priority); } @@ -2226,7 +2226,7 @@ static void pim_show_neighbors_secondary(struct pim_instance *pim, struct interface *ifp; vty_out(vty, - "Interface Address Neighbor Secondary \n"); + "Interface Address Neighbor Secondary \n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; @@ -2263,7 +2263,7 @@ static void pim_show_neighbors_secondary(struct pim_instance *pim, prefix2str(p, neigh_sec_str, sizeof(neigh_sec_str)); - vty_out(vty, "%-9s %-15s %-15s %-15s\n", + vty_out(vty, "%-16s %-15s %-15s %-15s\n", ifp->name, inet_ntoa(ifaddr), neigh_src_str, neigh_sec_str); } @@ -2350,7 +2350,7 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, json = json_object_new_object(); else vty_out(vty, - "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n"); + "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n"); for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { char src_str[INET_ADDRSTRLEN]; @@ -2370,9 +2370,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, up->t_join_timer); /* - * If we have a J/P timer for the neighbor display that + * If the upstream is not dummy and it has a J/P timer for the + * neighbor display that */ - if (!up->t_join_timer) { + if (!up->t_join_timer && up->rpf.source_nexthop.interface) { struct pim_neighbor *nbr; nbr = pim_neighbor_find( @@ -2412,8 +2413,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, json_row = json_object_new_object(); json_object_pim_upstream_add(json_row, up); json_object_string_add( - json_row, "inboundInterface", - up->rpf.source_nexthop.interface->name); + json_row, "inboundInterface", + up->rpf.source_nexthop.interface + ? up->rpf.source_nexthop.interface->name + : "Unknown"); /* * The RPF address we use is slightly different @@ -2462,9 +2465,11 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, json_object_object_add(json_group, src_str, json_row); } else { vty_out(vty, - "%-10s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n", - up->rpf.source_nexthop.interface->name, src_str, - grp_str, state_str, uptime, join_timer, + "%-16s%-15s %-15s %-11s %-8s %-9s %-9s %-9s %6d\n", + up->rpf.source_nexthop.interface + ? up->rpf.source_nexthop.interface->name + : "Unknown", + src_str, grp_str, state_str, uptime, join_timer, rs_timer, ka_timer, up->ref_count); } } @@ -2522,7 +2527,7 @@ static void pim_show_join_desired_helper(struct pim_instance *pim, json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n", + vty_out(vty, "%-16s %-15s %-15s %-10s %-5s %-10s %-11s %-6s\n", ch->interface->name, src_str, grp_str, pim_macro_ch_lost_assert(ch) ? "yes" : "no", pim_macro_chisin_joins(ch) ? "yes" : "no", @@ -2548,7 +2553,7 @@ static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, json = json_object_new_object(); else vty_out(vty, - "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n"); + "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD\n"); /* scan per-interface (S,G) state */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -2584,7 +2589,7 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, json = json_object_new_object(); else vty_out(vty, - "Source Group RpfIface RibNextHop RpfAddress \n"); + "Source Group RpfIface RibNextHop RpfAddress \n"); for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { char src_str[INET_ADDRSTRLEN]; @@ -2627,7 +2632,7 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, rpf_addr_str); json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-15s %-15s %-8s %-15s %-15s\n", src_str, + vty_out(vty, "%-15s %-15s %-16s %-15s %-15s\n", src_str, grp_str, rpf_ifname, rpf_nexthop_str, rpf_addr_str); } @@ -2721,7 +2726,7 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj) show_rpf_refresh_stats(vty, pim, now, json); vty_out(vty, "\n"); vty_out(vty, - "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n"); + "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n"); } for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) { @@ -2769,7 +2774,7 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj) json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-15s %-15s %-8s %-15s %-15s %6d %4d\n", + vty_out(vty, "%-15s %-15s %-16s %-15s %-15s %6d %4d\n", src_str, grp_str, rpf_ifname, rpf_addr_str, rib_nexthop_str, rpf->source_nexthop.mrib_route_metric, @@ -2804,7 +2809,7 @@ static int pim_print_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg) ifp = if_lookup_by_index(first_ifindex, pim->vrf_id); vty_out(vty, "%-15s ", inet_ntoa(pnc->rpf.rpf_addr.u.prefix4)); - vty_out(vty, "%-14s ", ifp ? ifp->name : "NULL"); + vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL"); vty_out(vty, "%s ", inet_ntoa(nh_node->gate.ipv4)); vty_out(vty, "\n"); } @@ -2819,8 +2824,8 @@ static void pim_show_nexthop(struct pim_instance *pim, struct vty *vty) cwd.pim = pim; vty_out(vty, "Number of registered addresses: %lu\n", pim->rpf_hash->count); - vty_out(vty, "Address Interface Nexthop\n"); - vty_out(vty, "-------------------------------------------\n"); + vty_out(vty, "Address Interface Nexthop\n"); + vty_out(vty, "---------------------------------------------\n"); hash_walk(pim->rpf_hash, pim_print_pnc_cache_walkcb, &cwd); } @@ -2839,7 +2844,7 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) json = json_object_new_object(); else vty_out(vty, - "Interface Address Group Mode Timer Srcs V Uptime \n"); + "Interface Address Group Mode Timer Srcs V Uptime \n"); /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -2919,7 +2924,7 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) } else { vty_out(vty, - "%-9s %-15s %-15s %4s %8s %4d %d %8s\n", + "%-16s %-15s %-15s %4s %8s %4d %d %8s\n", ifp->name, ifaddr_str, group_str, grp->igmp_version == 3 @@ -2951,7 +2956,7 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, struct interface *ifp; vty_out(vty, - "Interface Address Group RetTimer Counter RetSrcs\n"); + "Interface Address Group RetTimer Counter RetSrcs\n"); /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -2999,7 +3004,7 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, } } - vty_out(vty, "%-9s %-15s %-15s %-8s %7d %7d\n", + vty_out(vty, "%-16s %-15s %-15s %-8s %7d %7d\n", ifp->name, ifaddr_str, group_str, grp_retr_mmss, grp->group_specific_query_retransmit_count, @@ -3018,7 +3023,7 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) now = pim_time_monotonic_sec(); vty_out(vty, - "Interface Address Group Source Timer Fwd Uptime \n"); + "Interface Address Group Source Timer Fwd Uptime \n"); /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -3070,7 +3075,7 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) now - src->source_creation); vty_out(vty, - "%-9s %-15s %-15s %-15s %5s %3s %8s\n", + "%-16s %-15s %-15s %-15s %5s %3s %8s\n", ifp->name, ifaddr_str, group_str, source_str, mmss, IGMP_SOURCE_TEST_FORWARDING( @@ -3091,7 +3096,7 @@ static void igmp_show_source_retransmission(struct pim_instance *pim, struct interface *ifp; vty_out(vty, - "Interface Address Group Source Counter\n"); + "Interface Address Group Source Counter\n"); /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { @@ -3133,7 +3138,7 @@ static void igmp_show_source_retransmission(struct pim_instance *pim, source_str, sizeof(source_str)); vty_out(vty, - "%-9s %-15s %-15s %-15s %7d\n", + "%-16s %-15s %-15s %-15s %7d\n", ifp->name, ifaddr_str, group_str, source_str, src->source_query_retransmit_count); @@ -4373,7 +4378,7 @@ static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty) vty_out(vty, "\n"); vty_out(vty, - "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n"); + "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n"); FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; @@ -4398,7 +4403,7 @@ static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty) ifaddr = pim_ifp->primary_address; - vty_out(vty, "%-12s %-15s %3d %3d %7lu %7lu %10lu %10lu\n", + vty_out(vty, "%-16s %-15s %3d %3d %7lu %7lu %10lu %10lu\n", ifp->name, inet_ntoa(ifaddr), ifp->ifindex, pim_ifp->mroute_vif_index, (unsigned long)vreq.icount, (unsigned long)vreq.ocount, (unsigned long)vreq.ibytes, @@ -4527,7 +4532,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, json = json_object_new_object(); } else { vty_out(vty, - "Source Group Proto Input Output TTL Uptime\n"); + "Source Group Proto Input Output TTL Uptime\n"); } now = pim_time_monotonic_sec(); @@ -4589,7 +4594,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) { struct interface *ifp_out; - char oif_uptime[10]; + char mroute_uptime[10]; int ttl; ttl = c_oil->oil.mfcc_ttls[oif_vif_index]; @@ -4598,8 +4603,8 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index); pim_time_uptime( - oif_uptime, sizeof(oif_uptime), - now - c_oil->oif_creation[oif_vif_index]); + mroute_uptime, sizeof(mroute_uptime), + now - c_oil->mroute_creation); found_oif = 1; if (ifp_out) @@ -4647,7 +4652,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, oif_vif_index); json_object_int_add(json_ifp_out, "ttl", ttl); json_object_string_add(json_ifp_out, "upTime", - oif_uptime); + mroute_uptime); if (!json_oil) { json_oil = json_object_new_object(); json_object_object_add(json_source, @@ -4677,9 +4682,9 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, } vty_out(vty, - "%-15s %-15s %-6s %-10s %-10s %-3d %8s\n", + "%-15s %-15s %-6s %-16s %-16s %-3d %8s\n", src_str, grp_str, proto, in_ifname, - out_ifname, ttl, oif_uptime); + out_ifname, ttl, mroute_uptime); if (first) { src_str[0] = '\0'; @@ -4691,7 +4696,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, } if (!uj && !found_oif) { - vty_out(vty, "%-15s %-15s %-6s %-10s %-10s %-3d %8s\n", + vty_out(vty, "%-15s %-15s %-6s %-16s %-16s %-3d %8s\n", src_str, grp_str, "none", in_ifname, "none", 0, "--:--:--"); } @@ -4798,7 +4803,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, json_ifp_out); } else { vty_out(vty, - "%-15s %-15s %-6s %-10s %-10s %-3d %8s %s\n", + "%-15s %-15s %-6s %-16s %-16s %-3d %8s %s\n", src_str, grp_str, proto, in_ifname, out_ifname, ttl, oif_uptime, pim->vrf->name); @@ -4813,7 +4818,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, if (!uj && !found_oif) { vty_out(vty, - "%-15s %-15s %-6s %-10s %-10s %-3d %8s %s\n", + "%-15s %-15s %-6s %-16s %-16s %-3d %8s %s\n", src_str, grp_str, proto, in_ifname, "none", 0, "--:--:--", pim->vrf->name); } diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 14ce8d7d9f..0fe4110f60 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -911,7 +911,7 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT)) { if (PIM_DEBUG_TRACE) zlog_debug( - "%s: Received prune with no relevant ifchannel %s(%s) state: %d", + "%s: Received prune with no relevant ifchannel %s%s state: %d", __PRETTY_FUNCTION__, ifp->name, pim_str_sg_dump(sg), source_flags); return; diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 1fb624a6a0..f51e0c0d2f 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -133,6 +133,13 @@ static bool mtrace_fwd_info(struct pim_instance *pim, if (!up) return false; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return false; + } + ifp_in = up->rpf.source_nexthop.interface; nh_addr = up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4; total = htonl(MTRACE_UNKNOWN_COUNT); diff --git a/pimd/pim_join.c b/pimd/pim_join.c index ae5032be73..cbacaf3ea8 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -439,9 +439,6 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) size_t packet_size = 0; size_t group_size = 0; - on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface, - rpf->rpf_addr.u.prefix4); - if (rpf->source_nexthop.interface) pim_ifp = rpf->source_nexthop.interface->info; else { @@ -450,6 +447,9 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups) return -1; } + on_trace(__PRETTY_FUNCTION__, rpf->source_nexthop.interface, + rpf->rpf_addr.u.prefix4); + if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index 7726ffda57..06a9e6d0d6 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -213,8 +213,18 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore) { #ifdef PIM_JP_AGG_DEBUG struct interface *ifp; - struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info; - struct pim_instance *pim = pim_ifp->pim; + struct pim_interface *pim_ifp; + struct pim_instance *pim; + + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + + pim_ifp = up->rpf.source_nexthop.interface->info; + pim = pim_ifp->pim; FOR_ALL_INTERFACES (pim->vrf, ifp) { pim_ifp = ifp->info; diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index dd9e21cae8..999a1eb580 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -234,7 +234,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, up->channel_oil->cc.pktcnt++; PIM_UPSTREAM_FLAG_SET_FHR(up->flags); // resolve mfcc_parent prior to mroute_add in channel_add_oif - if (up->channel_oil->oil.mfcc_parent >= MAXVIFS) { + if (up->rpf.source_nexthop.interface && + up->channel_oil->oil.mfcc_parent >= MAXVIFS) { int vif_index = 0; vif_index = pim_if_find_vifindex_by_ifindex( pim_ifp->pim, @@ -301,6 +302,13 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, return 0; } + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + pim_ifp = up->rpf.source_nexthop.interface->info; rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL; @@ -956,6 +964,8 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) } c_oil->installed = 1; + c_oil->mroute_creation = pim_time_monotonic_sec(); + return 0; } @@ -1022,7 +1032,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) sg.grp = c_oil->oil.mfcc_mcastgrp; if (PIM_DEBUG_MROUTE) zlog_debug( - "Channel(%s) is not installed no need to collect data from kernel", + "Channel%s is not installed no need to collect data from kernel", pim_str_sg_dump(&sg)); } return; @@ -1041,7 +1051,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) sg.grp = c_oil->oil.mfcc_mcastgrp; zlog_warn( - "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s): errno=%d: %s", + "ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=%s: errno=%d: %s", (unsigned long)SIOCGETSGCNT, pim_str_sg_dump(&sg), errno, safe_strerror(errno)); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index b6cd1a7d11..9b5379384c 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -39,6 +39,7 @@ #include "pim_jp_agg.h" #include "pim_zebra.h" #include "pim_zlookup.h" +#include "pim_rp.h" /** * pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister @@ -170,6 +171,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; struct zclient *zclient = NULL; + struct listnode *upnode = NULL; + struct pim_upstream *upstream = NULL; zclient = pim_zebra_zclient_get(); @@ -177,8 +180,30 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, lookup.rpf.rpf_addr = *addr; pnc = hash_lookup(pim->rpf_hash, &lookup); if (pnc) { - if (rp) + if (rp) { + /* Release the (*, G)upstream from pnc->upstream_hash, + * whose Group belongs to the RP getting deleted + */ + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, + upstream)) { + struct prefix grp; + struct rp_info *trp_info; + + if (upstream->sg.src.s_addr != INADDR_ANY) + continue; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = upstream->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + if (trp_info == rp) + hash_release(pnc->upstream_hash, + upstream); + } listnode_delete(pnc->rp_list, rp); + } + if (up) hash_release(pnc->upstream_hash, up); @@ -207,6 +232,17 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, } } +void pim_rp_nexthop_del(struct rp_info *rp_info) +{ + rp_info->rp.source_nexthop.interface = NULL; + rp_info->rp.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = + PIM_NET_INADDR_ANY; + rp_info->rp.source_nexthop.mrib_metric_preference = + router->infinite_assert_metric.metric_preference; + rp_info->rp.source_nexthop.mrib_route_metric = + router->infinite_assert_metric.route_metric; +} + /* Update RP nexthop info based on Nexthop update received from Zebra.*/ static void pim_update_rp_nh(struct pim_instance *pim, struct pim_nexthop_cache *pnc) @@ -220,9 +256,11 @@ static void pim_update_rp_nh(struct pim_instance *pim, continue; // Compute PIM RPF using cached nexthop - pim_ecmp_nexthop_search(pim, pnc, &rp_info->rp.source_nexthop, - &rp_info->rp.rpf_addr, &rp_info->group, - 1); + if (!pim_ecmp_nexthop_search(pim, pnc, + &rp_info->rp.source_nexthop, + &rp_info->rp.rpf_addr, &rp_info->group, + 1)) + pim_rp_nexthop_del(rp_info); } } @@ -278,12 +316,12 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg) old.source_nexthop.interface = up->rpf.source_nexthop.interface; rpf_result = pim_rpf_update(pim, up, &old, 0); if (rpf_result == PIM_RPF_FAILURE) { - pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + pim_upstream_rpf_clear(pim, up); return HASHWALK_CONTINUE; } /* update kernel multicast forwarding cache (MFC) */ - if (up->channel_oil) { + if (up->rpf.source_nexthop.interface) { ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex; vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); @@ -306,9 +344,10 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg) if (PIM_DEBUG_PIM_NHT) { zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s", - __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, - old.source_nexthop.interface->name, - up->rpf.source_nexthop.interface->name); + __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, + old.source_nexthop.interface + ? old.source_nexthop.interface->name : "Unknwon", + up->rpf.source_nexthop.interface->name); } return HASHWALK_CONTINUE; diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index 796fbf9731..6eff7bbc89 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -68,4 +68,5 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, void pim_resolve_upstream_nh(struct pim_instance *pim, struct prefix *nht_p); int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, struct prefix *src, struct prefix *grp); +void pim_rp_nexthop_del(struct rp_info *rp_info); #endif diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 2e12d728cf..55d26113f7 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -168,13 +168,15 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, return c_oil; } - ifp = pim_if_find_by_vif_index(pim, input_vif_index); - if (!ifp) { - /* warning only */ - zlog_warn( - "%s: (S,G)=%s could not find input interface for input_vif_index=%d", - __PRETTY_FUNCTION__, pim_str_sg_dump(sg), - input_vif_index); + if (input_vif_index != MAXVIFS) { + ifp = pim_if_find_by_vif_index(pim, input_vif_index); + if (!ifp) { + /* warning only */ + zlog_warn( + "%s: (S,G)=%s could not find input interface for input_vif_index=%d", + __PRETTY_FUNCTION__, pim_str_sg_dump(sg), + input_vif_index); + } } c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); @@ -447,25 +449,31 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; - if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { - if (PIM_DEBUG_MROUTE) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<group?>", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("<source?>", - channel_oil->oil.mfcc_origin, source_str, - sizeof(source_str)); - zlog_debug( - "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", - __FILE__, __PRETTY_FUNCTION__, oif->name, - pim_ifp->mroute_vif_index, source_str, - group_str); - } + /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not + * valid to get installed in kernel. + */ + if (channel_oil->oil.mfcc_parent != MAXVIFS) { + if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { + if (PIM_DEBUG_MROUTE) { + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<group?>", + channel_oil->oil.mfcc_mcastgrp, + group_str, sizeof(group_str)); + pim_inet4_dump("<source?>", + channel_oil->oil.mfcc_origin, source_str, + sizeof(source_str)); + zlog_debug( + "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", + __FILE__, __PRETTY_FUNCTION__, oif->name, + pim_ifp->mroute_vif_index, source_str, + group_str); + } - channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; - return -5; + channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] + = old_ttl; + return -5; + } } channel_oil->oif_creation[pim_ifp->mroute_vif_index] = diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 94d3840e98..8b95324142 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -64,6 +64,25 @@ struct channel_counts { Each channel_oil.oil is used to control an (S,G) entry in the Kernel Multicast Forwarding Cache. + + There is a case when we create a channel_oil but don't install in the kernel + + Case where (S, G) entry not installed in the kernel: + FRR receives IGMP/PIM (*, G) join and RP is not configured or + not-reachable, then create a channel_oil for the group G with the incoming + interface(channel_oil.oil.mfcc_parent) as invalid i.e "MAXVIF" and populate + the outgoing interface where join is received. Keep this entry in the stack, + but don't install in the kernel(channel_oil.installed = 0). + + Case where (S, G) entry installed in the kernel: + When RP is configured and is reachable for the group G, and receiving a + join if channel_oil is already present then populate the incoming interface + and install the entry in the kernel, if channel_oil not present, then create + a new_channel oil(channel_oil.installed = 1). + + is_valid: indicate if this entry is valid to get installed in kernel. + installed: indicate if this entry is installed in the kernel. + */ struct channel_oil { @@ -78,6 +97,7 @@ struct channel_oil { uint32_t oif_flags[MAXVIFS]; struct channel_counts cc; struct pim_upstream *up; + time_t mroute_creation; }; extern struct list *pim_channel_oil_list; diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 4b402de634..386ed1d424 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -97,7 +97,7 @@ void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg, pinfo = (struct pim_interface *)ifp->info; if (!pinfo) { if (PIM_DEBUG_PIM_TRACE) - zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__); + zlog_debug("%s: No pinfo!", __PRETTY_FUNCTION__); return; } if (pim_msg_send(pinfo->pim_sock_fd, src, originator, buffer, @@ -279,14 +279,13 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); - if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, ip_hdr->ip_dst, - dest_addr)) { + if (!pim_rp_check_is_my_ip_address(pim_ifp->pim, dest_addr)) { if (PIM_DEBUG_PIM_REG) { char dest[INET_ADDRSTRLEN]; pim_inet4_dump("<dst?>", dest_addr, dest, sizeof(dest)); zlog_debug( - "%s: Received Register message for %s that I do not own", + "%s: Received Register message for destination address: %s that I do not own", __func__, dest); } return 0; @@ -330,9 +329,8 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_debug( - "Received Register message(%s) from %s on %s, rp: %d", - pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp); + zlog_debug("Received Register message%s from %s on %s, rp: %d", + pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp); } if (i_am_rp diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 308d5a5e06..b7db7d0418 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -45,7 +45,9 @@ #include "pim_iface.h" #include "pim_msdp.h" #include "pim_nht.h" - +#include "pim_mroute.h" +#include "pim_oil.h" +#include "pim_zebra.h" /* Cleanup pim->rpf_hash each node data */ void pim_rp_list_hash_clean(void *data) @@ -200,7 +202,7 @@ static struct rp_info *pim_rp_find_exact(struct pim_instance *pim, /* * Given a group, return the rp_info for that group */ -static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, +struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, const struct prefix *group) { struct listnode *node; @@ -333,6 +335,77 @@ static void pim_rp_check_interfaces(struct pim_instance *pim, } } +void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) +{ + struct pim_rpf old_rpf; + enum pim_rpf_result rpf_result; + struct in_addr old_upstream_addr; + struct in_addr new_upstream_addr; + struct prefix nht_p; + + old_upstream_addr = up->upstream_addr; + pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src, + up->sg.grp); + + if (PIM_DEBUG_TRACE) + zlog_debug("%s: pim upstream update for old upstream %s", + __PRETTY_FUNCTION__, + inet_ntoa(old_upstream_addr)); + + if (old_upstream_addr.s_addr == new_upstream_addr.s_addr) + return; + + /* Lets consider a case, where a PIM upstream has a better RP as a + * result of a new RP configuration with more precise group range. + * This upstream has to be added to the upstream hash of new RP's + * NHT(pnc) and has to be removed from old RP's NHT upstream hash + */ + if (old_upstream_addr.s_addr != INADDR_ANY) { + /* Deregister addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = old_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(pim, &nht_p, up, NULL); + } + + /* Update the upstream address */ + up->upstream_addr = new_upstream_addr; + + old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface; + + rpf_result = pim_rpf_update(pim, up, &old_rpf, 1); + if (rpf_result == PIM_RPF_FAILURE) + pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + + /* update kernel multicast forwarding cache (MFC) */ + if (up->rpf.source_nexthop.interface && up->channel_oil) { + ifindex_t ifindex = up->rpf.source_nexthop.interface->ifindex; + int vif_index = pim_if_find_vifindex_by_ifindex(pim, ifindex); + /* Pass Current selected NH vif index to mroute download */ + if (vif_index) + pim_scan_individual_oil(up->channel_oil, vif_index); + else { + if (PIM_DEBUG_PIM_NHT) + zlog_debug( + "%s: NHT upstream %s channel_oil IIF %s vif_index is not valid", + __PRETTY_FUNCTION__, up->sg_str, + up->rpf.source_nexthop.interface->name); + } + } + + if (rpf_result == PIM_RPF_CHANGED) + pim_zebra_upstream_rpf_changed(pim, up, &old_rpf); + + pim_zebra_update_all_interfaces(pim); +} + int pim_rp_new(struct pim_instance *pim, const char *rp, const char *group_range, const char *plist) { @@ -347,6 +420,8 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, struct prefix temp; struct pim_nexthop_cache pnc; struct route_node *rn; + struct pim_upstream *up; + struct listnode *upnode; rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); @@ -468,6 +543,27 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, "%s: NHT Register rp_all addr %s grp %s ", __PRETTY_FUNCTION__, buf, buf1); } + + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, + up)) { + /* Find (*, G) upstream whose RP is not + * configured yet + */ + if ((up->upstream_addr.s_addr == INADDR_ANY) + && (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + struct rp_info *trp_info; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, + &grp); + if (trp_info == rp_all) + pim_upstream_update(pim, up); + } + } + memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); if (pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all, &pnc)) { @@ -535,6 +631,21 @@ int pim_rp_new(struct pim_instance *pim, const char *rp, rn->lock); } + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + if (up->sg.src.s_addr == INADDR_ANY) { + struct prefix grp; + struct rp_info *trp_info; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, &grp); + + if (trp_info == rp_info) + pim_upstream_update(pim, up); + } + } + /* Register addr with Zebra NHT */ nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; @@ -577,6 +688,9 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, struct prefix nht_p; struct route_node *rn; bool was_plist = false; + struct rp_info *trp_info; + struct pim_upstream *up; + struct listnode *upnode; if (group_range == NULL) result = str2prefix("224.0.0.0/4", &group); @@ -621,6 +735,23 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, rp_all = pim_rp_find_match_group(pim, &g_all); if (rp_all == rp_info) { + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + /* Find the upstream (*, G) whose upstream address is + * same as the deleted RP + */ + if ((up->upstream_addr.s_addr == rp_addr.s_addr) && + (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + trp_info = pim_rp_find_match_group(pim, &grp); + if (trp_info == rp_all) { + pim_upstream_rpf_clear(pim, up); + up->upstream_addr.s_addr = INADDR_ANY; + } + } + } rp_all->rp.rpf_addr.family = AF_INET; rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; rp_all->i_am_rp = 0; @@ -655,6 +786,34 @@ int pim_rp_del(struct pim_instance *pim, const char *rp, pim_rp_refresh_group_to_rp_mapping(pim); + for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) { + /* Find the upstream (*, G) whose upstream address is same as + * the deleted RP + */ + if ((up->upstream_addr.s_addr == rp_addr.s_addr) && + (up->sg.src.s_addr == INADDR_ANY)) { + struct prefix grp; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + + /* RP not found for the group grp */ + if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + pim_upstream_rpf_clear(pim, up); + pim_rp_set_upstream_addr(pim, + &up->upstream_addr, + up->sg.src, up->sg.grp); + } + + /* RP found for the group grp */ + else + pim_upstream_update(pim, up); + } + } + XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; } @@ -681,6 +840,7 @@ void pim_rp_setup(struct pim_instance *pim) else { if (PIM_DEBUG_PIM_NHT_RP) { char buf[PREFIX2STR_BUFFER]; + prefix2str(&nht_p, buf, sizeof(buf)); zlog_debug( "%s: NHT Local Nexthop not found for RP %s ", @@ -869,7 +1029,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) * the rp configured and the source address * * If we have don't have a RP configured and the source address is * - * then return failure. + * then set the upstream addr as INADDR_ANY and return failure. * */ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, @@ -890,6 +1050,7 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); + up->s_addr = INADDR_ANY; return 0; } @@ -930,34 +1091,13 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, return count; } -int pim_rp_check_is_my_ip_address(struct pim_instance *pim, - struct in_addr group, - struct in_addr dest_addr) +bool pim_rp_check_is_my_ip_address(struct pim_instance *pim, + struct in_addr dest_addr) { - struct rp_info *rp_info; - struct prefix g; - - memset(&g, 0, sizeof(g)); - g.family = AF_INET; - g.prefixlen = 32; - g.u.prefix4 = group; - - rp_info = pim_rp_find_match_group(pim, &g); - /* - * See if we can short-cut some? - * This might not make sense if we ever leave a static RP - * type of configuration. - * Note - Premature optimization might bite our patooeys' here. - */ - if (I_am_RP(pim, group)) { - if (dest_addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) - return 1; - } - if (if_lookup_exact_address(&dest_addr, AF_INET, pim->vrf_id)) - return 1; + return true; - return 0; + return false; } void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) @@ -974,7 +1114,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) json = json_object_new_object(); else vty_out(vty, - "RP address group/prefix-list OIF I am RP\n"); + "RP address group/prefix-list OIF I am RP\n"); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) { @@ -1037,11 +1177,11 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) 48)); if (rp_info->rp.source_nexthop.interface) - vty_out(vty, "%-10s ", + vty_out(vty, "%-16s ", rp_info->rp.source_nexthop .interface->name); else - vty_out(vty, "%-10s ", "(Unknown)"); + vty_out(vty, "%-16s ", "(Unknown)"); if (rp_info->i_am_rp) vty_out(vty, "yes\n"); diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 672a696319..e0f8e16be0 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -55,9 +55,8 @@ int pim_rp_i_am_rp(struct pim_instance *pim, struct in_addr group); void pim_rp_check_on_if_add(struct pim_interface *pim_ifp); void pim_i_am_rp_re_evaluate(struct pim_instance *pim); -int pim_rp_check_is_my_ip_address(struct pim_instance *pim, - struct in_addr group, - struct in_addr dest_addr); +bool pim_rp_check_is_my_ip_address(struct pim_instance *pim, + struct in_addr dest_addr); int pim_rp_set_upstream_addr(struct pim_instance *pim, struct in_addr *up, struct in_addr source, struct in_addr group); @@ -71,4 +70,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj); void pim_resolve_rp_nh(struct pim_instance *pim); int pim_rp_list_cmp(void *v1, void *v2); +struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, + const struct prefix *group); +void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up); #endif diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 814d2e076b..ee145a5b51 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -205,6 +205,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct prefix src, grp; bool neigh_needed = true; + if (up->upstream_addr.s_addr == INADDR_ANY) { + zlog_debug("%s: RP is not configured yet for %s", + __PRETTY_FUNCTION__, up->sg_str); + return PIM_RPF_OK; + } + saved.source_nexthop = rpf->source_nexthop; saved.rpf_addr = rpf->rpf_addr; @@ -308,6 +314,33 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, } /* + * In the case of RP deletion and RP unreachablity, + * uninstall the mroute in the kernel and clear the + * rpf information in the pim upstream and pim channel + * oil data structure. + */ +void pim_upstream_rpf_clear(struct pim_instance *pim, + struct pim_upstream *up) +{ + if (up->rpf.source_nexthop.interface) { + if (up->channel_oil) { + up->channel_oil->oil.mfcc_parent = MAXVIFS; + pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + + } + pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED); + up->rpf.source_nexthop.interface = NULL; + up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = + PIM_NET_INADDR_ANY; + up->rpf.source_nexthop.mrib_metric_preference = + router->infinite_assert_metric.metric_preference; + up->rpf.source_nexthop.mrib_route_metric = + router->infinite_assert_metric.route_metric; + up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY; + } +} + +/* RFC 4601: 4.1.6. State Summarization Macros neighbor RPF'(S,G) { diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index b9fe162f21..a4793df667 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -64,7 +64,8 @@ int pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old, uint8_t is_new); - +void pim_upstream_rpf_clear(struct pim_instance *pim, + struct pim_upstream *up); int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf); int pim_rpf_addr_is_inaddr_any(struct pim_rpf *rpf); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index c6ab8f5a2a..2a0804e10b 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -219,17 +219,25 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, pim_msdp_up_del(pim, &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); + /* When RP gets deleted, pim_rp_del() deregister addr with Zebra NHT + * and assign up->upstream_addr as INADDR_ANY. + * So before de-registering the upstream address, check if is not equal + * to INADDR_ANY. This is done in order to avoid de-registering for + * 255.255.255.255 which is maintained for some reason.. + */ + if (up->upstream_addr.s_addr != INADDR_ANY) { + /* 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(pim, &nht_p, up, NULL); } - pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); XFREE(MTYPE_PIM_UPSTREAM, up); @@ -238,6 +246,13 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, void pim_upstream_send_join(struct pim_upstream *up) { + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + if (PIM_DEBUG_TRACE) { char rpf_str[PREFIX_STRLEN]; pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, @@ -263,6 +278,13 @@ static int on_join_timer(struct thread *t) up = THREAD_ARG(t); + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + /* * In the case of a HFR we will not ahve anyone to send this to. */ @@ -284,12 +306,13 @@ static int on_join_timer(struct thread *t) static void join_timer_stop(struct pim_upstream *up) { - struct pim_neighbor *nbr; + struct pim_neighbor *nbr = NULL; THREAD_OFF(up->t_join_timer); - nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr.u.prefix4); + if (up->rpf.source_nexthop.interface) + 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); @@ -356,6 +379,13 @@ void pim_upstream_join_suppress(struct pim_upstream *up, long t_joinsuppress_msec; long join_timer_remain_msec; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), 1000 * holdtime); @@ -389,6 +419,13 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, long join_timer_remain_msec; int t_override_msec; + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + 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); @@ -511,6 +548,20 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, { enum pim_upstream_state old_state = up->join_state; + if (up->upstream_addr.s_addr == INADDR_ANY) { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: RPF not configured for %s", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: RP not reachable for %s", + __PRETTY_FUNCTION__, up->sg_str); + return; + } + if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("%s: PIM_UPSTREAM_%s: (S,G) old: %s new: %s", __PRETTY_FUNCTION__, up->sg_str, @@ -558,11 +609,14 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, && !I_am_RP(pim, 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); + "%s: *,G IIF %s S,G IIF %s ", + __PRETTY_FUNCTION__, + up->parent->rpf.source_nexthop.interface ? + up->parent->rpf.source_nexthop.interface->name + : "Unknown", + up->rpf.source_nexthop.interface ? + up->rpf.source_nexthop.interface->name : + "Unknown"); pim_jp_agg_single_upstream_send(&up->parent->rpf, up->parent, 1 /* (W,G) Join */); @@ -611,15 +665,14 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, ch->upstream = up; up = hash_get(pim->upstream_hash, up, hash_alloc_intern); + /* Set up->upstream_addr as INADDR_ANY, if RP is not + * configured and retain the upstream data structure + */ if (!pim_rp_set_upstream_addr(pim, &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(pim, up); @@ -659,45 +712,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (up->sg.src.s_addr != INADDR_ANY) wheel_add_item(pim->upstream_sg_wheel, up); - rpf_result = pim_rpf_update(pim, 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(pim, &nht_p, up, NULL); + if (up->upstream_addr.s_addr == INADDR_ANY) + /* Create a dummmy channel oil with incoming ineterface MAXVIFS, + * since RP is not configured + */ + up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS); - if (up->parent) { - listnode_delete(up->parent->sources, up); - up->parent = NULL; + else { + rpf_result = pim_rpf_update(pim, up, NULL, 1); + if (rpf_result == PIM_RPF_FAILURE) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: Attempting to create upstream(%s), Unable to RPF for source", + __PRETTY_FUNCTION__, up->sg_str); + /* Create a dummmy channel oil with incoming ineterface + * MAXVIFS, since RP is not reachable + */ + up->channel_oil = pim_channel_oil_add( + pim, &up->sg, MAXVIFS); } - if (up->sg.src.s_addr != INADDR_ANY) - wheel_remove_item(pim->upstream_sg_wheel, up); - - pim_upstream_remove_children(pim, up); - if (up->sources) - list_delete(&up->sources); - - list_delete(&up->ifchannels); - - 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(pim, + &up->sg, pim_ifp->mroute_vif_index); + } } - if (up->rpf.source_nexthop.interface) { - pim_ifp = up->rpf.source_nexthop.interface->info; - if (pim_ifp) - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, pim_ifp->mroute_vif_index); - } listnode_add_sort(pim->upstream_list, up); if (PIM_DEBUG_TRACE) { @@ -783,7 +825,7 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim, 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" , + up->rpf.source_nexthop.interface->name : "Unknown" , found, up->ref_count); } else zlog_debug("%s(%s): (%s) failure to create", @@ -896,7 +938,7 @@ void pim_upstream_update_join_desired(struct pim_instance *pim, PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); /* switched from false to true */ - if (is_join_desired && !was_join_desired) { + if (is_join_desired && (up->join_state == PIM_UPSTREAM_NOTJOINED)) { pim_upstream_switch(pim, up, PIM_UPSTREAM_JOINED); return; } @@ -973,7 +1015,9 @@ void pim_upstream_rpf_interface_changed(struct pim_upstream *up, (old_rpf_ifp == ch->interface) && /* RPF_interface(S) stopped being I */ (ch->upstream->rpf.source_nexthop - .interface != ch->interface)) { + .interface) && + (ch->upstream->rpf.source_nexthop + .interface != ch->interface)) { assert_action_a5(ch); } } /* PIM_IFASSERT_I_AM_LOSER */ @@ -1339,6 +1383,13 @@ static int pim_upstream_register_stop_timer(struct thread *t) case PIM_REG_JOIN: break; case PIM_REG_PRUNE: + if (!up->rpf.source_nexthop.interface) { + if (PIM_DEBUG_TRACE) + zlog_debug("%s: up %s RPF is not present", + __PRETTY_FUNCTION__, up->sg_str); + return 0; + } + pim_ifp = up->rpf.source_nexthop.interface->info; if (!pim_ifp) { if (PIM_DEBUG_TRACE) @@ -1515,11 +1566,19 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) * 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 (up->upstream_addr.s_addr == INADDR_ANY) { + if (PIM_DEBUG_TRACE) + zlog_debug( + "%s: RP not configured for Upstream %s", + __PRETTY_FUNCTION__, up->sg_str); + continue; + } + 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); + "%s: Upstream %s without a path to send join, checking", + __PRETTY_FUNCTION__, up->sg_str); pim_rpf_update(pim, up, NULL, 1); } } @@ -1586,7 +1645,8 @@ 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, + if (up->rpf.source_nexthop.interface && + pim_if_connected_to_source(up->rpf.source_nexthop.interface, up->sg.src)) { return true; } @@ -1622,7 +1682,7 @@ static void pim_upstream_sg_running(void *arg) // No packet can have arrived here if this is the case if (!up->channel_oil->installed) { if (PIM_DEBUG_TRACE) - zlog_debug("%s: %s[%s] is not installed in mroute", + zlog_debug("%s: %s%s is not installed in mroute", __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name); return; @@ -1679,7 +1739,8 @@ static void pim_upstream_sg_running(void *arg) } else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags)) pim_upstream_keep_alive_timer_start(up, pim->keep_alive_time); - if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) { + if ((up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE) && + (up->rpf.source_nexthop.interface)) { pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface); } return; diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index f44b95c811..70e70140d1 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -88,10 +88,30 @@ enum pim_upstream_sptbit { /* Upstream (S,G) channel in Joined state - (S,G) in the "Not Joined" state is not represented - See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message + + upstream_addr : Who we are talking to. + For (*, G), upstream_addr is RP address or INADDR_ANY(if RP not configured) + For (S, G), upstream_addr is source address + + rpf: contains the nexthop information to whom we are talking to. + + join_state: JOINED/NOTJOINED + + In the case when FRR receives IGMP/PIM (*, G) join for group G and RP is not + configured, then create a pim_upstream with the below information. + pim_upstream->upstream address: INADDR_ANY + pim_upstream->rpf: Unknown + pim_upstream->state: NOTJOINED + + When a new RP gets configured for G, find the corresponding pim upstream (*,G) + entries and update the upstream address as new RP address if it the better one + for the group G. + + When RP becomes reachable, populate the nexthop information in + pim_upstream->rpf and update the state to JOINED. + */ struct pim_upstream { struct pim_upstream *parent; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 11ca6e8a10..70f099b0d7 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -150,6 +150,8 @@ static int pim_zebra_if_del(int command, struct zclient *zclient, if (!if_is_operative(ifp)) pim_if_addr_del_all(ifp); + if_set_index(ifp, IFINDEX_INTERNAL); + return 0; } @@ -472,99 +474,84 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old) { - struct pim_neighbor *nbr; + if (old->source_nexthop.interface) { + struct pim_neighbor *nbr; - nbr = pim_neighbor_find(old->source_nexthop.interface, - old->rpf_addr.u.prefix4); - if (nbr) - pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); + nbr = pim_neighbor_find(old->source_nexthop.interface, + old->rpf_addr.u.prefix4); + if (nbr) + pim_jp_agg_remove_group(nbr->upstream_jp_agg, up); - /* - * We have detected a case where we might need - * to rescan the inherited o_list so do it. - */ - if (up->channel_oil->oil_inherited_rescan) { - pim_upstream_inherited_olist_decide(pim, up); - up->channel_oil->oil_inherited_rescan = 0; - } - - if (up->join_state == PIM_UPSTREAM_JOINED) { /* - * If we come up real fast we can be here - * where the mroute has not been installed - * so install it. + * We have detected a case where we might need + * to rescan the inherited o_list so do it. */ - if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } + + if (up->join_state == PIM_UPSTREAM_JOINED) { + /* + * If we come up real fast we can be here + * where the mroute has not been installed + * so install it. + */ + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, + __PRETTY_FUNCTION__); + + /* + * 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. + */ + pim_jp_agg_switch_interface(old, &up->rpf, up); + + pim_upstream_join_timer_restart(up, old); + } /* up->join_state == PIM_UPSTREAM_JOINED */ + } + else { /* - * 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. + * We have detected a case where we might need + * to rescan the inherited o_list so do it. */ - pim_jp_agg_switch_interface(old, &up->rpf, up); + if (up->channel_oil->oil_inherited_rescan) { + pim_upstream_inherited_olist_decide(pim, up); + up->channel_oil->oil_inherited_rescan = 0; + } - pim_upstream_join_timer_restart(up, old); - } /* up->join_state == PIM_UPSTREAM_JOINED */ + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + } - /* FIXME can join_desired actually be changed by - pim_rpf_update() - returning PIM_RPF_CHANGED ? */ + /* FIXME can join_desired actually be changed by pim_rpf_update() + * returning PIM_RPF_CHANGED ? + */ pim_upstream_update_join_desired(pim, up); } -static void scan_upstream_rpf_cache(struct pim_instance *pim) -{ - struct listnode *up_node; - struct listnode *up_nextnode; - struct pim_upstream *up; - - for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { - enum pim_rpf_result rpf_result; - struct pim_rpf old; - struct prefix nht_p; - - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; - pim_resolve_upstream_nh(pim, &nht_p); - - old.source_nexthop.interface = up->rpf.source_nexthop.interface; - old.source_nexthop.nbr = up->rpf.source_nexthop.nbr; - rpf_result = pim_rpf_update(pim, up, &old, 0); - - if (rpf_result == PIM_RPF_FAILURE) - continue; - - if (rpf_result == PIM_RPF_CHANGED) - pim_zebra_upstream_rpf_changed(pim, up, &old); - - } /* for (qpim_upstream_list) */ - - pim_zebra_update_all_interfaces(pim); -} - void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) { struct in_addr vif_source; int input_iface_vif_index; int old_vif_index; - if (!pim_rp_set_upstream_addr(c_oil->pim, &vif_source, + pim_rp_set_upstream_addr(c_oil->pim, &vif_source, c_oil->oil.mfcc_origin, - c_oil->oil.mfcc_mcastgrp)) - return; + c_oil->oil.mfcc_mcastgrp); if (in_vif_index) input_iface_vif_index = in_vif_index; @@ -719,9 +706,6 @@ static int on_rpf_cache_refresh(struct thread *t) { struct pim_instance *pim = THREAD_ARG(t); - /* update PIM protocol state */ - scan_upstream_rpf_cache(pim); - /* update kernel multicast forwarding cache (MFC) */ pim_scan_oil(pim); @@ -950,112 +934,141 @@ void igmp_source_forward_start(struct pim_instance *pim, struct pim_upstream *up = NULL; if (!pim_rp_set_upstream_addr(pim, &vif_source, - source->source_addr, sg.grp)) - return; - - /* Register addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = vif_source; - memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache)); + source->source_addr, sg.grp)) { + /*Create a dummy channel oil */ + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, MAXVIFS); - src.family = AF_INET; - src.prefixlen = IPV4_MAX_BITLEN; - src.u.prefix4 = vif_source; // RP or Src address - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = sg.grp; + if (!source->source_channel_oil) { + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg)); + } + return; + } + } - if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, + else { + /* Register addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = vif_source; + memset(&out_pnc, 0, sizeof(struct pim_nexthop_cache)); + + src.family = AF_INET; + src.prefixlen = IPV4_MAX_BITLEN; + src.u.prefix4 = vif_source; // RP or Src address + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = sg.grp; + + if (pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, &out_pnc)) { - if (out_pnc.nexthop_num) { - up = pim_upstream_find(pim, &sg); - memset(&nexthop, 0, sizeof(nexthop)); - if (up) - memcpy(&nexthop, - &up->rpf.source_nexthop, - sizeof(struct pim_nexthop)); - pim_ecmp_nexthop_search(pim, &out_pnc, &nexthop, - &src, &grp, 0); - if (nexthop.interface) - input_iface_vif_index = + if (out_pnc.nexthop_num) { + up = pim_upstream_find(pim, &sg); + memset(&nexthop, 0, sizeof(nexthop)); + if (up) + memcpy(&nexthop, + &up->rpf.source_nexthop, + sizeof(struct pim_nexthop)); + pim_ecmp_nexthop_search(pim, &out_pnc, + &nexthop, + &src, &grp, 0); + if (nexthop.interface) + input_iface_vif_index = pim_if_find_vifindex_by_ifindex( - pim, - nexthop.interface->ifindex); - } else { - if (PIM_DEBUG_ZEBRA) { - char buf1[INET_ADDRSTRLEN]; - char buf2[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", + pim, + nexthop.interface->ifindex); + } else { + if (PIM_DEBUG_ZEBRA) { + char buf1[INET_ADDRSTRLEN]; + char buf2[INET_ADDRSTRLEN]; + + pim_inet4_dump("<source?>", nht_p.u.prefix4, buf1, sizeof(buf1)); - pim_inet4_dump("<source?>", + pim_inet4_dump("<source?>", grp.u.prefix4, buf2, sizeof(buf2)); - zlog_debug( + zlog_debug( "%s: NHT Nexthop not found for addr %s grp %s", __PRETTY_FUNCTION__, buf1, buf2); + } } - } - } else - input_iface_vif_index = - pim_ecmp_fib_lookup_if_vif_index(pim, &src, + } else + input_iface_vif_index = + pim_ecmp_fib_lookup_if_vif_index(pim, &src, &grp); - if (PIM_DEBUG_ZEBRA) { - char buf2[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", vif_source, buf2, - sizeof(buf2)); - zlog_debug("%s: NHT %s vif_source %s vif_index:%d ", - __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), - buf2, input_iface_vif_index); - } - - if (input_iface_vif_index < 1) { - if (PIM_DEBUG_IGMP_TRACE) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", source->source_addr, - source_str, sizeof(source_str)); - zlog_debug( - "%s %s: could not find input interface for source %s", - __FILE__, __PRETTY_FUNCTION__, - source_str); - } - return; - } + if (PIM_DEBUG_ZEBRA) { + char buf2[INET_ADDRSTRLEN]; - /* - Protect IGMP against adding looped MFC entries created by both - source and receiver attached to the same interface. See TODO - T22. - */ - if (input_iface_vif_index == pim_oif->mroute_vif_index) { - /* ignore request for looped MFC entry */ - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d", + pim_inet4_dump("<source?>", vif_source, buf2, + sizeof(buf2)); + zlog_debug("%s: NHT %s vif_source %s vif_index:%d ", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), - source->source_group->group_igmp_sock - ->fd, - source->source_group->group_igmp_sock - ->interface->name, - input_iface_vif_index); + buf2, input_iface_vif_index); } - return; - } - source->source_channel_oil = - pim_channel_oil_add(pim, &sg, input_iface_vif_index); - if (!source->source_channel_oil) { - if (PIM_DEBUG_IGMP_TRACE) { - zlog_debug( - "%s %s: could not create OIL for channel (S,G)=%s", - __FILE__, __PRETTY_FUNCTION__, - pim_str_sg_dump(&sg)); + if (input_iface_vif_index < 1) { + if (PIM_DEBUG_IGMP_TRACE) { + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<source?>", + source->source_addr, + source_str, sizeof(source_str)); + zlog_debug( + "%s %s: could not find input interface for source %s", + __FILE__, __PRETTY_FUNCTION__, + source_str); + } + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, MAXVIFS); + } + + else { + /* + * Protect IGMP against adding looped MFC + * entries created by both source and receiver + * attached to the same interface. See TODO + * T22. + */ + if (input_iface_vif_index == + pim_oif->mroute_vif_index) { + /* ignore request for looped MFC entry + */ + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d", + __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg), + source->source_group + ->group_igmp_sock->fd, + source->source_group + ->group_igmp_sock + ->interface->name, + input_iface_vif_index); + } + return; + } + + source->source_channel_oil = + pim_channel_oil_add(pim, &sg, + input_iface_vif_index); + if (!source->source_channel_oil) { + if (PIM_DEBUG_IGMP_TRACE) { + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, + __PRETTY_FUNCTION__, + pim_str_sg_dump(&sg)); + } + return; + } } - return; } } @@ -1188,15 +1201,13 @@ void pim_forward_start(struct pim_ifchannel *ch) sizeof(upstream_str)); zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name, - upstream_str); + inet_ntoa(up->upstream_addr)); } /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS, as part of mroute_del called by pim_forward_stop. */ - if (!up->channel_oil - || (up->channel_oil - && up->channel_oil->oil.mfcc_parent >= MAXVIFS)) { + if ((up->upstream_addr.s_addr != INADDR_ANY) && (!up->channel_oil)) { struct prefix nht_p, src, grp; struct pim_nexthop_cache out_pnc; @@ -1267,17 +1278,33 @@ void pim_forward_start(struct pim_ifchannel *ch) __FILE__, __PRETTY_FUNCTION__, source_str); } - return; + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + MAXVIFS); } + + else { + up->channel_oil = pim_channel_oil_add(pim, &up->sg, + input_iface_vif_index); + if (!up->channel_oil) { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug( + "%s %s: could not create OIL for channel (S,G)=%s", + __FILE__, __PRETTY_FUNCTION__, + up->sg_str); + return; + } + } + if (PIM_DEBUG_TRACE) { struct interface *in_intf = pim_if_find_by_vif_index( pim, input_iface_vif_index); zlog_debug( "%s: Update channel_oil IIF %s VIFI %d entry %s ", __PRETTY_FUNCTION__, - in_intf ? in_intf->name : "NIL", + in_intf ? in_intf->name : "Unknown", input_iface_vif_index, up->sg_str); } + up->channel_oil = pim_channel_oil_add(pim, &up->sg, input_iface_vif_index); if (!up->channel_oil) { diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 0ffe313c17..6d93a40b91 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -499,7 +499,7 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) more.src = c_oil->oil.mfcc_origin; more.grp = c_oil->oil.mfcc_mcastgrp; zlog_debug( - "Sending Request for New Channel Oil Information(%s) VIIF %d(%s)", + "Sending Request for New Channel Oil Information%s VIIF %d(%s)", pim_str_sg_dump(&more), c_oil->oil.mfcc_parent, c_oil->pim->vrf->name); } diff --git a/pimd/pimd.c b/pimd/pimd.c index 656b000579..889a83a136 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -127,8 +127,6 @@ void pim_terminate(void) { struct zclient *zclient; - pim_free(); - /* reverse prefix_list_init */ prefix_list_add_hook(NULL); prefix_list_delete_hook(NULL); @@ -142,6 +140,8 @@ void pim_terminate(void) zclient_free(zclient); } + pim_free(); pim_router_terminate(); + frr_fini(); } |
