#include "pim_msdp.h"
#include "pim_jp_agg.h"
#include "pim_nht.h"
+#include "pim_ssm.h"
struct hash *pim_upstream_hash = NULL;
struct list *pim_upstream_list = NULL;
}
}
-void
+struct pim_upstream *
pim_upstream_del(struct pim_upstream *up, const char *name)
{
bool notify_msdp = false;
struct prefix nht_p;
if (PIM_DEBUG_TRACE)
- zlog_debug ("%s(%s): Delete %s ref count: %d",
- __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count);
+ zlog_debug ("%s(%s): Delete %s ref count: %d, flags: %d (Pre decrement)",
+ __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count, up->flags);
--up->ref_count;
if (up->ref_count >= 1)
- return;
+ return up;
THREAD_OFF(up->t_ka_timer);
THREAD_OFF(up->t_rs_timer);
}
join_timer_stop(up);
+ pim_jp_agg_upstream_verification (up, false);
up->rpf.source_nexthop.interface = NULL;
if (up->sg.src.s_addr != INADDR_ANY) {
upstream_channel_oil_detach(up);
if (up->sources)
- list_delete (up->sources);
+ {
+ struct listnode *node, *nnode;
+ struct pim_upstream *child;
+ for (ALL_LIST_ELEMENTS (up->sources, node, nnode, child))
+ {
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags))
+ {
+ PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
+ pim_upstream_del(child, __PRETTY_FUNCTION__);
+ }
+ }
+
+ list_delete (up->sources);
+ }
up->sources = NULL;
+ list_delete (up->ifchannels);
+
/*
notice that listnode_delete() can't be moved
into pim_upstream_free() because the later is
{
char buf[PREFIX2STR_BUFFER];
prefix2str (&nht_p, buf, sizeof (buf));
- zlog_debug ("%s: Deregister upstream %s upstream addr %s with NHT ",
- __PRETTY_FUNCTION__, up->sg_str, buf);
+ zlog_debug ("%s: Deregister upstream %s addr %s with Zebra",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
}
pim_delete_tracked_nexthop (&nht_p, up, NULL);
pim_upstream_free (up);
+
+ return NULL;
}
void
{
struct pim_neighbor *nbr;
+ THREAD_OFF (up->t_join_timer);
+
nbr = pim_neighbor_find (up->rpf.source_nexthop.interface,
up->rpf.rpf_addr.u.prefix4);
if (nbr)
pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
- THREAD_OFF (up->t_join_timer);
+ pim_jp_agg_upstream_verification (up, false);
}
void
on_join_timer,
up, qpim_t_periodic);
}
+ pim_jp_agg_upstream_verification (up, true);
}
/*
*/
void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old)
{
- struct pim_neighbor *nbr;
-
- nbr = pim_neighbor_find (old->source_nexthop.interface,
- old->rpf_addr.u.prefix4);
- if (nbr)
- pim_jp_agg_remove_group (nbr->upstream_jp_agg, up);
-
//THREAD_OFF(up->t_join_timer);
join_timer_start(up);
}
{
struct listnode *chnode;
struct listnode *chnextnode;
- struct pim_interface *pim_ifp;
- struct pim_ifchannel *ch;
+ struct pim_ifchannel *ch = NULL;
/* scan (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
- pim_ifp = ch->interface->info;
- if (!pim_ifp)
- continue;
-
- if (ch->upstream != up)
- continue;
-
+ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
if (pim_macro_chisin_oiflist(ch))
pim_forward_start(ch);
{
struct listnode *chnode;
struct listnode *chnextnode;
- struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
/* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
- pim_ifp = ch->interface->info;
- if (!pim_ifp)
- continue;
-
- if (ch->upstream != up)
- continue;
+ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
pim_forward_stop(ch);
static int
pim_upstream_could_register (struct pim_upstream *up)
{
- struct pim_interface *pim_ifp = up->rpf.source_nexthop.interface->info;
+ struct pim_interface *pim_ifp = NULL;
+
+ if (up->rpf.source_nexthop.interface)
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ else
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str);
+ }
if (pim_ifp && PIM_I_am_DR (pim_ifp) &&
pim_if_connected_to_source (up->rpf.source_nexthop.interface, up->sg.src))
return 0;
}
+/* Source registration is supressed for SSM groups. When the SSM range changes
+ * we re-revaluate register setup for existing upstream entries */
+void
+pim_upstream_register_reevaluate (void)
+{
+ struct listnode *upnode;
+ struct pim_upstream *up;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, upnode, up))
+ {
+ /* If FHR is set CouldRegister is True. Also check if the flow
+ * is actually active; if it is not kat setup will trigger source
+ * registration whenever the flow becomes active. */
+ if (!PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) || !up->t_ka_timer)
+ continue;
+
+ if (pim_is_grp_ssm (up->sg.grp))
+ {
+ /* clear the register state for SSM groups */
+ if (up->reg_state != PIM_REG_NOINFO)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("Clear register for %s as G is now SSM",
+ up->sg_str);
+ /* remove regiface from the OIL if it is there*/
+ pim_channel_del_oif (up->channel_oil, pim_regiface,
+ PIM_OIF_FLAG_PROTO_PIM);
+ up->reg_state = PIM_REG_NOINFO;
+ }
+ }
+ else
+ {
+ /* register ASM sources with the RP */
+ if (up->reg_state == PIM_REG_NOINFO)
+ {
+ if (PIM_DEBUG_PIM_EVENTS)
+ zlog_debug ("Register %s as G is now ASM", up->sg_str);
+ pim_channel_add_oif (up->channel_oil, pim_regiface,
+ PIM_OIF_FLAG_PROTO_PIM);
+ up->reg_state = PIM_REG_JOIN;
+ }
+ }
+ }
+}
+
void
pim_upstream_switch(struct pim_upstream *up,
enum pim_upstream_state new_state)
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
{
- up->reg_state = PIM_REG_JOIN;
pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
- pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
+ pim_register_join (up);
}
}
else
up->rpf.rpf_addr.family = AF_INET;
up->rpf.rpf_addr.u.prefix4.s_addr = PIM_NET_INADDR_ANY;
+ up->ifchannels = list_new();
+ up->ifchannels->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
+
if (up->sg.src.s_addr != INADDR_ANY)
wheel_add_item (pim_upstream_sg_wheel, up);
rpf_result = pim_rpf_update(up, NULL, 1);
if (rpf_result == PIM_RPF_FAILURE) {
+ struct prefix nht_p;
+
if (PIM_DEBUG_TRACE)
zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
up->sg_str);
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = up->upstream_addr;
+ pim_delete_tracked_nexthop (&nht_p, up, NULL);
+
if (up->parent)
{
listnode_delete (up->parent->sources, up);
return NULL;
}
- pim_ifp = up->rpf.source_nexthop.interface->info;
- if (pim_ifp)
- up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
-
+ if (up->rpf.source_nexthop.interface)
+ {
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (pim_ifp)
+ up->channel_oil = pim_channel_oil_add(&up->sg, pim_ifp->mroute_vif_index);
+ }
listnode_add_sort(pim_upstream_list, up);
if (PIM_DEBUG_TRACE)
return up;
}
-static void pim_upstream_ref(struct pim_upstream *up, int flags)
+void
+pim_upstream_ref(struct pim_upstream *up, int flags)
{
up->flags |= flags;
++up->ref_count;
if (PIM_DEBUG_TRACE)
{
if (up)
- zlog_debug("%s(%s): %s, found: %d: ref_count: %d",
+ {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str (&up->rpf.rpf_addr, buf, sizeof (buf));
+ zlog_debug("%s(%s): %s, iif %s found: %d: ref_count: %d",
__PRETTY_FUNCTION__, name,
- up->sg_str, found,
+ up->sg_str, buf, found,
up->ref_count);
+ }
else
zlog_debug("%s(%s): (%s) failure to create",
__PRETTY_FUNCTION__, name,
return up;
}
+/*
+ * Passed in up must be the upstream for ch. starch is NULL if no
+ * information
+ */
int
pim_upstream_evaluate_join_desired_interface (struct pim_upstream *up,
- struct pim_ifchannel *ch)
+ struct pim_ifchannel *ch,
+ struct pim_ifchannel *starch)
{
- struct pim_upstream *parent = up->parent;
-
- if (ch->upstream == up)
+ if (ch)
{
- if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
- return 1;
-
if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
- return 0;
+ return 0;
+
+ if (!pim_macro_ch_lost_assert(ch) && pim_macro_chisin_joins_or_include(ch))
+ return 1;
}
/*
* joins (*,G)
*/
- if (parent && ch->upstream == parent)
+ if (starch)
{
- if (!pim_macro_ch_lost_assert (ch) && pim_macro_chisin_joins_or_include (ch))
- return 1;
+ if (PIM_IF_FLAG_TEST_S_G_RPT (starch->upstream->flags))
+ return 0;
+
+ if (!pim_macro_ch_lost_assert (starch) && pim_macro_chisin_joins_or_include (starch))
+ return 1;
}
return 0;
*/
int pim_upstream_evaluate_join_desired(struct pim_upstream *up)
{
- struct listnode *chnode;
- struct listnode *chnextnode;
- struct pim_interface *pim_ifp;
- struct pim_ifchannel *ch;
+ struct interface *ifp;
+ struct listnode *node;
+ struct pim_ifchannel *ch, *starch;
+ struct pim_upstream *starup = up->parent;
int ret = 0;
- /* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch))
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
{
- pim_ifp = ch->interface->info;
- if (!pim_ifp)
- continue;
+ if (!ifp->info)
+ continue;
+
+ ch = pim_ifchannel_find (ifp, &up->sg);
- ret += pim_upstream_evaluate_join_desired_interface (up, ch);
+ if (starup)
+ starch = pim_ifchannel_find (ifp, &starup->sg);
+ else
+ starch = NULL;
+
+ if (!ch && !starch)
+ continue;
+
+ ret += pim_upstream_evaluate_join_desired_interface (up, ch, starch);
} /* scan iface channel list */
return ret; /* false */
struct listnode *chnode;
struct listnode *chnextnode;
struct pim_ifchannel *ch;
- struct pim_interface *pim_ifp;
/* search all ifchannels */
- for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
-
- pim_ifp = ch->interface->info;
- if (!pim_ifp)
- continue;
-
- if (ch->upstream != up)
- continue;
-
+ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) {
if (
/* RPF_interface(S) was NOT I */
{
struct listnode *chnode;
struct listnode *chnextnode;
- struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
/* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
- pim_ifp = ch->interface->info;
- if (!pim_ifp)
- continue;
-
- if (ch->upstream != up)
- continue;
-
+ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
pim_ifchannel_update_could_assert(ch);
} /* scan iface channel list */
}
{
struct listnode *chnode;
struct listnode *chnextnode;
- struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
/* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
- pim_ifp = ch->interface->info;
- if (!pim_ifp)
- continue;
-
- if (ch->upstream != up)
- continue;
-
+ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
pim_ifchannel_update_my_assert_metric(ch);
} /* scan iface channel list */
struct pim_ifchannel *ch;
/* scan per-interface (S,G) state */
- for (ALL_LIST_ELEMENTS(pim_ifchannel_list, chnode, chnextnode, ch)) {
+ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
pim_ifp = ch->interface->info;
if (!pim_ifp)
continue;
- if (ch->upstream != up)
- continue;
-
pim_ifchannel_update_assert_tracking_desired(ch);
} /* scan iface channel list */
zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
- if (up->reg_state == PIM_REG_NOINFO) {
- pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
- up->reg_state = PIM_REG_JOIN;
- }
+ if (up->reg_state == PIM_REG_NOINFO)
+ pim_register_join (up);
}
}
up->t_ka_timer = NULL;
if (I_am_RP (up->sg.grp))
- {
- pim_br_clear_pmbr (&up->sg);
- /*
- * We need to do more here :)
- * But this is the start.
- */
- }
+ {
+ pim_br_clear_pmbr (&up->sg);
+ /*
+ * We need to do more here :)
+ * But this is the start.
+ */
+ }
/* source is no longer active - pull the SA from MSDP's cache */
pim_msdp_sa_local_del(&up->sg);
/* if entry was created because of activity we need to deref it */
if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
- {
- pim_upstream_fhr_kat_expiry(up);
- if (PIM_DEBUG_TRACE)
- zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
- PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
- pim_upstream_del(up, __PRETTY_FUNCTION__);
- }
+ {
+ pim_upstream_fhr_kat_expiry(up);
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
+ PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
+ pim_upstream_del(up, __PRETTY_FUNCTION__);
+ }
+ else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
+ {
+ PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
+ pim_upstream_del(up, __PRETTY_FUNCTION__);
+ }
return 0;
}
struct listnode *chnode;
struct pim_ifchannel *ch;
- for (ALL_LIST_ELEMENTS_RO(pim_ifchannel_list, chnode, ch))
+ for (ALL_LIST_ELEMENTS_RO(up->ifchannels, chnode, ch))
{
- if ((ch->upstream == up) &&
- (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)))
- return 1;
+ if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags))
+ return 1;
}
return 0;
int
pim_upstream_inherited_olist_decide (struct pim_upstream *up)
{
- struct pim_interface *pim_ifp;
- struct listnode *chnextnode;
- struct pim_ifchannel *ch;
- struct listnode *chnode;
+ struct interface *ifp;
+ struct pim_interface *pim_ifp = NULL;
+ struct pim_ifchannel *ch, *starch;
+ struct listnode *node;
+ struct pim_upstream *starup = up->parent;
int output_intf = 0;
- pim_ifp = up->rpf.source_nexthop.interface->info;
+ if (up->rpf.source_nexthop.interface)
+ pim_ifp = up->rpf.source_nexthop.interface->info;
+ else
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str);
+ }
if (pim_ifp && !up->channel_oil)
up->channel_oil = pim_channel_oil_add (&up->sg, pim_ifp->mroute_vif_index);
- for (ALL_LIST_ELEMENTS (pim_ifchannel_list, chnode, chnextnode, ch))
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
{
- pim_ifp = ch->interface->info;
- if (!pim_ifp)
- continue;
+ if (!ifp->info)
+ continue;
- if (pim_upstream_evaluate_join_desired_interface (up, ch))
- {
+ ch = pim_ifchannel_find (ifp, &up->sg);
+
+ if (starup)
+ starch = pim_ifchannel_find (ifp, &starup->sg);
+ else
+ starch = NULL;
+
+ if (!ch && !starch)
+ continue;
+
+ if (pim_upstream_evaluate_join_desired_interface (up, ch, starch))
+ {
int flag = PIM_OIF_FLAG_PROTO_PIM;
- if (ch->sg.src.s_addr == INADDR_ANY && ch->upstream != up)
+ if (!ch)
flag = PIM_OIF_FLAG_PROTO_STAR;
- pim_channel_add_oif (up->channel_oil, ch->interface, flag);
- output_intf++;
- }
+
+ pim_channel_add_oif (up->channel_oil, ifp, flag);
+ output_intf++;
+ }
}
return output_intf;
return;
}
- if (pim_upstream_kat_start_ok(up)) {
- /* Add a source reference to the stream if
- * one doesn't already exist */
- if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+ if (pim_upstream_kat_start_ok(up))
{
- if (PIM_DEBUG_TRACE)
- zlog_debug ("source reference created on kat restart %s", up->sg_str);
+ /* Add a source reference to the stream if
+ * one doesn't already exist */
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("source reference created on kat restart %s", up->sg_str);
- pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
- PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
- pim_upstream_fhr_kat_start(up);
+ pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
+ PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
+ pim_upstream_fhr_kat_start(up);
+ }
+ pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
}
+ else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
- }
if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
- {
- pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
- }
+ {
+ pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
+ }
return;
}
+void
+pim_upstream_add_lhr_star_pimreg (void)
+{
+ struct pim_upstream *up;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+ {
+ if (up->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+ continue;
+
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ }
+}
+
+void
+pim_upstream_spt_prefix_list_update (struct prefix_list *pl)
+{
+ const char *pname = prefix_list_name (pl);
+
+ if (pimg->spt.plist && strcmp (pimg->spt.plist, pname) == 0)
+ {
+ pim_upstream_remove_lhr_star_pimreg (pname);
+ }
+}
+
+/*
+ * nlist -> The new prefix list
+ *
+ * Per Group Application of pimreg to the OIL
+ * If the prefix list tells us DENY then
+ * we need to Switchover to SPT immediate
+ * so add the pimreg.
+ * If the prefix list tells us to ACCEPT than
+ * we need to Never do the SPT so remove
+ * the interface
+ *
+ */
+void
+pim_upstream_remove_lhr_star_pimreg (const char *nlist)
+{
+ struct pim_upstream *up;
+ struct listnode *node;
+ struct prefix_list *np;
+ struct prefix g;
+ enum prefix_list_type apply_new;
+
+ np = prefix_list_lookup (AFI_IP, nlist);
+
+ g.family = AF_INET;
+ g.prefixlen = IPV4_MAX_PREFIXLEN;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+ {
+ if (up->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+ continue;
+
+ if (!nlist)
+ {
+ pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ continue;
+ }
+ g.u.prefix4 = up->sg.grp;
+ apply_new = prefix_list_apply (np, &g);
+ if (apply_new == PREFIX_DENY)
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ else
+ pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ }
+}
+
void
pim_upstream_init (void)
{