]> git.proxmox.com Git - mirror_frr.git/commitdiff
pimd: Use PIM EVPN MLAG Infra for syncing PIM MLAG Entries
authorSatheesh Kumar K <sathk@cumulusnetworks.com>
Mon, 19 Aug 2019 09:06:00 +0000 (02:06 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 6 Mar 2020 21:03:36 +0000 (16:03 -0500)
Initially, MLAG Sync is happened at pim_ifchannel, this is mainly to
support even config mismatches(missing configuration of dual active).
But this causes more syncs for each entry.

and also it is not In-line with PIM EVPN. to avoid that moving to
pm_upstream based syncing.

Signed-off-by: Satheesh Kumar K <sathk@cumulusnetworks.com>
pimd/pim_iface.h
pimd/pim_ifchannel.c
pimd/pim_mlag.c
pimd/pim_mlag.h
pimd/pim_upstream.c
pimd/pim_upstream.h

index 1b76b5230595f24e85e0ffc070816ba73db8b752..570bf5eac31135bdc1450169fb13b76ded57d23c 100644 (file)
@@ -55,6 +55,7 @@
 #define PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) &= ~PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION)
 
 #define PIM_I_am_DR(pim_ifp) (pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr
+#define PIM_I_am_DualActive(pim_ifp) (pim_ifp)->activeactive == true
 
 struct pim_iface_upstream_switch {
        struct in_addr address;
index 528c93ce16e70999695990bf9c7a94d300bb57b5..e23d3dc3dada2f4fd905d8adb4711b0a512f4141 100644 (file)
@@ -43,6 +43,7 @@
 #include "pim_upstream.h"
 #include "pim_ssm.h"
 #include "pim_rp.h"
+#include "pim_mlag.h"
 
 RB_GENERATE(pim_ifchannel_rb, pim_ifchannel, pim_ifp_rb, pim_ifchannel_compare);
 
@@ -130,6 +131,21 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
 
        pim_ifp = ch->interface->info;
 
+       if (PIM_I_am_DualActive(pim_ifp)) {
+               if (PIM_DEBUG_MLAG)
+                       zlog_debug(
+                               "%s: if-chnanel-%s is deleted from a Dual "
+                               "active Interface",
+                               __func__, ch->sg_str);
+               /* Post Delete only if it is the last Dual-active Interface */
+               if (ch->upstream->dualactive_ifchannel_count == 1) {
+                       pim_mlag_up_local_del(pim_ifp->pim, ch->upstream);
+                       PIM_UPSTREAM_FLAG_UNSET_MLAG_INTERFACE(
+                               ch->upstream->flags);
+               }
+               ch->upstream->dualactive_ifchannel_count--;
+       }
+
        if (ch->upstream->channel_oil) {
                uint32_t mask = PIM_OIF_FLAG_PROTO_PIM;
                if (ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP)
@@ -586,6 +602,24 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
        else
                PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags);
 
+       /*
+        * advertise MLAG Data to MLAG peer
+        */
+       if (PIM_I_am_DualActive(pim_ifp)) {
+               up->dualactive_ifchannel_count++;
+               /* Sync once for upstream */
+               if (up->dualactive_ifchannel_count == 1) {
+                       PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(up->flags);
+                       pim_mlag_up_local_add(pim_ifp->pim, up);
+               }
+               if (PIM_DEBUG_MLAG)
+                       zlog_debug(
+                               "%s: New Dual active if-chnanel is added to upstream:%s "
+                               "count:%d, flags:0x%x",
+                               __func__, up->sg_str,
+                               up->dualactive_ifchannel_count, up->flags);
+       }
+
        if (PIM_DEBUG_PIM_TRACE)
                zlog_debug("%s: ifchannel %s is created ", __func__,
                           ch->sg_str);
index defe41674c439c4bfc938a1c608dfe1c99858718..321745590d640fdfcdac55d4629f6970b42566d2 100644 (file)
@@ -32,6 +32,76 @@ extern struct zclient *zclient;
 
 #define PIM_MLAG_METADATA_LEN 4
 
+/*********************ACtual Data processing *****************************/
+/* TBD: There can be duplicate updates to FIB***/
+#define PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil)                                    \
+       do {                                                                   \
+               if (PIM_DEBUG_MLAG)                                            \
+                       zlog_debug(                                            \
+                               "%s: add Dual-active Interface to %s "         \
+                               "to oil:%s",                                   \
+                               __func__, ch->interface->name, ch->sg_str);    \
+               pim_channel_add_oif(ch_oil, ch->interface,                     \
+                                   PIM_OIF_FLAG_PROTO_IGMP, __func__);        \
+       } while (0)
+
+#define PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil)                                    \
+       do {                                                                   \
+               if (PIM_DEBUG_MLAG)                                            \
+                       zlog_debug(                                            \
+                               "%s: del Dual-active Interface to %s "         \
+                               "to oil:%s",                                   \
+                               __func__, ch->interface->name, ch->sg_str);    \
+               pim_channel_del_oif(ch_oil, ch->interface,                     \
+                                   PIM_OIF_FLAG_PROTO_IGMP, __func__);        \
+       } while (0)
+
+
+static void pim_mlag_calculate_df_for_ifchannels(struct pim_upstream *up,
+                                                bool is_df)
+{
+       struct listnode *chnode;
+       struct listnode *chnextnode;
+       struct pim_ifchannel *ch;
+       struct pim_interface *pim_ifp = NULL;
+       struct channel_oil *ch_oil = NULL;
+
+       ch_oil = (up) ? up->channel_oil : NULL;
+
+       if (!ch_oil)
+               return;
+
+       if (PIM_DEBUG_MLAG)
+               zlog_debug("%s: Calculating DF for Dual active if-channel%s",
+                          __func__, up->sg_str);
+
+       for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
+               pim_ifp = (ch->interface) ? ch->interface->info : NULL;
+               if (!pim_ifp || !PIM_I_am_DualActive(pim_ifp))
+                       continue;
+
+               if (is_df)
+                       PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil);
+               else
+                       PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil);
+       }
+}
+
+static void pim_mlag_inherit_mlag_flags(struct pim_upstream *up, bool is_df)
+{
+       struct listnode *listnode;
+       struct pim_upstream *child;
+
+       for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, child)) {
+               PIM_UPSTREAM_FLAG_SET_MLAG_PEER(child->flags);
+               if (is_df)
+                       PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(child->flags);
+               else
+                       PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child->flags);
+               pim_mlag_calculate_df_for_ifchannels(child, is_df);
+       }
+}
+
 /******************************* pim upstream sync **************************/
 /* Update DF role for the upstream entry and return true on role change */
 bool pim_mlag_up_df_role_update(struct pim_instance *pim,
@@ -59,6 +129,15 @@ bool pim_mlag_up_df_role_update(struct pim_instance *pim,
                PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags);
 
 
+       /*
+        * This Upstream entry synced to peer Because of Dual-active
+        * Interface configuration
+        */
+       if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) {
+               pim_mlag_calculate_df_for_ifchannels(up, is_df);
+               pim_mlag_inherit_mlag_flags(up, is_df);
+       }
+
        /* If the DF role has changed check if ipmr-lo needs to be
         * muted/un-muted. Active-Active devices and vxlan termination
         * devices (ipmr-lo) are suppressed on the non-DF.
@@ -91,7 +170,8 @@ static bool pim_mlag_up_df_role_elect(struct pim_instance *pim,
        uint32_t local_cost;
        bool rv;
 
-       if (!pim_up_mlag_is_local(up))
+       if (!pim_up_mlag_is_local(up)
+           && !PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
                return false;
 
        /* We are yet to rx a status update from the local MLAG daemon so
@@ -417,7 +497,8 @@ static void pim_mlag_up_local_replay(void)
        RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
                pim = vrf->info;
                frr_each (rb_pim_upstream, &pim->upstream_head, up) {
-                       if (pim_up_mlag_is_local(up))
+                       if (pim_up_mlag_is_local(up)
+                           || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
                                pim_mlag_up_local_add_send(pim, up);
                }
        }
@@ -438,7 +519,9 @@ static void pim_mlag_up_local_reeval(bool mlagd_send, const char *reason_code)
        RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
                pim = vrf->info;
                frr_each (rb_pim_upstream, &pim->upstream_head, up) {
-                       if (!pim_up_mlag_is_local(up))
+                       if (!pim_up_mlag_is_local(up)
+                           && !PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(
+                                   up->flags))
                                continue;
                        /* if role changes re-send to peer */
                        if (pim_mlag_up_df_role_elect(pim, up) &&
@@ -772,6 +855,12 @@ int pim_zebra_mlag_process_up(void)
        if (PIM_DEBUG_MLAG)
                zlog_debug("%s: Received Process-Up from Mlag", __func__);
 
+       /*
+        * Incase of local MLAG restart, PIM needs to replay all the data
+        * since MLAG is empty.
+        */
+       router->connected_to_mlag = true;
+       router->mlag_flags |= PIM_MLAGF_LOCAL_CONN_UP;
        return 0;
 }
 
