]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_rp.c
Merge pull request #3863 from patrasar/RP_addition_deletion_changes
[mirror_frr.git] / pimd / pim_rp.c
index 308d5a5e06c6791895787fd27440810ac6f8cea3..7094b93a45d5fe62f3bfe54339e3f6af01569968 100644 (file)
@@ -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;
        }