]> git.puffer.fish Git - mirror/frr.git/commitdiff
pim-anycast-rp: Add limited support for secondary addresses.
authoranuradhak <anuradhak@cumulusnetworks.com>
Fri, 18 Nov 2016 17:12:27 +0000 (09:12 -0800)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Thu, 22 Dec 2016 01:26:16 +0000 (20:26 -0500)
Anycast requires that the lo interface be associated with multiple
addresses. One is the anycast IP address (which is the same on all RPs
participating in RP redundancy) and the second is the unique IP address
that will be used as the router id by routing protocols.

To accomodate that we maintain a list of secondary addresses per-pim iface
and allow any of them to be the RP address. This lets the I_am_RP macro
succeed on anycast RPs.

Note that the support is limited i.e. we don't actually advertise a
secondary list to the neighbors. This is assuming the anycast IP will never
be used as a router id i.e. will never be an RPF neighbor.

Sample output:
==============
dell-s6000-04# sh ip pim interface lo
Interface : lo
State     : up
Address   : 100.1.1.1 (primary)
            100.1.1.2
            100.1.1.3
            100.1.2.1
>>>>>>> SNIP >>>>>>>>>>>>>>>
dell-s6000-04# sh ip pim interface lo json
{
  "lo":{
    "name":"lo",
    "state":"up",
    "address":"100.1.1.1",
    "index":1,
    "lanDelayEnabled":true,
    "secondaryAddressList":[
      "100.1.1.2",
      "100.1.1.3",
      "100.1.2.1"
    ],
>>>>>>> SNIP >>>>>>>>>>>>>>>
dell-s6000-04#sh ip pim rp-info
RP address       group/prefix-list   OIF         I am RP
100.1.2.1        224.0.0.0/4         lo          yes
dell-s6000-04#

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
pimd/pim_cmd.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_main.c
pimd/pim_memory.c
pimd/pim_memory.h
pimd/pim_msdp.c
pimd/pim_msg.c
pimd/pim_rp.c
pimd/pim_rp.h
pimd/pim_zebra.c

index ecfa94cba94578badec597a550a46ad212ea99d3..aa97907a3027d60a698c183e637c71fe3e749bae 100644 (file)
@@ -787,6 +787,8 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
   json_object *json_group = NULL;
   json_object *json_group_source = NULL;
   json_object *json_fhr_sources = NULL;
+  struct pim_secondary_addr *sec_addr;
+  struct listnode *sec_node;
 
   now = pim_time_monotonic_sec();
 
@@ -818,6 +820,16 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
       json_row = json_object_new_object();
       json_object_pim_ifp_add(json_row, ifp);
 
+      if (pim_ifp->sec_addr_list) {
+        json_object *sec_list = NULL;
+
+        sec_list = json_object_new_array();
+        for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
+          json_object_array_add(sec_list, json_object_new_string(inet_ntoa(sec_addr->addr)));
+        }
+        json_object_object_add(json_row, "secondaryAddressList", sec_list);
+      }
+
       // PIM neighbors
       if (pim_ifp->pim_neighbor_list->count) {
         json_pim_neighbors = json_object_new_object();
@@ -900,7 +912,16 @@ static void pim_show_interfaces_single(struct vty *vty, const char *ifname, u_ch
     } else {
       vty_out(vty, "Interface : %s%s", ifp->name, VTY_NEWLINE);
       vty_out(vty, "State     : %s%s", if_is_up(ifp) ? "up" : "down", VTY_NEWLINE);
-      vty_out(vty, "Address   : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
+      if (pim_ifp->sec_addr_list) {
+        vty_out(vty, "Address   : %s (primary)%s",
+                                    inet_ntoa(ifaddr), VTY_NEWLINE);
+        for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, sec_node, sec_addr)) {
+          vty_out(vty, "            %s%s",
+                                    inet_ntoa(sec_addr->addr), VTY_NEWLINE);
+        }
+      } else {
+        vty_out(vty, "Address   : %s%s", inet_ntoa(ifaddr), VTY_NEWLINE);
+      }
       vty_out(vty, "%s", VTY_NEWLINE);
 
       // PIM neighbors
@@ -4248,7 +4269,6 @@ static int
 pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
 {
   struct pim_interface *pim_ifp = ifp->info;
-  struct in_addr null = { .s_addr = 0 };
 
   if (!pim_ifp) {
     pim_ifp = pim_if_new(ifp, 0 /* igmp=false */, 1 /* pim=true */);
@@ -4263,8 +4283,6 @@ pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
   pim_ifp->itype = itype;
   pim_if_addr_add_all(ifp);
   pim_if_membership_refresh(ifp);
-
-  pim_rp_check_rp (null, pim_ifp->primary_address);
   return 1;
 }
 
index b83e8c17852c65d72bf482a576ff70c243af18b0..fcf07c253a3d004db049f9f4f28e9a83e81497bc 100644 (file)
@@ -27,6 +27,7 @@
 #include "prefix.h"
 #include "vrf.h"
 #include "linklist.h"
+#include "plist.h"
 
 #include "pimd.h"
 #include "pim_iface.h"
@@ -40,6 +41,7 @@
 #include "pim_sock.h"
 #include "pim_time.h"
 #include "pim_ssmpingd.h"
+#include "pim_rp.h"
 
 struct interface *pim_regiface = NULL;
 struct list *pim_ifchannel_list = NULL;
@@ -304,17 +306,177 @@ static int detect_primary_address_change(struct interface *ifp,
   return changed;
 }
 
+static int pim_sec_addr_comp(const void *p1, const void *p2)
+{
+  const struct pim_secondary_addr *sec1 = p1;
+  const struct pim_secondary_addr *sec2 = p2;
+
+  if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr))
+    return -1;
+
+  if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
+    return 1;
+
+  return 0;
+}
+
+static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
+{
+  XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
+}
+
+static struct pim_secondary_addr *
+pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
+{
+  struct pim_secondary_addr *sec_addr;
+  struct listnode *node;
+
+  if (!pim_ifp->sec_addr_list) {
+    return NULL;
+  }
+
+  for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
+    if (sec_addr->addr.s_addr == addr.s_addr) {
+      return sec_addr;
+    }
+  }
+
+  return NULL;
+}
+
+static void pim_sec_addr_del(struct pim_interface *pim_ifp,
+                             struct pim_secondary_addr *sec_addr)
+{
+  listnode_delete(pim_ifp->sec_addr_list, sec_addr);
+  pim_sec_addr_free(sec_addr);
+}
+
+static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
+{
+  int changed = 0;
+  struct pim_secondary_addr *sec_addr;
+
+  sec_addr = pim_sec_addr_find(pim_ifp, addr);
+  if (sec_addr) {
+    sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
+    return changed;
+  }
+
+  if (!pim_ifp->sec_addr_list) {
+    pim_ifp->sec_addr_list = list_new();
+    pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
+    pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp;
+  }
+
+  sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
+  if (!sec_addr) {
+    if (list_isempty(pim_ifp->sec_addr_list)) {
+      list_free(pim_ifp->sec_addr_list);
+      pim_ifp->sec_addr_list = NULL;
+    }
+    return changed;
+  }
+
+  changed = 1;
+  sec_addr->addr = addr;
+  listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
+
+  return changed;
+}
+
+static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
+{
+  int changed = 0;
+
+  if (!pim_ifp->sec_addr_list) {
+    return changed;
+  }
+  if (!list_isempty(pim_ifp->sec_addr_list)) {
+    changed = 1;
+    /* remove all nodes and free up the list itself */
+    list_delete_all_node(pim_ifp->sec_addr_list);
+    list_free(pim_ifp->sec_addr_list);
+    pim_ifp->sec_addr_list = NULL;
+  }
+
+  return changed;
+}
+
+static int pim_sec_addr_update(struct interface *ifp)
+{
+  struct pim_interface *pim_ifp = ifp->info;
+  struct connected *ifc;
+  struct listnode *node;
+  struct listnode *nextnode;
+  struct pim_secondary_addr *sec_addr;
+  int changed = 0;
+
+  if (pim_ifp->sec_addr_list) {
+    for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
+      sec_addr->flags |= PIM_SEC_ADDRF_STALE;
+    }
+  }
+
+  for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+    struct prefix *p = ifc->address;
+
+    if (p->family != AF_INET) {
+      continue;
+    }
+
+    if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
+      continue;
+    }
+
+    if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) {
+      /* don't add the primary address into the secondary address list */
+      continue;
+    }
+
+    if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
+      changed = 1;
+    }
+  }
+
+  if (pim_ifp->sec_addr_list) {
+    /* Drop stale entries */
+    for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, sec_addr)) {
+      if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
+        pim_sec_addr_del(pim_ifp, sec_addr);
+        changed = 1;
+      }
+    }
+
+    /* If the list went empty free it up */
+    if (list_isempty(pim_ifp->sec_addr_list)) {
+      list_free(pim_ifp->sec_addr_list);
+      pim_ifp->sec_addr_list = NULL;
+    }
+  }
+
+  return changed;
+}
+
 static void detect_secondary_address_change(struct interface *ifp,
+              int force_prim_as_any,
                                            const char *caller)
 {
   struct pim_interface *pim_ifp;
-  int changed;
+  int changed = 0;
 
   pim_ifp = ifp->info;
   if (!pim_ifp)
     return;
 
-  changed = 1; /* true */
+  if (force_prim_as_any) {
+    /* if primary address is being forced to zero just flush the
+     * secondary address list */
+    pim_sec_addr_del_all(pim_ifp);
+  } else {
+    /* re-evaluate the secondary address list */
+    changed = pim_sec_addr_update(ifp);
+  }
+
   if (PIM_DEBUG_ZEBRA)
     zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
              __PRETTY_FUNCTION__, ifp->name);
