summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pimd/pim_vxlan.c128
-rw-r--r--pimd/pim_vxlan.h1
2 files changed, 129 insertions, 0 deletions
diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c
index d6d6eaec1b..b51329ea86 100644
--- a/pimd/pim_vxlan.c
+++ b/pimd/pim_vxlan.c
@@ -468,6 +468,130 @@ static void pim_vxlan_orig_mr_del(struct pim_vxlan_sg *vxlan_sg)
pim_vxlan_orig_mr_up_del(vxlan_sg);
}
+/**************************** vxlan termination mroutes ***********************
+ * For every bum-mcast-grp registered by evpn a *G termination
+ * mroute is setup by pimd. The purpose of this mroute is to pull down vxlan
+ * packets with the bum-mcast-grp dip from the underlay and terminate the
+ * tunnel. This is done by including the vxlan termination device (ipmr-lo) in
+ * its OIL. The vxlan de-capsulated packets are subject to subsequent overlay
+ * bridging.
+ *
+ * Sample mroute:
+ * (0.0.0.0, 239.1.1.100) Iif: uplink-1 Oifs: ipmr-lo, uplink-1
+ *****************************************************************************/
+struct pim_interface *pim_vxlan_get_term_ifp(struct pim_instance *pim)
+{
+ return pim->vxlan.term_if ?
+ (struct pim_interface *)pim->vxlan.term_if->info : NULL;
+}
+
+static void pim_vxlan_term_mr_oif_add(struct pim_vxlan_sg *vxlan_sg)
+{
+ if (vxlan_sg->flags & PIM_VXLAN_SGF_OIF_INSTALLED)
+ return;
+
+ if (PIM_DEBUG_VXLAN)
+ zlog_debug("vxlan SG %s term-oif %s add",
+ vxlan_sg->sg_str, vxlan_sg->term_oif->name);
+
+ if (pim_ifchannel_local_membership_add(vxlan_sg->term_oif,
+ &vxlan_sg->sg)) {
+ vxlan_sg->flags |= PIM_VXLAN_SGF_OIF_INSTALLED;
+ } else {
+ zlog_warn("vxlan SG %s term-oif %s add failed",
+ vxlan_sg->sg_str, vxlan_sg->term_oif->name);
+ }
+}
+
+static void pim_vxlan_term_mr_oif_del(struct pim_vxlan_sg *vxlan_sg)
+{
+ if (!(vxlan_sg->flags & PIM_VXLAN_SGF_OIF_INSTALLED))
+ return;
+
+ if (PIM_DEBUG_VXLAN)
+ zlog_debug("vxlan SG %s oif %s del",
+ vxlan_sg->sg_str, vxlan_sg->term_oif->name);
+
+ vxlan_sg->flags &= ~PIM_VXLAN_SGF_OIF_INSTALLED;
+ pim_ifchannel_local_membership_del(vxlan_sg->term_oif, &vxlan_sg->sg);
+}
+
+static void pim_vxlan_term_mr_up_add(struct pim_vxlan_sg *vxlan_sg)
+{
+ struct pim_upstream *up;
+ int flags = 0;
+
+ if (vxlan_sg->up) {
+ /* nothing to do */
+ return;
+ }
+
+ if (PIM_DEBUG_VXLAN)
+ zlog_debug("vxlan SG %s term mroute-up add",
+ vxlan_sg->sg_str);
+
+ PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags);
+ /* enable MLAG designated-forwarder election on termination mroutes */
+ PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags);
+
+ up = pim_upstream_add(vxlan_sg->pim, &vxlan_sg->sg,
+ NULL /* iif */, flags,
+ __PRETTY_FUNCTION__, NULL);
+ vxlan_sg->up = up;
+
+ if (!up) {
+ zlog_warn("vxlan SG %s term mroute-up add failed",
+ vxlan_sg->sg_str);
+ }
+}
+
+static void pim_vxlan_term_mr_up_del(struct pim_vxlan_sg *vxlan_sg)
+{
+ struct pim_upstream *up = vxlan_sg->up;
+
+ if (!up)
+ return;
+
+ if (PIM_DEBUG_VXLAN)
+ zlog_debug("vxlan SG %s term mroute-up del",
+ vxlan_sg->sg_str);
+ vxlan_sg->up = NULL;
+ if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) {
+ /* clear out all the vxlan related flags */
+ up->flags &= ~(PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM |
+ PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN);
+
+ pim_upstream_del(vxlan_sg->pim, up,
+ __PRETTY_FUNCTION__);
+ }
+}
+
+static void pim_vxlan_term_mr_add(struct pim_vxlan_sg *vxlan_sg)
+{
+ if (PIM_DEBUG_VXLAN)
+ zlog_debug("vxlan SG %s term mroute add", vxlan_sg->sg_str);
+
+ vxlan_sg->term_oif = vxlan_sg->pim->vxlan.term_if;
+ if (!vxlan_sg->term_oif)
+ /* defer termination mroute till we have a termination device */
+ return;
+
+ pim_vxlan_term_mr_up_add(vxlan_sg);
+ /* set up local membership for the term-oif */
+ pim_vxlan_term_mr_oif_add(vxlan_sg);
+}
+
+static void pim_vxlan_term_mr_del(struct pim_vxlan_sg *vxlan_sg)
+{
+ if (PIM_DEBUG_VXLAN)
+ zlog_debug("vxlan SG %s term mroute del", vxlan_sg->sg_str);
+
+ /* remove local membership associated with the term oif */
+ pim_vxlan_term_mr_oif_del(vxlan_sg);
+ /* remove references to the upstream entry */
+ pim_vxlan_term_mr_up_del(vxlan_sg);
+}
+
/************************** vxlan SG cache management ************************/
static unsigned int pim_vxlan_sg_hash_key_make(void *p)
{
@@ -527,6 +651,8 @@ struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim,
if (pim_vxlan_is_orig_mroute(vxlan_sg))
pim_vxlan_orig_mr_add(vxlan_sg);
+ else
+ pim_vxlan_term_mr_add(vxlan_sg);
return vxlan_sg;
}
@@ -545,6 +671,8 @@ void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg)
if (pim_vxlan_is_orig_mroute(vxlan_sg))
pim_vxlan_orig_mr_del(vxlan_sg);
+ else
+ pim_vxlan_term_mr_del(vxlan_sg);
hash_release(vxlan_sg->pim->vxlan.sg_hash, vxlan_sg);
diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h
index 5b810c3071..ad84fa8e04 100644
--- a/pimd/pim_vxlan.h
+++ b/pimd/pim_vxlan.h
@@ -122,5 +122,6 @@ extern struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim,
extern void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg);
extern void pim_vxlan_update_sg_reg_state(struct pim_instance *pim,
struct pim_upstream *up, bool reg_join);
+extern struct pim_interface *pim_vxlan_get_term_ifp(struct pim_instance *pim);
#endif /* PIM_VXLAN_H */