summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoranuradhak <anuradhak@cumulusnetworks.com>2016-11-18 18:12:27 +0100
committerDonald Sharp <sharpd@cumulusnetworks.com>2016-12-22 02:26:16 +0100
commit7176984f745f73c1350b69100295b25824d20dd4 (patch)
tree56a938670f28efb2428d03d26dad82c4878aa810
parentpimd: Set pim socket receive buffer to a larger value (diff)
downloadfrr-7176984f745f73c1350b69100295b25824d20dd4.tar.xz
frr-7176984f745f73c1350b69100295b25824d20dd4.zip
pim-anycast-rp: Add limited support for secondary addresses.
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>
-rw-r--r--pimd/pim_cmd.c26
-rw-r--r--pimd/pim_iface.c182
-rw-r--r--pimd/pim_iface.h11
-rw-r--r--pimd/pim_main.c1
-rw-r--r--pimd/pim_memory.c1
-rw-r--r--pimd/pim_memory.h1
-rw-r--r--pimd/pim_msdp.c16
-rw-r--r--pimd/pim_msg.c1
-rw-r--r--pimd/pim_rp.c115
-rw-r--r--pimd/pim_rp.h3
-rw-r--r--pimd/pim_zebra.c17
11 files changed, 315 insertions, 59 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index ecfa94cba..aa97907a3 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -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;
}
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index b83e8c178..fcf07c253 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -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)
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index b1759c0da..e2097c870 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -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 */
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index 24163b0bd..39cab7fb9 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -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
diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c
index a8d4c3404..ccd0fa81a 100644
--- a/pimd/pim_memory.c
+++ b/pimd/pim_memory.c
@@ -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")
diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h
index 0f47fc22b..b6b9b2323 100644
--- a/pimd/pim_memory.h
+++ b/pimd/pim_memory.h
@@ -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 */
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
index bee5e734d..e10289e90 100644
--- a/pimd/pim_msdp.c
+++ b/pimd/pim_msdp.c
@@ -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,
diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c
index bb73e3406..0de9518d7 100644
--- a/pimd/pim_msg.c
+++ b/pimd/pim_msg.c
@@ -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"
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 118c8a313..b6d604b59 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -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();
+ }
}
/*
diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h
index 1e1912ff9..b32228ed4 100644
--- a/pimd/pim_rp.h
+++ b/pimd/pim_rp.h
@@ -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);
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index f5c73efe2..294d8bba2 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -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;
}