@@ -327,7 +489,8 @@ static void detect_secondary_address_change(struct interface *ifp,
     return;
   }
 
-  pim_addr_change(ifp);
+  /* XXX - re-evaluate i_am_rp on addr change */
+  //pim_addr_change(ifp);
 }
 
 static void detect_address_change(struct interface *ifp,
@@ -343,7 +506,7 @@ static void detect_address_change(struct interface *ifp,
     return;
   }
 
-  detect_secondary_address_change(ifp, caller);
+  detect_secondary_address_change(ifp, force_prim_as_any, caller);
 }
 
 void pim_if_addr_add(struct connected *ifc)
@@ -506,9 +669,11 @@ void pim_if_addr_add_all(struct interface *ifp)
   struct listnode *nextnode;
   int v4_addrs = 0;
   int v6_addrs = 0;
+  struct pim_interface *pim_ifp = ifp->info;
+
 
   /* PIM/IGMP enabled ? */
-  if (!ifp->info)
+  if (!pim_ifp)
     return;
 
   for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
@@ -526,9 +691,7 @@ void pim_if_addr_add_all(struct interface *ifp)
 
   if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
     {
-      struct pim_interface *pim_ifp = ifp->info;
-
-      if (pim_ifp && PIM_IF_TEST_PIM(pim_ifp->options)) {
+      if (PIM_IF_TEST_PIM(pim_ifp->options)) {
 
        /* Interface has a valid primary address ? */
        if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
@@ -544,6 +707,8 @@ void pim_if_addr_add_all(struct interface *ifp)
        }
       } /* pim */
     }
