diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index b1c55c1f4343..1c66007fbb46 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -190,8 +190,6 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, sg.grp = msg->im_dst; if (!(PIM_I_am_DR(pim_ifp))) { - struct channel_oil *c_oil; - if (PIM_DEBUG_MROUTE_DETAIL) zlog_debug("%s: Interface is not the DR blackholing incoming traffic for %s", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); @@ -206,10 +204,10 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, * that I see no way to get rid of. Just noting * this for future reference. */ - c_oil = pim_channel_oil_add(pim_ifp->pim, &sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - pim_mroute_add(c_oil, __PRETTY_FUNCTION__); + up = pim_upstream_find_or_add( + &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, + __PRETTY_FUNCTION__); + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); return 0; } @@ -238,7 +236,8 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, vif_index = pim_if_find_vifindex_by_ifindex( pim_ifp->pim, up->rpf.source_nexthop.interface->ifindex); - up->channel_oil->oil.mfcc_parent = vif_index; + pim_channel_oil_change_iif(pim_ifp->pim, up->channel_oil, + vif_index, __PRETTY_FUNCTION__); } pim_register_join(up); @@ -453,7 +452,6 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, struct pim_upstream *up; struct prefix_sg star_g; struct prefix_sg sg; - struct channel_oil *oil; pim_ifp = ifp->info; @@ -517,11 +515,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, up->upstream_register); up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; } - if (!up->channel_oil) - up->channel_oil = pim_channel_oil_add( - pim_ifp->pim, &sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); + pim_upstream_inherited_olist(pim_ifp->pim, up); if (!up->channel_oil->installed) pim_mroute_add(up->channel_oil, @@ -546,10 +540,6 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, } pim_ifp = ifp->info; - oil = pim_channel_oil_add(pim_ifp->pim, &sg, pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - if (!oil->installed) - pim_mroute_add(oil, __PRETTY_FUNCTION__); if (pim_if_connected_to_source(ifp, sg.src)) { up = pim_upstream_add(pim_ifp->pim, &sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR, @@ -564,13 +554,18 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); pim_upstream_keep_alive_timer_start( up, pim_ifp->pim->keep_alive_time); - up->channel_oil = oil; up->channel_oil->cc.pktcnt++; pim_register_join(up); pim_upstream_inherited_olist(pim_ifp->pim, up); // Send the packet to the RP pim_mroute_msg_wholepkt(fd, ifp, buf); + } else { + up = pim_upstream_add(pim_ifp->pim, &sg, ifp, + PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, + __PRETTY_FUNCTION__, NULL); + if (!up->channel_oil->installed) + pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); } return 0; diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index d4fc03e20c4a..d14293491663 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -146,6 +146,43 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, return c_oil; } +void pim_channel_oil_change_iif(struct pim_instance *pim, + struct channel_oil *c_oil, + int input_vif_index, + const char *name) +{ + int old_vif_index = c_oil->oil.mfcc_parent; + struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp, + .grp = c_oil->oil.mfcc_origin}; + + if (c_oil->oil.mfcc_parent == input_vif_index) { + if (PIM_DEBUG_MROUTE_DETAIL) + zlog_debug("%s(%s): Existing channel oil %pSG4 already using %d as IIF", + __PRETTY_FUNCTION__, name, &sg, + input_vif_index); + + return; + } + + if (PIM_DEBUG_MROUTE_DETAIL) + zlog_debug("%s(%s): Changing channel oil %pSG4 IIF from %d to %d installed: %d", + __PRETTY_FUNCTION__, name, &sg, + c_oil->oil.mfcc_parent, input_vif_index, + c_oil->installed); + + c_oil->oil.mfcc_parent = input_vif_index; + if (c_oil->installed) { + if (input_vif_index == MAXVIFS) + pim_mroute_del(c_oil, name); + else + pim_mroute_add(c_oil, name); + } else + if (old_vif_index == MAXVIFS) + pim_mroute_add(c_oil, name); + + return; +} + struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, struct prefix_sg *sg, int input_vif_index, const char *name) @@ -164,7 +201,8 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, c_oil->oil.mfcc_parent, input_vif_index); } - c_oil->oil.mfcc_parent = input_vif_index; + pim_channel_oil_change_iif(pim, c_oil, input_vif_index, + name); ++c_oil->oil_ref_count; /* channel might be present prior to upstream */ c_oil->up = pim_upstream_find(pim, sg); diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 485299196db4..319a1c91a321 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -114,6 +114,9 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, struct prefix_sg *sg, int input_vif_index, const char *name); +void pim_channel_oil_change_iif(struct pim_instance *pim, + struct channel_oil *c_oil, int input_vif_index, + const char *name); void pim_channel_oil_del(struct channel_oil *c_oil, const char *name); int pim_channel_add_oif(struct channel_oil *c_oil, struct interface *oif, diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 7d263e99e38c..357ad6ba46de 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -307,11 +307,11 @@ void pim_upstream_rpf_clear(struct pim_instance *pim, struct pim_upstream *up) { if (up->rpf.source_nexthop.interface) { - if (up->channel_oil) { - up->channel_oil->oil.mfcc_parent = MAXVIFS; - pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); + if (up->channel_oil) + pim_channel_oil_change_iif(pim, up->channel_oil, + MAXVIFS, + __PRETTY_FUNCTION__); - } pim_upstream_switch(pim, up, PIM_UPSTREAM_NOTJOINED); up->rpf.source_nexthop.interface = NULL; up->rpf.source_nexthop.mrib_nexthop_addr.u.prefix4.s_addr = diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 62c3216e8649..e3138360c825 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -138,7 +138,9 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, } else { /* input interface changed */ s_route->iif = iif_index; - s_route->c_oil.oil.mfcc_parent = iif_index; + pim_channel_oil_change_iif(pim, &s_route->c_oil, + iif_index, + __PRETTY_FUNCTION__); #ifdef PIM_ENFORCE_LOOPFREE_MFC /* check to make sure the new input was not an diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 50df2fdbf917..c0651561ac47 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -716,7 +716,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, up->join_state = PIM_UPSTREAM_NOTJOINED; up->reg_state = PIM_REG_NOINFO; up->state_transition = pim_time_monotonic_sec(); - up->channel_oil = NULL; + up->channel_oil = + pim_channel_oil_add(pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); up->sptbit = PIM_UPSTREAM_SPTBIT_FALSE; up->rpf.source_nexthop.interface = NULL; @@ -736,52 +737,34 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (up->sg.src.s_addr != INADDR_ANY) wheel_add_item(pim->upstream_sg_wheel, up); - if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) { + if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags) + || PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) { pim_upstream_fill_static_iif(up, incoming); pim_ifp = up->rpf.source_nexthop.interface->info; assert(pim_ifp); - up->channel_oil = pim_channel_oil_add(pim, &up->sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - } else if (up->upstream_addr.s_addr == INADDR_ANY) { - /* Create a dummmy channel oil with incoming ineterface MAXVIFS, - * since RP is not configured - */ - up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS, - __PRETTY_FUNCTION__); - - } else { + pim_channel_oil_change_iif(pim, up->channel_oil, + pim_ifp->mroute_vif_index, + __PRETTY_FUNCTION__); + + if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) + pim_upstream_keep_alive_timer_start( + up, pim->keep_alive_time); + } else if (up->upstream_addr.s_addr != INADDR_ANY) { rpf_result = pim_rpf_update(pim, up, NULL); if (rpf_result == PIM_RPF_FAILURE) { if (PIM_DEBUG_TRACE) zlog_debug( "%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__, up->sg_str); - /* Create a dummmy channel oil with incoming ineterface - * MAXVIFS, since RP is not reachable - */ - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); } if (up->rpf.source_nexthop.interface) { pim_ifp = up->rpf.source_nexthop.interface->info; if (pim_ifp) - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); - else { - /* - * Yeah this should not happen - * but let's be sure that we are not - * doing something stupid, all paths - * through upstream creation will - * create a channel oil - */ - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, MAXVIFS, + pim_channel_oil_change_iif( + pim, up->channel_oil, + pim_ifp->mroute_vif_index, __PRETTY_FUNCTION__); - } } } @@ -1201,6 +1184,13 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc( if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__)) return NULL; } + if (PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(up->flags)) { + PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(up->flags); + + if (!pim_upstream_del(pim, up, __PRETTY_FUNCTION__)) + return NULL; + } + /* upstream reference would have been added to track the local * membership if it is LHR. We have to clear it when KAT expires. * Otherwise would result in stale entry with uncleared ref count. @@ -1526,22 +1516,14 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim, struct pim_upstream *up) { struct interface *ifp; - struct pim_interface *pim_ifp = NULL; struct pim_ifchannel *ch, *starch; struct pim_upstream *starup = up->parent; int output_intf = 0; - if (up->rpf.source_nexthop.interface) - pim_ifp = up->rpf.source_nexthop.interface->info; - else { + if (!up->rpf.source_nexthop.interface) 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(pim, &up->sg, - pim_ifp->mroute_vif_index, - __PRETTY_FUNCTION__); FOR_ALL_INTERFACES (pim->vrf, ifp) { if (!ifp->info) diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 02ae99829057..c6c9291eed49 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -74,6 +74,13 @@ * blackholing the traffic pulled down to the LHR. */ #define PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF (1 << 17) +/* + * We are creating a non-joined upstream data structure + * for this S,G as that we want to have a channel oil + * associated with an upstream + */ +#define PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE (1 << 19) + #define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) @@ -95,6 +102,7 @@ #define PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)) #define PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(flags) ((flags) &PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -133,6 +141,7 @@ #define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_TERM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) #define PIM_UPSTREAM_FLAG_UNSET_MLAG_VXLAN(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE) enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 675e81f5a1fe..b0db23f54ac0 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -601,7 +601,6 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) { struct in_addr vif_source; int input_iface_vif_index; - int old_vif_index; pim_rp_set_upstream_addr(c_oil->pim, &vif_source, c_oil->oil.mfcc_origin, @@ -701,33 +700,9 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) } /* update iif vif_index */ - old_vif_index = c_oil->oil.mfcc_parent; - c_oil->oil.mfcc_parent = input_iface_vif_index; - - /* update kernel multicast forwarding cache (MFC) */ - if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) { - if (PIM_DEBUG_MROUTE) { - /* just log warning */ - struct interface *old_iif = pim_if_find_by_vif_index( - c_oil->pim, old_vif_index); - struct interface *new_iif = pim_if_find_by_vif_index( - c_oil->pim, input_iface_vif_index); - char source_str[INET_ADDRSTRLEN]; - char group_str[INET_ADDRSTRLEN]; - pim_inet4_dump("", c_oil->oil.mfcc_origin, - source_str, sizeof(source_str)); - pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - zlog_debug( - "%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d", - __FILE__, __PRETTY_FUNCTION__, source_str, - group_str, - old_iif ? old_iif->name : "", - c_oil->oil.mfcc_parent, - new_iif ? new_iif->name : "", - input_iface_vif_index); - } - } + pim_channel_oil_change_iif(c_oil->pim, c_oil, input_iface_vif_index, + __PRETTY_FUNCTION__); + pim_mroute_add(c_oil, __PRETTY_FUNCTION__); } void pim_scan_oil(struct pim_instance *pim) @@ -1256,14 +1231,15 @@ void pim_forward_start(struct pim_ifchannel *ch) __FILE__, __PRETTY_FUNCTION__, source_str); } - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, MAXVIFS, __PRETTY_FUNCTION__); + pim_channel_oil_change_iif(pim, up->channel_oil, + MAXVIFS, + __PRETTY_FUNCTION__); } else - up->channel_oil = pim_channel_oil_add( - pim, &up->sg, input_iface_vif_index, - __PRETTY_FUNCTION__); + pim_channel_oil_change_iif(pim, up->channel_oil, + input_iface_vif_index, + __PRETTY_FUNCTION__); if (PIM_DEBUG_TRACE) { struct interface *in_intf = pim_if_find_by_vif_index( @@ -1274,10 +1250,6 @@ void pim_forward_start(struct pim_ifchannel *ch) in_intf ? in_intf->name : "Unknown", input_iface_vif_index, up->sg_str); } - - up->channel_oil = - pim_channel_oil_add(pim, &up->sg, input_iface_vif_index, - __PRETTY_FUNCTION__); } if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)