*/
int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
struct pim_upstream *up, struct rp_info *rp,
+ bool bsr_track_needed,
struct pim_nexthop_cache *out_pnc)
{
struct pim_nexthop_cache *pnc = NULL;
if (up != NULL)
hash_get(pnc->upstream_hash, up, hash_alloc_intern);
+ if (bsr_track_needed)
+ pnc->bsr_tracking = true;
+
if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) {
if (out_pnc)
memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
}
void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
- struct pim_upstream *up, struct rp_info *rp)
+ struct pim_upstream *up, struct rp_info *rp,
+ bool del_bsr_tracking)
{
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();
/* 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)) {
+ frr_each (rb_pim_upstream, &pim->upstream_head,
+ upstream) {
struct prefix grp;
struct rp_info *trp_info;
if (up)
hash_release(pnc->upstream_hash, up);
+ if (del_bsr_tracking)
+ pnc->bsr_tracking = false;
+
if (PIM_DEBUG_PIM_NHT) {
char buf[PREFIX_STRLEN];
prefix2str(addr, buf, sizeof buf);
}
if (pnc->rp_list->count == 0
- && pnc->upstream_hash->count == 0) {
+ && pnc->upstream_hash->count == 0
+ && pnc->bsr_tracking == false) {
pim_sendmsg_zebra_rnh(pim, zclient, pnc,
ZEBRA_NEXTHOP_UNREGISTER);
}
}
+/* Given a source address and a neighbor address, check if the neighbor is one
+ * of the next hop to reach the source. search from zebra route database
+ */
+bool pim_nexthop_match(struct pim_instance *pim, struct in_addr addr,
+ struct in_addr ip_src)
+{
+ struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
+ int i = 0;
+ ifindex_t first_ifindex = 0;
+ struct interface *ifp = NULL;
+ struct pim_neighbor *nbr = NULL;
+ int num_ifindex;
+
+ if (addr.s_addr == INADDR_NONE)
+ return 0;
+
+ memset(nexthop_tab, 0,
+ sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
+ num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
+ addr, PIM_NEXTHOP_LOOKUP_MAX);
+ if (num_ifindex < 1) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
+ zlog_warn(
+ "%s %s: could not find nexthop ifindex for address %s",
+ __FILE__, __PRETTY_FUNCTION__, addr_str);
+ return 0;
+ }
+
+ while (i < num_ifindex) {
+ first_ifindex = nexthop_tab[i].ifindex;
+
+ ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ if (!ifp) {
+ if (PIM_DEBUG_ZEBRA) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s %s: could not find interface for ifindex %d (address %s)",
+ __FILE__, __PRETTY_FUNCTION__,
+ first_ifindex, addr_str);
+ }
+ i++;
+ continue;
+ }
+
+ if (!ifp->info) {
+ if (PIM_DEBUG_ZEBRA) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
+ __PRETTY_FUNCTION__, ifp->name,
+ first_ifindex, addr_str);
+ }
+ i++;
+ continue;
+ }
+
+ if (!pim_if_connected_to_source(ifp, addr)) {
+ nbr = pim_neighbor_find(
+ ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
+ if (PIM_DEBUG_PIM_TRACE_DETAIL)
+ zlog_debug("ifp name: %s, pim nbr: %p",
+ ifp->name, nbr);
+ if (!nbr && !if_is_loopback(ifp)) {
+ i++;
+ continue;
+ }
+ }
+
+ if (nexthop_tab[i].nexthop_addr.u.prefix4.s_addr
+ == ip_src.s_addr)
+ return 1;
+
+ i++;
+ }
+
+ return 0;
+}
+
+/* Given a source address and a neighbor address, check if the neighbor is one
+ * of the next hop to reach the source. search from pim next hop cache
+ */
+bool pim_nexthop_match_nht_cache(struct pim_instance *pim, struct in_addr addr,
+ struct in_addr ip_src)
+{
+ struct pim_rpf rpf;
+ ifindex_t first_ifindex;
+ struct interface *ifp = NULL;
+ uint8_t nh_iter = 0;
+ struct pim_neighbor *nbr = NULL;
+ struct nexthop *nh_node = NULL;
+ struct pim_nexthop_cache *pnc = NULL;
+
+ memset(&rpf, 0, sizeof(struct pim_rpf));
+ rpf.rpf_addr.family = AF_INET;
+ rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
+ rpf.rpf_addr.u.prefix4 = addr;
+
+ pnc = pim_nexthop_cache_find(pim, &rpf);
+ if (!pnc || !pnc->nexthop_num)
+ return 0;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
+ first_ifindex = nh_node->ifindex;
+ ifp = if_lookup_by_index(first_ifindex, pim->vrf_id);
+ if (!ifp) {
+ if (PIM_DEBUG_PIM_NHT) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s %s: could not find interface for ifindex %d (address %s(%s))",
+ __FILE__, __PRETTY_FUNCTION__,
+ first_ifindex, addr_str,
+ pim->vrf->name);
+ }
+ nh_iter++;
+ continue;
+ }
+ if (!ifp->info) {
+ if (PIM_DEBUG_PIM_NHT) {
+ char addr_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<addr?>", addr, addr_str,
+ sizeof(addr_str));
+ zlog_debug(
+ "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
+ __PRETTY_FUNCTION__, ifp->name,
+ pim->vrf->name, first_ifindex,
+ addr_str);
+ }
+ nh_iter++;
+ continue;
+ }
+
+ if (!pim_if_connected_to_source(ifp, addr)) {
+ nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4);
+ if (!nbr && !if_is_loopback(ifp)) {
+ if (PIM_DEBUG_PIM_NHT)
+ zlog_debug(
+ "%s: pim nbr not found on input interface %s(%s)",
+ __PRETTY_FUNCTION__, ifp->name,
+ pim->vrf->name);
+ nh_iter++;
+ continue;
+ }
+ }
+
+ if (nh_node->gate.ipv4.s_addr == ip_src.s_addr)
+ return 1;
+ }
+
+ return 0;
+}
+
void pim_rp_nexthop_del(struct rp_info *rp_info)
{
rp_info->rp.source_nexthop.interface = NULL;
{
struct pim_instance *pim = (struct pim_instance *)arg;
struct pim_upstream *up = (struct pim_upstream *)bucket->data;
- int vif_index = 0;
enum pim_rpf_result rpf_result;
struct pim_rpf old;
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_upstream_rpf_clear(pim, up);
- return HASHWALK_CONTINUE;
- }
+ rpf_result = pim_rpf_update(pim, up, &old, __func__);
- /* update kernel multicast forwarding cache (MFC) */
- 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);
- /* 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);
- }
- }
+ /* update kernel multicast forwarding cache (MFC); if the
+ * RPF nbr is now unreachable the MFC has already been updated
+ * by pim_rpf_clear
+ */
+ if (rpf_result != PIM_RPF_FAILURE)
+ pim_upstream_mroute_iif_update(up->channel_oil, __func__);
- if (rpf_result == PIM_RPF_CHANGED)
+ if (rpf_result == PIM_RPF_CHANGED ||
+ (rpf_result == PIM_RPF_FAILURE && old.source_nexthop.interface))
pim_zebra_upstream_rpf_changed(pim, up, &old);
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
- ? old.source_nexthop.interface->name : "Unknwon",
- up->rpf.source_nexthop.interface->name);
+ ? old.source_nexthop.interface->name : "Unknown",
+ up->rpf.source_nexthop.interface
+ ? up->rpf.source_nexthop.interface->name : "Unknown");
}
return HASHWALK_CONTINUE;
}
if (!ifp->info) {
+ /*
+ * Though Multicast is not enabled on this
+ * Interface store it in database otheriwse we
+ * may miss this update and this will not cause
+ * any issue, because while choosing the path we
+ * are ommitting the Interfaces which are not
+ * multicast enabled
+ */
if (PIM_DEBUG_PIM_NHT) {
char buf[NEXTHOP_STRLEN];
nexthop2str(nexthop, buf,
sizeof(buf)));
}
- nexthop_free(nexthop);
- continue;
}
if (nhlist_tail) {