back to topotato report
topotato coverage report
Current view: top level - pimd - pim_mlag.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 33 513 6.4 %
Date: 2023-02-24 19:38:44 Functions: 5 34 14.7 %

          Line data    Source code
       1             : /*
       2             :  * This is an implementation of PIM MLAG Functionality
       3             :  *
       4             :  * Module name: PIM MLAG
       5             :  *
       6             :  * Author: sathesh Kumar karra <sathk@cumulusnetworks.com>
       7             :  *
       8             :  * Copyright (C) 2019 Cumulus Networks http://www.cumulusnetworks.com
       9             :  *
      10             :  * This program is free software; you can redistribute it and/or modify it
      11             :  * under the terms of the GNU General Public License as published by the Free
      12             :  * Software Foundation; either version 2 of the License, or (at your option)
      13             :  * any later version.
      14             :  *
      15             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      16             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      17             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      18             :  * more details.
      19             :  *
      20             :  * You should have received a copy of the GNU General Public License along
      21             :  * with this program; see the file COPYING; if not, write to the Free Software
      22             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      23             :  */
      24             : #include <zebra.h>
      25             : 
      26             : #include "pimd.h"
      27             : #include "pim_mlag.h"
      28             : #include "pim_upstream.h"
      29             : #include "pim_vxlan.h"
      30             : 
      31             : extern struct zclient *zclient;
      32             : 
      33             : #define PIM_MLAG_METADATA_LEN 4
      34             : 
      35             : /*********************ACtual Data processing *****************************/
      36             : /* TBD: There can be duplicate updates to FIB***/
      37             : #define PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil)                                    \
      38             :         do {                                                                   \
      39             :                 if (PIM_DEBUG_MLAG)                                            \
      40             :                         zlog_debug(                                            \
      41             :                                 "%s: add Dual-active Interface to %s "         \
      42             :                                 "to oil:%s",                                   \
      43             :                                 __func__, ch->interface->name, ch->sg_str);    \
      44             :                 pim_channel_update_oif_mute(ch_oil, ch->interface->info);      \
      45             :         } while (0)
      46             : 
      47             : #define PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil)                                    \
      48             :         do {                                                                   \
      49             :                 if (PIM_DEBUG_MLAG)                                            \
      50             :                         zlog_debug(                                            \
      51             :                                 "%s: del Dual-active Interface to %s "         \
      52             :                                 "to oil:%s",                                   \
      53             :                                 __func__, ch->interface->name, ch->sg_str);    \
      54             :                 pim_channel_update_oif_mute(ch_oil, ch->interface->info);      \
      55             :         } while (0)
      56             : 
      57             : 
      58           0 : static void pim_mlag_calculate_df_for_ifchannels(struct pim_upstream *up,
      59             :                                                  bool is_df)
      60             : {
      61           0 :         struct listnode *chnode;
      62           0 :         struct listnode *chnextnode;
      63           0 :         struct pim_ifchannel *ch;
      64           0 :         struct pim_interface *pim_ifp = NULL;
      65           0 :         struct channel_oil *ch_oil = NULL;
      66             : 
      67           0 :         ch_oil = (up) ? up->channel_oil : NULL;
      68             : 
      69           0 :         if (!ch_oil)
      70             :                 return;
      71             : 
      72           0 :         if (PIM_DEBUG_MLAG)
      73           0 :                 zlog_debug("%s: Calculating DF for Dual active if-channel%s",
      74             :                            __func__, up->sg_str);
      75             : 
      76           0 :         for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
      77           0 :                 pim_ifp = (ch->interface) ? ch->interface->info : NULL;
      78           0 :                 if (!pim_ifp || !PIM_I_am_DualActive(pim_ifp))
      79           0 :                         continue;
      80             : 
      81           0 :                 if (is_df)
      82           0 :                         PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil);
      83             :                 else
      84           0 :                         PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil);
      85             :         }
      86             : }
      87             : 
      88           0 : static void pim_mlag_inherit_mlag_flags(struct pim_upstream *up, bool is_df)
      89             : {
      90           0 :         struct listnode *listnode;
      91           0 :         struct pim_upstream *child;
      92           0 :         struct listnode *chnode;
      93           0 :         struct listnode *chnextnode;
      94           0 :         struct pim_ifchannel *ch;
      95           0 :         struct pim_interface *pim_ifp = NULL;
      96           0 :         struct channel_oil *ch_oil = NULL;
      97             : 
      98           0 :         if (PIM_DEBUG_MLAG)
      99           0 :                 zlog_debug("%s: Updating DF for uptream:%s children", __func__,
     100             :                            up->sg_str);
     101             : 
     102             : 
     103           0 :         for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) {
     104           0 :                 pim_ifp = (ch->interface) ? ch->interface->info : NULL;
     105           0 :                 if (!pim_ifp || !PIM_I_am_DualActive(pim_ifp))
     106           0 :                         continue;
     107             : 
     108           0 :                 for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, child)) {
     109           0 :                         if (PIM_DEBUG_MLAG)
     110           0 :                                 zlog_debug("%s: Updating DF for child:%s",
     111             :                                            __func__, child->sg_str);
     112           0 :                         ch_oil = (child) ? child->channel_oil : NULL;
     113             : 
     114           0 :                         if (!ch_oil)
     115           0 :                                 continue;
     116             : 
     117           0 :                         if (is_df)
     118           0 :                                 PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil);
     119             :                         else
     120           0 :                                 PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil);
     121             :                 }
     122             :         }
     123           0 : }
     124             : 
     125             : /******************************* pim upstream sync **************************/
     126             : /* Update DF role for the upstream entry and return true on role change */
     127           0 : bool pim_mlag_up_df_role_update(struct pim_instance *pim,
     128             :                 struct pim_upstream *up, bool is_df, const char *reason)
     129             : {
     130           0 :         struct channel_oil *c_oil = up->channel_oil;
     131           0 :         bool old_is_df = !PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags);
     132           0 :         struct pim_interface *vxlan_ifp;
     133             : 
     134           0 :         if (is_df == old_is_df) {
     135           0 :                 if (PIM_DEBUG_MLAG)
     136           0 :                         zlog_debug(
     137             :                                 "%s: Ignoring Role update for %s, since no change",
     138             :                                 __func__, up->sg_str);
     139           0 :                 return false;
     140             :         }
     141             : 
     142           0 :         if (PIM_DEBUG_MLAG)
     143           0 :                 zlog_debug("local MLAG mroute %s role changed to %s based on %s",
     144             :                                 up->sg_str, is_df ? "df" : "non-df", reason);
     145             : 
     146           0 :         if (is_df)
     147           0 :                 PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(up->flags);
     148             :         else
     149           0 :                 PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags);
     150             : 
     151             : 
     152             :         /*
     153             :          * This Upstream entry synced to peer Because of Dual-active
     154             :          * Interface configuration
     155             :          */
     156           0 :         if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) {
     157           0 :                 pim_mlag_inherit_mlag_flags(up, is_df);
     158           0 :                 pim_mlag_calculate_df_for_ifchannels(up, is_df);
     159             :         }
     160             : 
     161             :         /* If the DF role has changed check if ipmr-lo needs to be
     162             :          * muted/un-muted. Active-Active devices and vxlan termination
     163             :          * devices (ipmr-lo) are suppressed on the non-DF.
     164             :          * This may leave the mroute with the empty OIL in which case the
     165             :          * the forwarding entry's sole purpose is to just blackhole the flow
     166             :          * headed to the switch.
     167             :          */
     168           0 :         if (c_oil) {
     169           0 :                 vxlan_ifp = pim_vxlan_get_term_ifp(pim);
     170           0 :                 if (vxlan_ifp)
     171           0 :                         pim_channel_update_oif_mute(c_oil, vxlan_ifp);
     172             :         }
     173             : 
     174             :         /* If DF role changed on a (*,G) termination mroute update the
     175             :          * associated DF role on the inherited (S,G) entries
     176             :          */
     177           0 :         if (pim_addr_is_any(up->sg.src) &&
     178           0 :             PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags))
     179           0 :                 pim_vxlan_inherit_mlag_flags(pim, up, true /* inherit */);
     180             : 
     181             :         return true;
     182             : }
     183             : 
     184             : /* Run per-upstream entry DF election and return true on role change */
     185           0 : static bool pim_mlag_up_df_role_elect(struct pim_instance *pim,
     186             :                 struct pim_upstream *up)
     187             : {
     188           0 :         bool is_df;
     189           0 :         uint32_t peer_cost;
     190           0 :         uint32_t local_cost;
     191           0 :         bool rv;
     192             : 
     193           0 :         if (!pim_up_mlag_is_local(up))
     194             :                 return false;
     195             : 
     196             :         /* We are yet to rx a status update from the local MLAG daemon so
     197             :          * we will assume DF status.
     198             :          */
     199           0 :         if (!(router->mlag_flags & PIM_MLAGF_STATUS_RXED))
     200           0 :                 return pim_mlag_up_df_role_update(pim, up,
     201             :                                 true /*is_df*/, "mlagd-down");
     202             : 
     203             :         /* If not connected to peer assume DF role on the MLAG primary
     204             :          * switch (and non-DF on the secondary switch.
     205             :          */
     206           0 :         if (!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)) {
     207           0 :                 is_df = (router->mlag_role == MLAG_ROLE_PRIMARY) ? true : false;
     208           0 :                 return pim_mlag_up_df_role_update(pim, up,
     209             :                                 is_df, "peer-down");
     210             :         }
     211             : 
     212             :         /* If MLAG peer session is up but zebra is down on the peer
     213             :          * assume DF role.
     214             :          */
     215           0 :         if (!(router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP))
     216           0 :                 return pim_mlag_up_df_role_update(pim, up,
     217             :                                 true /*is_df*/, "zebra-down");
     218             : 
     219             :         /* If we are connected to peer switch but don't have a mroute
     220             :          * from it we have to assume non-DF role to avoid duplicates.
     221             :          * Note: When the peer connection comes up we wait for initial
     222             :          * replay to complete before moving "strays" i.e. local-mlag-mroutes
     223             :          * without a peer reference to non-df role.
     224             :          */
     225           0 :         if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags))
     226           0 :                 return pim_mlag_up_df_role_update(pim, up,
     227             :                                 false /*is_df*/, "no-peer-mroute");
     228             : 
     229             :         /* switch with the lowest RPF cost wins. if both switches have the same
     230             :          * cost MLAG role is used as a tie breaker (MLAG primary wins).
     231             :          */
     232           0 :         peer_cost = up->mlag.peer_mrib_metric;
     233           0 :         local_cost = pim_up_mlag_local_cost(up);
     234           0 :         if (local_cost == peer_cost) {
     235           0 :                 is_df = (router->mlag_role == MLAG_ROLE_PRIMARY) ? true : false;
     236           0 :                 rv = pim_mlag_up_df_role_update(pim, up, is_df, "equal-cost");
     237             :         } else {
     238           0 :                 is_df = (local_cost < peer_cost) ? true : false;
     239           0 :                 rv = pim_mlag_up_df_role_update(pim, up, is_df, "cost");
     240             :         }
     241             : 
     242             :         return rv;
     243             : }
     244             : 
     245             : /* Handle upstream entry add from the peer MLAG switch -
     246             :  * - if a local entry doesn't exist one is created with reference
     247             :  *   _MLAG_PEER
     248             :  * - if a local entry exists and has a MLAG OIF DF election is run.
     249             :  *   the non-DF switch stop forwarding traffic to MLAG devices.
     250             :  */
     251           0 : static void pim_mlag_up_peer_add(struct mlag_mroute_add *msg)
     252             : {
     253           0 :         struct pim_upstream *up;
     254           0 :         struct pim_instance *pim;
     255           0 :         int flags = 0;
     256           0 :         pim_sgaddr sg;
     257           0 :         struct vrf *vrf;
     258             : 
     259           0 :         memset(&sg, 0, sizeof(sg));
     260           0 :         sg.src.s_addr = htonl(msg->source_ip);
     261           0 :         sg.grp.s_addr = htonl(msg->group_ip);
     262             : 
     263           0 :         if (PIM_DEBUG_MLAG)
     264           0 :                 zlog_debug("peer MLAG mroute add %s:%pSG cost %d",
     265             :                            msg->vrf_name, &sg, msg->cost_to_rp);
     266             : 
     267             :         /* XXX - this is not correct. we MUST cache updates to avoid losing
     268             :          * an entry because of race conditions with the peer switch.
     269             :          */
     270           0 :         vrf = vrf_lookup_by_name(msg->vrf_name);
     271           0 :         if  (!vrf) {
     272           0 :                 if (PIM_DEBUG_MLAG)
     273           0 :                         zlog_debug(
     274             :                                 "peer MLAG mroute add failed %s:%pSG; no vrf",
     275             :                                 msg->vrf_name, &sg);
     276           0 :                 return;
     277             :         }
     278           0 :         pim = vrf->info;
     279             : 
     280           0 :         up = pim_upstream_find(pim, &sg);
     281           0 :         if (up) {
     282             :                 /* upstream already exists; create peer reference if it
     283             :                  * doesn't already exist.
     284             :                  */
     285           0 :                 if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags))
     286           0 :                         pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_MLAG_PEER,
     287             :                                          __func__);
     288             :         } else {
     289           0 :                 PIM_UPSTREAM_FLAG_SET_MLAG_PEER(flags);
     290           0 :                 up = pim_upstream_add(pim, &sg, NULL /*iif*/, flags, __func__,
     291             :                                       NULL /*if_ch*/);
     292             : 
     293           0 :                 if (!up) {
     294           0 :                         if (PIM_DEBUG_MLAG)
     295           0 :                                 zlog_debug(
     296             :                                         "peer MLAG mroute add failed %s:%pSG",
     297             :                                         vrf->name, &sg);
     298           0 :                         return;
     299             :                 }
     300             :         }
     301           0 :         up->mlag.peer_mrib_metric = msg->cost_to_rp;
     302           0 :         pim_mlag_up_df_role_elect(pim, up);
     303             : }
     304             : 
     305             : /* Handle upstream entry del from the peer MLAG switch -
     306             :  * - peer reference is removed. this can result in the upstream
     307             :  *   being deleted altogether.
     308             :  * - if a local entry continues to exisy and has a MLAG OIF DF election
     309             :  *   is re-run (at the end of which the local entry will be the DF).
     310             :  */
     311           0 : static struct pim_upstream *pim_mlag_up_peer_deref(struct pim_instance *pim,
     312             :                                                    struct pim_upstream *up)
     313             : {
     314           0 :         if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags))
     315             :                 return up;
     316             : 
     317           0 :         PIM_UPSTREAM_FLAG_UNSET_MLAG_PEER(up->flags);
     318           0 :         up = pim_upstream_del(pim, up, __func__);
     319           0 :         if (up)
     320           0 :                 pim_mlag_up_df_role_elect(pim, up);
     321             : 
     322             :         return up;
     323             : }
     324             : 
     325           0 : static void pim_mlag_up_peer_del(struct mlag_mroute_del *msg)
     326             : {
     327           0 :         struct pim_upstream *up;
     328           0 :         struct pim_instance *pim;
     329           0 :         pim_sgaddr sg;
     330           0 :         struct vrf *vrf;
     331             : 
     332           0 :         memset(&sg, 0, sizeof(sg));
     333           0 :         sg.src.s_addr = htonl(msg->source_ip);
     334           0 :         sg.grp.s_addr = htonl(msg->group_ip);
     335             : 
     336           0 :         if (PIM_DEBUG_MLAG)
     337           0 :                 zlog_debug("peer MLAG mroute del %s:%pSG", msg->vrf_name, &sg);
     338             : 
     339           0 :         vrf = vrf_lookup_by_name(msg->vrf_name);
     340           0 :         if  (!vrf) {
     341           0 :                 if (PIM_DEBUG_MLAG)
     342           0 :                         zlog_debug(
     343             :                                 "peer MLAG mroute del skipped %s:%pSG; no vrf",
     344             :                                 msg->vrf_name, &sg);
     345           0 :                 return;
     346             :         }
     347           0 :         pim = vrf->info;
     348             : 
     349           0 :         up = pim_upstream_find(pim, &sg);
     350           0 :         if  (!up) {
     351           0 :                 if (PIM_DEBUG_MLAG)
     352           0 :                         zlog_debug(
     353             :                                 "peer MLAG mroute del skipped %s:%pSG; no up",
     354             :                                 vrf->name, &sg);
     355           0 :                 return;
     356             :         }
     357             : 
     358           0 :         (void)pim_mlag_up_peer_deref(pim, up);
     359             : }
     360             : 
     361             : /* When we lose connection to the local MLAG daemon we can drop all peer
     362             :  * references.
     363             :  */
     364           0 : static void pim_mlag_up_peer_del_all(void)
     365             : {
     366           0 :         struct list *temp = list_new();
     367           0 :         struct pim_upstream *up;
     368           0 :         struct vrf *vrf;
     369           0 :         struct pim_instance *pim;
     370             : 
     371             :         /*
     372             :          * So why these gyrations?
     373             :          * pim->upstream_head has the list of *,G and S,G
     374             :          * that are in the system.  The problem of course
     375             :          * is that it is an ordered list:
     376             :          * (*,G1) -> (S1,G1) -> (S2,G2) -> (S3, G2) -> (*,G2) -> (S1,G2)
     377             :          * And the *,G1 has pointers to S1,G1 and S2,G1
     378             :          * if we delete *,G1 then we have a situation where
     379             :          * S1,G1 and S2,G2 can be deleted as well.  Then a
     380             :          * simple ALL_LIST_ELEMENTS will have the next listnode
     381             :          * pointer become invalid and we crash.
     382             :          * So let's grab the list of MLAG_PEER upstreams
     383             :          * add a refcount put on another list and delete safely
     384             :          */
     385           0 :         RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
     386           0 :                 pim = vrf->info;
     387           0 :                 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
     388           0 :                         if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags))
     389           0 :                                 continue;
     390           0 :                         listnode_add(temp, up);
     391             :                         /*
     392             :                          * Add a reference since we are adding to this
     393             :                          * list for deletion
     394             :                          */
     395           0 :                         up->ref_count++;
     396             :                 }
     397             : 
     398           0 :                 while (temp->count) {
     399           0 :                         up = listnode_head(temp);
     400           0 :                         listnode_delete(temp, up);
     401             : 
     402           0 :                         up = pim_mlag_up_peer_deref(pim, up);
     403             :                         /*
     404             :                          * This is the deletion of the reference added
     405             :                          * above
     406             :                          */
     407           0 :                         if (up)
     408           0 :                                 pim_upstream_del(pim, up, __func__);
     409             :                 }
     410             :         }
     411             : 
     412           0 :         list_delete(&temp);
     413           0 : }
     414             : 
     415             : /* Send upstream entry to the local MLAG daemon (which will subsequently
     416             :  * send it to the peer MLAG switch).
     417             :  */
     418           0 : static void pim_mlag_up_local_add_send(struct pim_instance *pim,
     419             :                 struct pim_upstream *up)
     420             : {
     421           0 :         struct stream *s = NULL;
     422           0 :         struct vrf *vrf = pim->vrf;
     423             : 
     424           0 :         if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP))
     425             :                 return;
     426             : 
     427           0 :         s = stream_new(sizeof(struct mlag_mroute_add) + PIM_MLAG_METADATA_LEN);
     428           0 :         if (!s)
     429             :                 return;
     430             : 
     431           0 :         if (PIM_DEBUG_MLAG)
     432           0 :                 zlog_debug("local MLAG mroute add %s:%s",
     433             :                                 vrf->name, up->sg_str);
     434             : 
     435           0 :         ++router->mlag_stats.msg.mroute_add_tx;
     436             : 
     437           0 :         stream_putl(s, MLAG_MROUTE_ADD);
     438           0 :         stream_put(s, vrf->name, VRF_NAMSIZ);
     439           0 :         stream_putl(s, ntohl(up->sg.src.s_addr));
     440           0 :         stream_putl(s, ntohl(up->sg.grp.s_addr));
     441             : 
     442           0 :         stream_putl(s, pim_up_mlag_local_cost(up));
     443             :         /* XXX - who is addding*/
     444           0 :         stream_putl(s, MLAG_OWNER_VXLAN);
     445             :         /* XXX - am_i_DR field should be removed */
     446           0 :         stream_putc(s, false);
     447           0 :         stream_putc(s, !(PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)));
     448           0 :         stream_putl(s, vrf->vrf_id);
     449             :         /* XXX - this field is a No-op for VXLAN*/
     450           0 :         stream_put(s, NULL, INTERFACE_NAMSIZ);
     451             : 
     452           0 :         stream_fifo_push_safe(router->mlag_fifo, s);
     453           0 :         pim_mlag_signal_zpthread();
     454             : }
     455             : 
     456           0 : static void pim_mlag_up_local_del_send(struct pim_instance *pim,
     457             :                 struct pim_upstream *up)
     458             : {
     459           0 :         struct stream *s = NULL;
     460           0 :         struct vrf *vrf = pim->vrf;
     461             : 
     462           0 :         if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP))
     463             :                 return;
     464             : 
     465           0 :         s = stream_new(sizeof(struct mlag_mroute_del) + PIM_MLAG_METADATA_LEN);
     466           0 :         if (!s)
     467             :                 return;
     468             : 
     469           0 :         if (PIM_DEBUG_MLAG)
     470           0 :                 zlog_debug("local MLAG mroute del %s:%s",
     471             :                                 vrf->name, up->sg_str);
     472             : 
     473           0 :         ++router->mlag_stats.msg.mroute_del_tx;
     474             : 
     475           0 :         stream_putl(s, MLAG_MROUTE_DEL);
     476           0 :         stream_put(s, vrf->name, VRF_NAMSIZ);
     477           0 :         stream_putl(s, ntohl(up->sg.src.s_addr));
     478           0 :         stream_putl(s, ntohl(up->sg.grp.s_addr));
     479             :         /* XXX - who is adding */
     480           0 :         stream_putl(s, MLAG_OWNER_VXLAN);
     481           0 :         stream_putl(s, vrf->vrf_id);
     482             :         /* XXX - this field is a No-op for VXLAN */
     483           0 :         stream_put(s, NULL, INTERFACE_NAMSIZ);
     484             : 
     485             :         /* XXX - is this the the most optimal way to do things */
     486           0 :         stream_fifo_push_safe(router->mlag_fifo, s);
     487           0 :         pim_mlag_signal_zpthread();
     488             : }
     489             : 
     490             : 
     491             : /* Called when a local upstream entry is created or if it's cost changes */
     492           0 : void pim_mlag_up_local_add(struct pim_instance *pim,
     493             :                 struct pim_upstream *up)
     494             : {
     495           0 :         pim_mlag_up_df_role_elect(pim, up);
     496             :         /* XXX - need to add some dup checks here */
     497           0 :         pim_mlag_up_local_add_send(pim, up);
     498           0 : }
     499             : 
     500             : /* Called when local MLAG reference is removed from an upstream entry */
     501           0 : void pim_mlag_up_local_del(struct pim_instance *pim,
     502             :                 struct pim_upstream *up)
     503             : {
     504           0 :         pim_mlag_up_df_role_elect(pim, up);
     505           0 :         pim_mlag_up_local_del_send(pim, up);
     506           0 : }
     507             : 
     508             : /* When connection to local MLAG daemon is established all the local
     509             :  * MLAG upstream entries are replayed to it.
     510             :  */
     511           0 : static void pim_mlag_up_local_replay(void)
     512             : {
     513           0 :         struct pim_upstream *up;
     514           0 :         struct vrf *vrf;
     515           0 :         struct pim_instance *pim;
     516             : 
     517           0 :         RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
     518           0 :                 pim = vrf->info;
     519           0 :                 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
     520           0 :                         if (pim_up_mlag_is_local(up))
     521           0 :                                 pim_mlag_up_local_add_send(pim, up);
     522             :                 }
     523             :         }
     524           0 : }
     525             : 
     526             : /* on local/peer mlag connection and role changes the DF status needs
     527             :  * to be re-evaluated
     528             :  */
     529           0 : static void pim_mlag_up_local_reeval(bool mlagd_send, const char *reason_code)
     530             : {
     531           0 :         struct pim_upstream *up;
     532           0 :         struct vrf *vrf;
     533           0 :         struct pim_instance *pim;
     534             : 
     535           0 :         if (PIM_DEBUG_MLAG)
     536           0 :                 zlog_debug("%s re-run DF election because of %s",
     537             :                                 __func__, reason_code);
     538           0 :         RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
     539           0 :                 pim = vrf->info;
     540           0 :                 frr_each (rb_pim_upstream, &pim->upstream_head, up) {
     541           0 :                         if (!pim_up_mlag_is_local(up))
     542           0 :                                 continue;
     543             :                         /* if role changes re-send to peer */
     544           0 :                         if (pim_mlag_up_df_role_elect(pim, up) &&
     545             :                                         mlagd_send)
     546           0 :                                 pim_mlag_up_local_add_send(pim, up);
     547             :                 }
     548             :         }
     549           0 : }
     550             : 
     551             : /*****************PIM Actions for MLAG state changes**********************/
     552             : 
     553             : /* notify the anycast VTEP component about state changes */
     554           0 : static inline void pim_mlag_vxlan_state_update(void)
     555             : {
     556           0 :         bool enable = !!(router->mlag_flags & PIM_MLAGF_STATUS_RXED);
     557           0 :         bool peer_state = !!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP);
     558             : 
     559           0 :         pim_vxlan_mlag_update(enable, peer_state, router->mlag_role,
     560             :                         router->peerlink_rif_p, &router->local_vtep_ip);
     561             : 
     562           0 : }
     563             : 
     564             : /**************End of PIM Actions for MLAG State changes******************/
     565             : 
     566             : 
     567             : /********************API to process PIM MLAG Data ************************/
     568             : 
     569           0 : static void pim_mlag_process_mlagd_state_change(struct mlag_status msg)
     570             : {
     571           0 :         bool role_chg = false;
     572           0 :         bool state_chg = false;
     573           0 :         bool notify_vxlan = false;
     574           0 :         struct interface *peerlink_rif_p;
     575           0 :         char buf[MLAG_ROLE_STRSIZE];
     576             : 
     577           0 :         if (PIM_DEBUG_MLAG)
     578           0 :                 zlog_debug("%s: msg dump: my_role: %s, peer_state: %s",
     579             :                            __func__,
     580             :                            mlag_role2str(msg.my_role, buf, sizeof(buf)),
     581             :                            (msg.peer_state == MLAG_STATE_RUNNING ? "RUNNING"
     582             :                                                                  : "DOWN"));
     583             : 
     584           0 :         if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) {
     585           0 :                 if (PIM_DEBUG_MLAG)
     586           0 :                         zlog_debug("%s: msg ignored mlagd process state down",
     587             :                                         __func__);
     588           0 :                 return;
     589             :         }
     590           0 :         ++router->mlag_stats.msg.mlag_status_updates;
     591             : 
     592             :         /* evaluate the changes first */
     593           0 :         if (router->mlag_role != msg.my_role) {
     594           0 :                 role_chg = true;
     595           0 :                 notify_vxlan = true;
     596           0 :                 router->mlag_role = msg.my_role;
     597             :         }
     598             : 
     599           0 :         strlcpy(router->peerlink_rif, msg.peerlink_rif,
     600             :                 sizeof(router->peerlink_rif));
     601             : 
     602             :         /* XXX - handle the case where we may rx the interface name from the
     603             :          * MLAG daemon before we get the interface from zebra.
     604             :          */
     605           0 :         peerlink_rif_p = if_lookup_by_name(router->peerlink_rif, VRF_DEFAULT);
     606           0 :         if (router->peerlink_rif_p != peerlink_rif_p) {
     607           0 :                 router->peerlink_rif_p = peerlink_rif_p;
     608           0 :                 notify_vxlan = true;
     609             :         }
     610             : 
     611           0 :         if (msg.peer_state == MLAG_STATE_RUNNING) {
     612           0 :                 if (!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)) {
     613           0 :                         state_chg = true;
     614           0 :                         notify_vxlan = true;
     615           0 :                         router->mlag_flags |= PIM_MLAGF_PEER_CONN_UP;
     616             :                 }
     617           0 :                 router->connected_to_mlag = true;
     618             :         } else {
     619           0 :                 if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP) {
     620           0 :                         ++router->mlag_stats.peer_session_downs;
     621           0 :                         state_chg = true;
     622           0 :                         notify_vxlan = true;
     623           0 :                         router->mlag_flags &= ~PIM_MLAGF_PEER_CONN_UP;
     624             :                 }
     625           0 :                 router->connected_to_mlag = false;
     626             :         }
     627             : 
     628             :         /* apply the changes */
     629             :         /* when connection to mlagd comes up we hold send mroutes till we have
     630             :          * rxed the status and had a chance to re-valuate DF state
     631             :          */
     632           0 :         if (!(router->mlag_flags & PIM_MLAGF_STATUS_RXED)) {
     633           0 :                 router->mlag_flags |= PIM_MLAGF_STATUS_RXED;
     634           0 :                 pim_mlag_vxlan_state_update();
     635             :                 /* on session up re-eval DF status */
     636           0 :                 pim_mlag_up_local_reeval(false /*mlagd_send*/, "mlagd_up");
     637             :                 /* replay all the upstream entries to the local MLAG daemon */
     638           0 :                 pim_mlag_up_local_replay();
     639           0 :                 return;
     640             :         }
     641             : 
     642           0 :         if (notify_vxlan)
     643           0 :                 pim_mlag_vxlan_state_update();
     644             : 
     645           0 :         if (state_chg) {
     646           0 :                 if (!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP))
     647             :                         /* when a connection goes down the primary takes over
     648             :                          * DF role for all entries
     649             :                          */
     650           0 :                         pim_mlag_up_local_reeval(true /*mlagd_send*/,
     651             :                                         "peer_down");
     652             :                 else
     653             :                         /* XXX - when session comes up we need to wait for
     654             :                          * PEER_REPLAY_DONE before running re-election on
     655             :                          * local-mlag entries that are missing peer reference
     656             :                          */
     657           0 :                         pim_mlag_up_local_reeval(true /*mlagd_send*/,
     658             :                                         "peer_up");
     659           0 :         } else if (role_chg) {
     660             :                 /* MLAG role changed without a state change */
     661           0 :                 pim_mlag_up_local_reeval(true /*mlagd_send*/, "role_chg");
     662             :         }
     663             : }
     664             : 
     665           0 : static void pim_mlag_process_peer_frr_state_change(struct mlag_frr_status msg)
     666             : {
     667           0 :         if (PIM_DEBUG_MLAG)
     668           0 :                 zlog_debug(
     669             :                         "%s: msg dump: peer_frr_state: %s", __func__,
     670             :                         (msg.frr_state == MLAG_FRR_STATE_UP ? "UP" : "DOWN"));
     671             : 
     672           0 :         if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) {
     673           0 :                 if (PIM_DEBUG_MLAG)
     674           0 :                         zlog_debug("%s: msg ignored mlagd process state down",
     675             :                                         __func__);
     676           0 :                 return;
     677             :         }
     678           0 :         ++router->mlag_stats.msg.peer_zebra_status_updates;
     679             : 
     680             :         /* evaluate the changes first */
     681           0 :         if (msg.frr_state == MLAG_FRR_STATE_UP) {
     682           0 :                 if (!(router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)) {
     683           0 :                         router->mlag_flags |= PIM_MLAGF_PEER_ZEBRA_UP;
     684             :                         /* XXX - when peer zebra comes up we need to wait for
     685             :                          * for some time to let the peer setup MDTs before
     686             :                          * before relinquishing DF status
     687             :                          */
     688           0 :                         pim_mlag_up_local_reeval(true /*mlagd_send*/,
     689             :                                         "zebra_up");
     690             :                 }
     691             :         } else {
     692           0 :                 if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP) {
     693           0 :                         ++router->mlag_stats.peer_zebra_downs;
     694           0 :                         router->mlag_flags &= ~PIM_MLAGF_PEER_ZEBRA_UP;
     695             :                         /* when a peer zebra goes down we assume DF role */
     696           0 :                         pim_mlag_up_local_reeval(true /*mlagd_send*/,
     697             :                                         "zebra_down");
     698             :                 }
     699             :         }
     700             : }
     701             : 
     702           0 : static void pim_mlag_process_vxlan_update(struct mlag_vxlan *msg)
     703             : {
     704           0 :         char addr_buf1[INET_ADDRSTRLEN];
     705           0 :         char addr_buf2[INET_ADDRSTRLEN];
     706           0 :         uint32_t local_ip;
     707             : 
     708           0 :         if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) {
     709           0 :                 if (PIM_DEBUG_MLAG)
     710           0 :                         zlog_debug("%s: msg ignored mlagd process state down",
     711             :                                         __func__);
     712           0 :                 return;
     713             :         }
     714             : 
     715           0 :         ++router->mlag_stats.msg.vxlan_updates;
     716           0 :         router->anycast_vtep_ip.s_addr = htonl(msg->anycast_ip);
     717           0 :         local_ip = htonl(msg->local_ip);
     718           0 :         if (router->local_vtep_ip.s_addr != local_ip) {
     719           0 :                 router->local_vtep_ip.s_addr = local_ip;
     720           0 :                 pim_mlag_vxlan_state_update();
     721             :         }
     722             : 
     723           0 :         if (PIM_DEBUG_MLAG) {
     724           0 :                 inet_ntop(AF_INET, &router->local_vtep_ip,
     725             :                                 addr_buf1, INET_ADDRSTRLEN);
     726           0 :                 inet_ntop(AF_INET, &router->anycast_vtep_ip,
     727             :                                 addr_buf2, INET_ADDRSTRLEN);
     728             : 
     729           0 :                 zlog_debug("%s: msg dump: local-ip:%s, anycast-ip:%s",
     730             :                                 __func__, addr_buf1, addr_buf2);
     731             :         }
     732             : }
     733             : 
     734           0 : static void pim_mlag_process_mroute_add(struct mlag_mroute_add msg)
     735             : {
     736           0 :         if (PIM_DEBUG_MLAG) {
     737           0 :                 pim_sgaddr sg;
     738             : 
     739           0 :                 sg.grp.s_addr = ntohl(msg.group_ip);
     740           0 :                 sg.src.s_addr = ntohl(msg.source_ip);
     741             : 
     742           0 :                 zlog_debug(
     743             :                         "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x (%pSG) cost: %u",
     744             :                         __func__, msg.vrf_name, msg.source_ip, msg.group_ip,
     745             :                         &sg, msg.cost_to_rp);
     746           0 :                 zlog_debug(
     747             :                         "(%pSG)owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s",
     748             :                         &sg, msg.owner_id, msg.am_i_dr, msg.am_i_dual_active,
     749             :                         msg.vrf_id, msg.intf_name);
     750             :         }
     751             : 
     752           0 :         if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) {
     753           0 :                 if (PIM_DEBUG_MLAG)
     754           0 :                         zlog_debug("%s: msg ignored mlagd process state down",
     755             :                                         __func__);
     756           0 :                 return;
     757             :         }
     758             : 
     759           0 :         ++router->mlag_stats.msg.mroute_add_rx;
     760             : 
     761           0 :         pim_mlag_up_peer_add(&msg);
     762             : }
     763             : 
     764           0 : static void pim_mlag_process_mroute_del(struct mlag_mroute_del msg)
     765             : {
     766           0 :         if (PIM_DEBUG_MLAG) {
     767           0 :                 pim_sgaddr sg;
     768             : 
     769           0 :                 sg.grp.s_addr = ntohl(msg.group_ip);
     770           0 :                 sg.src.s_addr = ntohl(msg.source_ip);
     771           0 :                 zlog_debug(
     772             :                         "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x(%pSG)",
     773             :                         __func__, msg.vrf_name, msg.source_ip, msg.group_ip,
     774             :                         &sg);
     775           0 :                 zlog_debug("(%pSG)owner_id: %d, vrf_id: 0x%x intf_name: %s",
     776             :                            &sg, msg.owner_id, msg.vrf_id, msg.intf_name);
     777             :         }
     778             : 
     779           0 :         if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) {
     780           0 :                 if (PIM_DEBUG_MLAG)
     781           0 :                         zlog_debug("%s: msg ignored mlagd process state down",
     782             :                                         __func__);
     783           0 :                 return;
     784             :         }
     785             : 
     786           0 :         ++router->mlag_stats.msg.mroute_del_rx;
     787             : 
     788           0 :         pim_mlag_up_peer_del(&msg);
     789             : }
     790             : 
     791           0 : int pim_zebra_mlag_handle_msg(int cmd, struct zclient *zclient,
     792             :                               uint16_t zapi_length, vrf_id_t vrf_id)
     793             : {
     794           0 :         struct stream *s = zclient->ibuf;
     795           0 :         struct mlag_msg mlag_msg;
     796           0 :         char buf[80];
     797           0 :         int rc = 0;
     798           0 :         size_t length;
     799             : 
     800           0 :         rc = mlag_lib_decode_mlag_hdr(s, &mlag_msg, &length);
     801           0 :         if (rc)
     802             :                 return (rc);
     803             : 
     804           0 :         if (PIM_DEBUG_MLAG)
     805           0 :                 zlog_debug("%s: Received msg type: %s length: %d, bulk_cnt: %d",
     806             :                            __func__,
     807             :                            mlag_lib_msgid_to_str(mlag_msg.msg_type, buf,
     808             :                                                  sizeof(buf)),
     809             :                            mlag_msg.data_len, mlag_msg.msg_cnt);
     810             : 
     811           0 :         switch (mlag_msg.msg_type) {
     812           0 :         case MLAG_STATUS_UPDATE: {
     813           0 :                 struct mlag_status msg;
     814             : 
     815           0 :                 rc = mlag_lib_decode_mlag_status(s, &msg);
     816           0 :                 if (rc)
     817           0 :                         return (rc);
     818           0 :                 pim_mlag_process_mlagd_state_change(msg);
     819           0 :         } break;
     820           0 :         case MLAG_PEER_FRR_STATUS: {
     821           0 :                 struct mlag_frr_status msg;
     822             : 
     823           0 :                 rc = mlag_lib_decode_frr_status(s, &msg);
     824           0 :                 if (rc)
     825           0 :                         return (rc);
     826           0 :                 pim_mlag_process_peer_frr_state_change(msg);
     827           0 :         } break;
     828           0 :         case MLAG_VXLAN_UPDATE: {
     829           0 :                 struct mlag_vxlan msg;
     830             : 
     831           0 :                 rc = mlag_lib_decode_vxlan_update(s, &msg);
     832           0 :                 if (rc)
     833           0 :                         return rc;
     834           0 :                 pim_mlag_process_vxlan_update(&msg);
     835           0 :         } break;
     836           0 :         case MLAG_MROUTE_ADD: {
     837           0 :                 struct mlag_mroute_add msg;
     838             : 
     839           0 :                 rc = mlag_lib_decode_mroute_add(s, &msg, &length);
     840           0 :                 if (rc)
     841           0 :                         return (rc);
     842           0 :                 pim_mlag_process_mroute_add(msg);
     843           0 :         } break;
     844           0 :         case MLAG_MROUTE_DEL: {
     845           0 :                 struct mlag_mroute_del msg;
     846             : 
     847           0 :                 rc = mlag_lib_decode_mroute_del(s, &msg, &length);
     848           0 :                 if (rc)
     849           0 :                         return (rc);
     850           0 :                 pim_mlag_process_mroute_del(msg);
     851           0 :         } break;
     852             :         case MLAG_MROUTE_ADD_BULK: {
     853             :                 struct mlag_mroute_add msg;
     854             :                 int i;
     855             : 
     856           0 :                 for (i = 0; i < mlag_msg.msg_cnt; i++) {
     857           0 :                         rc = mlag_lib_decode_mroute_add(s, &msg, &length);
     858           0 :                         if (rc)
     859           0 :                                 return (rc);
     860           0 :                         pim_mlag_process_mroute_add(msg);
     861             :                 }
     862           0 :         } break;
     863             :         case MLAG_MROUTE_DEL_BULK: {
     864             :                 struct mlag_mroute_del msg;
     865             :                 int i;
     866             : 
     867           0 :                 for (i = 0; i < mlag_msg.msg_cnt; i++) {
     868           0 :                         rc = mlag_lib_decode_mroute_del(s, &msg, &length);
     869           0 :                         if (rc)
     870           0 :                                 return (rc);
     871           0 :                         pim_mlag_process_mroute_del(msg);
     872             :                 }
     873           0 :         } break;
     874             :         case MLAG_MSG_NONE:
     875             :         case MLAG_REGISTER:
     876             :         case MLAG_DEREGISTER:
     877             :         case MLAG_DUMP:
     878             :         case MLAG_PIM_CFG_DUMP:
     879             :                 break;
     880             :         }
     881             :         return 0;
     882             : }
     883             : 
     884             : /****************End of PIM Mesasge processing handler********************/
     885             : 
     886           0 : int pim_zebra_mlag_process_up(ZAPI_CALLBACK_ARGS)
     887             : {
     888           0 :         if (PIM_DEBUG_MLAG)
     889           0 :                 zlog_debug("%s: Received Process-Up from Mlag", __func__);
     890             : 
     891             :         /*
     892             :          * Incase of local MLAG restart, PIM needs to replay all the data
     893             :          * since MLAG is empty.
     894             :          */
     895           0 :         router->connected_to_mlag = true;
     896           0 :         router->mlag_flags |= PIM_MLAGF_LOCAL_CONN_UP;
     897           0 :         return 0;
     898             : }
     899             : 
     900          18 : static void pim_mlag_param_reset(void)
     901             : {
     902             :         /* reset the cached params and stats */
     903          18 :         router->mlag_flags &= ~(PIM_MLAGF_STATUS_RXED |
     904             :                         PIM_MLAGF_LOCAL_CONN_UP |
     905             :                         PIM_MLAGF_PEER_CONN_UP |
     906             :                         PIM_MLAGF_PEER_ZEBRA_UP);
     907          18 :         router->local_vtep_ip.s_addr = INADDR_ANY;
     908          18 :         router->anycast_vtep_ip.s_addr = INADDR_ANY;
     909          18 :         router->mlag_role = MLAG_ROLE_NONE;
     910          18 :         memset(&router->mlag_stats.msg, 0, sizeof(router->mlag_stats.msg));
     911          18 :         router->peerlink_rif[0] = '\0';
     912          18 : }
     913             : 
     914           0 : int pim_zebra_mlag_process_down(ZAPI_CALLBACK_ARGS)
     915             : {
     916           0 :         if (PIM_DEBUG_MLAG)
     917           0 :                 zlog_debug("%s: Received Process-Down from Mlag", __func__);
     918             : 
     919             :         /* Local CLAG is down, reset peer data and forward the traffic if
     920             :          * we are DR
     921             :          */
     922           0 :         if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)
     923           0 :                 ++router->mlag_stats.peer_session_downs;
     924           0 :         if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)
     925           0 :                 ++router->mlag_stats.peer_zebra_downs;
     926           0 :         router->connected_to_mlag = false;
     927           0 :         pim_mlag_param_reset();
     928             :         /* on mlagd session down re-eval DF status */
     929           0 :         pim_mlag_up_local_reeval(false /*mlagd_send*/, "mlagd_down");
     930             :         /* flush all peer references */
     931           0 :         pim_mlag_up_peer_del_all();
     932             :         /* notify the vxlan component */
     933           0 :         pim_mlag_vxlan_state_update();
     934           0 :         return 0;
     935             : }
     936             : 
     937           0 : static void pim_mlag_register_handler(struct thread *thread)
     938             : {
     939           0 :         uint32_t bit_mask = 0;
     940             : 
     941           0 :         if (!zclient)
     942             :                 return;
     943             : 
     944           0 :         SET_FLAG(bit_mask, (1 << MLAG_STATUS_UPDATE));
     945           0 :         SET_FLAG(bit_mask, (1 << MLAG_MROUTE_ADD));
     946           0 :         SET_FLAG(bit_mask, (1 << MLAG_MROUTE_DEL));
     947           0 :         SET_FLAG(bit_mask, (1 << MLAG_DUMP));
     948           0 :         SET_FLAG(bit_mask, (1 << MLAG_MROUTE_ADD_BULK));
     949           0 :         SET_FLAG(bit_mask, (1 << MLAG_MROUTE_DEL_BULK));
     950           0 :         SET_FLAG(bit_mask, (1 << MLAG_PIM_CFG_DUMP));
     951           0 :         SET_FLAG(bit_mask, (1 << MLAG_VXLAN_UPDATE));
     952           0 :         SET_FLAG(bit_mask, (1 << MLAG_PEER_FRR_STATUS));
     953             : 
     954           0 :         if (PIM_DEBUG_MLAG)
     955           0 :                 zlog_debug("%s: Posting Client Register to MLAG mask: 0x%x",
     956             :                            __func__, bit_mask);
     957             : 
     958           0 :         zclient_send_mlag_register(zclient, bit_mask);
     959             : }
     960             : 
     961           0 : void pim_mlag_register(void)
     962             : {
     963           0 :         if (router->mlag_process_register)
     964             :                 return;
     965             : 
     966           0 :         router->mlag_process_register = true;
     967             : 
     968           0 :         thread_add_event(router->master, pim_mlag_register_handler, NULL, 0,
     969             :                          NULL);
     970             : }
     971             : 
     972           0 : static void pim_mlag_deregister_handler(struct thread *thread)
     973             : {
     974           0 :         if (!zclient)
     975             :                 return;
     976             : 
     977           0 :         if (PIM_DEBUG_MLAG)
     978           0 :                 zlog_debug("%s: Posting Client De-Register to MLAG from PIM",
     979             :                            __func__);
     980           0 :         router->connected_to_mlag = false;
     981           0 :         zclient_send_mlag_deregister(zclient);
     982             : }
     983             : 
     984           0 : void pim_mlag_deregister(void)
     985             : {
     986             :         /* if somebody still interested in the MLAG channel skip de-reg */
     987           0 :         if (router->pim_mlag_intf_cnt || pim_vxlan_do_mlag_reg())
     988           0 :                 return;
     989             : 
     990             :         /* not registered; nothing do */
     991           0 :         if (!router->mlag_process_register)
     992             :                 return;
     993             : 
     994           0 :         router->mlag_process_register = false;
     995             : 
     996           0 :         thread_add_event(router->master, pim_mlag_deregister_handler, NULL, 0,
     997             :                          NULL);
     998             : }
     999             : 
    1000           0 : void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp)
    1001             : {
    1002           0 :         if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == true)
    1003             :                 return;
    1004             : 
    1005           0 :         if (PIM_DEBUG_MLAG)
    1006           0 :                 zlog_debug("%s: Configuring active-active on Interface: %s",
    1007             :                            __func__, "NULL");
    1008             : 
    1009           0 :         pim_ifp->activeactive = true;
    1010           0 :         if (pim_ifp->pim)
    1011           0 :                 pim_ifp->pim->inst_mlag_intf_cnt++;
    1012             : 
    1013           0 :         router->pim_mlag_intf_cnt++;
    1014           0 :         if (PIM_DEBUG_MLAG)
    1015           0 :                 zlog_debug(
    1016             :                         "%s: Total MLAG configured Interfaces on router: %d, Inst: %d",
    1017             :                         __func__, router->pim_mlag_intf_cnt,
    1018             :                         pim_ifp->pim->inst_mlag_intf_cnt);
    1019             : 
    1020           0 :         if (router->pim_mlag_intf_cnt == 1) {
    1021             :                 /*
    1022             :                  * at least one Interface is configured for MLAG, send register
    1023             :                  * to Zebra for receiving MLAG Updates
    1024             :                  */
    1025           0 :                 pim_mlag_register();
    1026             :         }
    1027             : }
    1028             : 
    1029           0 : void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp)
    1030             : {
    1031           0 :         if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == false)
    1032             :                 return;
    1033             : 
    1034           0 :         if (PIM_DEBUG_MLAG)
    1035           0 :                 zlog_debug("%s: UnConfiguring active-active on Interface: %s",
    1036             :                            __func__, "NULL");
    1037             : 
    1038           0 :         pim_ifp->activeactive = false;
    1039           0 :         pim_ifp->pim->inst_mlag_intf_cnt--;
    1040             : 
    1041           0 :         router->pim_mlag_intf_cnt--;
    1042           0 :         if (PIM_DEBUG_MLAG)
    1043           0 :                 zlog_debug(
    1044             :                         "%s: Total MLAG configured Interfaces on router: %d, Inst: %d",
    1045             :                         __func__, router->pim_mlag_intf_cnt,
    1046             :                         pim_ifp->pim->inst_mlag_intf_cnt);
    1047             : 
    1048           0 :         if (router->pim_mlag_intf_cnt == 0) {
    1049             :                 /*
    1050             :                  * all the Interfaces are MLAG un-configured, post MLAG
    1051             :                  * De-register to Zebra
    1052             :                  */
    1053           0 :                 pim_mlag_deregister();
    1054           0 :                 pim_mlag_param_reset();
    1055             :         }
    1056             : }
    1057             : 
    1058             : 
    1059          18 : void pim_instance_mlag_init(struct pim_instance *pim)
    1060             : {
    1061          18 :         if (!pim)
    1062             :                 return;
    1063             : 
    1064          18 :         pim->inst_mlag_intf_cnt = 0;
    1065             : }
    1066             : 
    1067             : 
    1068          18 : void pim_instance_mlag_terminate(struct pim_instance *pim)
    1069             : {
    1070          18 :         struct interface *ifp;
    1071             : 
    1072          18 :         if (!pim)
    1073             :                 return;
    1074             : 
    1075          96 :         FOR_ALL_INTERFACES (pim->vrf, ifp) {
    1076          60 :                 struct pim_interface *pim_ifp = ifp->info;
    1077             : 
    1078          60 :                 if (!pim_ifp || pim_ifp->activeactive == false)
    1079          60 :                         continue;
    1080             : 
    1081           0 :                 pim_if_unconfigure_mlag_dualactive(pim_ifp);
    1082             :         }
    1083          18 :         pim->inst_mlag_intf_cnt = 0;
    1084             : }
    1085             : 
    1086          18 : void pim_mlag_terminate(void)
    1087             : {
    1088          18 :         stream_free(router->mlag_stream);
    1089          18 :         router->mlag_stream = NULL;
    1090          18 :         stream_fifo_free(router->mlag_fifo);
    1091          18 :         router->mlag_fifo = NULL;
    1092          18 : }
    1093             : 
    1094          18 : void pim_mlag_init(void)
    1095             : {
    1096          18 :         pim_mlag_param_reset();
    1097          18 :         router->pim_mlag_intf_cnt = 0;
    1098          18 :         router->connected_to_mlag = false;
    1099          18 :         router->mlag_fifo = stream_fifo_new();
    1100          18 :         router->zpthread_mlag_write = NULL;
    1101          18 :         router->mlag_stream = stream_new(MLAG_BUF_LIMIT);
    1102          18 : }

Generated by: LCOV version v1.16-topotato