static bool pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, struct pim_upstream *xg_up) { if (!(sa->flags & PIM_MSDP_SAF_PEER)) { /* SA should have been rxed from a peer */ return false; } /* check if we are RP */ if (!I_am_RP(sa->pim, sa->sg.grp)) { return false; } /* check if we have a (*, G) with a non-empty immediate OIL */ if (!xg_up) { struct prefix_sg sg; memset(&sg, 0, sizeof(sg)); sg.grp = sa->sg.grp; xg_up = pim_upstream_find(sa->pim, &sg); } if (!xg_up || (xg_up->join_state != PIM_UPSTREAM_JOINED)) { /* join desired will be true for such (*, G) entries so we will * just look at join_state and let the PIM state machine do the * rest of * the magic */ return false; } return true; }
/* Upstream add evaluation needs to happen everytime - * 1. Peer reference is added or removed. * 2. The RP for a group changes. * 3. joinDesired for the associated (*, G) changes * 4. associated (*, G) is removed - this seems like a bit redundant * (considering #4); but just in case an entry gets nuked without * upstream state transition * */ static void pim_msdp_sa_upstream_update(struct pim_msdp_sa *sa, struct pim_upstream *xg_up, const char *ctx) { struct pim_upstream *up; if (!pim_msdp_sa_upstream_add_ok(sa, xg_up)) { pim_msdp_sa_upstream_del(sa); return; } if (sa->up) { /* nothing to do */ return; } up = pim_upstream_find(sa->pim, &sa->sg); if (up && (PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(up->flags))) { /* somehow we lost track of the upstream ptr? best log it */ sa->up = up; if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA %s SPT reference missing", sa->sg_str); } return; } /* RFC3618: "RP triggers a (S, G) join event towards the data source * as if a JP message was rxed addressed to the RP itself." */ up = pim_upstream_add(sa->pim, &sa->sg, NULL /* iif */, PIM_UPSTREAM_FLAG_MASK_SRC_MSDP, __PRETTY_FUNCTION__, NULL); sa->up = up; if (up) { /* update inherited oil */ pim_upstream_inherited_olist(sa->pim, up); /* should we also start the kat in parallel? we will need it * when the * SA ages out */ if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA %s referenced SPT", sa->sg_str); } } else { if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA %s SPT reference failed", sa->sg_str); } } }
struct pim_upstream *pim_upstream_add(struct in_addr source_addr, struct in_addr group_addr) { struct pim_upstream *up; up = pim_upstream_find(source_addr, group_addr); if (up) { ++up->ref_count; } else { up = pim_upstream_new(source_addr, group_addr); } return up; }
/* For every VxLAN BUM multicast group we setup a SG-up that has the following * "forced properties" - * 1. Directly connected on a DR interface i.e. we must act as an FHR * 2. We prime the pump i.e. no multicast data is needed to register this * source with the FHR. To do that we send periodic null registers if * the SG entry is in a register-join state. We also prevent expiry of * KAT. * 3. As this SG is setup without data there is no need to register encapsulate * data traffic. This encapsulation is explicitly skipped for the following * reasons - * a) Many levels of encapsulation are needed creating MTU disc challenges. * Overlay BUM is encapsulated in a vxlan/UDP/IP header and then * encapsulated again in a pim-register header. * b) On a vxlan-aa setup both switches rx a copy of each BUM packet. if * they both reg encapsulated traffic the RP will accept the duplicates * as there are no RPF checks for this encapsulated data. * a), b) can be workarounded if needed, but there is really no need because * of (2) i.e. the pump is primed without data. */ 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; if (vxlan_sg->up) { /* nothing to do */ return; } if (PIM_DEBUG_VXLAN) zlog_debug("vxlan SG %s orig mroute-up add with iif %s", vxlan_sg->sg_str, vxlan_sg->iif?vxlan_sg->iif->name:"-"); PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_ORIG(flags); /* pin the IIF to lo or peerlink-subinterface and disable NHT */ PIM_UPSTREAM_FLAG_SET_STATIC_IIF(flags); /* Fake traffic by setting SRC_STREAM and starting KAT */ /* We intentionally skip updating ref count for SRC_STREAM/FHR. * Setting SRC_VXLAN should have already created a reference * preventing the entry from being deleted */ PIM_UPSTREAM_FLAG_SET_FHR(flags); PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags); /* Force pimreg even if non-DR. This is needed on a MLAG setup for * VxLAN AA */ PIM_UPSTREAM_FLAG_SET_FORCE_PIMREG(flags); /* prevent KAT expiry. we want the MDT setup even if there is no BUM * traffic */ PIM_UPSTREAM_FLAG_SET_DISABLE_KAT_EXPIRY(flags); /* SPT for vxlan BUM groups is primed and maintained via NULL * registers so there is no need to reg-encapsulate * vxlan-encapsulated overlay data traffic */ PIM_UPSTREAM_FLAG_SET_NO_PIMREG_DATA(flags); /* On a MLAG setup we force a copy to the MLAG peer while also * accepting traffic from the peer. To do this we set peerlink-rif as * the IIF and also add it to the OIL */ PIM_UPSTREAM_FLAG_SET_ALLOW_IIF_IN_OIL(flags); /* XXX: todo: defer pim_upstream add if pim is not enabled on the iif */ up = pim_upstream_find(vxlan_sg->pim, &vxlan_sg->sg); if (up) { /* if the iif is set to something other than the vxlan_sg->iif * we must dereg the old nexthop and force to new "static" * iif */ if (!PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) { nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = up->upstream_addr; pim_delete_tracked_nexthop(vxlan_sg->pim, &nht_p, up, NULL, false); } pim_upstream_ref(up, flags, __PRETTY_FUNCTION__); vxlan_sg->up = up; pim_vxlan_orig_mr_up_iif_update(vxlan_sg); } else { up = pim_upstream_add(vxlan_sg->pim, &vxlan_sg->sg, vxlan_sg->iif, flags, __PRETTY_FUNCTION__, NULL); vxlan_sg->up = up; } if (!up) { if (PIM_DEBUG_VXLAN) zlog_debug("vxlan SG %s orig mroute-up add failed", vxlan_sg->sg_str); return; } pim_upstream_keep_alive_timer_start(up, vxlan_sg->pim->keep_alive_time); /* register the source with the RP */ if (up->reg_state == PIM_REG_NOINFO) { pim_register_join(up); pim_null_register_send(up); } /* update the inherited OIL */ pim_upstream_inherited_olist(vxlan_sg->pim, up); }