+
+  pim_rp_check_on_if_add(pim_ifp);
 }
 
 void pim_if_addr_del_all(struct interface *ifp)
@@ -564,6 +729,7 @@ void pim_if_addr_del_all(struct interface *ifp)
 
     pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
   }
+  pim_i_am_rp_re_evaluate();
 }
 
 void pim_if_addr_del_all_igmp(struct interface *ifp)
index b1759c0da9f5c48aa6b534e23fccc2b59ac62a27..e2097c870e4dfe63f3fa909d6b7d3db8f099ddae 100644 (file)
@@ -59,11 +59,22 @@ enum pim_interface_type {
   PIM_INTERFACE_SM
 };
 
+enum pim_secondary_addr_flags {
+  PIM_SEC_ADDRF_NONE = 0,
+  PIM_SEC_ADDRF_STALE = (1 << 0)
+};
+
+struct pim_secondary_addr {
+  struct in_addr addr;
+  enum pim_secondary_addr_flags flags;
+};
+
 struct pim_interface {
   enum pim_interface_type itype;
   uint32_t       options;                            /* bit vector */
   ifindex_t      mroute_vif_index;
   struct in_addr primary_address; /* remember addr to detect change */
+  struct list    *sec_addr_list; /* list of struct pim_secondary_addr */
 
   int          igmp_version;                                /* IGMP version */
   int          igmp_default_robustness_variable;            /* IGMPv3 QRV */
index 24163b0bd0031fa52ee1ebcc3768488f14583854..39cab7fb97c9cd506152542331c99b32b8c45f6a 100644 (file)
@@ -45,6 +45,7 @@
 #include "pim_signals.h"
 #include "pim_zebra.h"
 #include "pim_msdp.h"
+#include "pim_iface.h"
 #include "pim_rp.h"
 
 #ifdef PIM_ZCLIENT_DEBUG
index a8d4c3404e8c2081dafbd0e47732c0c57dc87eb8..ccd0fa81ac2292d112142652df5c7d4289de6f26 100644 (file)
@@ -46,3 +46,4 @@ DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME,      "PIM MSDP mesh-group name")
 DEFINE_MTYPE(PIMD, PIM_MSDP_SA,           "PIM MSDP source-active cache")
 DEFINE_MTYPE(PIMD, PIM_MSDP_MG,           "PIM MSDP mesh group")
 DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR,       "PIM MSDP mesh group mbr")
