diff options
| -rw-r--r-- | pimd/pim_mroute.c | 81 | ||||
| -rw-r--r-- | pimd/pim_mroute.h | 3 | ||||
| -rw-r--r-- | pimd/pim_oil.c | 10 | ||||
| -rw-r--r-- | pimd/pim_static.c | 4 | ||||
| -rw-r--r-- | pimd/pim_upstream.c | 101 | ||||
| -rw-r--r-- | pimd/pim_upstream.h | 12 | ||||
| -rw-r--r-- | pimd/pim_vxlan.c | 4 | ||||
| -rw-r--r-- | pimd/pim_zebra.c | 11 |
8 files changed, 173 insertions, 53 deletions
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index f28d801f0b..c8e9202586 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -207,7 +207,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, up = pim_upstream_find_or_add( &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __PRETTY_FUNCTION__); - pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + pim_upstream_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); return 0; } @@ -228,7 +228,6 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time); up->channel_oil->cc.pktcnt++; - PIM_UPSTREAM_FLAG_SET_FHR(up->flags); // resolve mfcc_parent prior to mroute_add in channel_add_oif if (up->rpf.source_nexthop.interface && up->channel_oil->oil.mfcc_parent >= MAXVIFS) { @@ -518,7 +517,7 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, pim_upstream_inherited_olist(pim_ifp->pim, up); if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, + pim_upstream_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); } else { if (I_am_RP(pim_ifp->pim, up->sg.grp)) { @@ -557,6 +556,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, up->channel_oil->cc.pktcnt++; pim_register_join(up); pim_upstream_inherited_olist(pim_ifp->pim, up); + if (!up->channel_oil->installed) + pim_upstream_mroute_add(up->channel_oil, __func__); // Send the packet to the RP pim_mroute_msg_wholepkt(fd, ifp, buf); @@ -565,7 +566,8 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __PRETTY_FUNCTION__, NULL); if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + pim_upstream_mroute_add(up->channel_oil, + __PRETTY_FUNCTION__); } return 0; @@ -899,7 +901,10 @@ static inline void pim_mroute_copy(struct mfcctl *oil, } } -int pim_mroute_add(struct channel_oil *c_oil, const char *name) +/* This function must not be called directly 0 + * use pim_upstream_mroute_add or pim_static_mroute_add instead + */ +static int pim_mroute_add(struct channel_oil *c_oil, const char *name) { struct pim_instance *pim = c_oil->pim; struct mfcctl tmp_oil; @@ -908,18 +913,6 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) pim->mroute_add_last = pim_time_monotonic_sec(); ++pim->mroute_add_events; - /* Do not install route if incoming interface is undefined. */ - if (c_oil->oil.mfcc_parent >= MAXVIFS) { - if (PIM_DEBUG_MROUTE) { - char buf[1000]; - zlog_debug( - "%s(%s) %s Attempting to add vifi that is invalid to mroute table", - __PRETTY_FUNCTION__, name, - pim_channel_oil_dump(c_oil, buf, sizeof(buf))); - } - return -2; - } - /* Copy the oil to a temporary structure to fixup (without need to * later restore) before sending the mroute add to the dataplane */ @@ -976,6 +969,60 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) return 0; } +/* In the case of "PIM state machine" added mroutes an upstream entry + * must be present to decide on the SPT-forwarding vs. RPT-forwarding. + */ +int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name) +{ + vifi_t iif = MAXVIFS; + char buf[1000]; + struct interface *ifp = NULL; + struct pim_interface *pim_ifp; + struct pim_upstream *up = c_oil->up; + + if (up) { + if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) { + if (up->parent) + ifp = up->parent->rpf.source_nexthop.interface; + } else { + ifp = up->rpf.source_nexthop.interface; + } + if (ifp) { + pim_ifp = (struct pim_interface *)ifp->info; + if (pim_ifp) + iif = pim_ifp->mroute_vif_index; + } + } + + c_oil->oil.mfcc_parent = iif; + + if (c_oil->oil.mfcc_parent >= MAXVIFS) { + /* the c_oil cannot be installed as a mroute yet */ + if (PIM_DEBUG_MROUTE) + zlog_debug( + "%s(%s) %s mroute not ready to be installed; %s", + __PRETTY_FUNCTION__, name, + pim_channel_oil_dump(c_oil, buf, + sizeof(buf)), + c_oil->installed ? + "uninstall" : "skip"); + /* if already installed flush it out as we are going to stop + * updates to it leaving it in a stale state + */ + if (c_oil->installed) + pim_mroute_del(c_oil, name); + /* return success (skipped) */ + return 0; + } + + return pim_mroute_add(c_oil, name); +} + +int pim_static_mroute_add(struct channel_oil *c_oil, const char *name) +{ + return pim_mroute_add(c_oil, name); +} + int pim_mroute_del(struct channel_oil *c_oil, const char *name) { struct pim_instance *pim = c_oil->pim; diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index bd71acbf82..3f54681432 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -174,7 +174,8 @@ int pim_mroute_add_vif(struct interface *ifp, struct in_addr ifaddr, unsigned char flags); int pim_mroute_del_vif(struct interface *ifp); -int pim_mroute_add(struct channel_oil *c_oil, const char *name); +int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name); +int pim_static_mroute_add(struct channel_oil *c_oil, const char *name); int pim_mroute_del(struct channel_oil *c_oil, const char *name); void pim_mroute_update_counters(struct channel_oil *c_oil); diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 8933245de1..3e73e6cc8f 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -178,10 +178,10 @@ void pim_channel_oil_change_iif(struct pim_instance *pim, if (input_vif_index == MAXVIFS) pim_mroute_del(c_oil, name); else - pim_mroute_add(c_oil, name); + pim_upstream_mroute_add(c_oil, name); } else if (old_vif_index == MAXVIFS) - pim_mroute_add(c_oil, name); + pim_upstream_mroute_add(c_oil, name); return; } @@ -368,7 +368,7 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, /* clear mute; will be re-evaluated when the OIF becomes valid again */ channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~PIM_OIF_FLAG_MUTE; - if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { + if (pim_upstream_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { if (PIM_DEBUG_MROUTE) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -475,7 +475,7 @@ void pim_channel_update_oif_mute(struct channel_oil *c_oil, c_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~PIM_OIF_FLAG_MUTE; - pim_mroute_add(c_oil, __PRETTY_FUNCTION__); + pim_upstream_mroute_add(c_oil, __PRETTY_FUNCTION__); } /* pim_upstream has been set or cleared on the c_oil. re-eval mute state @@ -654,7 +654,7 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, * valid to get installed in kernel. */ if (channel_oil->oil.mfcc_parent != MAXVIFS) { - if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { + if (pim_upstream_mroute_add(channel_oil, __PRETTY_FUNCTION__)) { if (PIM_DEBUG_MROUTE) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_static.c b/pimd/pim_static.c index e3138360c8..be2321dc33 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -179,7 +179,7 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, s_route->c_oil.pim = pim; - if (pim_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) { + if (pim_static_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) { char gifaddr_str[INET_ADDRSTRLEN]; char sifaddr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<ifaddr?>", group, gifaddr_str, @@ -264,7 +264,7 @@ int pim_static_del(struct pim_instance *pim, struct interface *iif, if (s_route->c_oil.oil_ref_count <= 0 ? pim_mroute_del(&s_route->c_oil, __PRETTY_FUNCTION__) - : pim_mroute_add(&s_route->c_oil, + : pim_static_mroute_add(&s_route->c_oil, __PRETTY_FUNCTION__)) { char gifaddr_str[INET_ADDRSTRLEN]; char sifaddr_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index fdb7363042..e9382be33f 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -561,6 +561,63 @@ void pim_upstream_register_reevaluate(struct pim_instance *pim) } } +/* RFC7761, Section 4.2 “Data Packet Forwarding Rules” says we should + * forward a S - + * 1. along the SPT if SPTbit is set + * 2. and along the RPT if SPTbit is not set + * If forwarding is hw accelerated i.e. control and dataplane components + * are separate you may not be able to reliably set SPT bit on intermediate + * routers while still fowarding on the (S,G,rpt). + * + * This macro is a slight deviation on the RFC and uses "traffic-agnostic" + * criteria to decide between using the RPT vs. SPT for forwarding. + */ +void pim_upstream_update_use_rpt(struct pim_upstream *up, + bool update_mroute) +{ + bool old_use_rpt; + bool new_use_rpt; + + if (up->sg.src.s_addr == INADDR_ANY) + return; + + old_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags); + + /* We will use the SPT (IIF=RPF_interface(S) if - + * 1. We have decided to join the SPT + * 2. We are FHR + * 3. Source is directly connected + * 4. We are RP (parent's IIF is lo or vrf-device) + * In all other cases the source will stay along the RPT and + * IIF=RPF_interface(RP). + */ + if (up->join_state == PIM_UPSTREAM_JOINED || + PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) || + pim_if_connected_to_source( + up->rpf.source_nexthop.interface, + up->sg.src) || + /* XXX - need to switch this to a more efficient + * lookup API + */ + I_am_RP(up->pim, up->sg.grp)) + /* use SPT */ + PIM_UPSTREAM_FLAG_UNSET_USE_RPT(up->flags); + else + /* use RPT */ + PIM_UPSTREAM_FLAG_SET_USE_RPT(up->flags); + + new_use_rpt = !!PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags); + if (old_use_rpt != new_use_rpt) { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s switched from %s to %s", + up->sg_str, + old_use_rpt?"RPT":"SPT", + new_use_rpt?"RPT":"SPT"); + if (update_mroute) + pim_upstream_mroute_add(up->channel_oil, __func__); + } +} + void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, enum pim_upstream_state new_state) { @@ -642,6 +699,9 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, 0 /* prune */); join_timer_stop(up); } + + if (old_state != new_state) + pim_upstream_update_use_rpt(up, true /*update_mroute*/); } int pim_upstream_compare(void *arg1, void *arg2) @@ -693,6 +753,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, up = XCALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); + up->pim = pim; up->sg = *sg; pim_str_sg_set(sg, up->sg_str); if (ch) @@ -776,6 +837,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, pim_ifp->mroute_vif_index, __PRETTY_FUNCTION__); } + pim_upstream_update_use_rpt(up, + false /*update_mroute*/); } listnode_add_sort(pim->upstream_list, up); @@ -802,35 +865,26 @@ struct pim_upstream *pim_upstream_find(struct pim_instance *pim, } struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, - struct interface *incoming, - int flags, const char *name) + struct interface *incoming, + int flags, const char *name) { - struct pim_upstream *up; - struct pim_interface *pim_ifp; - - pim_ifp = incoming->info; - - up = pim_upstream_find(pim_ifp->pim, sg); + struct pim_interface *pim_ifp = incoming->info; - if (up) { - if (!(up->flags & flags)) { - up->flags |= flags; - up->ref_count++; - if (PIM_DEBUG_PIM_TRACE) - zlog_debug( - "%s(%s): upstream %s ref count %d increment", - __PRETTY_FUNCTION__, name, up->sg_str, - up->ref_count); - } - } else - up = pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name, - NULL); - - return up; + return (pim_upstream_add(pim_ifp->pim, sg, incoming, flags, name, + NULL)); } void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name) { + /* when we go from non-FHR to FHR we need to re-eval traffic + * forwarding path + */ + if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags) && + PIM_UPSTREAM_FLAG_TEST_FHR(flags)) { + PIM_UPSTREAM_FLAG_SET_FHR(up->flags); + pim_upstream_update_use_rpt(up, true /*update_mroute*/); + } + up->flags |= flags; ++up->ref_count; if (PIM_DEBUG_PIM_TRACE) @@ -1146,6 +1200,7 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up) PIM_UPSTREAM_FLAG_SET_FHR(up->flags); if (up->reg_state == PIM_REG_NOINFO) pim_register_join(up); + pim_upstream_update_use_rpt(up, true /*update_mroute*/); } } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index c6c9291eed..7597baaa32 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -80,6 +80,12 @@ * associated with an upstream */ #define PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE (1 << 19) +/* By default as SG entry will use the SPT for forwarding traffic + * unless it was setup as a result of a Prune(S,G,rpt) from a + * downstream router and has JoinDesired(S,G) as False. + * This flag is only relevant for (S,G) entries. + */ +#define PIM_UPSTREAM_FLAG_MASK_USE_RPT (1 << 20) #define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF @@ -103,6 +109,7 @@ #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_TEST_USE_RPT(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_USE_RPT) #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) @@ -122,6 +129,7 @@ #define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) #define PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_SET_USE_RPT(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_USE_RPT) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -142,6 +150,7 @@ #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) +#define PIM_UPSTREAM_FLAG_UNSET_USE_RPT(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_USE_RPT) enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, @@ -188,6 +197,7 @@ enum pim_upstream_sptbit { */ struct pim_upstream { + struct pim_instance *pim; struct pim_upstream *parent; struct in_addr upstream_addr; /* Who we are talking to */ struct in_addr upstream_register; /*Who we received a register from*/ @@ -324,4 +334,6 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc( struct pim_upstream *up); void pim_upstream_fill_static_iif(struct pim_upstream *up, struct interface *incoming); +void pim_upstream_update_use_rpt(struct pim_upstream *up, + bool update_mroute); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 4ca75e57ea..daec0951c3 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -347,6 +347,8 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) pim_delete_tracked_nexthop(vxlan_sg->pim, &nht_p, up, NULL, false); } + /* We are acting FHR; clear out use_rpt setting if any */ + pim_upstream_update_use_rpt(up, false /*update_mroute*/); pim_upstream_ref(up, flags, __PRETTY_FUNCTION__); vxlan_sg->up = up; pim_vxlan_orig_mr_up_iif_update(vxlan_sg); @@ -378,6 +380,8 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) /* update the inherited OIL */ pim_upstream_inherited_olist(vxlan_sg->pim, up); + if (!up->channel_oil->installed) + pim_upstream_mroute_add(up->channel_oil, __func__); } static void pim_vxlan_orig_mr_oif_add(struct pim_vxlan_sg *vxlan_sg) diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index a0ca618b73..9b1261976d 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -289,7 +289,7 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, * so install it. */ if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, + pim_upstream_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); /* @@ -325,7 +325,8 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, } if (!up->channel_oil->installed) - pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + pim_upstream_mroute_add(up->channel_oil, + __PRETTY_FUNCTION__); } /* FIXME can join_desired actually be changed by pim_rpf_update() @@ -440,7 +441,7 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) if (input_iface_vif_index == c_oil->oil.mfcc_parent) { if (!c_oil->installed) - pim_mroute_add(c_oil, __PRETTY_FUNCTION__); + pim_upstream_mroute_add(c_oil, __PRETTY_FUNCTION__); /* RPF unchanged */ return; @@ -490,7 +491,7 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index) /* update iif 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__); + pim_upstream_mroute_add(c_oil, __PRETTY_FUNCTION__); } void pim_scan_oil(struct pim_instance *pim) @@ -1008,7 +1009,7 @@ void pim_forward_stop(struct pim_ifchannel *ch, bool install_it) PIM_OIF_FLAG_PROTO_PIM, __func__); if (install_it && !up->channel_oil->installed) - pim_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); + pim_upstream_mroute_add(up->channel_oil, __PRETTY_FUNCTION__); } void pim_zebra_zclient_update(struct vty *vty) |
