#include "pim_br.h"
#include "pim_register.h"
#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;
struct timer_wheel *pim_upstream_sg_wheel = NULL;
-static void join_timer_start(struct pim_upstream *up);
+static void join_timer_stop(struct pim_upstream *up);
static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up);
/*
void pim_upstream_free(struct pim_upstream *up)
{
XFREE(MTYPE_PIM_UPSTREAM, up);
+ up = NULL;
}
static void upstream_channel_oil_detach(struct pim_upstream *up)
}
}
-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_join_timer);
THREAD_OFF(up->t_ka_timer);
THREAD_OFF(up->t_rs_timer);
THREAD_OFF(up->t_msdp_reg_timer);
if (up->join_state == PIM_UPSTREAM_JOINED) {
- pim_joinprune_send (up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr.u.prefix4,
- up, 0);
+ pim_jp_agg_single_upstream_send (&up->rpf, up, 0);
+
if (up->sg.src.s_addr == INADDR_ANY) {
/* if a (*, G) entry in the joined state is being deleted we
* need to notify MSDP */
}
}
+ 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) {
wheel_remove_item (pim_upstream_sg_wheel, up);
notify_msdp = true;
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
listnode_delete (pim_upstream_list, up);
hash_release (pim_upstream_hash, up);
- if (notify_msdp) {
- pim_msdp_up_del(&up->sg);
- }
- pim_upstream_free(up);
+ if (notify_msdp)
+ {
+ pim_msdp_up_del (&up->sg);
+ }
+
+ /* Deregister addr with Zebra NHT */
+ nht_p.family = AF_INET;
+ nht_p.prefixlen = IPV4_MAX_BITLEN;
+ nht_p.u.prefix4 = up->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",
+ __PRETTY_FUNCTION__, up->sg_str, buf);
+ }
+ pim_delete_tracked_nexthop (&nht_p, up, NULL);
+
+ pim_upstream_free (up);
+
+ return NULL;
}
void
}
/* send Join(S,G) to the current upstream neighbor */
- pim_joinprune_send(up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr.u.prefix4,
- up,
- 1 /* join */);
+ pim_jp_agg_single_upstream_send(&up->rpf, up, 1 /* join */);
}
static int on_join_timer(struct thread *t)
* Don't send the join if the outgoing interface is a loopback
* But since this might change leave the join timer running
*/
- if (!if_is_loopback (up->rpf.source_nexthop.interface))
+ if (up->rpf.source_nexthop.interface &&
+ !if_is_loopback (up->rpf.source_nexthop.interface))
pim_upstream_send_join (up);
join_timer_start(up);
return 0;
}
-static void join_timer_start(struct pim_upstream *up)
+static void join_timer_stop(struct pim_upstream *up)
{
- if (PIM_DEBUG_PIM_EVENTS) {
- zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
- __PRETTY_FUNCTION__,
- qpim_t_periodic,
- up->sg_str);
- }
+ struct pim_neighbor *nbr;
THREAD_OFF (up->t_join_timer);
- THREAD_TIMER_ON(master, up->t_join_timer,
- on_join_timer,
- up, qpim_t_periodic);
+
+ 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);
+
+ pim_jp_agg_upstream_verification (up, false);
}
-void pim_upstream_join_timer_restart(struct pim_upstream *up)
+void
+join_timer_start(struct pim_upstream *up)
{
- THREAD_OFF(up->t_join_timer);
+ struct pim_neighbor *nbr = NULL;
+
+ if (up->rpf.source_nexthop.interface)
+ {
+ nbr = pim_neighbor_find (up->rpf.source_nexthop.interface,
+ up->rpf.rpf_addr.u.prefix4);
+
+ if (PIM_DEBUG_PIM_EVENTS) {
+ zlog_debug("%s: starting %d sec timer for upstream (S,G)=%s",
+ __PRETTY_FUNCTION__,
+ qpim_t_periodic,
+ up->sg_str);
+ }
+ }
+
+ if (nbr)
+ pim_jp_agg_add_group (nbr->upstream_jp_agg, up, 1);
+ else
+ {
+ THREAD_OFF (up->t_join_timer);
+ THREAD_TIMER_ON(master, up->t_join_timer,
+ on_join_timer,
+ up, qpim_t_periodic);
+ }
+ pim_jp_agg_upstream_verification (up, true);
+}
+
+/*
+ * This is only called when we are switching the upstream
+ * J/P from one neighbor to another
+ *
+ * As such we need to remove from the old list and
+ * add to the new list.
+ */
+void pim_upstream_join_timer_restart(struct pim_upstream *up, struct pim_rpf *old)
+{
+ //THREAD_OFF(up->t_join_timer);
join_timer_start(up);
}
}
void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label,
- struct pim_upstream *up,
- struct in_addr rpf_addr)
+ struct pim_upstream *up)
{
long join_timer_remain_msec;
int t_override_msec;
if (PIM_DEBUG_TRACE) {
char rpf_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str));
+ pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str, sizeof(rpf_str));
zlog_debug("%s: to RPF'%s=%s: join_timer=%ld msec t_override=%d msec",
debug_label,
up->sg_str, rpf_str,
{
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_state2str (new_state));
}
- /*
- * This code still needs work.
- */
- switch (up->join_state)
- {
- case PIM_UPSTREAM_PRUNE:
- if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
- {
- up->join_state = new_state;
- up->state_transition = pim_time_monotonic_sec ();
- }
- break;
- case PIM_UPSTREAM_JOIN_PENDING:
- break;
- case PIM_UPSTREAM_NOTJOINED:
- case PIM_UPSTREAM_JOINED:
- up->join_state = new_state;
- if (old_state != new_state)
- up->state_transition = pim_time_monotonic_sec();
-
- break;
- }
+ up->join_state = new_state;
+ if (old_state != new_state)
+ up->state_transition = pim_time_monotonic_sec();
pim_upstream_update_assert_tracking_desired(up);
if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
{
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
}
}
else {
+
forward_off(up);
if (old_state == PIM_UPSTREAM_JOINED)
pim_msdp_up_join_state_changed(up);
- pim_joinprune_send(up->rpf.source_nexthop.interface,
- up->rpf.rpf_addr.u.prefix4,
- up,
- 0 /* prune */);
- if (up->t_join_timer)
- THREAD_OFF(up->t_join_timer);
+
+ pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */);
+ join_timer_stop(up);
}
}
-static int
+int
pim_upstream_compare (void *arg1, void *arg2)
{
const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
struct pim_upstream *up;
up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up));
- if (!up) {
- zlog_err("%s: PIM XCALLOC(%zu) failure",
+ if (!up)
+ {
+ zlog_err("%s: PIM XCALLOC(%zu) failure",
__PRETTY_FUNCTION__, sizeof(*up));
- return NULL;
- }
+ return NULL;
+ }
up->sg = *sg;
pim_str_sg_set (sg, up->sg_str);
up->t_ka_timer = NULL;
up->t_rs_timer = NULL;
up->t_msdp_reg_timer = NULL;
- up->join_state = 0;
+ up->join_state = PIM_UPSTREAM_NOTJOINED;
+ up->reg_state = PIM_REG_NOINFO;
up->state_transition = pim_time_monotonic_sec();
up->channel_oil = NULL;
up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE;
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);
+ 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)
- zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, up->sg_str);
+ {
+ zlog_debug ("%s: Created Upstream %s upstream_addr %s",
+ __PRETTY_FUNCTION__, up->sg_str,
+ inet_ntoa (up->upstream_addr));
+ }
return up;
}
return up;
}
-static void pim_upstream_ref(struct pim_upstream *up, int flags)
+struct pim_upstream *
+pim_upstream_find_or_add(struct prefix_sg *sg,
+ struct interface *incoming,
+ int flags, const char *name)
+{
+ struct pim_upstream *up;
+
+ up = pim_upstream_find(sg);
+
+ if (up)
+ {
+ if (!(up->flags & flags))
+ {
+ up->flags |= flags;
+ up->ref_count++;
+ }
+ }
+ else
+ up = pim_upstream_add (sg, incoming, flags, name);
+
+ return up;
+}
+
+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;
}
-static int
+/*
+ * 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);
+
+ if (starup)
+ starch = pim_ifchannel_find (ifp, &starup->sg);
+ else
+ starch = NULL;
- ret += pim_upstream_evaluate_join_desired_interface (up, ch);
+ if (!ch && !starch)
+ continue;
+
+ ret += pim_upstream_evaluate_join_desired_interface (up, ch, starch);
} /* scan iface channel list */
return ret; /* false */
continue;
pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change",
- up, neigh_addr);
+ up);
}
}
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 */
THREAD_OFF(up->t_rs_timer);
/* remove regiface from the OIL if it is there*/
pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
- /* move to "not-joined" */
- up->join_state = PIM_UPSTREAM_NOTJOINED;
+ /* clear the register state */
+ up->reg_state = PIM_REG_NOINFO;
PIM_UPSTREAM_FLAG_UNSET_FHR(up->flags);
}
zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
- if (up->join_state == PIM_UPSTREAM_NOTJOINED) {
- pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
- up->join_state = PIM_UPSTREAM_JOINED;
- }
+ 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;
case PIM_UPSTREAM_JOINED:
return "Joined";
break;
- case PIM_UPSTREAM_JOIN_PENDING:
- return "JoinPending";
+ }
+ return "Unknown";
+}
+
+const char *
+pim_reg_state2str (enum pim_reg_state reg_state, char *state_str)
+{
+ switch (reg_state)
+ {
+ case PIM_REG_NOINFO:
+ strcpy (state_str, "RegNoInfo");
+ break;
+ case PIM_REG_JOIN:
+ strcpy (state_str, "RegJoined");
break;
- case PIM_UPSTREAM_PRUNE:
- return "Prune";
+ case PIM_REG_JOIN_PENDING:
+ strcpy (state_str, "RegJoinPend");
break;
+ case PIM_REG_PRUNE:
+ strcpy (state_str, "RegPrune");
+ break;
+ default:
+ strcpy (state_str, "RegUnknown");
}
- return "Unknown";
+ return state_str;
}
static int
if (PIM_DEBUG_TRACE)
{
+ char state_str[PIM_REG_STATE_STR_LEN];
zlog_debug ("%s: (S,G)=%s upstream register stop timer %s",
__PRETTY_FUNCTION__, up->sg_str,
- pim_upstream_state2str(up->join_state));
+ pim_reg_state2str(up->reg_state, state_str));
}
- switch (up->join_state)
+ switch (up->reg_state)
{
- case PIM_UPSTREAM_JOIN_PENDING:
- up->join_state = PIM_UPSTREAM_JOINED;
+ case PIM_REG_JOIN_PENDING:
+ up->reg_state = PIM_REG_JOIN;
pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM);
break;
- case PIM_UPSTREAM_JOINED:
+ case PIM_REG_JOIN:
break;
- case PIM_UPSTREAM_PRUNE:
+ case PIM_REG_PRUNE:
pim_ifp = up->rpf.source_nexthop.interface->info;
if (!pim_ifp)
{
__PRETTY_FUNCTION__, up->rpf.source_nexthop.interface->name);
return 0;
}
- up->join_state = PIM_UPSTREAM_JOIN_PENDING;
+ up->reg_state = PIM_REG_JOIN_PENDING;
pim_upstream_start_register_stop_timer (up, 1);
if (((up->channel_oil->cc.lastused/100) > PIM_KEEPALIVE_PERIOD) &&
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))
- {
- pim_channel_add_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM);
- output_intf++;
- }
+ 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)
+ flag = PIM_OIF_FLAG_PROTO_STAR;
+
+ pim_channel_add_oif (up->channel_oil, ifp, flag);
+ output_intf++;
+ }
}
return output_intf;
if (PIM_DEBUG_TRACE)
zlog_debug ("Upstream %s without a path to send join, checking",
up->sg_str);
- pim_rpf_update (up, NULL);
+ pim_rpf_update (up, NULL, 1);
}
}
}
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)
{