#include "pim_oil.h"
#include "pim_upstream.h"
#include "pim_ssm.h"
+#include "pim_rp.h"
-int pim_ifchannel_compare(struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
+RB_GENERATE(pim_ifchannel_rb, pim_ifchannel,
+ pim_ifp_rb, pim_ifchannel_compare);
+
+int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
+ const struct pim_ifchannel *ch2)
{
struct pim_interface *pim_ifp1;
struct pim_interface *pim_ifp2;
{
struct pim_interface *pim_ifp = ch->interface->info;
struct pim_ifchannel *child;
- struct listnode *ch_node;
// Basic Sanity that we are not being silly
if ((ch->sg.src.s_addr != INADDR_ANY)
&& (ch->sg.grp.s_addr == INADDR_ANY))
return;
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node,
- child)) {
+ RB_FOREACH (child, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
if ((ch->sg.grp.s_addr != INADDR_ANY)
&& (child->sg.grp.s_addr == ch->sg.grp.s_addr)
&& (child != ch)) {
pim_ifchannel_remove_children(ch);
if (ch->sources)
- list_delete(ch->sources);
+ list_delete_and_null(&ch->sources);
listnode_delete(ch->upstream->ifchannels, ch);
if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) {
- pim_upstream_update_join_desired(ch->upstream);
+ pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
}
/* upstream is common across ifchannels, check if upstream's
ifchannel list is empty before deleting upstream_del
ref count will take care of it.
*/
- pim_upstream_del(ch->upstream, __PRETTY_FUNCTION__);
+ pim_upstream_del(pim_ifp->pim, ch->upstream, __PRETTY_FUNCTION__);
ch->upstream = NULL;
THREAD_OFF(ch->t_ifjoin_expiry_timer);
listnode_delete(ch->parent->sources, ch);
ch->parent = NULL;
}
- /*
- notice that listnode_delete() can't be moved
- into pim_ifchannel_free() because the later is
- called by list_delete_all_node()
- */
- listnode_delete(pim_ifp->pim_ifchannel_list, ch);
- hash_release(pim_ifp->pim_ifchannel_hash, ch);
- listnode_delete(pim_ifchannel_list, ch);
+
+ RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: ifchannel entry %s is deleted ",
void pim_ifchannel_delete_all(struct interface *ifp)
{
struct pim_interface *pim_ifp;
- struct listnode *ifchannel_node;
- struct listnode *ifchannel_nextnode;
- struct pim_ifchannel *ifchannel;
+ struct pim_ifchannel *ch;
pim_ifp = ifp->info;
if (!pim_ifp)
return;
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, ifchannel_node,
- ifchannel_nextnode, ifchannel)) {
- pim_ifchannel_delete(ifchannel);
+ while ((ch = RB_ROOT(pim_ifchannel_rb,
+ &pim_ifp->ifchannel_rb)) != NULL) {
+ pim_ifchannel_delete(ch);
}
}
enum pim_ifjoin_state new_state)
{
enum pim_ifjoin_state old_state = ch->ifjoin_state;
+ struct pim_interface *pim_ifp = ch->interface->info;
if (PIM_DEBUG_PIM_EVENTS)
zlog_debug(
child)) {
struct channel_oil *c_oil =
child->channel_oil;
- struct pim_interface *pim_ifp =
- ch->interface->info;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
continue;
if (!pim_upstream_evaluate_join_desired(
- child)) {
+ pim_ifp->pim, child)) {
pim_channel_del_oif(
c_oil, ch->interface,
PIM_OIF_FLAG_PROTO_STAR);
pim_upstream_update_join_desired(
- child);
+ pim_ifp->pim, child);
}
/*
* if channel. So remove it.
* I think this is dead code now. is it?
*/
- if (!ch
- && c_oil->oil.mfcc_ttls
- [pim_ifp->mroute_vif_index])
+ if (c_oil->oil.mfcc_ttls
+ [pim_ifp->mroute_vif_index])
pim_channel_del_oif(
c_oil, ch->interface,
PIM_OIF_FLAG_PROTO_STAR);
up->sg_str);
if (pim_upstream_evaluate_join_desired(
- child)) {
+ pim_ifp->pim, child)) {
pim_channel_add_oif(
child->channel_oil,
ch->interface,
PIM_OIF_FLAG_PROTO_STAR);
pim_upstream_update_join_desired(
- child);
+ pim_ifp->pim, child);
}
}
}
*/
ch->ifjoin_creation = pim_time_monotonic_sec();
- pim_upstream_update_join_desired(ch->upstream);
+ pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
pim_ifchannel_update_could_assert(ch);
pim_ifchannel_update_assert_tracking_desired(ch);
}
switch (ifjoin_state) {
case PIM_IFJOIN_NOINFO:
if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
- return "SGRpt";
+ return "SGRpt(NI)";
else
return "NOINFO";
break;
return "JOIN";
break;
case PIM_IFJOIN_PRUNE:
- return "PRUNE";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(P)";
+ else
+ return "PRUNE";
break;
case PIM_IFJOIN_PRUNE_PENDING:
- return "PRUNEP";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(PP)";
+ else
+ return "PRUNEP";
break;
case PIM_IFJOIN_PRUNE_TMP:
- return "PRUNET";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(P')";
+ else
+ return "PRUNET";
break;
case PIM_IFJOIN_PRUNE_PENDING_TMP:
- return "PRUNEPT";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(PP')";
+ else
+ return "PRUNEPT";
break;
}
}
lookup.sg = *sg;
- ch = hash_lookup(pim_ifp->pim_ifchannel_hash, &lookup);
+ lookup.interface = ifp;
+ ch = RB_FIND(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, &lookup);
return ch;
}
static void ifmembership_set(struct pim_ifchannel *ch,
enum pim_ifmembership membership)
{
+ struct pim_interface *pim_ifp = ch->interface->info;
+
if (ch->local_ifmembership == membership)
return;
ch->local_ifmembership = membership;
- pim_upstream_update_join_desired(ch->upstream);
+ pim_upstream_update_join_desired(pim_ifp->pim, ch->upstream);
pim_ifchannel_update_could_assert(ch);
pim_ifchannel_update_assert_tracking_desired(ch);
}
void pim_ifchannel_membership_clear(struct interface *ifp)
{
struct pim_interface *pim_ifp;
- struct listnode *ch_node;
struct pim_ifchannel *ch;
pim_ifp = ifp->info;
zassert(pim_ifp);
- for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
+ RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb)
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
- }
}
void pim_ifchannel_delete_on_noinfo(struct interface *ifp)
{
struct pim_interface *pim_ifp;
- struct listnode *node;
- struct listnode *next_node;
- struct pim_ifchannel *ch;
+ struct pim_ifchannel *ch, *ch_tmp;
pim_ifp = ifp->info;
zassert(pim_ifp);
- for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node,
- ch)) {
+ RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch_tmp)
delete_on_noinfo(ch);
- }
}
/*
}
struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
- struct prefix_sg *sg, int flags)
+ struct prefix_sg *sg,
+ uint8_t source_flags, int up_flags)
{
struct pim_interface *pim_ifp;
struct pim_ifchannel *ch;
pim_ifp = ifp->info;
- up = pim_upstream_add(sg, NULL, flags, __PRETTY_FUNCTION__);
- if (!up) {
- zlog_err(
- "%s: could not attach upstream (S,G)=%s on interface %s",
- __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name);
- return NULL;
- }
-
ch = XCALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch));
if (!ch) {
zlog_warn(
"%s: pim_ifchannel_new() failure for (S,G)=%s on interface %s",
- __PRETTY_FUNCTION__, up->sg_str, ifp->name);
-
- pim_upstream_del(up, __PRETTY_FUNCTION__);
+ __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name);
return NULL;
}
ch->flags = 0;
- ch->upstream = up;
+ if ((source_flags & PIM_ENCODE_RPT_BIT)
+ && !(source_flags & PIM_ENCODE_WC_BIT))
+ PIM_IF_FLAG_SET_S_G_RPT(ch->flags);
+
ch->interface = ifp;
ch->sg = *sg;
pim_str_sg_set(sg, ch->sg_str);
ch->t_ifjoin_prune_pending_timer = NULL;
ch->ifjoin_creation = 0;
+ RB_INSERT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
+
+ up = pim_upstream_add(pim_ifp->pim, sg, NULL, up_flags,
+ __PRETTY_FUNCTION__, ch);
+
+ if (!up) {
+ zlog_err(
+ "%s: could not attach upstream (S,G)=%s on interface %s",
+ __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name);
+
+ if (ch->parent)
+ listnode_delete(ch->parent->sources, ch);
+
+ pim_ifchannel_remove_children(ch);
+ if (ch->sources)
+ list_delete_and_null(&ch->sources);
+
+ THREAD_OFF(ch->t_ifjoin_expiry_timer);
+ THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
+ THREAD_OFF(ch->t_ifassert_timer);
+
+ RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
+ XFREE(MTYPE_PIM_IFCHANNEL, ch);
+ return NULL;
+ }
+ ch->upstream = up;
+
+ listnode_add_sort(up->ifchannels, ch);
+
ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch);
ch->ifassert_winner_metric = pim_macro_ch_my_assert_metric_eval(ch);
else
PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
- /* Attach to list */
- listnode_add_sort(pim_ifp->pim_ifchannel_list, ch);
- 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);
-
if (PIM_DEBUG_PIM_TRACE)
zlog_debug("%s: ifchannel %s is created ", __PRETTY_FUNCTION__,
ch->sg_str);
static void ifjoin_to_noinfo(struct pim_ifchannel *ch, bool ch_del)
{
- pim_forward_stop(ch);
+ pim_forward_stop(ch, !ch_del);
pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO);
if (ch_del)
delete_on_noinfo(ch);
ch = THREAD_ARG(t);
if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING) {
- /* Send PruneEcho(S,G) ? */
ifp = ch->interface;
pim_ifp = ifp->info;
- send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
-
- if (send_prune_echo) {
- struct pim_rpf rpf;
+ if (!PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
+ /* Send PruneEcho(S,G) ? */
+ send_prune_echo =
+ (listcount(pim_ifp->pim_neighbor_list) > 1);
+
+ if (send_prune_echo) {
+ struct pim_rpf rpf;
+
+ rpf.source_nexthop.interface = ifp;
+ rpf.rpf_addr.u.prefix4 =
+ pim_ifp->primary_address;
+ pim_jp_agg_single_upstream_send(&rpf,
+ ch->upstream,
+ 0);
+ }
- rpf.source_nexthop.interface = ifp;
- rpf.rpf_addr.u.prefix4 = pim_ifp->primary_address;
- pim_jp_agg_single_upstream_send(&rpf, ch->upstream, 0);
- }
- /* If SGRpt flag is set on ifchannel, Trigger SGRpt
- message on RP path upon prune timer expiry.
- */
- if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
- if (ch->upstream)
- pim_upstream_update_join_desired(ch->upstream);
- /*
- ch->ifjoin_state transition to NOINFO state
- ch_del is set to 0 for not deleteing from here.
- Holdtime expiry (ch_del set to 1) delete the entry.
- */
- ifjoin_to_noinfo(ch, false);
- } else
ifjoin_to_noinfo(ch, true);
+ } else {
+ /* If SGRpt flag is set on ifchannel, Trigger SGRpt
+ * message on RP path upon prune timer expiry.
+ */
+ ch->ifjoin_state = PIM_IFJOIN_PRUNE;
+ if (ch->upstream)
+ pim_upstream_update_join_desired(pim_ifp->pim,
+ ch->upstream);
+ }
/* from here ch may have been deleted */
} else {
zlog_warn(
uint8_t source_flags, int holdtime)
{
struct pim_upstream *up;
+ struct pim_interface *pim_ifp = recv_ifp->info;
/* Upstream (S,G) in Joined state ? */
- up = pim_upstream_find(sg);
+ up = pim_upstream_find(pim_ifp->pim, sg);
if (!up)
return;
if (up->join_state != PIM_UPSTREAM_JOINED)
return;
}
- ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
+ ch = pim_ifchannel_add(ifp, sg, source_flags,
+ PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
if (!ch)
return;
pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch,
PIM_IFJOIN_JOIN);
if (pim_macro_chisin_oiflist(ch)) {
- pim_upstream_inherited_olist(ch->upstream);
+ pim_upstream_inherited_olist(pim_ifp->pim,
+ 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)
+ 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,
__PRETTY_FUNCTION__);
pim_upstream_keep_alive_timer_start(
- ch->upstream, qpim_keep_alive_time);
+ ch->upstream, pim_ifp->pim->keep_alive_time);
}
break;
case PIM_IFJOIN_JOIN:
return;
}
- ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
+ ch = pim_ifchannel_add(ifp, sg, source_flags,
+ PIM_UPSTREAM_FLAG_MASK_SRC_PIM);
if (!ch)
return;
&ch->t_ifjoin_prune_pending_timer);
thread_add_timer(master, on_ifjoin_expiry_timer, ch,
holdtime, &ch->t_ifjoin_expiry_timer);
- pim_upstream_update_join_desired(ch->upstream);
+ pim_upstream_update_join_desired(pim_ifp->pim,
+ ch->upstream);
}
break;
case PIM_IFJOIN_PRUNE_PENDING:
{
struct pim_ifchannel *ch, *starch;
struct pim_interface *pim_ifp;
+ struct pim_instance *pim;
/* PIM enabled on interface? */
pim_ifp = ifp->info;
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return 0;
+ pim = pim_ifp->pim;
+
/* skip (*,G) ch creation if G is of type SSM */
if (sg->src.s_addr == INADDR_ANY) {
- if (pim_is_grp_ssm(sg->grp)) {
+ if (pim_is_grp_ssm(pim, sg->grp)) {
if (PIM_DEBUG_PIM_EVENTS)
zlog_debug(
"%s: local membership (S,G)=%s ignored as group is SSM",
}
}
- ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
+ ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
if (!ch) {
return 0;
}
ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE);
if (sg->src.s_addr == INADDR_ANY) {
- struct pim_upstream *up = pim_upstream_find(sg);
+ struct pim_upstream *up = pim_upstream_find(pim, sg);
struct pim_upstream *child;
struct listnode *up_node;
child, ch, starch)) {
pim_channel_add_oif(child->channel_oil, ifp,
PIM_OIF_FLAG_PROTO_STAR);
- pim_upstream_switch(child, PIM_UPSTREAM_JOINED);
+ pim_upstream_switch(pim, child,
+ PIM_UPSTREAM_JOINED);
}
}
- if (pimg->spt.switchover == PIM_SPT_INFINITY) {
- if (pimg->spt.plist) {
+ if (pim->spt.switchover == PIM_SPT_INFINITY) {
+ if (pim->spt.plist) {
struct prefix_list *plist = prefix_list_lookup(
- AFI_IP, pimg->spt.plist);
+ AFI_IP, pim->spt.plist);
struct prefix g;
g.family = AF_INET;
g.prefixlen = IPV4_MAX_PREFIXLEN;
if (prefix_list_apply(plist, &g)
== PREFIX_DENY) {
pim_channel_add_oif(
- up->channel_oil, pim_regiface,
+ up->channel_oil, pim->regiface,
PIM_OIF_FLAG_PROTO_IGMP);
}
}
} else
- pim_channel_add_oif(up->channel_oil, pim_regiface,
+ pim_channel_add_oif(up->channel_oil, pim->regiface,
PIM_OIF_FLAG_PROTO_IGMP);
}
orig = ch = pim_ifchannel_find(ifp, sg);
if (!ch)
return;
-
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
if (sg->src.s_addr == INADDR_ANY) {
- struct pim_upstream *up = pim_upstream_find(sg);
+ struct pim_upstream *up = pim_upstream_find(pim_ifp->pim, sg);
struct pim_upstream *child;
struct listnode *up_node, *up_nnode;
*/
void pim_ifchannel_scan_forward_start(struct interface *new_ifp)
{
- struct listnode *ifnode;
- struct interface *ifp;
struct pim_interface *new_pim_ifp = new_ifp->info;
+ struct pim_instance *pim = new_pim_ifp->pim;
+ struct interface *ifp;
- for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), ifnode, ifp)) {
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *loop_pim_ifp = ifp->info;
- struct listnode *ch_node;
struct pim_ifchannel *ch;
if (!loop_pim_ifp)
if (new_pim_ifp == loop_pim_ifp)
continue;
- for (ALL_LIST_ELEMENTS_RO(loop_pim_ifp->pim_ifchannel_list,
- ch_node, ch)) {
+ RB_FOREACH (ch, pim_ifchannel_rb, &loop_pim_ifp->ifchannel_rb) {
if (ch->ifjoin_state == PIM_IFJOIN_JOIN) {
struct pim_upstream *up = ch->upstream;
if ((!up->channel_oil)
* we get End of Message
*/
void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
- uint8_t source_flags, uint8_t join,
- uint8_t starg_alone)
+ uint8_t join)
{
struct pim_ifchannel *child;
- struct listnode *ch_node;
+ struct listnode *ch_node, *nch_node;
+ struct pim_instance *pim =
+ ((struct pim_interface *)ch->interface->info)->pim;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
if (!ch->sources)
return;
- for (ALL_LIST_ELEMENTS_RO(ch->sources, ch_node, child)) {
- /* Only *,G Join received and no (SG-RPT) prune.
- eom = 1, only (W,G) join_alone is true, WC and RPT are set.
- Scan all S,G associated to G and if any SG-RPT
- remove the SG-RPT flag.
- */
- if (eom && starg_alone && (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: SGRpt flag is cleared, 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);
- pim_ifchannel_ifjoin_switch(
- __PRETTY_FUNCTION__, child,
- PIM_IFJOIN_JOIN);
- }
- }
- }
-
+ for (ALL_LIST_ELEMENTS(ch->sources, ch_node, nch_node, child)) {
if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
continue;
break;
case PIM_IFJOIN_PRUNE_TMP:
case PIM_IFJOIN_PRUNE_PENDING_TMP:
- if (eom)
- child->ifjoin_state = PIM_IFJOIN_NOINFO;
+ if (!eom)
+ break;
+
+ if (child->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING_TMP)
+ THREAD_OFF(child->t_ifjoin_prune_pending_timer);
+ THREAD_OFF(child->t_ifjoin_expiry_timer);
+ struct pim_upstream *parent =
+ child->upstream->parent;
+
+ PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
+ child->ifjoin_state = PIM_IFJOIN_NOINFO;
+
+ if (I_am_RP(pim, child->sg.grp)) {
+ pim_channel_add_oif(
+ child->upstream->channel_oil,
+ ch->interface,
+ PIM_OIF_FLAG_PROTO_STAR);
+ pim_upstream_switch(
+ pim, child->upstream,
+ PIM_UPSTREAM_JOINED);
+ pim_jp_agg_single_upstream_send(
+ &child->upstream->rpf,
+ child->upstream, true);
+ }
+ if (parent)
+ pim_jp_agg_single_upstream_send(
+ &parent->rpf,
+ parent, true);
+
+ delete_on_noinfo(child);
break;
}
}
return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0);
}
-
-int pim_ifchannel_equal(const void *arg1, const void *arg2)
-{
- const struct pim_ifchannel *ch1 = (const struct pim_ifchannel *)arg1;
- const struct pim_ifchannel *ch2 = (const struct pim_ifchannel *)arg2;
-
- if ((ch1->sg.grp.s_addr == ch2->sg.grp.s_addr)
- && (ch1->sg.src.s_addr == ch2->sg.src.s_addr))
- return 1;
-
- return 0;
-}