From: Donald Sharp Date: Thu, 28 Jul 2016 16:21:31 +0000 (-0400) Subject: pimd: Allow ifchannel S,G's to know their *,G parent X-Git-Tag: frr-3.0-branchpoint~64^2~10^2~334 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=1a10fc742fcdb05024be3721b7641e19107edad7;p=mirror%2Ffrr.git pimd: Allow ifchannel S,G's to know their *,G parent Given a S,G ifchannel, create a parent pointer for any *,G state for that interface. When removing a *,G remove S,G pointers. We need to think about the case where their is a *,G but no S,G for a interface when we are determing. Signed-off-by: Donald Sharp --- diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index f940c4d4ef..bbab8197dd 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -38,6 +38,65 @@ #include "pim_rpf.h" #include "pim_macro.h" +/* + * A (*,G) or a (*,*) is going away + * remove the parent pointer from + * those pointing at us + */ +static void +pim_ifchannel_remove_children (struct pim_ifchannel *ch) +{ + struct pim_interface *pim_ifp = ch->interface->info; + struct listnode *ch_node; + struct pim_ifchannel *child; + + // Basic sanity, (*,*) not currently supported + if ((ch->sg.u.sg.src.s_addr == INADDR_ANY) && + (ch->sg.u.sg.grp.s_addr == INADDR_ANY)) + return; + + // Basic sanity (S,G) have no children + if ((ch->sg.u.sg.src.s_addr != INADDR_ANY) && + (ch->sg.u.sg.grp.s_addr != INADDR_ANY)) + return; + + for (ALL_LIST_ELEMENTS_RO (pim_ifp->pim_ifchannel_list, ch_node, child)) + { + if (child->parent == ch) + child->parent = NULL; + } +} + +/* + * A (*,G) or a (*,*) is being created + * find all the children that would point + * at us. + */ +static void +pim_ifchannel_find_new_children (struct pim_ifchannel *ch) +{ + 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.u.sg.src.s_addr != INADDR_ANY) && + (ch->sg.u.sg.grp.s_addr != INADDR_ANY)) + return; + + if ((ch->sg.u.sg.src.s_addr == INADDR_ANY) && + (ch->sg.u.sg.grp.s_addr == INADDR_ANY)) + return; + + for (ALL_LIST_ELEMENTS_RO (pim_ifp->pim_ifchannel_list, ch_node, child)) + { + if ((ch->sg.u.sg.grp.s_addr != INADDR_ANY) && + (child->sg.u.sg.grp.s_addr == ch->sg.u.sg.grp.s_addr) && + (child != ch)) + child->parent = ch; + } +} + void pim_ifchannel_free(struct pim_ifchannel *ch) { zassert(!ch->t_ifjoin_expiry_timer); @@ -54,6 +113,13 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) pim_ifp = ch->interface->info; zassert(pim_ifp); + /* + * When this channel is removed + * we need to find all our children + * and make sure our pointers are fixed + */ + pim_ifchannel_remove_children (ch); + if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) { pim_upstream_update_join_desired(ch->upstream); } @@ -260,8 +326,41 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp) } } -struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, - struct prefix *sg) +/* + * For a given Interface, if we are given a S,G + * Find the *,G (If we have it). + * If we are passed a *,G, find the *,* ifchannel + * if we have it. + */ +static struct pim_ifchannel * +pim_ifchannel_find_parent (struct interface *ifp, + struct prefix *sg) +{ + struct prefix parent_sg = *sg; + + // (*,*) || (S,*) + if (((sg->u.sg.src.s_addr == INADDR_ANY) && + (sg->u.sg.grp.s_addr == INADDR_ANY)) || + ((sg->u.sg.src.s_addr != INADDR_ANY) && + (sg->u.sg.grp.s_addr == INADDR_ANY))) + return NULL; + + // (S,G) + if ((sg->u.sg.src.s_addr != INADDR_ANY) && + (sg->u.sg.grp.s_addr != INADDR_ANY)) + { + parent_sg.u.sg.src.s_addr = INADDR_ANY; + return pim_ifchannel_find (ifp, &parent_sg); + } + + // (*,G) -- Not going to find anything currently + parent_sg.u.sg.grp.s_addr = INADDR_ANY; + return pim_ifchannel_find (ifp, &parent_sg); +} + +struct pim_ifchannel * +pim_ifchannel_add(struct interface *ifp, + struct prefix *sg) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; @@ -295,6 +394,8 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, ch->upstream = up; ch->interface = ifp; ch->sg = *sg; + ch->parent = pim_ifchannel_find_parent (ifp, sg); + pim_ifchannel_find_new_children (ch); ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO; ch->ifjoin_state = PIM_IFJOIN_NOINFO; diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index e262944f03..2767e4862b 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -73,6 +73,7 @@ struct pim_assert_metric { Per-interface (S,G) state */ struct pim_ifchannel { + struct pim_ifchannel *parent; struct prefix sg; struct interface *interface; /* backpointer to interface */ uint32_t flags;