index 4639f5682609987077d9a138dc4a2588fabe6699..eb316695f76a6f937428908e407677cd2ca06f96 100644 (file)
@@ -32,8 +32,6 @@ extern void pim_instance_mlag_init(struct pim_instance *pim);
 extern void pim_instance_mlag_terminate(struct pim_instance *pim);
 extern void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp);
 extern void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp);
-extern void pim_mlag_register(void);
-extern void pim_mlag_deregister(void);
 extern int pim_zebra_mlag_process_up(void);
 extern int pim_zebra_mlag_process_down(void);
 extern int pim_zebra_mlag_handle_msg(struct stream *msg, int len);
@@ -43,10 +41,13 @@ extern int pim_mlag_signal_zpthread(void);
 extern void pim_zpthread_init(void);
 extern void pim_zpthread_terminate(void);
 
+extern void pim_mlag_register(void);
+extern void pim_mlag_deregister(void);
 extern void pim_mlag_up_local_add(struct pim_instance *pim,
-               struct pim_upstream *upstream);
+                                 struct pim_upstream *upstream);
 extern void pim_mlag_up_local_del(struct pim_instance *pim,
-               struct pim_upstream *upstream);
+                                 struct pim_upstream *upstream);
 extern bool pim_mlag_up_df_role_update(struct pim_instance *pim,
-               struct pim_upstream *up, bool is_df, const char *reason);
+                                      struct pim_upstream *up, bool is_df,
+                                      const char *reason);
 #endif
