diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index e5686a94f4..8e7f46d42c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1988,7 +1988,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty, json = json_object_new_object(); } else { vty_out(vty, - "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN"); + "Codes: J -> Pim Join, I -> IGMP Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted"); vty_out(vty, "\nInstalled Source Group IIF OIL\n"); } @@ -2117,25 +2117,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty, } else { if (first_oif) { first_oif = 0; - vty_out(vty, "%s(%c%c%c%c)", out_ifname, - (c_oil->oif_flags[oif_vif_index] - & PIM_OIF_FLAG_PROTO_IGMP) - ? 'I' - : ' ', - (c_oil->oif_flags[oif_vif_index] - & PIM_OIF_FLAG_PROTO_PIM) - ? 'J' - : ' ', - (c_oil->oif_flags[oif_vif_index] - & PIM_OIF_FLAG_PROTO_VXLAN) - ? 'V' - : ' ', - (c_oil->oif_flags[oif_vif_index] - & PIM_OIF_FLAG_PROTO_STAR) - ? '*' - : ' '); - } else - vty_out(vty, ", %s(%c%c%c%c)", + vty_out(vty, "%s(%c%c%c%c%c)", out_ifname, (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_IGMP) @@ -2152,6 +2134,33 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty, (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_STAR) ? '*' + : ' ', + (c_oil->oif_flags[oif_vif_index] + & PIM_OIF_FLAG_MUTE) + ? 'M' + : ' '); + } else + vty_out(vty, ", %s(%c%c%c%c%c)", + out_ifname, + (c_oil->oif_flags[oif_vif_index] + & PIM_OIF_FLAG_PROTO_IGMP) + ? 'I' + : ' ', + (c_oil->oif_flags[oif_vif_index] + & PIM_OIF_FLAG_PROTO_PIM) + ? 'J' + : ' ', + (c_oil->oif_flags[oif_vif_index] + & PIM_OIF_FLAG_PROTO_VXLAN) + ? 'V' + : ' ', + (c_oil->oif_flags[oif_vif_index] + & PIM_OIF_FLAG_PROTO_STAR) + ? '*' + : ' ', + (c_oil->oif_flags[oif_vif_index] + & PIM_OIF_FLAG_MUTE) + ? 'M' : ' '); } } @@ -5292,6 +5301,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, if (ttl < 1) continue; + /* do not display muted OIFs */ + if (c_oil->oif_flags[oif_vif_index] + & PIM_OIF_FLAG_MUTE) + continue; + ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index); pim_time_uptime( mroute_uptime, sizeof(mroute_uptime), diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index 7e88ea4fb6..64979ed7ed 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -31,6 +31,7 @@ #include "pim_str.h" #include "pim_iface.h" #include "pim_time.h" +#include "pim_vxlan.h" // struct list *pim_channel_oil_list = NULL; // struct hash *pim_channel_oil_hash = NULL; @@ -311,7 +312,8 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask; - if (channel_oil->oif_flags[pim_ifp->mroute_vif_index]) { + if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & + PIM_OIF_FLAG_PROTO_ANY) { if (PIM_DEBUG_MROUTE) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -333,6 +335,8 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, } channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0; + /* 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_DEBUG_MROUTE) { @@ -373,6 +377,77 @@ int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif, } +static bool pim_channel_eval_oif_mute(struct channel_oil *c_oil, + struct pim_interface *pim_ifp) +{ + struct pim_interface *pim_reg_ifp; + struct pim_interface *vxlan_ifp; + bool do_mute = false; + struct pim_instance *pim = c_oil->pim; + + if (!c_oil->up) + return do_mute; + + pim_reg_ifp = pim->regiface->info; + if (pim_ifp == pim_reg_ifp) { + /* suppress pimreg in the OIL if the mroute is not supposed to + * trigger register encapsulated data + */ + if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags)) + do_mute = true; + + return do_mute; + } + + vxlan_ifp = pim_vxlan_get_term_ifp(pim); + if (pim_ifp == vxlan_ifp) { + /* 1. vxlan termination device must never be added to the + * origination mroute (and that can actually happen because + * of XG inheritance from the termination mroute) otherwise + * traffic will end up looping. + * PS: This check has also been extended to non-orig mroutes + * that have a local SIP as such mroutes can move back and + * forth between orig<=>non-orig type. + * 2. vxlan termination device should be removed from the non-DF + * to prevent duplicates to the overlay rxer + */ + if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) || + PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags) || + pim_vxlan_is_local_sip(c_oil->up)) + do_mute = true; + + return do_mute; + } + + return do_mute; +} + +void pim_channel_update_oif_mute(struct channel_oil *c_oil, + struct pim_interface *pim_ifp) +{ + bool old_mute; + bool new_mute; + + /* If pim_ifp is not a part of the OIL there is nothing to do */ + if (!c_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]) + return; + + old_mute = !!(c_oil->oif_flags[pim_ifp->mroute_vif_index] & + PIM_OIF_FLAG_MUTE); + new_mute = pim_channel_eval_oif_mute(c_oil, pim_ifp); + if (old_mute == new_mute) + return; + + if (new_mute) + c_oil->oif_flags[pim_ifp->mroute_vif_index] |= + PIM_OIF_FLAG_MUTE; + else + c_oil->oif_flags[pim_ifp->mroute_vif_index] &= + ~PIM_OIF_FLAG_MUTE; + + pim_mroute_add(c_oil, __PRETTY_FUNCTION__); +} + int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask, const char *caller) { @@ -517,6 +592,18 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; + /* Some OIFs are held in a muted state i.e. the PIM state machine + * decided to include the OIF but additional status check such as + * MLAG DF role prevent it from being activated for traffic + * forwarding. + */ + if (pim_channel_eval_oif_mute(channel_oil, pim_ifp)) + channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= + PIM_OIF_FLAG_MUTE; + else + channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= + ~PIM_OIF_FLAG_MUTE; + /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not * valid to get installed in kernel. */ @@ -581,5 +668,5 @@ int pim_channel_oil_empty(struct channel_oil *c_oil) inited = 1; } - return !memcmp(c_oil->oif_flags, zero, MAXVIFS * sizeof(uint32_t)); + return !memcmp(c_oil->oil.mfcc_ttls, zero, MAXVIFS * sizeof(uint32_t)); } diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 3d4488a422..a371e2a7c6 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -21,6 +21,7 @@ #define PIM_OIL_H #include "pim_mroute.h" +#include "pim_iface.h" /* * Where did we get this (S,G) from? @@ -38,6 +39,8 @@ (PIM_OIF_FLAG_PROTO_IGMP | PIM_OIF_FLAG_PROTO_PIM \ | PIM_OIF_FLAG_PROTO_STAR | PIM_OIF_FLAG_PROTO_VXLAN) +/* OIF is present in the OIL but must not be used for forwarding traffic */ +#define PIM_OIF_FLAG_MUTE (1 << 4) /* * We need a pimreg vif id from the kernel. * Since ifindex == vif id for most cases and the number @@ -127,4 +130,7 @@ int pim_channel_del_oif(struct channel_oil *c_oil, struct interface *oif, int pim_channel_oil_empty(struct channel_oil *c_oil); char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size); + +void pim_channel_update_oif_mute(struct channel_oil *c_oil, + struct pim_interface *pim_ifp); #endif /* PIM_OIL_H */ diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 7e0958700b..4ca75e57ea 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -292,6 +292,7 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) struct pim_upstream *up; int flags = 0; struct prefix nht_p; + struct pim_instance *pim = vxlan_sg->pim; if (vxlan_sg->up) { /* nothing to do */ @@ -349,6 +350,10 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) pim_upstream_ref(up, flags, __PRETTY_FUNCTION__); vxlan_sg->up = up; pim_vxlan_orig_mr_up_iif_update(vxlan_sg); + /* mute pimreg on origination mroutes */ + if (pim->regiface) + pim_channel_update_oif_mute(up->channel_oil, + pim->regiface->info); } else { up = pim_upstream_add(vxlan_sg->pim, &vxlan_sg->sg, vxlan_sg->iif, flags,