pimd: enforce PIM_ENFORCE_LOOPFREE_MFC at the time of MFC programming

This is needed for two reasons -
1. The inherited OIL needs to be setup independent of the RPF interface
to allow correct computation of the JoinDesired macro.
2. The RPF interface is computed at the time of MFC programming so
it is not possible to permanently evict the OIF at that time oif_add

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
Anuradha Karuppiah 2019-11-15 11:46:04 -08:00
parent 11913c322b
commit 60eb7e6b80
4 changed files with 53 additions and 43 deletions

View File

@ -5405,6 +5405,11 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
& PIM_OIF_FLAG_MUTE)
continue;
if (c_oil->oil.mfcc_parent == oif_vif_index &&
!pim_mroute_allow_iif_in_oil(c_oil,
oif_vif_index))
continue;
ifp_out = pim_if_find_by_vif_index(pim, oif_vif_index);
pim_time_uptime(
mroute_uptime, sizeof(mroute_uptime),

View File

@ -878,6 +878,46 @@ int pim_mroute_del_vif(struct interface *ifp)
return 0;
}
/*
* Prevent creating MFC entry with OIF=IIF.
*
* This is a protection against implementation mistakes.
*
* PIM protocol implicitely ensures loopfree multicast topology.
*
* IGMP must be protected against adding looped MFC entries created
* by both source and receiver attached to the same interface. See
* TODO T22.
* We shall allow igmp to create upstream when it is DR for the intf.
* Assume RP reachable via non DR.
*/
bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
int oif_index)
{
#ifdef PIM_ENFORCE_LOOPFREE_MFC
struct interface *ifp_out;
struct pim_interface *pim_ifp;
if (c_oil->up &&
PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
return true;
ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
if (!ifp_out)
return false;
pim_ifp = ifp_out->info;
if (!pim_ifp)
return false;
if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_IGMP) &&
PIM_I_am_DR(pim_ifp))
return true;
return false;
#else
return true;
#endif
}
static inline void pim_mroute_copy(struct mfcctl *oil,
struct channel_oil *c_oil)
{
@ -888,6 +928,12 @@ static inline void pim_mroute_copy(struct mfcctl *oil,
oil->mfcc_parent = c_oil->oil.mfcc_parent;
for (i = 0; i < MAXVIFS; ++i) {
if ((oil->mfcc_parent == i) &&
!pim_mroute_allow_iif_in_oil(c_oil, i)) {
oil->mfcc_ttls[i] = 0;
continue;
}
if (c_oil->oif_flags[i] & PIM_OIF_FLAG_MUTE)
oil->mfcc_ttls[i] = 0;
else

View File

@ -183,4 +183,6 @@ void pim_static_mroute_iif_update(struct channel_oil *c_oil,
int pim_mroute_del(struct channel_oil *c_oil, const char *name);
void pim_mroute_update_counters(struct channel_oil *c_oil);
bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
int oif_index);
#endif /* PIM_MROUTE_H */

View File

@ -460,7 +460,6 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
{
struct pim_interface *pim_ifp;
int old_ttl;
bool allow_iif_in_oil = false;
/*
* If we've gotten here we've gone bad, but let's
@ -473,48 +472,6 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
pim_ifp = oif->info;
#ifdef PIM_ENFORCE_LOOPFREE_MFC
/*
Prevent creating MFC entry with OIF=IIF.
This is a protection against implementation mistakes.
PIM protocol implicitely ensures loopfree multicast topology.
IGMP must be protected against adding looped MFC entries created
by both source and receiver attached to the same interface. See
TODO T22.
We shall allow igmp to create upstream when it is DR for the intf.
Assume RP reachable via non DR.
*/
if ((channel_oil->up &&
PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(channel_oil->up->flags)) ||
((proto_mask == PIM_OIF_FLAG_PROTO_IGMP) && PIM_I_am_DR(pim_ifp))) {
allow_iif_in_oil = true;
}
if (!allow_iif_in_oil &&
pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
channel_oil->oil_inherited_rescan = 1;
if (PIM_DEBUG_MROUTE) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<group?>",
channel_oil->oil.mfcc_mcastgrp,
group_str, sizeof(group_str));
pim_inet4_dump("<source?>",
channel_oil->oil.mfcc_origin, source_str,
sizeof(source_str));
zlog_debug(
"%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
__FILE__, __PRETTY_FUNCTION__, proto_mask,
oif->name, pim_ifp->mroute_vif_index,
source_str, group_str);
}
return -2;
}
#endif
/* Prevent single protocol from subscribing same interface to
channel (S,G) multiple times */
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {