mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-16 08:32:45 +00:00
pimd: pim upstream child list
Add the ability to keep the list of S,G's associated with a *,G. Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
2a333e0f22
commit
03417ccd6d
@ -807,26 +807,23 @@ void pim_ifchannel_local_membership_add(struct interface *ifp,
|
|||||||
struct pim_upstream *child;
|
struct pim_upstream *child;
|
||||||
struct listnode *up_node;
|
struct listnode *up_node;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, up_node, child))
|
for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
|
||||||
{
|
{
|
||||||
if (child->parent == up)
|
if (PIM_DEBUG_EVENTS)
|
||||||
{
|
{
|
||||||
if (PIM_DEBUG_EVENTS)
|
char buff[100];
|
||||||
{
|
|
||||||
char buff[100];
|
|
||||||
|
|
||||||
strcpy (buff, pim_str_sg_dump (&up->sg));
|
strcpy (buff, pim_str_sg_dump (&child->sg));
|
||||||
zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
|
zlog_debug("%s %s: IGMP (S,G)=%s(%s) from %s",
|
||||||
__FILE__, __PRETTY_FUNCTION__,
|
__FILE__, __PRETTY_FUNCTION__,
|
||||||
buff, ifp->name, pim_str_sg_dump (sg));
|
buff, ifp->name, pim_str_sg_dump (sg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pim_upstream_evaluate_join_desired (child))
|
if (pim_upstream_evaluate_join_desired (child))
|
||||||
{
|
{
|
||||||
pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
||||||
pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
|
pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -856,34 +853,31 @@ void pim_ifchannel_local_membership_del(struct interface *ifp,
|
|||||||
struct pim_upstream *child;
|
struct pim_upstream *child;
|
||||||
struct listnode *up_node;
|
struct listnode *up_node;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, up_node, child))
|
for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
|
||||||
{
|
{
|
||||||
if (child->parent == up)
|
struct channel_oil *c_oil = child->channel_oil;
|
||||||
{
|
struct pim_ifchannel *chchannel = pim_ifchannel_find (ifp, &child->sg);
|
||||||
struct channel_oil *c_oil = child->channel_oil;
|
struct pim_interface *pim_ifp = ifp->info;
|
||||||
struct pim_ifchannel *chchannel = pim_ifchannel_find (ifp, &child->sg);
|
|
||||||
struct pim_interface *pim_ifp = ifp->info;
|
|
||||||
|
|
||||||
if (PIM_DEBUG_EVENTS)
|
if (PIM_DEBUG_EVENTS)
|
||||||
{
|
{
|
||||||
char buff[100];
|
char buff[100];
|
||||||
strcpy (buff, pim_str_sg_dump (&up->sg));
|
strcpy (buff, pim_str_sg_dump (&child->sg));
|
||||||
zlog_debug("%s %s: Prune(S,G)=%s(%s) from %s",
|
zlog_debug("%s %s: Prune(S,G)=%s(%s) from %s",
|
||||||
__FILE__, __PRETTY_FUNCTION__,
|
__FILE__, __PRETTY_FUNCTION__,
|
||||||
buff, ifp->name, pim_str_sg_dump (&child->sg));
|
buff, ifp->name, pim_str_sg_dump (&child->sg));
|
||||||
}
|
|
||||||
|
|
||||||
if (!pim_upstream_evaluate_join_desired (child))
|
|
||||||
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the S,G has no if channel and the c_oil still
|
|
||||||
* has output here then the *,G was supplying the implied
|
|
||||||
* if channel. So remove it.
|
|
||||||
*/
|
|
||||||
if (!chchannel && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
|
|
||||||
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pim_upstream_evaluate_join_desired (child))
|
||||||
|
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the S,G has no if channel and the c_oil still
|
||||||
|
* has output here then the *,G was supplying the implied
|
||||||
|
* if channel. So remove it.
|
||||||
|
*/
|
||||||
|
if (!chchannel && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
|
||||||
|
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete_on_noinfo(ch);
|
delete_on_noinfo(ch);
|
||||||
|
@ -117,24 +117,21 @@ static void recv_join(struct interface *ifp,
|
|||||||
if (!up)
|
if (!up)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, up_node, child))
|
for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
|
||||||
{
|
{
|
||||||
if (child->parent == up)
|
char buff[100];
|
||||||
{
|
|
||||||
char buff[100];
|
|
||||||
|
|
||||||
strcpy (buff, pim_str_sg_dump (&up->sg));
|
strcpy (buff, pim_str_sg_dump (&child->sg));
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
if (PIM_DEBUG_PIM_TRACE)
|
||||||
zlog_debug("%s %s: Join(S,G)=%s from %s",
|
zlog_debug("%s %s: Join(S,G)=%s from %s",
|
||||||
__FILE__, __PRETTY_FUNCTION__,
|
__FILE__, __PRETTY_FUNCTION__,
|
||||||
buff, pim_str_sg_dump (&sg));
|
buff, pim_str_sg_dump (&sg));
|
||||||
|
|
||||||
if (pim_upstream_evaluate_join_desired (child))
|
if (pim_upstream_evaluate_join_desired (child))
|
||||||
{
|
{
|
||||||
pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
pim_channel_add_oif (child->channel_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
||||||
pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
|
pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,36 +191,33 @@ static void recv_prune(struct interface *ifp,
|
|||||||
if (!up)
|
if (!up)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, up_node, child))
|
for (ALL_LIST_ELEMENTS_RO (up->sources, up_node, child))
|
||||||
{
|
{
|
||||||
if (child->parent == up)
|
struct channel_oil *c_oil = child->channel_oil;
|
||||||
{
|
struct pim_ifchannel *ch = pim_ifchannel_find (ifp, &child->sg);
|
||||||
struct channel_oil *c_oil = child->channel_oil;
|
struct pim_interface *pim_ifp = ifp->info;
|
||||||
struct pim_ifchannel *ch = pim_ifchannel_find (ifp, &child->sg);
|
|
||||||
struct pim_interface *pim_ifp = ifp->info;
|
|
||||||
|
|
||||||
if (PIM_DEBUG_PIM_TRACE)
|
if (PIM_DEBUG_PIM_TRACE)
|
||||||
{
|
{
|
||||||
char buff[100];
|
char buff[100];
|
||||||
strcpy (buff, pim_str_sg_dump (&up->sg));
|
strcpy (buff, pim_str_sg_dump (&child->sg));
|
||||||
zlog_debug("%s %s: Prune(S,G)=%s from %s",
|
zlog_debug("%s %s: Prune(S,G)=%s from %s",
|
||||||
__FILE__, __PRETTY_FUNCTION__,
|
__FILE__, __PRETTY_FUNCTION__,
|
||||||
buff, pim_str_sg_dump (&child->sg));
|
buff, pim_str_sg_dump (&sg));
|
||||||
}
|
|
||||||
if (!c_oil)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!pim_upstream_evaluate_join_desired (child))
|
|
||||||
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the S,G has no if channel and the c_oil still
|
|
||||||
* has output here then the *,G was supplying the implied
|
|
||||||
* if channel. So remove it.
|
|
||||||
*/
|
|
||||||
if (!ch && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
|
|
||||||
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
|
||||||
}
|
}
|
||||||
|
if (!c_oil)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!pim_upstream_evaluate_join_desired (child))
|
||||||
|
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the S,G has no if channel and the c_oil still
|
||||||
|
* has output here then the *,G was supplying the implied
|
||||||
|
* if channel. So remove it.
|
||||||
|
*/
|
||||||
|
if (!ch && c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index])
|
||||||
|
pim_channel_del_oif (c_oil, ifp, PIM_OIF_FLAG_PROTO_PIM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,23 +65,16 @@ static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up)
|
|||||||
static void
|
static void
|
||||||
pim_upstream_remove_children (struct pim_upstream *up)
|
pim_upstream_remove_children (struct pim_upstream *up)
|
||||||
{
|
{
|
||||||
struct listnode *ch_node;
|
|
||||||
struct pim_upstream *child;
|
struct pim_upstream *child;
|
||||||
|
|
||||||
// Basic sanity, (*,*) not currently supported
|
if (!up->sources)
|
||||||
if ((up->sg.src.s_addr == INADDR_ANY) &&
|
|
||||||
(up->sg.grp.s_addr == INADDR_ANY))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Basic sanity (S,G) have no children
|
while (!list_isempty (up->sources))
|
||||||
if ((up->sg.src.s_addr != INADDR_ANY) &&
|
|
||||||
(up->sg.grp.s_addr != INADDR_ANY))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, ch_node, child))
|
|
||||||
{
|
{
|
||||||
if (child->parent == up)
|
child = listnode_head (up->sources);
|
||||||
child->parent = NULL;
|
child->parent = NULL;
|
||||||
|
listnode_delete (up->sources, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +102,10 @@ pim_upstream_find_new_children (struct pim_upstream *up)
|
|||||||
if ((up->sg.grp.s_addr != INADDR_ANY) &&
|
if ((up->sg.grp.s_addr != INADDR_ANY) &&
|
||||||
(child->sg.grp.s_addr == up->sg.grp.s_addr) &&
|
(child->sg.grp.s_addr == up->sg.grp.s_addr) &&
|
||||||
(child != up))
|
(child != up))
|
||||||
child->parent = up;
|
{
|
||||||
|
child->parent = up;
|
||||||
|
listnode_add_sort (up->sources, child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,28 +115,25 @@ pim_upstream_find_new_children (struct pim_upstream *up)
|
|||||||
* If we have a (*,G), find the (*,*)
|
* If we have a (*,G), find the (*,*)
|
||||||
*/
|
*/
|
||||||
static struct pim_upstream *
|
static struct pim_upstream *
|
||||||
pim_upstream_find_parent (struct prefix_sg *sg)
|
pim_upstream_find_parent (struct pim_upstream *child)
|
||||||
{
|
{
|
||||||
struct prefix_sg any = *sg;
|
struct prefix_sg any = child->sg;
|
||||||
|
struct pim_upstream *up = NULL;
|
||||||
// (*,*) || (S,*)
|
|
||||||
if (((sg->src.s_addr == INADDR_ANY) &&
|
|
||||||
(sg->grp.s_addr == INADDR_ANY)) ||
|
|
||||||
((sg->src.s_addr != INADDR_ANY) &&
|
|
||||||
(sg->grp.s_addr == INADDR_ANY)))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// (S,G)
|
// (S,G)
|
||||||
if ((sg->src.s_addr != INADDR_ANY) &&
|
if ((child->sg.src.s_addr != INADDR_ANY) &&
|
||||||
(sg->grp.s_addr != INADDR_ANY))
|
(child->sg.grp.s_addr != INADDR_ANY))
|
||||||
{
|
{
|
||||||
any.src.s_addr = INADDR_ANY;
|
any.src.s_addr = INADDR_ANY;
|
||||||
return pim_upstream_find (&any);
|
up = pim_upstream_find (&any);
|
||||||
|
|
||||||
|
if (up)
|
||||||
|
listnode_add (up->sources, child);
|
||||||
|
|
||||||
|
return up;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (*,G)
|
return NULL;
|
||||||
any.grp.s_addr = INADDR_ANY;
|
|
||||||
return pim_upstream_find (&any);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pim_upstream_free(struct pim_upstream *up)
|
void pim_upstream_free(struct pim_upstream *up)
|
||||||
@ -181,11 +174,20 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
|
|||||||
pim_mroute_del (up->channel_oil);
|
pim_mroute_del (up->channel_oil);
|
||||||
upstream_channel_oil_detach(up);
|
upstream_channel_oil_detach(up);
|
||||||
|
|
||||||
|
if (up->sources)
|
||||||
|
list_delete (up->sources);
|
||||||
|
up->sources = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
notice that listnode_delete() can't be moved
|
notice that listnode_delete() can't be moved
|
||||||
into pim_upstream_free() because the later is
|
into pim_upstream_free() because the later is
|
||||||
called by list_delete_all_node()
|
called by list_delete_all_node()
|
||||||
*/
|
*/
|
||||||
|
if (up->parent)
|
||||||
|
{
|
||||||
|
listnode_delete (up->parent->sources, up);
|
||||||
|
up->parent = NULL;
|
||||||
|
}
|
||||||
listnode_delete (pim_upstream_list, up);
|
listnode_delete (pim_upstream_list, up);
|
||||||
hash_release (pim_upstream_hash, up);
|
hash_release (pim_upstream_hash, up);
|
||||||
|
|
||||||
@ -488,6 +490,27 @@ pim_upstream_switch(struct pim_upstream *up,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pim_upstream_compare (void *arg1, void *arg2)
|
||||||
|
{
|
||||||
|
const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
|
||||||
|
const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
|
||||||
|
|
||||||
|
if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
|
static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
|
||||||
struct interface *incoming,
|
struct interface *incoming,
|
||||||
int flags)
|
int flags)
|
||||||
@ -509,11 +532,20 @@ static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
|
|||||||
if (PIM_DEBUG_PIM_TRACE)
|
if (PIM_DEBUG_PIM_TRACE)
|
||||||
zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
|
zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
|
hash_release (pim_upstream_hash, up);
|
||||||
XFREE (MTYPE_PIM_UPSTREAM, up);
|
XFREE (MTYPE_PIM_UPSTREAM, up);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
up->parent = pim_upstream_find_parent (sg);
|
up->parent = pim_upstream_find_parent (up);
|
||||||
|
if (up->sg.src.s_addr == INADDR_ANY)
|
||||||
|
{
|
||||||
|
up->sources = list_new ();
|
||||||
|
up->sources->cmp = pim_upstream_compare;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
up->sources = NULL;
|
||||||
|
|
||||||
pim_upstream_find_new_children (up);
|
pim_upstream_find_new_children (up);
|
||||||
up->flags = flags;
|
up->flags = flags;
|
||||||
up->ref_count = 1;
|
up->ref_count = 1;
|
||||||
@ -538,12 +570,26 @@ static struct pim_upstream *pim_upstream_new(struct prefix_sg *sg,
|
|||||||
if (PIM_DEBUG_PIM_TRACE)
|
if (PIM_DEBUG_PIM_TRACE)
|
||||||
zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
|
zlog_debug ("%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__,
|
||||||
pim_str_sg_dump (&up->sg));
|
pim_str_sg_dump (&up->sg));
|
||||||
|
|
||||||
|
if (up->parent)
|
||||||
|
{
|
||||||
|
listnode_delete (up->parent->sources, up);
|
||||||
|
up->parent = NULL;
|
||||||
|
}
|
||||||
|
pim_upstream_remove_children (up);
|
||||||
|
if (up->sources)
|
||||||
|
list_delete (up->sources);
|
||||||
|
|
||||||
|
hash_release (pim_upstream_hash, up);
|
||||||
XFREE(MTYPE_PIM_UPSTREAM, up);
|
XFREE(MTYPE_PIM_UPSTREAM, up);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
listnode_add_sort(pim_upstream_list, up);
|
listnode_add_sort(pim_upstream_list, up);
|
||||||
|
|
||||||
|
if (PIM_DEBUG_PIM_TRACE)
|
||||||
|
zlog_debug ("%s: Created Upstream %s", __PRETTY_FUNCTION__, pim_str_sg_dump (&up->sg));
|
||||||
|
|
||||||
return up;
|
return up;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1162,27 +1208,6 @@ pim_upstream_find_new_rpf (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
pim_upstream_compare (const void *arg1, const void *arg2)
|
|
||||||
{
|
|
||||||
const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
|
|
||||||
const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
|
|
||||||
|
|
||||||
if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (ntohl(up1->sg.grp.s_addr) > ntohl(up2->sg.grp.s_addr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (ntohl(up1->sg.src.s_addr) < ntohl(up2->sg.src.s_addr))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (ntohl(up1->sg.src.s_addr) > ntohl(up2->sg.src.s_addr))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
pim_upstream_hash_key (void *arg)
|
pim_upstream_hash_key (void *arg)
|
||||||
{
|
{
|
||||||
@ -1222,6 +1247,6 @@ pim_upstream_init (void)
|
|||||||
|
|
||||||
pim_upstream_list = list_new ();
|
pim_upstream_list = list_new ();
|
||||||
pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
|
pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
|
||||||
pim_upstream_list->cmp = (int (*)(void *, void *)) pim_upstream_compare;
|
pim_upstream_list->cmp = pim_upstream_compare;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,7 @@ struct pim_upstream {
|
|||||||
struct prefix_sg sg; /* (S,G) group key */
|
struct prefix_sg sg; /* (S,G) group key */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
struct channel_oil *channel_oil;
|
struct channel_oil *channel_oil;
|
||||||
|
struct list *sources;
|
||||||
|
|
||||||
enum pim_upstream_state join_state;
|
enum pim_upstream_state join_state;
|
||||||
enum pim_upstream_sptbit sptbit;
|
enum pim_upstream_sptbit sptbit;
|
||||||
|
Loading…
Reference in New Issue
Block a user