+DEFINE_MTYPE(PIMD, PIM_SEC_ADDR,          "PIM secondary address")
index 0f47fc22b47a8a945affa2e4b1b43415a6e15d87..b6b9b23239049a015a6ee1e391f6f56a18c51377 100644 (file)
@@ -45,5 +45,6 @@ DECLARE_MTYPE(PIM_MSDP_MG_NAME)
 DECLARE_MTYPE(PIM_MSDP_SA)
 DECLARE_MTYPE(PIM_MSDP_MG)
 DECLARE_MTYPE(PIM_MSDP_MG_MBR)
+DECLARE_MTYPE(PIM_SEC_ADDR)
 
 #endif /* _QUAGGA_PIM_MEMORY_H */
index bee5e734db734cadd445da59c9cdd46767e0d0c3..e10289e90c6d7aeef9594eada91b2a170848e8ec 100644 (file)
@@ -33,6 +33,7 @@
 #include "pimd.h"
 #include "pim_cmd.h"
 #include "pim_memory.h"
+#include "pim_iface.h"
 #include "pim_rp.h"
 #include "pim_str.h"
 #include "pim_time.h"
@@ -526,6 +527,7 @@ void
 pim_msdp_i_am_rp_changed(void)
 {
   struct listnode *sanode;
+  struct listnode *nextnode;
   struct pim_msdp_sa *sa;
 
   if (!(msdp->flags & PIM_MSDPF_ENABLE)) {
@@ -547,16 +549,18 @@ pim_msdp_i_am_rp_changed(void)
   /* re-setup local SA entries */
   pim_msdp_sa_local_setup();
 
-  for (ALL_LIST_ELEMENTS_RO(msdp->sa_list, sanode, sa)) {
+  for (ALL_LIST_ELEMENTS(msdp->sa_list, sanode, nextnode, sa)) {
     /* purge stale SA entries */
     if (sa->flags & PIM_MSDP_SAF_STALE) {
       /* clear the stale flag; the entry may be kept even after
        * "local-deref" */
       sa->flags &= ~PIM_MSDP_SAF_STALE;
+      /* sa_deref can end up freeing the sa; so don't access contents after */
       pim_msdp_sa_deref(sa, PIM_MSDP_SAF_LOCAL);
+    } else {
+      /* if the souce is still active check if we can influence SPT */
+      pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "rp-change");
     }
-    /* also check if we can still influence SPT */
-    pim_msdp_sa_upstream_update(sa, NULL /* xg_up */, "rp-change");
   }
 }
 
@@ -1216,6 +1220,8 @@ pim_msdp_mg_free(struct pim_msdp_mg *mg)
     XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
   XFREE(MTYPE_PIM_MSDP_MG, mg);
 
+  if (mg->mbr_list)
+    list_free(mg->mbr_list);
   msdp->mg = NULL;
 }
 
