diff options
Diffstat (limited to 'pimd/pim_rp.c')
| -rw-r--r-- | pimd/pim_rp.c | 202 |
1 files changed, 171 insertions, 31 deletions
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"); |