index c905dd146aeb8555321a081d82b2cf99d09ff391..998720e8f6d47656cf44e55f1818f482ca17080d 100644 (file)
@@ -141,6 +141,18 @@ static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim,
                if (up)
                        listnode_add(up->sources, child);
 
+               /*
+                * In case parent is MLAG entry copy the data to child
+                */
+               if (up && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) {
+                       PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(child->flags);
+                       if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))
+                               PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child->flags);
+                       else
+                               PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(
+                                       child->flags);
+               }
+
                return up;
        }
 
@@ -903,7 +915,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
        /* XXX - duplicate send is possible here if pim_rpf_update
         * successfully resolved the nexthop
         */
-       if (pim_up_mlag_is_local(up))
+       if (pim_up_mlag_is_local(up)
+           || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags))
                pim_mlag_up_local_add(pim, up);
 
        if (PIM_DEBUG_PIM_TRACE) {
@@ -918,7 +931,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
 
 uint32_t pim_up_mlag_local_cost(struct pim_upstream *up)
 {
-       if (!(pim_up_mlag_is_local(up)))
+       if (!(pim_up_mlag_is_local(up))
+           && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE))
                return router->infinite_assert_metric.route_metric;
 
        if ((up->rpf.source_nexthop.interface ==
@@ -1752,6 +1766,7 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
                                   up->sg_str);
 
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
+               struct pim_interface *pim_ifp;
                if (!ifp->info)
                        continue;
 
@@ -1765,6 +1780,12 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
                if (!ch && !starch)
                        continue;
 
+               pim_ifp = ifp->info;
+               if (PIM_I_am_DualActive(pim_ifp)
+                   && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)
+                   && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)
+                       || !PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)))
+                       continue;
                if (pim_upstream_evaluate_join_desired_interface(up, ch,
                                                                 starch)) {
                        int flag = PIM_OIF_FLAG_PROTO_PIM;
index 4d693b8b64d359339e6f6e7b5fe2fc6b996f6901..ca693ee73f9a4346536ec635443370c1bc23f440 100644 (file)
@@ -237,6 +237,8 @@ struct pim_upstream {
        struct channel_oil *channel_oil;
        struct list *sources;
        struct list *ifchannels;
+       /* Counter for Dual active ifchannels*/
+       uint32_t dualactive_ifchannel_count;
 
        enum pim_upstream_state join_state;
        enum pim_reg_state reg_state;