@@ -1536,10 +1542,6 @@ pim_msdp_enable(void)
 void
 pim_msdp_init(struct thread_master *master)
 {
-  /* XXX: temporarily enable noisy logs; will be disabled once dev is
-   * complete */
-  PIM_DO_DEBUG_MSDP_INTERNAL;
-
   msdp->master = master;
 
   msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make,
index bb73e34062ff87f92950df906c739b364cd3a4c2..0de9518d766913f1ee20c86ebab232a329788bd9 100644 (file)
@@ -33,6 +33,7 @@
 #include "pim_msg.h"
 #include "pim_util.h"
 #include "pim_str.h"
+#include "pim_iface.h"
 #include "pim_rp.h"
 #include "pim_rpf.h"
 
index 118c8a31303f7d49ef2675845cb56dd7417b6a14..b6d604b59aac8ed07019b9873ada93a36452e7fe 100644 (file)
@@ -34,6 +34,7 @@
 #include "pimd.h"
 #include "pim_vty.h"
 #include "pim_str.h"
+#include "pim_iface.h"
 #include "pim_rp.h"
 #include "pim_str.h"
 #include "pim_rpf.h"
@@ -250,12 +251,36 @@ pim_rp_prefix_list_update (struct prefix_list *plist)
     pim_rp_refresh_group_to_rp_mapping();
 }
 
