diff options
| -rw-r--r-- | bgpd/bgp_evpn.c | 40 | ||||
| -rw-r--r-- | pimd/pim_cmd.c | 17 | ||||
| -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 | 10 | ||||
| -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 | 19 | ||||
| -rw-r--r-- | pimd/pim_rp.c | 167 | ||||
| -rw-r--r-- | pimd/pim_rp.h | 3 | ||||
| -rw-r--r-- | pimd/pim_rpf.c | 33 | ||||
| -rw-r--r-- | pimd/pim_rpf.h | 3 | ||||
| -rw-r--r-- | pimd/pim_upstream.c | 187 | ||||
| -rw-r--r-- | pimd/pim_upstream.h | 24 | ||||
| -rw-r--r-- | pimd/pim_zebra.c | 337 |
17 files changed, 733 insertions, 250 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 19cda453f5..6ced286dde 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -48,6 +48,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_addpath.h" +#include "bgpd/bgp_mac.h" /* * Definitions and external declarations. @@ -2945,6 +2946,41 @@ static int install_uninstall_routes_for_es(struct bgp *bgp, return 0; } +/* This API will scan evpn routes for checking attribute's rmac + * macthes with bgp instance router mac. It avoid installing + * route into bgp vrf table and remote rmac in bridge table. + */ +static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf, + struct prefix_evpn *evp, + struct bgp_path_info *pi) +{ + /* evpn route could have learnt prior to L3vni has come up, + * perform rmac check before installing route and + * remote router mac. + * The route will be removed from global bgp table once + * SVI comes up with MAC and stored in hash, triggers + * bgp_mac_rescan_all_evpn_tables. + */ + if (pi->attr && + memcmp(&bgp_vrf->rmac, &pi->attr->rmac, ETH_ALEN) == 0) { + if (bgp_debug_update(pi->peer, NULL, NULL, 1)) { + char buf1[PREFIX_STRLEN]; + char attr_str[BUFSIZ] = {0}; + + bgp_dump_attr(pi->attr, attr_str, BUFSIZ); + + zlog_debug("%s: bgp %u prefix %s with attr %s - DENIED due to self mac", + __func__, bgp_vrf->vrf_id, + prefix2str(evp, buf1, sizeof(buf1)), + attr_str); + } + + return 1; + } + + return 0; +} + /* * Install or uninstall mac-ip routes are appropriate for this * particular VRF. @@ -3001,6 +3037,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) continue; if (is_route_matching_for_vrf(bgp_vrf, pi)) { + if (bgp_evpn_route_rmac_self_check( + bgp_vrf, evp, pi)) + continue; + if (install) ret = install_evpn_route_entry_in_vrf( bgp_vrf, evp, pi); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 012c3b4f1d..f058b7adbf 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -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 @@ -2463,8 +2466,10 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, } 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, + 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); } } 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..67b1a95f74 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; 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..5dd4e8b326 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 { diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 308d5a5e06..7094b93a45 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; } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 672a696319..7769864c08 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -71,4 +71,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..cb89e30a50 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; } @@ -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..78cccd5877 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -472,55 +472,72 @@ 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); } @@ -535,6 +552,14 @@ static void scan_upstream_rpf_cache(struct pim_instance *pim) struct pim_rpf old; struct prefix nht_p; + 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; + } + nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; @@ -561,10 +586,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) 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; @@ -950,112 +974,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 +1241,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 +1318,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) { |
