diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 889e0704c4..b27374e302 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -36,6 +36,7 @@ #include "pim_time.h" #include "pim_nht.h" #include "pim_oil.h" +#include "pim_mlag.h" static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 8f7e1741e7..6ef0290adf 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -921,6 +921,14 @@ uint32_t pim_up_mlag_local_cost(struct pim_upstream *up) if (!(pim_up_mlag_is_local(up))) return router->infinite_assert_metric.route_metric; + if ((up->rpf.source_nexthop.interface == + up->pim->vxlan.peerlink_rif) && + (up->rpf.source_nexthop.mrib_route_metric < + (router->infinite_assert_metric.route_metric - + PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC))) + return up->rpf.source_nexthop.mrib_route_metric + + PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC; + return up->rpf.source_nexthop.mrib_route_metric; } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 1c1f180083..0e718a3c31 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -157,6 +157,12 @@ #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) +/* The RPF cost is incremented by 10 if the RPF interface is the peerlink-rif. + * This is used to force the MLAG switch with the lowest cost to the RPF + * to become the MLAG DF. + */ +#define PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC 10 + enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, PIM_UPSTREAM_JOINED, diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 58d988e920..abfea538e1 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -477,13 +477,14 @@ static void pim_vxlan_orig_mr_del(struct pim_vxlan_sg *vxlan_sg) static void pim_vxlan_orig_mr_iif_update(struct hash_backet *backet, void *arg) { - struct interface *ifp = (struct interface *)arg; + struct interface *ifp; struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data; struct interface *old_iif = vxlan_sg->iif; if (!pim_vxlan_is_orig_mroute(vxlan_sg)) return; + ifp = pim_vxlan_orig_mr_iif_get(vxlan_sg->pim); if (PIM_DEBUG_VXLAN) zlog_debug("vxlan SG %s iif changed from %s to %s", vxlan_sg->sg_str, @@ -895,7 +896,63 @@ static void pim_vxlan_set_default_iif(struct pim_instance *pim, */ if (pim->vxlan.sg_hash) hash_iterate(pim->vxlan.sg_hash, - pim_vxlan_orig_mr_iif_update, ifp); + pim_vxlan_orig_mr_iif_update, NULL); +} + +static void pim_vxlan_up_cost_update(struct pim_instance *pim, + struct pim_upstream *up, + struct interface *old_peerlink_rif) +{ + if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags)) + return; + + if (up->rpf.source_nexthop.interface && + ((up->rpf.source_nexthop.interface == + pim->vxlan.peerlink_rif) || + (up->rpf.source_nexthop.interface == + old_peerlink_rif))) { + if (PIM_DEBUG_VXLAN) + zlog_debug("RPF cost adjust for %s on peerlink-rif (old: %s, new: %s) change", + up->sg_str, + old_peerlink_rif ? + old_peerlink_rif->name : "-", + pim->vxlan.peerlink_rif ? + pim->vxlan.peerlink_rif->name : "-"); + pim_mlag_up_local_add(pim, up); + } +} + +static void pim_vxlan_term_mr_cost_update(struct hash_backet *backet, + void *arg) +{ + struct interface *old_peerlink_rif = (struct interface *)arg; + struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data; + struct pim_upstream *up; + struct listnode *listnode; + struct pim_upstream *child; + + if (pim_vxlan_is_orig_mroute(vxlan_sg)) + return; + + /* Lookup all XG and SG entries with RPF-interface peerlink_rif */ + up = vxlan_sg->up; + if (!up) + return; + + pim_vxlan_up_cost_update(vxlan_sg->pim, up, + old_peerlink_rif); + + for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, + child)) + pim_vxlan_up_cost_update(vxlan_sg->pim, child, + old_peerlink_rif); +} + +static void pim_vxlan_sg_peerlink_rif_update(struct hash_backet *backet, + void *arg) +{ + pim_vxlan_orig_mr_iif_update(backet, NULL); + pim_vxlan_term_mr_cost_update(backet, arg); } static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim, @@ -928,7 +985,7 @@ static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim, */ if (pim->vxlan.sg_hash) hash_iterate(pim->vxlan.sg_hash, - pim_vxlan_orig_mr_iif_update, ifp); + pim_vxlan_sg_peerlink_rif_update, old_iif); } void pim_vxlan_add_vif(struct interface *ifp)