+static int
+pim_rp_check_interface_addrs(struct rp_info *rp_info,
+                             struct pim_interface *pim_ifp)
+{
+  struct listnode *node;
+  struct pim_secondary_addr *sec_addr;
+
+  if (pim_ifp->primary_address.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
+    return 1;
+
+  if (!pim_ifp->sec_addr_list) {
+    return 0;
+  }
+
+  for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
+    if (sec_addr->addr.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
 static void
 pim_rp_check_interfaces (struct rp_info *rp_info)
 {
   struct listnode *node;
   struct interface *ifp;
 
+  rp_info->i_am_rp = 0;
   for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
     {
       struct pim_interface *pim_ifp = ifp->info;
@@ -263,8 +288,9 @@ pim_rp_check_interfaces (struct rp_info *rp_info)
       if (!pim_ifp)
         continue;
 
-      if (pim_ifp->primary_address.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
-       rp_info->i_am_rp = 1;
+      if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
+        rp_info->i_am_rp = 1;
+      }
     }
 }
 
@@ -507,10 +533,11 @@ pim_rp_setup (void)
 }
 
 /*
- * Checks to see if we should elect ourself the actual RP
+ * Checks to see if we should elect ourself the actual RP when new if
+ * addresses are added against an interface.
  */
 void
-pim_rp_check_rp (struct in_addr old, struct in_addr new)
+pim_rp_check_on_if_add(struct pim_interface *pim_ifp)
 {
   struct listnode *node;
   struct rp_info *rp_info;
@@ -519,40 +546,70 @@ pim_rp_check_rp (struct in_addr old, struct in_addr new)
   if (qpim_rp_list == NULL)
     return;
 
-  for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info))
-    {
+  for (ALL_LIST_ELEMENTS_RO (qpim_rp_list, node, rp_info)) {
+    if (pim_rpf_addr_is_inaddr_none (&rp_info->rp))
+      continue;
+
+    /* if i_am_rp is already set nothing to be done (adding new addresses
+     * is not going to make a difference). */
+    if (rp_info->i_am_rp) {
+      continue;
+    }
+
+    if (pim_rp_check_interface_addrs(rp_info, pim_ifp)) {
+      i_am_rp_changed = true;
+      rp_info->i_am_rp = 1;
       if (PIM_DEBUG_ZEBRA) {
-        char sold[INET_ADDRSTRLEN];
-        char snew[INET_ADDRSTRLEN];
         char rp[PREFIX_STRLEN];
         pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
-        pim_inet4_dump("<old?>", old, sold, sizeof(sold));
-        pim_inet4_dump("<new?>", new, snew, sizeof(snew));
-        zlog_debug("%s: %s for old %s new %s", __func__, rp, sold, snew );
+        zlog_debug("%s: %s: i am rp", __func__, rp);
       }
-      if (pim_rpf_addr_is_inaddr_none (&rp_info->rp))
-        continue;
+    }
+  }
 
-      if (new.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
-        {
-          if (!rp_info->i_am_rp) {
-            i_am_rp_changed = true;
-          }
-          rp_info->i_am_rp = 1;
-        }
+  if (i_am_rp_changed) {
+    pim_msdp_i_am_rp_changed();
+  }
+}
 
-      if (old.s_addr == rp_info->rp.rpf_addr.u.prefix4.s_addr)
-        {
-          if (rp_info->i_am_rp) {
-            i_am_rp_changed = true;
-          }
-          rp_info->i_am_rp = 0;
+/* up-optimized re-evaluation of "i_am_rp". this is used when ifaddresses
+ * are removed. Removing numbers is an uncommon event in an active network
+ * so I have made no attempt to optimize it. */
+void
+pim_i_am_rp_re_evaluate(void)
+{
+  struct listnode *node;
+  struct rp_info *rp_info;
+  bool i_am_rp_changed = false;
+  int old_i_am_rp;
+
+  if (qpim_rp_list == NULL)
+    return;
+
+  for (ALL_LIST_ELEMENTS_RO(qpim_rp_list, node, rp_info)) {
+    if (pim_rpf_addr_is_inaddr_none(&rp_info->rp))
+      continue;
+
+    old_i_am_rp = rp_info->i_am_rp;
+    pim_rp_check_interfaces(rp_info);
+
+    if (old_i_am_rp != rp_info->i_am_rp) {
+      i_am_rp_changed = true;
+      if (PIM_DEBUG_ZEBRA) {
+        char rp[PREFIX_STRLEN];
+        pim_addr_dump("<rp?>", &rp_info->rp.rpf_addr, rp, sizeof(rp));
+        if (rp_info->i_am_rp) {
+          zlog_debug("%s: %s: i am rp", __func__, rp);
+        } else {
+          zlog_debug("%s: %s: i am no longer rp", __func__, rp);
         }
+      }
     }
+  }
 
-    if (i_am_rp_changed) {
-      pim_msdp_i_am_rp_changed();
-    }
+  if (i_am_rp_changed) {
+    pim_msdp_i_am_rp_changed();
+  }
 }
 
 /*
index 1e1912ff967c57ec2eaee58dd5adff3290d17dad..b32228ed49daa5e7df48b408c100089eacc67881 100644 (file)
@@ -32,8 +32,9 @@ int pim_rp_config_write (struct vty *vty);
 
 int pim_rp_setup (void);
 
-void pim_rp_check_rp (struct in_addr old, struct in_addr new);
 int pim_rp_i_am_rp (struct in_addr group);
+void pim_rp_check_on_if_add(struct pim_interface *pim_ifp);
+void pim_i_am_rp_re_evaluate(void);
 
 int pim_rp_check_is_my_ip_address (struct in_addr group, struct in_addr dest_addr);
 
index f5c73efe2dfbda74eab06d91339551d351cbb4ac..294d8bba25a422b4d033b81829afd921c6daa31b 100644 (file)
@@ -223,7 +223,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
 {
   struct connected *c;
   struct prefix *p;
-  struct in_addr old = { .s_addr = 0 };
+  struct pim_interface *pim_ifp;
 
   /*
     zebra api notifies address adds/dels events by using the same call
@@ -237,6 +237,7 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
   if (!c)
     return 0;
 
+  pim_ifp = c->ifp->info;
   p = c->address;
 
   if (PIM_DEBUG_ZEBRA) {
@@ -254,7 +255,6 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
 
   if (p->family != AF_INET)
     {
-      struct pim_interface *pim_ifp = c->ifp->info;
       struct listnode *cnode;
       struct connected *conn;
       int v4addrs = 0;
@@ -273,8 +273,6 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
       return 0;
     }
 
-  pim_rp_check_rp (old, p->u.prefix4);
-
   if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
     /* trying to add primary address */
 
@@ -284,20 +282,20 @@ static int pim_zebra_if_address_add(int command, struct zclient *zclient,
        /* but we had a primary address already */
 
        char buf[BUFSIZ];
-       char old[INET_ADDRSTRLEN];
 
        prefix2str(p, buf, BUFSIZ);
-       pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
 
-       zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
+       zlog_warn("%s: %s : forcing secondary flag on %s",
                  __PRETTY_FUNCTION__,
-                 c->ifp->name, old, buf);
+                 c->ifp->name, buf);
       }
       SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
     }
   }
 
   pim_if_addr_add(c);
+  if (pim_ifp)
+    pim_rp_check_on_if_add(pim_ifp);
 
   if (if_is_loopback (c->ifp))
     {
@@ -319,7 +317,6 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
 {
   struct connected *c;
   struct prefix *p;
-  struct in_addr new = { .s_addr = 0 };
 
   /*
     zebra api notifies address adds/dels events by using the same call
@@ -350,8 +347,8 @@ static int pim_zebra_if_address_del(int command, struct zclient *client,
 #endif
   }
 
-  pim_rp_check_rp (p->u.prefix4, new);
   pim_if_addr_del(c, 0);
+  pim_i_am_rp_re_evaluate();
   
   return 0;
 }