]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_nht.c
Merge pull request #5767 from ton31337/fix/replace_s_addr_0_to_INADDR_ANY
[mirror_frr.git] / pimd / pim_nht.c
index 48b9f1f284a16ba47cc5e371d3bc7690246c662c..5cb9492ec36ae2c8e68162bad175f16ef3237ab0 100644 (file)
@@ -121,6 +121,7 @@ static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim,
  */
 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;
@@ -157,6 +158,9 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
        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));
@@ -167,12 +171,12 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr,
 }
 
 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();
@@ -185,8 +189,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
                        /* 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;
 
@@ -208,6 +212,9 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
                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);
@@ -218,7 +225,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
                }
 
                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);
 
@@ -233,6 +241,169 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
        }
 }
 
+/* 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;
@@ -269,37 +440,22 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
 {
        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);
 
 
@@ -307,8 +463,9 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
                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;
@@ -670,6 +827,14 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
                        }
 
                        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];
 
@@ -681,8 +846,6 @@ int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS)
                                                nexthop2str(nexthop, buf,
                                                            sizeof(buf)));
                                }
-                               nexthop_free(nexthop);
-                               continue;
                        }
 
                        if (nhlist_tail) {