summaryrefslogtreecommitdiff
path: root/pimd/pim_ifchannel.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/pim_ifchannel.c')
-rw-r--r--pimd/pim_ifchannel.c142
1 files changed, 108 insertions, 34 deletions
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index ebd36f8782..f4fe609605 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -27,6 +27,7 @@
#include "vrf.h"
#include "hash.h"
#include "jhash.h"
+#include "prefix.h"
#include "pimd.h"
#include "pim_str.h"
@@ -49,30 +50,25 @@ pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
struct pim_interface *pim_ifp1;
struct pim_interface *pim_ifp2;
- if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr))
- return -1;
-
- if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr))
- return 1;
+ pim_ifp1 = ch1->interface->info;
+ pim_ifp2 = ch2->interface->info;
- if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr))
+ if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index)
return -1;
- if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr))
+ if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index)
return 1;
- pim_ifp1 = ch1->interface->info;
- pim_ifp2 = ch2->interface->info;
- if (ntohl(pim_ifp1->primary_address.s_addr) < ntohl(pim_ifp2->primary_address.s_addr))
+ if (ntohl(ch1->sg.grp.s_addr) < ntohl(ch2->sg.grp.s_addr))
return -1;
- if (ntohl(pim_ifp1->primary_address.s_addr) > ntohl(pim_ifp2->primary_address.s_addr))
+ if (ntohl(ch1->sg.grp.s_addr) > ntohl(ch2->sg.grp.s_addr))
return 1;
- if (pim_ifp1->mroute_vif_index < pim_ifp2->mroute_vif_index)
+ if (ntohl(ch1->sg.src.s_addr) < ntohl(ch2->sg.src.s_addr))
return -1;
- if (pim_ifp1->mroute_vif_index > pim_ifp2->mroute_vif_index)
+ if (ntohl(ch1->sg.src.s_addr) > ntohl(ch2->sg.src.s_addr))
return 1;
return 0;
@@ -149,6 +145,9 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
mask = PIM_OIF_FLAG_PROTO_IGMP;
+ /* SGRpt entry could have empty oil */
+ if (ch->upstream->channel_oil)
+ pim_channel_del_oif (ch->upstream->channel_oil, ch->interface, mask);
pim_channel_del_oif (ch->upstream->channel_oil, ch->interface, mask);
/*
* Do we have any S,G's that are inheriting?
@@ -174,6 +173,8 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
if (ch->sources)
list_delete (ch->sources);
+ listnode_delete(ch->upstream->ifchannels, ch);
+
if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
pim_upstream_update_join_desired(ch->upstream);
}
@@ -568,6 +569,8 @@ pim_ifchannel_add(struct interface *ifp,
ch = hash_get (pim_ifp->pim_ifchannel_hash, ch, hash_alloc_intern);
listnode_add_sort(pim_ifchannel_list, ch);
+ listnode_add_sort(up->ifchannels, ch);
+
return ch;
}
@@ -610,6 +613,7 @@ static int on_ifjoin_prune_pending_timer(struct thread *t)
pim_ifp = ifp->info;
send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
+ //ch->ifjoin_state transition to NOINFO
ifjoin_to_noinfo(ch);
/* from here ch may have been deleted */
@@ -790,6 +794,16 @@ void pim_ifchannel_join_add(struct interface *ifp,
pim_upstream_inherited_olist (ch->upstream);
pim_forward_start(ch);
}
+ /*
+ * If we are going to be a LHR, we need to note it
+ */
+ if (ch->upstream->parent &&
+ (ch->upstream->parent->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) &&
+ !(ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_LHR))
+ {
+ pim_upstream_ref (ch->upstream, PIM_UPSTREAM_FLAG_MASK_SRC_LHR);
+ pim_upstream_keep_alive_timer_start (ch->upstream, qpim_keep_alive_time);
+ }
break;
case PIM_IFJOIN_JOIN:
zassert(!ch->t_ifjoin_prune_pending_timer);
@@ -958,7 +972,7 @@ int
pim_ifchannel_local_membership_add(struct interface *ifp,
struct prefix_sg *sg)
{
- struct pim_ifchannel *ch;
+ struct pim_ifchannel *ch, *starch;
struct pim_interface *pim_ifp;
/* PIM enabled on interface? */
@@ -993,21 +1007,41 @@ pim_ifchannel_local_membership_add(struct interface *ifp,
struct pim_upstream *child;
struct listnode *up_node;
+ starch = ch;
+
for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
{
- if (PIM_DEBUG_EVENTS)
- zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
- __FILE__, __PRETTY_FUNCTION__,
- child->sg_str, ifp->name, up->sg_str);
+ if (PIM_DEBUG_EVENTS)
+ zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ child->sg_str, ifp->name, up->sg_str);
- if (pim_upstream_evaluate_join_desired_interface (child, ch))
- {
- pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
- pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
- }
+ ch = pim_ifchannel_find (ifp, &child->sg);
+ if (pim_upstream_evaluate_join_desired_interface (child, ch, starch))
+ {
+ pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
+ pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
+ }
}
- if (pimg->spt_switchover != PIM_SPT_INFINITY)
- pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+
+ if (pimg->spt.switchover == PIM_SPT_INFINITY)
+ {
+ if (pimg->spt.plist)
+ {
+ struct prefix_list *plist = prefix_list_lookup (AFI_IP, pimg->spt.plist);
+ struct prefix g;
+ g.family = AF_INET;
+ g.prefixlen = IPV4_MAX_PREFIXLEN;
+ g.u.prefix4 = up->sg.grp;
+
+ if (prefix_list_apply (plist, &g) == PREFIX_DENY)
+ {
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ }
+ }
+ }
+ else
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
}
return 1;
@@ -1016,7 +1050,7 @@ pim_ifchannel_local_membership_add(struct interface *ifp,
void pim_ifchannel_local_membership_del(struct interface *ifp,
struct prefix_sg *sg)
{
- struct pim_ifchannel *ch;
+ struct pim_ifchannel *starch, *ch, *orig;
struct pim_interface *pim_ifp;
/* PIM enabled on interface? */
@@ -1026,7 +1060,7 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return;
- ch = pim_ifchannel_find(ifp, sg);
+ orig = ch = pim_ifchannel_find(ifp, sg);
if (!ch)
return;
@@ -1036,9 +1070,11 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
{
struct pim_upstream *up = pim_upstream_find (sg);
struct pim_upstream *child;
- struct listnode *up_node;
+ struct listnode *up_node, *up_nnode;
- for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
+ starch = ch;
+
+ for (ALL_LIST_ELEMENTS (up->sources, up_node, up_nnode, child))
{
struct channel_oil *c_oil = child->channel_oil;
struct pim_ifchannel *chchannel = pim_ifchannel_find (ifp, &child->sg);
@@ -1049,7 +1085,8 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
__FILE__, __PRETTY_FUNCTION__,
up->sg_str, ifp->name, child->sg_str);
- if (c_oil && !pim_upstream_evaluate_join_desired_interface (child, ch))
+ ch = pim_ifchannel_find (ifp, &child->sg);
+ if (c_oil && !pim_upstream_evaluate_join_desired_interface (child, ch, starch))
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
/*
@@ -1059,9 +1096,11 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
*/
if (!chchannel && c_oil && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_STAR);
+
+ /* Child node removal/ref count-- will happen as part of parent' delete_no_info */
}
}
- delete_on_noinfo(ch);
+ delete_on_noinfo(orig);
}
void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch)
@@ -1223,20 +1262,55 @@ pim_ifchannel_scan_forward_start (struct interface *new_ifp)
* we get End of Message
*/
void
-pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom)
+pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom, uint8_t source_flags, uint8_t join)
{
struct pim_ifchannel *child;
struct listnode *ch_node;
if (PIM_DEBUG_PIM_TRACE)
- zlog_debug ("%s: %s %s eom: %d", __PRETTY_FUNCTION__,
+ zlog_debug ("%s: %s %s eom: %d join %u", __PRETTY_FUNCTION__,
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
- ch->sg_str, eom);
+ ch->sg_str, eom, join);
if (!ch->sources)
return;
for (ALL_LIST_ELEMENTS_RO (ch->sources, ch_node, child))
{
+ /* Only *,G Join received and no (SG-RPT) prune.
+ Scan all S,G associated to G and if any SG-RPT
+ remove the SG-RPT flag.
+ */
+ if (join && (source_flags & PIM_RPT_BIT_MASK) &&
+ (source_flags & PIM_WILDCARD_BIT_MASK))
+ {
+ if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
+ {
+ struct pim_upstream *up = child->upstream;
+
+ PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
+ if (up)
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: clearing SGRpt flag, add inherit oif to up %s ", __PRETTY_FUNCTION__, up->sg_str);
+ pim_channel_add_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR);
+ }
+ }
+ }
+ /* Received SG-RPT Prune delete oif from S,G */
+ else if (join == 0 && (source_flags & PIM_RPT_BIT_MASK) &&
+ !(source_flags & PIM_WILDCARD_BIT_MASK))
+ {
+ struct pim_upstream *up = child->upstream;
+
+ PIM_IF_FLAG_SET_S_G_RPT(child->flags);
+ if (up)
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("%s: del inherit oif from up %s", __PRETTY_FUNCTION__, up->sg_str);
+ pim_channel_del_oif (up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_STAR);
+ }
+ }
+
if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
continue;