back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_evpn_mh.c (source / functions) Hit Total Coverage
Test: test_demo.py::AllStartupTest Lines: 74 1982 3.7 %
Date: 2023-02-24 18:37:51 Functions: 21 168 12.5 %

          Line data    Source code
       1             : /*
       2             :  * Zebra EVPN multihoming code
       3             :  *
       4             :  * Copyright (C) 2019 Cumulus Networks, Inc.
       5             :  * Anuradha Karuppiah
       6             :  *
       7             :  * This file is part of FRR.
       8             :  *
       9             :  * FRR is free software; you can redistribute it and/or modify it
      10             :  * under the terms of the GNU General Public License as published by the
      11             :  * Free Software Foundation; either version 2, or (at your option) any
      12             :  * later version.
      13             :  *
      14             :  * FRR is distributed in the hope that it will be useful, but
      15             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * General Public License for more details.
      18             :  */
      19             : 
      20             : #include <zebra.h>
      21             : 
      22             : #include "command.h"
      23             : #include "hash.h"
      24             : #include "if.h"
      25             : #include "jhash.h"
      26             : #include "linklist.h"
      27             : #include "log.h"
      28             : #include "memory.h"
      29             : #include "prefix.h"
      30             : #include "stream.h"
      31             : #include "table.h"
      32             : #include "vlan.h"
      33             : #include "vxlan.h"
      34             : 
      35             : #include "zebra/zebra_router.h"
      36             : #include "zebra/debug.h"
      37             : #include "zebra/interface.h"
      38             : #include "zebra/rib.h"
      39             : #include "zebra/rt.h"
      40             : #include "zebra/rt_netlink.h"
      41             : #include "zebra/if_netlink.h"
      42             : #include "zebra/zebra_errors.h"
      43             : #include "zebra/zebra_l2.h"
      44             : #include "zebra/zebra_ns.h"
      45             : #include "zebra/zebra_vrf.h"
      46             : #include "zebra/zebra_vxlan.h"
      47             : #include "zebra/zebra_evpn.h"
      48             : #include "zebra/zebra_evpn_mac.h"
      49             : #include "zebra/zebra_vxlan_private.h"
      50             : #include "zebra/zebra_router.h"
      51             : #include "zebra/zebra_evpn_mh.h"
      52             : #include "zebra/zebra_nhg.h"
      53             : 
      54           3 : DEFINE_MTYPE_STATIC(ZEBRA, ZACC_BD, "Access Broadcast Domain");
      55           3 : DEFINE_MTYPE_STATIC(ZEBRA, ZES, "Ethernet Segment");
      56           3 : DEFINE_MTYPE_STATIC(ZEBRA, ZES_EVI, "ES info per-EVI");
      57           3 : DEFINE_MTYPE_STATIC(ZEBRA, ZMH_INFO, "MH global info");
      58           3 : DEFINE_MTYPE_STATIC(ZEBRA, ZES_VTEP, "VTEP attached to the ES");
      59           3 : DEFINE_MTYPE_STATIC(ZEBRA, L2_NH, "L2 nexthop");
      60             : 
      61             : static void zebra_evpn_es_get_one_base_evpn(void);
      62             : static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
      63             :                                             struct zebra_evpn *zevpn, bool add);
      64             : static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp);
      65             : static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi);
      66             : static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
      67             :                                                 const char *caller);
      68             : static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set);
      69             : static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
      70             :                                               bool resync_dplane);
      71             : static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es);
      72             : static void zebra_evpn_mh_startup_delay_timer_start(const char *rc);
      73             : 
      74             : esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
      75             : 
      76             : /*****************************************************************************/
      77             : /* Ethernet Segment to EVI association -
      78             :  * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
      79             :  * (struct zebra_evpn.es_evi_rb_tree).
      80             :  * 2. Each local ES-EVI entry is sent to BGP which advertises it as an
      81             :  * EAD-EVI (Type-1 EVPN) route
      82             :  * 3. Local ES-EVI setup is re-evaluated on the following triggers -
      83             :  *    a. When an ESI is set or cleared on an access port.
      84             :  *    b. When an access port associated with an ESI is deleted.
      85             :  *    c. When VLAN member ship changes on an access port.
      86             :  *    d. When a VXLAN_IF is set or cleared on an access broadcast domain.
      87             :  *    e. When a L2-VNI is added or deleted for a VxLAN_IF.
      88             :  * 4. Currently zebra doesn't remote ES-EVIs. Those are managed and maintained
      89             :  * entirely in BGP which consolidates them into a remote ES. The remote ES
      90             :  * is then sent to zebra which allocates a NHG for it.
      91             :  */
      92             : 
      93             : /* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
      94           0 : static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi *es_evi1,
      95             :                 const struct zebra_evpn_es_evi *es_evi2)
      96             : {
      97           0 :         return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
      98             : }
      99           0 : RB_GENERATE(zebra_es_evi_rb_head, zebra_evpn_es_evi,
     100             :                 rb_node, zebra_es_evi_rb_cmp);
     101             : 
     102             : /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
     103             :  * tables.
     104             :  */
     105           0 : static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es,
     106             :                                                        struct zebra_evpn *zevpn)
     107             : {
     108           0 :         struct zebra_evpn_es_evi *es_evi;
     109             : 
     110           0 :         es_evi = XCALLOC(MTYPE_ZES_EVI, sizeof(struct zebra_evpn_es_evi));
     111             : 
     112           0 :         es_evi->es = es;
     113           0 :         es_evi->zevpn = zevpn;
     114             : 
     115             :         /* insert into the EVPN-ESI rb tree */
     116           0 :         RB_INSERT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi);
     117             : 
     118             :         /* add to the ES's VNI list */
     119           0 :         listnode_init(&es_evi->es_listnode, es_evi);
     120           0 :         listnode_add(es->es_evi_list, &es_evi->es_listnode);
     121             : 
     122           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     123           0 :                 zlog_debug("es %s evi %d new",
     124             :                                 es_evi->es->esi_str, es_evi->zevpn->vni);
     125             : 
     126           0 :         return es_evi;
     127             : }
     128             : 
     129             : /* Evaluate if the es_evi is ready to be sent BGP -
     130             :  * 1. If it is ready an add is sent to BGP
     131             :  * 2. If it is not ready a del is sent (if the ES had been previously added
     132             :  *   to BGP).
     133             :  */
     134           0 : static void zebra_evpn_es_evi_re_eval_send_to_client(
     135             :                 struct zebra_evpn_es_evi *es_evi)
     136             : {
     137           0 :         bool old_ready;
     138           0 :         bool new_ready;
     139             : 
     140           0 :         old_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
     141             : 
     142             :         /* ES and L2-VNI have to be individually ready for BGP */
     143           0 :         if ((es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) &&
     144           0 :                         (es_evi->es->flags & ZEBRA_EVPNES_READY_FOR_BGP) &&
     145           0 :                         zebra_evpn_send_to_client_ok(es_evi->zevpn))
     146           0 :                 es_evi->flags |= ZEBRA_EVPNES_EVI_READY_FOR_BGP;
     147             :         else
     148           0 :                 es_evi->flags &= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP;
     149             : 
     150           0 :         new_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
     151             : 
     152           0 :         if (old_ready == new_ready)
     153             :                 return;
     154             : 
     155           0 :         if (new_ready)
     156           0 :                 zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
     157             :                                 true /* add */);
     158             :         else
     159           0 :                 zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
     160             :                                 false /* add */);
     161             : }
     162             : 
     163             : /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
     164             :  * up the memory.
     165             :  */
     166           0 : static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi *es_evi)
     167             : {
     168           0 :         struct zebra_evpn_es *es = es_evi->es;
     169           0 :         struct zebra_evpn *zevpn = es_evi->zevpn;
     170             : 
     171           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     172           0 :                 zlog_debug("es %s evi %d free",
     173             :                                 es_evi->es->esi_str, es_evi->zevpn->vni);
     174             : 
     175             :         /* remove from the ES's VNI list */
     176           0 :         list_delete_node(es->es_evi_list, &es_evi->es_listnode);
     177             : 
     178             :         /* remove from the VNI-ESI rb tree */
     179           0 :         RB_REMOVE(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi);
     180             : 
     181             :         /* remove from the VNI-ESI rb tree */
     182           0 :         XFREE(MTYPE_ZES_EVI, es_evi);
     183           0 : }
     184             : 
     185             : /* find the ES-EVI in the per-L2-VNI RB tree */
     186           0 : struct zebra_evpn_es_evi *zebra_evpn_es_evi_find(struct zebra_evpn_es *es,
     187             :                                                  struct zebra_evpn *zevpn)
     188             : {
     189           0 :         struct zebra_evpn_es_evi es_evi;
     190             : 
     191           0 :         es_evi.es = es;
     192             : 
     193           0 :         return RB_FIND(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, &es_evi);
     194             : }
     195             : 
     196             : /* Tell BGP about an ES-EVI deletion and then delete it */
     197           0 : static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi *es_evi)
     198             : {
     199           0 :         if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
     200             :                 return;
     201             : 
     202           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     203           0 :                 zlog_debug("local es %s evi %d del",
     204             :                                 es_evi->es->esi_str, es_evi->zevpn->vni);
     205             : 
     206           0 :         if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP) {
     207             :                 /* send a del only if add was sent for it earlier */
     208           0 :                 zebra_evpn_es_evi_send_to_client(es_evi->es,
     209             :                                 es_evi->zevpn, false /* add */);
     210             :         }
     211             : 
     212             :         /* delete it from the EVPN's local list */
     213           0 :         list_delete_node(es_evi->zevpn->local_es_evi_list,
     214             :                         &es_evi->l2vni_listnode);
     215             : 
     216           0 :         es_evi->flags &= ~ZEBRA_EVPNES_EVI_LOCAL;
     217           0 :         zebra_evpn_es_evi_free(es_evi);
     218             : }
     219           0 : static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es *es,
     220             :                                         struct zebra_evpn *zevpn)
     221             : {
     222           0 :         struct zebra_evpn_es_evi *es_evi;
     223             : 
     224           0 :         es_evi = zebra_evpn_es_evi_find(es, zevpn);
     225           0 :         if (es_evi)
     226           0 :                 zebra_evpn_local_es_evi_do_del(es_evi);
     227           0 : }
     228             : 
     229             : /* If there are any existing MAC entries for this es/zevpn we need
     230             :  * to install it in the dataplane.
     231             :  *
     232             :  * Note: primary purpose of this is to handle es del/re-add windows where
     233             :  * sync MAC entries may be added by bgpd before the es-evi membership is
     234             :  * created in the dataplane and in zebra
     235             :  */
     236           0 : static void zebra_evpn_es_evi_mac_install(struct zebra_evpn_es_evi *es_evi)
     237             : {
     238           0 :         struct zebra_mac *mac;
     239           0 :         struct listnode *node;
     240           0 :         struct zebra_evpn_es *es = es_evi->es;
     241             : 
     242           0 :         if (listcount(es->mac_list) && IS_ZEBRA_DEBUG_EVPN_MH_ES)
     243           0 :                 zlog_debug("dp-mac install on es %s evi %d add", es->esi_str,
     244             :                            es_evi->zevpn->vni);
     245             : 
     246           0 :         for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
     247           0 :                 if (mac->zevpn != es_evi->zevpn)
     248           0 :                         continue;
     249             : 
     250           0 :                 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
     251           0 :                         continue;
     252             : 
     253           0 :                 zebra_evpn_sync_mac_dp_install(mac, false, false, __func__);
     254             :         }
     255           0 : }
     256             : 
     257             : /* Create an ES-EVI if it doesn't already exist and tell BGP */
     258           0 : static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es,
     259             :                                         struct zebra_evpn *zevpn)
     260             : {
     261           0 :         struct zebra_evpn_es_evi *es_evi;
     262             : 
     263           0 :         es_evi = zebra_evpn_es_evi_find(es, zevpn);
     264           0 :         if (!es_evi) {
     265           0 :                 es_evi = zebra_evpn_es_evi_new(es, zevpn);
     266           0 :                 if (!es_evi)
     267             :                         return;
     268             : 
     269           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     270           0 :                         zlog_debug("local es %s evi %d add",
     271             :                                         es_evi->es->esi_str, es_evi->zevpn->vni);
     272           0 :                 es_evi->flags |= ZEBRA_EVPNES_EVI_LOCAL;
     273             :                 /* add to the EVPN's local list */
     274           0 :                 listnode_init(&es_evi->l2vni_listnode, es_evi);
     275           0 :                 listnode_add(zevpn->local_es_evi_list, &es_evi->l2vni_listnode);
     276             : 
     277           0 :                 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
     278             : 
     279           0 :                 zebra_evpn_es_evi_mac_install(es_evi);
     280             :         }
     281             : }
     282             : 
     283           0 : static void zebra_evpn_es_evi_show_entry(struct vty *vty,
     284             :                                          struct zebra_evpn_es_evi *es_evi,
     285             :                                          json_object *json_array)
     286             : {
     287           0 :         char type_str[4];
     288             : 
     289           0 :         if (json_array) {
     290           0 :                 json_object *json;
     291           0 :                 json_object *json_types;
     292             : 
     293             :                 /* Separate JSON object for each es-evi entry */
     294           0 :                 json = json_object_new_object();
     295             : 
     296           0 :                 json_object_string_add(json, "esi", es_evi->es->esi_str);
     297           0 :                 json_object_int_add(json, "vni", es_evi->zevpn->vni);
     298           0 :                 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) {
     299           0 :                         json_types = json_object_new_array();
     300           0 :                         if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
     301           0 :                                 json_array_string_add(json_types, "local");
     302           0 :                         json_object_object_add(json, "type", json_types);
     303             :                 }
     304             : 
     305             :                 /* Add es-evi entry to json array */
     306           0 :                 json_object_array_add(json_array, json);
     307             :         } else {
     308           0 :                 type_str[0] = '\0';
     309           0 :                 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
     310           0 :                         strlcat(type_str, "L", sizeof(type_str));
     311             : 
     312           0 :                 vty_out(vty, "%-8d %-30s %-4s\n",
     313           0 :                                 es_evi->zevpn->vni, es_evi->es->esi_str,
     314             :                                 type_str);
     315             :         }
     316           0 : }
     317             : 
     318             : static void
     319           0 : zebra_evpn_es_evi_show_entry_detail(struct vty *vty,
     320             :                                     struct zebra_evpn_es_evi *es_evi,
     321             :                                     json_object *json_array)
     322             : {
     323           0 :         char type_str[4];
     324             : 
     325           0 :         if (json_array) {
     326           0 :                 json_object *json;
     327           0 :                 json_object *json_flags;
     328             : 
     329             :                 /* Separate JSON object for each es-evi entry */
     330           0 :                 json = json_object_new_object();
     331             : 
     332           0 :                 json_object_string_add(json, "esi", es_evi->es->esi_str);
     333           0 :                 json_object_int_add(json, "vni", es_evi->zevpn->vni);
     334           0 :                 if (es_evi->flags
     335           0 :                     & (ZEBRA_EVPNES_EVI_LOCAL
     336             :                        | ZEBRA_EVPNES_EVI_READY_FOR_BGP)) {
     337           0 :                         json_flags = json_object_new_array();
     338           0 :                         if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
     339           0 :                                 json_array_string_add(json_flags, "local");
     340           0 :                         if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP)
     341           0 :                                 json_array_string_add(json_flags,
     342             :                                                       "readyForBgp");
     343           0 :                         json_object_object_add(json, "flags", json_flags);
     344             :                 }
     345             : 
     346             :                 /* Add es-evi entry to json array */
     347           0 :                 json_object_array_add(json_array, json);
     348             :         } else {
     349           0 :                 type_str[0] = '\0';
     350           0 :                 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
     351           0 :                         strlcat(type_str, "L", sizeof(type_str));
     352             : 
     353           0 :                 vty_out(vty, "VNI %d ESI: %s\n",
     354           0 :                                 es_evi->zevpn->vni, es_evi->es->esi_str);
     355           0 :                 vty_out(vty, " Type: %s\n", type_str);
     356           0 :                 vty_out(vty, " Ready for BGP: %s\n",
     357           0 :                                 (es_evi->flags &
     358             :                                  ZEBRA_EVPNES_EVI_READY_FOR_BGP) ?
     359             :                                 "yes" : "no");
     360           0 :                 vty_out(vty, "\n");
     361             :         }
     362           0 : }
     363             : 
     364           0 : static void zebra_evpn_es_evi_show_one_evpn(struct zebra_evpn *zevpn,
     365             :                                             struct vty *vty,
     366             :                                             json_object *json_array, int detail)
     367             : {
     368           0 :         struct zebra_evpn_es_evi *es_evi;
     369             : 
     370           0 :         RB_FOREACH(es_evi, zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree) {
     371           0 :                 if (detail)
     372           0 :                         zebra_evpn_es_evi_show_entry_detail(vty, es_evi,
     373             :                                                             json_array);
     374             :                 else
     375           0 :                         zebra_evpn_es_evi_show_entry(vty, es_evi, json_array);
     376             :         }
     377           0 : }
     378             : 
     379             : struct evpn_mh_show_ctx {
     380             :         struct vty *vty;
     381             :         json_object *json;
     382             :         int detail;
     383             : };
     384             : 
     385           0 : static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket *bucket,
     386             :                 void *ctxt)
     387             : {
     388           0 :         struct zebra_evpn *zevpn = (struct zebra_evpn *)bucket->data;
     389           0 :         struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
     390             : 
     391           0 :         zebra_evpn_es_evi_show_one_evpn(zevpn, wctx->vty,
     392             :                         wctx->json, wctx->detail);
     393           0 : }
     394             : 
     395           0 : void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail)
     396             : {
     397           0 :         json_object *json_array = NULL;
     398           0 :         struct zebra_vrf *zvrf;
     399           0 :         struct evpn_mh_show_ctx wctx;
     400             : 
     401           0 :         zvrf = zebra_vrf_get_evpn();
     402           0 :         if (uj)
     403           0 :                 json_array = json_object_new_array();
     404             : 
     405           0 :         memset(&wctx, 0, sizeof(wctx));
     406           0 :         wctx.vty = vty;
     407           0 :         wctx.json = json_array;
     408           0 :         wctx.detail = detail;
     409             : 
     410           0 :         if (!detail && !json_array) {
     411           0 :                 vty_out(vty, "Type: L local, R remote\n");
     412           0 :                 vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
     413             :         }
     414             :         /* Display all L2-VNIs */
     415           0 :         hash_iterate(zvrf->evpn_table, zebra_evpn_es_evi_show_one_evpn_hash_cb,
     416             :                         &wctx);
     417             : 
     418           0 :         if (uj)
     419           0 :                 vty_json(vty, json_array);
     420           0 : }
     421             : 
     422           0 : void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
     423             : {
     424           0 :         json_object *json_array = NULL;
     425           0 :         struct zebra_evpn *zevpn;
     426             : 
     427           0 :         zevpn = zebra_evpn_lookup(vni);
     428           0 :         if (uj)
     429           0 :                 json_array = json_object_new_array();
     430             : 
     431           0 :         if (zevpn) {
     432           0 :                 if (!detail && !json_array) {
     433           0 :                         vty_out(vty, "Type: L local, R remote\n");
     434           0 :                         vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
     435             :                 }
     436           0 :                 zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
     437             :         } else {
     438           0 :                 if (!uj)
     439           0 :                         vty_out(vty, "VNI %d doesn't exist\n", vni);
     440             :         }
     441             : 
     442           0 :         if (uj)
     443           0 :                 vty_json(vty, json_array);
     444           0 : }
     445             : 
     446             : /* Initialize the ES tables maintained per-L2_VNI */
     447           0 : void zebra_evpn_es_evi_init(struct zebra_evpn *zevpn)
     448             : {
     449             :         /* Initialize the ES-EVI RB tree */
     450           0 :         RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree);
     451             : 
     452             :         /* Initialize the local and remote ES lists maintained for quick
     453             :          * walks by type
     454             :          */
     455           0 :         zevpn->local_es_evi_list = list_new();
     456           0 :         listset_app_node_mem(zevpn->local_es_evi_list);
     457           0 : }
     458             : 
     459             : /* Cleanup the ES info maintained per- EVPN */
     460           0 : void zebra_evpn_es_evi_cleanup(struct zebra_evpn *zevpn)
     461             : {
     462           0 :         struct zebra_evpn_es_evi *es_evi;
     463           0 :         struct zebra_evpn_es_evi *es_evi_next;
     464             : 
     465           0 :         RB_FOREACH_SAFE(es_evi, zebra_es_evi_rb_head,
     466             :                         &zevpn->es_evi_rb_tree, es_evi_next) {
     467           0 :                 zebra_evpn_local_es_evi_do_del(es_evi);
     468             :         }
     469             : 
     470           0 :         list_delete(&zevpn->local_es_evi_list);
     471           0 :         zebra_evpn_es_clear_base_evpn(zevpn);
     472           0 : }
     473             : 
     474             : /* called when the oper state or bridge membership changes for the
     475             :  * vxlan device
     476             :  */
     477           0 : void zebra_evpn_update_all_es(struct zebra_evpn *zevpn)
     478             : {
     479           0 :         struct zebra_evpn_es_evi *es_evi;
     480           0 :         struct listnode *node;
     481           0 :         struct interface *vlan_if;
     482           0 :         struct interface *vxlan_if;
     483           0 :         struct zebra_if *vxlan_zif;
     484             : 
     485             :         /* the EVPN is now elgible as a base for EVPN-MH */
     486           0 :         if (zebra_evpn_send_to_client_ok(zevpn))
     487           0 :                 zebra_evpn_es_set_base_evpn(zevpn);
     488             :         else
     489           0 :                 zebra_evpn_es_clear_base_evpn(zevpn);
     490             : 
     491           0 :         for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi))
     492           0 :                 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
     493             : 
     494             :         /* reinstall SVI MAC */
     495           0 :         vxlan_if = zevpn->vxlan_if;
     496           0 :         if (vxlan_if) {
     497           0 :                 vxlan_zif = vxlan_if->info;
     498           0 :                 if (if_is_operative(vxlan_if)
     499           0 :                     && vxlan_zif->brslave_info.br_if) {
     500           0 :                         vlan_if = zvni_map_to_svi(
     501           0 :                                 vxlan_zif->l2info.vxl.access_vlan,
     502             :                                 vxlan_zif->brslave_info.br_if);
     503           0 :                         if (vlan_if)
     504           0 :                                 zebra_evpn_acc_bd_svi_mac_add(vlan_if);
     505             :                 }
     506             :         }
     507           0 : }
     508             : 
     509             : /*****************************************************************************/
     510             : /* Access broadcast domains (BD)
     511             :  * 1. These broadcast domains can be VLAN aware (in which case
     512             :  * the key is VID) or VLAN unaware (in which case the key is
     513             :  * 2. A VID-BD is created when a VLAN is associated with an access port or
     514             :  *    when the VLAN is associated with VXLAN_IF
     515             :  * 3. A BD is translated into ES-EVI entries when a VNI is associated
     516             :  *  with the broadcast domain
     517             :  */
     518             : /* Hash key for VLAN based broadcast domains */
     519           0 : static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
     520             : {
     521           0 :         const struct zebra_evpn_access_bd *acc_bd = p;
     522             : 
     523           0 :         return jhash_1word(acc_bd->vid, 0);
     524             : }
     525             : 
     526             : /* Compare two VLAN based broadcast domains */
     527           0 : static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
     528             : {
     529           0 :         const struct zebra_evpn_access_bd *acc_bd1 = p1;
     530           0 :         const struct zebra_evpn_access_bd *acc_bd2 = p2;
     531             : 
     532           0 :         if (acc_bd1 == NULL && acc_bd2 == NULL)
     533             :                 return true;
     534             : 
     535           0 :         if (acc_bd1 == NULL || acc_bd2 == NULL)
     536             :                 return false;
     537             : 
     538           0 :         return (acc_bd1->vid == acc_bd2->vid);
     539             : }
     540             : 
     541             : /* Lookup VLAN based broadcast domain */
     542           0 : static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
     543             : {
     544           0 :         struct zebra_evpn_access_bd *acc_bd;
     545           0 :         struct zebra_evpn_access_bd tmp;
     546             : 
     547           0 :         tmp.vid = vid;
     548           0 :         acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
     549             : 
     550           0 :         return acc_bd;
     551             : }
     552             : 
     553             : /* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
     554             :  * mapping is added.
     555             :  */
     556             : static struct zebra_evpn_access_bd *
     557           0 : zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
     558             : {
     559           0 :         struct zebra_evpn_access_bd *acc_bd;
     560           0 :         struct interface *vlan_if;
     561             : 
     562           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     563           0 :                 zlog_debug("access vlan %d add", vid);
     564             : 
     565           0 :         acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
     566             : 
     567           0 :         acc_bd->vid = vid;
     568             : 
     569             :         /* Initialize the mbr list */
     570           0 :         acc_bd->mbr_zifs = list_new();
     571             : 
     572             :         /* Add to hash */
     573           0 :         (void)hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern);
     574             : 
     575             :         /* check if an svi exists for the vlan */
     576           0 :         if (br_if) {
     577           0 :                 vlan_if = zvni_map_to_svi(vid, br_if);
     578           0 :                 if (vlan_if) {
     579           0 :                         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     580           0 :                                 zlog_debug("vlan %d SVI %s set", vid,
     581             :                                            vlan_if->name);
     582           0 :                         acc_bd->vlan_zif = vlan_if->info;
     583             :                 }
     584             :         }
     585           0 :         return acc_bd;
     586             : }
     587             : 
     588             : /* Free VLAN based broadcast domain -
     589             :  * This just frees appropriate memory, caller should have taken other
     590             :  * needed actions.
     591             :  */
     592           0 : static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd *acc_bd)
     593             : {
     594           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     595           0 :                 zlog_debug("access vlan %d del", acc_bd->vid);
     596             : 
     597           0 :         if (acc_bd->vlan_zif && acc_bd->zevpn && acc_bd->zevpn->mac_table)
     598           0 :                 zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
     599             : 
     600             :         /* cleanup resources maintained against the ES */
     601           0 :         list_delete(&acc_bd->mbr_zifs);
     602             : 
     603             :         /* remove EVI from various tables */
     604           0 :         hash_release(zmh_info->evpn_vlan_table, acc_bd);
     605             : 
     606           0 :         XFREE(MTYPE_ZACC_BD, acc_bd);
     607           0 : }
     608             : 
     609           0 : static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket *bucket, void *arg)
     610             : {
     611           0 :         struct zebra_evpn_access_bd *acc_bd = bucket->data;
     612             : 
     613           0 :         zebra_evpn_acc_vl_free(acc_bd);
     614           0 : }
     615             : 
     616             : /* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
     617             :  * VLAN
     618             :  */
     619           0 : static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
     620             : {
     621           0 :         if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
     622             :                 return;
     623             : 
     624             :         /* if there are no references free the EVI */
     625           0 :         zebra_evpn_acc_vl_free(acc_bd);
     626             : }
     627             : 
     628             : /* called when a SVI is goes up/down */
     629           0 : void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
     630             :                                struct zebra_if *br_zif, bool is_up)
     631             : {
     632           0 :         struct zebra_evpn_access_bd *acc_bd;
     633           0 :         struct zebra_l2info_bridge *br;
     634           0 :         uint16_t vid;
     635           0 :         struct zebra_if *tmp_br_zif = br_zif;
     636             : 
     637           0 :         if (!tmp_br_zif) {
     638           0 :                 if (!vlan_zif->link || !vlan_zif->link->info)
     639             :                         return;
     640             : 
     641             :                 tmp_br_zif = vlan_zif->link->info;
     642             :         }
     643             : 
     644           0 :         br = &tmp_br_zif->l2info.br;
     645             :         /* ignore vlan unaware bridges */
     646           0 :         if (!br->vlan_aware)
     647             :                 return;
     648             : 
     649           0 :         vid = vlan_zif->l2info.vl.vid;
     650           0 :         acc_bd = zebra_evpn_acc_vl_find(vid);
     651           0 :         if (!acc_bd)
     652             :                 return;
     653             : 
     654           0 :         if (is_up) {
     655           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     656           0 :                         zlog_debug("vlan %d SVI %s set", vid,
     657             :                                    vlan_zif->ifp->name);
     658             : 
     659           0 :                 acc_bd->vlan_zif = vlan_zif;
     660           0 :                 if (acc_bd->zevpn)
     661           0 :                         zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
     662             :                                                acc_bd->zevpn);
     663           0 :         } else if (acc_bd->vlan_zif) {
     664           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     665           0 :                         zlog_debug("vlan %d SVI clear", vid);
     666           0 :                 acc_bd->vlan_zif = NULL;
     667           0 :                 if (acc_bd->zevpn && acc_bd->zevpn->mac_table)
     668           0 :                         zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn);
     669             :         }
     670             : }
     671             : 
     672             : /* On some events macs are force-flushed. This api can be used to reinstate
     673             :  * the svi-mac after such cleanup-events.
     674             :  */
     675           0 : void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if)
     676             : {
     677           0 :         zebra_evpn_acc_bd_svi_set(vlan_if->info, NULL,
     678           0 :                                   if_is_operative(vlan_if));
     679           0 : }
     680             : 
     681             : /* called when a EVPN-L2VNI is set or cleared against a BD */
     682           0 : static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
     683             :                                        struct zebra_evpn *zevpn,
     684             :                                        struct zebra_evpn *old_zevpn)
     685             : {
     686           0 :         struct zebra_if *zif;
     687           0 :         struct listnode *node;
     688             : 
     689           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     690           0 :                 zlog_debug("access vlan %d l2-vni %u set",
     691             :                                 acc_bd->vid, zevpn ? zevpn->vni : 0);
     692             : 
     693           0 :         for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
     694           0 :                 if (!zif->es_info.es)
     695           0 :                         continue;
     696             : 
     697           0 :                 if (zevpn)
     698           0 :                         zebra_evpn_local_es_evi_add(zif->es_info.es, zevpn);
     699           0 :                 else if (old_zevpn)
     700           0 :                         zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn);
     701             :         }
     702             : 
     703           0 :         if (acc_bd->vlan_zif) {
     704           0 :                 if (zevpn)
     705           0 :                         zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
     706             :                                                acc_bd->zevpn);
     707           0 :                 else if (old_zevpn && old_zevpn->mac_table)
     708           0 :                         zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp,
     709             :                                                old_zevpn);
     710             :         }
     711           0 : }
     712             : 
     713             : /* handle VLAN->VxLAN_IF association */
     714           0 : void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
     715             : {
     716           0 :         struct zebra_evpn_access_bd *acc_bd;
     717           0 :         struct zebra_if *old_vxlan_zif;
     718           0 :         struct zebra_evpn *old_zevpn;
     719             : 
     720           0 :         if (!vid)
     721             :                 return;
     722             : 
     723           0 :         acc_bd = zebra_evpn_acc_vl_find(vid);
     724           0 :         if (!acc_bd)
     725           0 :                 acc_bd = zebra_evpn_acc_vl_new(vid,
     726             :                                                vxlan_zif->brslave_info.br_if);
     727             : 
     728           0 :         old_vxlan_zif = acc_bd->vxlan_zif;
     729           0 :         acc_bd->vxlan_zif = vxlan_zif;
     730           0 :         if (vxlan_zif == old_vxlan_zif)
     731             :                 return;
     732             : 
     733           0 :         old_zevpn = acc_bd->zevpn;
     734           0 :         acc_bd->zevpn = zebra_evpn_lookup(vxlan_zif->l2info.vxl.vni);
     735           0 :         if (acc_bd->zevpn == old_zevpn)
     736             :                 return;
     737             : 
     738           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     739           0 :                 zlog_debug("access vlan %d vni %u ref",
     740             :                                 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
     741             : 
     742           0 :         if (old_zevpn)
     743           0 :                 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
     744             : 
     745           0 :         if (acc_bd->zevpn)
     746           0 :                 zebra_evpn_acc_bd_evpn_set(acc_bd, acc_bd->zevpn, NULL);
     747             : }
     748             : 
     749             : /* handle VLAN->VxLAN_IF deref */
     750           0 : void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
     751             : {
     752           0 :         struct zebra_evpn_access_bd *acc_bd;
     753             : 
     754           0 :         if (!vid)
     755             :                 return;
     756             : 
     757           0 :         acc_bd = zebra_evpn_acc_vl_find(vid);
     758           0 :         if (!acc_bd)
     759             :                 return;
     760             : 
     761             :         /* clear vxlan_if only if it matches */
     762           0 :         if (acc_bd->vxlan_zif != vxlan_zif)
     763             :                 return;
     764             : 
     765           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     766           0 :                 zlog_debug("access vlan %d vni %u deref",
     767             :                                 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
     768             : 
     769           0 :         if (acc_bd->zevpn)
     770           0 :                 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
     771             : 
     772           0 :         acc_bd->zevpn = NULL;
     773           0 :         acc_bd->vxlan_zif = NULL;
     774             : 
     775             :         /* if there are no other references the access_bd can be freed */
     776           0 :         zebra_evpn_acc_bd_free_on_deref(acc_bd);
     777             : }
     778             : 
     779             : /* handle EVPN add/del */
     780           0 : void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
     781             :                              bool set)
     782             : {
     783           0 :         struct zebra_l2info_vxlan *vxl;
     784           0 :         struct zebra_evpn_access_bd *acc_bd;
     785             : 
     786           0 :         if (!zif)
     787             :                 return;
     788             : 
     789             :         /* locate access_bd associated with the vxlan device */
     790           0 :         vxl = &zif->l2info.vxl;
     791           0 :         acc_bd = zebra_evpn_acc_vl_find(vxl->access_vlan);
     792           0 :         if (!acc_bd)
     793             :                 return;
     794             : 
     795           0 :         if (set) {
     796           0 :                 zebra_evpn_es_set_base_evpn(zevpn);
     797           0 :                 if (acc_bd->zevpn != zevpn) {
     798           0 :                         acc_bd->zevpn = zevpn;
     799           0 :                         zebra_evpn_acc_bd_evpn_set(acc_bd, zevpn, NULL);
     800             :                 }
     801             :         } else {
     802           0 :                 if (acc_bd->zevpn) {
     803           0 :                         struct zebra_evpn *old_zevpn = acc_bd->zevpn;
     804           0 :                         acc_bd->zevpn = NULL;
     805           0 :                         zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
     806             :                 }
     807             :         }
     808             : }
     809             : 
     810             : /* handle addition of new VLAN members */
     811           0 : void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
     812             : {
     813           0 :         struct zebra_evpn_access_bd *acc_bd;
     814             : 
     815           0 :         if (!vid)
     816             :                 return;
     817             : 
     818           0 :         acc_bd = zebra_evpn_acc_vl_find(vid);
     819           0 :         if (!acc_bd)
     820           0 :                 acc_bd = zebra_evpn_acc_vl_new(vid, zif->brslave_info.br_if);
     821             : 
     822           0 :         if (listnode_lookup(acc_bd->mbr_zifs, zif))
     823             :                 return;
     824             : 
     825           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     826           0 :                 zlog_debug("access vlan %d mbr %s ref",
     827             :                                 vid, zif->ifp->name);
     828             : 
     829           0 :         listnode_add(acc_bd->mbr_zifs, zif);
     830           0 :         if (acc_bd->zevpn && zif->es_info.es)
     831           0 :                 zebra_evpn_local_es_evi_add(zif->es_info.es, acc_bd->zevpn);
     832             : }
     833             : 
     834             : /* handle deletion of VLAN members */
     835           0 : void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
     836             : {
     837           0 :         struct zebra_evpn_access_bd *acc_bd;
     838           0 :         struct listnode *node;
     839             : 
     840           0 :         if (!vid)
     841             :                 return;
     842             : 
     843           0 :         acc_bd = zebra_evpn_acc_vl_find(vid);
     844           0 :         if (!acc_bd)
     845             :                 return;
     846             : 
     847           0 :         node = listnode_lookup(acc_bd->mbr_zifs, zif);
     848           0 :         if (!node)
     849             :                 return;
     850             : 
     851           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
     852           0 :                 zlog_debug("access vlan %d mbr %s deref",
     853             :                                 vid, zif->ifp->name);
     854             : 
     855           0 :         list_delete_node(acc_bd->mbr_zifs, node);
     856             : 
     857           0 :         if (acc_bd->zevpn && zif->es_info.es)
     858           0 :                 zebra_evpn_local_es_evi_del(zif->es_info.es, acc_bd->zevpn);
     859             : 
     860             :         /* if there are no other references the access_bd can be freed */
     861           0 :         zebra_evpn_acc_bd_free_on_deref(acc_bd);
     862             : }
     863             : 
     864           0 : static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket *bucket,
     865             :                                              void *ctxt)
     866             : {
     867           0 :         struct zebra_evpn_access_bd *acc_bd = bucket->data;
     868             : 
     869           0 :         if (acc_bd->vlan_zif && acc_bd->zevpn)
     870           0 :                 zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
     871           0 : }
     872             : 
     873             : /* called when advertise SVI MAC is enabled on the switch */
     874           0 : static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
     875             : {
     876           0 :         hash_iterate(zmh_info->evpn_vlan_table,
     877             :                      zebra_evpn_acc_vl_adv_svi_mac_cb, NULL);
     878           0 : }
     879             : 
     880           0 : static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd *acc_bd,
     881             :                                         json_object *json, bool detail)
     882             : {
     883           0 :         json_object_int_add(json, "vlan", acc_bd->vid);
     884           0 :         if (acc_bd->vxlan_zif)
     885           0 :                 json_object_string_add(json, "vxlanIf",
     886           0 :                                        acc_bd->vxlan_zif->ifp->name);
     887           0 :         if (acc_bd->zevpn)
     888           0 :                 json_object_int_add(json, "vni", acc_bd->zevpn->vni);
     889           0 :         if (acc_bd->mbr_zifs)
     890           0 :                 json_object_int_add(json, "memberIfCount",
     891           0 :                                     listcount(acc_bd->mbr_zifs));
     892             : 
     893           0 :         if (detail) {
     894           0 :                 json_object *json_mbrs;
     895           0 :                 json_object *json_mbr;
     896           0 :                 struct zebra_if *zif;
     897           0 :                 struct listnode *node;
     898             : 
     899             : 
     900           0 :                 json_mbrs = json_object_new_array();
     901           0 :                 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
     902           0 :                         json_mbr = json_object_new_object();
     903           0 :                         json_object_string_add(json_mbr, "ifName",
     904           0 :                                                zif->ifp->name);
     905           0 :                         json_object_array_add(json_mbrs, json_mbr);
     906             :                 }
     907           0 :                 json_object_object_add(json, "members", json_mbrs);
     908             :         }
     909           0 : }
     910             : 
     911           0 : static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
     912             :                 struct zebra_evpn_access_bd *acc_bd, json_object *json)
     913             : {
     914           0 :         struct zebra_if *zif;
     915           0 :         struct listnode *node;
     916             : 
     917           0 :         if (json) {
     918           0 :                 zebra_evpn_acc_vl_json_fill(acc_bd, json, true);
     919             :         } else {
     920           0 :                 vty_out(vty, "VLAN: %u\n", acc_bd->vid);
     921           0 :                 vty_out(vty, " VxLAN Interface: %s\n",
     922           0 :                                 acc_bd->vxlan_zif ?
     923           0 :                                 acc_bd->vxlan_zif->ifp->name : "-");
     924           0 :                 vty_out(vty, " SVI: %s\n",
     925           0 :                         acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-");
     926           0 :                 vty_out(vty, " L2-VNI: %d\n",
     927           0 :                                 acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
     928           0 :                 vty_out(vty, " Member Count: %d\n",
     929           0 :                                 listcount(acc_bd->mbr_zifs));
     930           0 :                 vty_out(vty, " Members: \n");
     931           0 :                 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif))
     932           0 :                         vty_out(vty, "    %s\n", zif->ifp->name);
     933           0 :                 vty_out(vty, "\n");
     934             :         }
     935           0 : }
     936             : 
     937           0 : static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
     938             :                 struct zebra_evpn_access_bd *acc_bd, json_object *json)
     939             : {
     940           0 :         if (json) {
     941           0 :                 zebra_evpn_acc_vl_json_fill(acc_bd, json, false);
     942             :         } else {
     943           0 :                 vty_out(vty, "%-5u %-15s %-8d %-15s %u\n", acc_bd->vid,
     944           0 :                         acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-",
     945           0 :                         acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
     946           0 :                         acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-",
     947           0 :                         listcount(acc_bd->mbr_zifs));
     948             :         }
     949           0 : }
     950             : 
     951           0 : static void zebra_evpn_acc_vl_show_hash(struct hash_bucket *bucket, void *ctxt)
     952             : {
     953           0 :         struct evpn_mh_show_ctx *wctx = ctxt;
     954           0 :         struct zebra_evpn_access_bd *acc_bd = bucket->data;
     955           0 :         json_object *json = NULL;
     956             : 
     957           0 :         if (wctx->json)
     958           0 :                 json = json_object_new_object();
     959           0 :         if (wctx->detail)
     960           0 :                 zebra_evpn_acc_vl_show_entry_detail(wctx->vty, acc_bd, json);
     961             :         else
     962           0 :                 zebra_evpn_acc_vl_show_entry(wctx->vty, acc_bd, json);
     963           0 :         if (json)
     964           0 :                 json_object_array_add(wctx->json, json);
     965           0 : }
     966             : 
     967           0 : void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
     968             : {
     969           0 :         struct evpn_mh_show_ctx wctx;
     970           0 :         json_object *json_array = NULL;
     971             : 
     972           0 :         if (uj)
     973           0 :                 json_array = json_object_new_array();
     974             : 
     975           0 :         memset(&wctx, 0, sizeof(wctx));
     976           0 :         wctx.vty = vty;
     977           0 :         wctx.json = json_array;
     978           0 :         wctx.detail = false;
     979             : 
     980           0 :         if (!uj)
     981           0 :                 vty_out(vty, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
     982             :                         "L2-VNI", "VXLAN-IF", "# Members");
     983             : 
     984           0 :         hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
     985             :                         &wctx);
     986             : 
     987           0 :         if (uj)
     988           0 :                 vty_json(vty, json_array);
     989           0 : }
     990             : 
     991           0 : void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
     992             : {
     993           0 :         struct evpn_mh_show_ctx wctx;
     994           0 :         json_object *json_array = NULL;
     995             : 
     996           0 :         if (uj)
     997           0 :                 json_array = json_object_new_array();
     998           0 :         memset(&wctx, 0, sizeof(wctx));
     999           0 :         wctx.vty = vty;
    1000           0 :         wctx.json = json_array;
    1001           0 :         wctx.detail = true;
    1002             : 
    1003           0 :         hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
    1004             :                         &wctx);
    1005             : 
    1006           0 :         if (uj)
    1007           0 :                 vty_json(vty, json_array);
    1008           0 : }
    1009             : 
    1010           0 : void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
    1011             : {
    1012           0 :         json_object *json = NULL;
    1013           0 :         struct zebra_evpn_access_bd *acc_bd;
    1014             : 
    1015           0 :         if (uj)
    1016           0 :                 json = json_object_new_object();
    1017             : 
    1018           0 :         acc_bd = zebra_evpn_acc_vl_find(vid);
    1019           0 :         if (acc_bd) {
    1020           0 :                 zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
    1021             :         } else {
    1022           0 :                 if (!json)
    1023           0 :                         vty_out(vty, "VLAN %u not present\n", vid);
    1024             :         }
    1025             : 
    1026           0 :         if (uj)
    1027           0 :                 vty_json(vty, json);
    1028           0 : }
    1029             : 
    1030             : /* Initialize VLAN member bitmap on an interface. Although VLAN membership
    1031             :  * is independent of EVPN we only process it if its of interest to EVPN-MH
    1032             :  * i.e. on access ports that can be setup as Ethernet Segments. And that is
    1033             :  * intended as an optimization.
    1034             :  */
    1035           7 : void zebra_evpn_if_init(struct zebra_if *zif)
    1036             : {
    1037          14 :         if (!zebra_evpn_is_if_es_capable(zif))
    1038             :                 return;
    1039             : 
    1040           0 :         if (!bf_is_inited(zif->vlan_bitmap))
    1041           0 :                 bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX);
    1042             : 
    1043             :         /* if an es_id and sysmac are already present against the interface
    1044             :          * activate it
    1045             :          */
    1046           0 :         zebra_evpn_local_es_update(zif, &zif->es_info.esi);
    1047             : }
    1048             : 
    1049             : /* handle deletion of an access port by removing it from all associated
    1050             :  * broadcast domains.
    1051             :  */
    1052           8 : void zebra_evpn_if_cleanup(struct zebra_if *zif)
    1053             : {
    1054           8 :         vlanid_t vid;
    1055           8 :         struct zebra_evpn_es *es;
    1056             : 
    1057           8 :         if (bf_is_inited(zif->vlan_bitmap)) {
    1058           0 :                 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX)
    1059             :                 {
    1060           0 :                         zebra_evpn_vl_mbr_deref(vid, zif);
    1061             :                 }
    1062             : 
    1063           0 :                 bf_free(zif->vlan_bitmap);
    1064             :         }
    1065             : 
    1066             :         /* Delete associated Ethernet Segment */
    1067           8 :         es = zif->es_info.es;
    1068           8 :         if (es)
    1069           0 :                 zebra_evpn_local_es_del(&es);
    1070           8 : }
    1071             : 
    1072             : /*****************************************************************************
    1073             :  * L2 NH/NHG Management
    1074             :  *   A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
    1075             :  * NH is then added to the L2-ECMP-NHG associated with the ES.
    1076             :  */
    1077           0 : static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es *es)
    1078             : {
    1079           0 :         uint32_t id;
    1080           0 :         uint32_t nh_id;
    1081             : 
    1082           0 :         bf_assign_index(zmh_info->nh_id_bitmap, id);
    1083             : 
    1084           0 :         if (!id)
    1085             :                 return 0;
    1086             : 
    1087           0 :         if (es) {
    1088           0 :                 nh_id = id | EVPN_NHG_ID_TYPE_BIT;
    1089             :                 /* Add to NHG hash */
    1090           0 :                 es->nhg_id = nh_id;
    1091           0 :                 (void)hash_get(zmh_info->nhg_table, es, hash_alloc_intern);
    1092             :         } else {
    1093           0 :                 nh_id = id | EVPN_NH_ID_TYPE_BIT;
    1094             :         }
    1095             : 
    1096             :         return nh_id;
    1097             : }
    1098             : 
    1099           0 : static void zebra_evpn_nhid_free(uint32_t nh_id, struct zebra_evpn_es *es)
    1100             : {
    1101           0 :         uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
    1102             : 
    1103           0 :         if (!id)
    1104             :                 return;
    1105             : 
    1106           0 :         if (es) {
    1107           0 :                 hash_release(zmh_info->nhg_table, es);
    1108           0 :                 es->nhg_id = 0;
    1109             :         }
    1110             : 
    1111           0 :         bf_release_index(zmh_info->nh_id_bitmap, id);
    1112             : }
    1113             : 
    1114           0 : static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p)
    1115             : {
    1116           0 :         const struct zebra_evpn_l2_nh *nh = p;
    1117             : 
    1118           0 :         return jhash_1word(nh->vtep_ip.s_addr, 0);
    1119             : }
    1120             : 
    1121           0 : static bool zebra_evpn_nh_ip_cmp(const void *p1, const void *p2)
    1122             : {
    1123           0 :         const struct zebra_evpn_l2_nh *nh1 = p1;
    1124           0 :         const struct zebra_evpn_l2_nh *nh2 = p2;
    1125             : 
    1126           0 :         if (nh1 == NULL && nh2 == NULL)
    1127             :                 return true;
    1128             : 
    1129           0 :         if (nh1 == NULL || nh2 == NULL)
    1130             :                 return false;
    1131             : 
    1132           0 :         return (nh1->vtep_ip.s_addr == nh2->vtep_ip.s_addr);
    1133             : }
    1134             : 
    1135           0 : static unsigned int zebra_evpn_nhg_hash_keymake(const void *p)
    1136             : {
    1137           0 :         const struct zebra_evpn_es *es = p;
    1138             : 
    1139           0 :         return jhash_1word(es->nhg_id, 0);
    1140             : }
    1141             : 
    1142           0 : static bool zebra_evpn_nhg_cmp(const void *p1, const void *p2)
    1143             : {
    1144           0 :         const struct zebra_evpn_es *es1 = p1;
    1145           0 :         const struct zebra_evpn_es *es2 = p2;
    1146             : 
    1147           0 :         if (es1 == NULL && es2 == NULL)
    1148             :                 return true;
    1149             : 
    1150           0 :         if (es1 == NULL || es2 == NULL)
    1151             :                 return false;
    1152             : 
    1153           0 :         return (es1->nhg_id == es2->nhg_id);
    1154             : }
    1155             : 
    1156             : /* Lookup ES using the NHG id associated with it */
    1157           0 : static struct zebra_evpn_es *zebra_evpn_nhg_find(uint32_t nhg_id)
    1158             : {
    1159           0 :         struct zebra_evpn_es *es;
    1160           0 :         struct zebra_evpn_es tmp;
    1161             : 
    1162           0 :         tmp.nhg_id = nhg_id;
    1163           0 :         es = hash_lookup(zmh_info->nhg_table, &tmp);
    1164             : 
    1165           0 :         return es;
    1166             : }
    1167             : 
    1168             : /* Returns TRUE if the NHG is associated with a local ES */
    1169           0 : bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id,
    1170             :                                 struct zebra_evpn_es **local_es)
    1171             : {
    1172           0 :         struct zebra_evpn_es *es;
    1173             : 
    1174           0 :         es = zebra_evpn_nhg_find(nhg_id);
    1175           0 :         if (es && (es->flags & ZEBRA_EVPNES_LOCAL)) {
    1176           0 :                 *local_es = es;
    1177           0 :                 return true;
    1178             :         }
    1179             : 
    1180           0 :         *local_es = NULL;
    1181           0 :         return false;
    1182             : }
    1183             : 
    1184             : /* update remote macs associated with the ES */
    1185           0 : static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es *es)
    1186             : {
    1187           0 :         struct zebra_mac *mac;
    1188           0 :         struct listnode *node;
    1189           0 :         bool local_via_nw;
    1190             : 
    1191           0 :         local_via_nw = zebra_evpn_es_local_mac_via_network_port(es);
    1192           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    1193           0 :                 zlog_debug("mac update on es %s nhg %s", es->esi_str,
    1194             :                            (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
    1195             :                                    ? "activate"
    1196             :                                    : "de-activate");
    1197             : 
    1198           0 :         for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
    1199           0 :                 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
    1200           0 :                     || (local_via_nw && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
    1201           0 :                         && zebra_evpn_mac_is_static(mac))) {
    1202           0 :                         if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
    1203           0 :                                 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    1204           0 :                                         zlog_debug(
    1205             :                                                 "%smac %pEA install via es %s nhg 0x%x",
    1206             :                                                 (mac->flags & ZEBRA_MAC_REMOTE)
    1207             :                                                         ? "rem"
    1208             :                                                         : "local-nw",
    1209             :                                                 &mac->macaddr, es->esi_str,
    1210             :                                                 es->nhg_id);
    1211           0 :                                 zebra_evpn_rem_mac_install(
    1212             :                                         mac->zevpn, mac, false /*was_static*/);
    1213             :                         } else {
    1214           0 :                                 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    1215           0 :                                         zlog_debug(
    1216             :                                                 "%smac %pEA un-install es %s",
    1217             :                                                 (mac->flags & ZEBRA_MAC_REMOTE)
    1218             :                                                         ? "rem"
    1219             :                                                         : "local-nw",
    1220             :                                                 &mac->macaddr, es->esi_str);
    1221           0 :                                 zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
    1222             :                                                              true /*force*/);
    1223             :                         }
    1224             :                 }
    1225             :         }
    1226           0 : }
    1227             : 
    1228             : /* The MAC ECMP group is activated on the first VTEP */
    1229           0 : static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
    1230             : {
    1231           0 :         uint32_t nh_cnt = 0;
    1232           0 :         struct nh_grp nh_ids[ES_VTEP_MAX_CNT];
    1233           0 :         struct zebra_evpn_es_vtep *es_vtep;
    1234           0 :         struct listnode *node;
    1235             : 
    1236           0 :         if (!es->nhg_id)
    1237           0 :                 return;
    1238             : 
    1239           0 :         for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
    1240           0 :                 if (!es_vtep->nh)
    1241           0 :                         continue;
    1242             : 
    1243           0 :                 if (nh_cnt >= ES_VTEP_MAX_CNT)
    1244             :                         break;
    1245             : 
    1246           0 :                 memset(&nh_ids[nh_cnt], 0, sizeof(struct nh_grp));
    1247           0 :                 nh_ids[nh_cnt].id = es_vtep->nh->nh_id;
    1248           0 :                 ++nh_cnt;
    1249             :         }
    1250             : 
    1251           0 :         if (nh_cnt) {
    1252           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_NH) {
    1253           0 :                         char nh_str[ES_VTEP_LIST_STR_SZ];
    1254           0 :                         uint32_t i;
    1255           0 :                         char nh_buf[16];
    1256             : 
    1257           0 :                         nh_str[0] = '\0';
    1258           0 :                         for (i = 0; i < nh_cnt; ++i) {
    1259           0 :                                 snprintf(nh_buf, sizeof(nh_buf), "%u ",
    1260             :                                          nh_ids[i].id);
    1261           0 :                                 strlcat(nh_str, nh_buf, sizeof(nh_str));
    1262             :                         }
    1263           0 :                         zlog_debug("es %s nhg %u add %s", es->esi_str,
    1264             :                                    es->nhg_id, nh_str);
    1265             :                 }
    1266             : 
    1267           0 :                 kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
    1268           0 :                 if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE)) {
    1269           0 :                         es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
    1270             :                         /* add backup NHG to the br-port */
    1271           0 :                         if ((es->flags & ZEBRA_EVPNES_LOCAL))
    1272           0 :                                 zebra_evpn_es_br_port_dplane_update(es,
    1273             :                                                                     __func__);
    1274           0 :                         zebra_evpn_nhg_mac_update(es);
    1275             :                 }
    1276             :         } else {
    1277           0 :                 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
    1278           0 :                         if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
    1279           0 :                                 zlog_debug("es %s nhg %u del", es->esi_str,
    1280             :                                            es->nhg_id);
    1281           0 :                         es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
    1282             :                         /* remove backup NHG from the br-port */
    1283           0 :                         if ((es->flags & ZEBRA_EVPNES_LOCAL))
    1284           0 :                                 zebra_evpn_es_br_port_dplane_update(es,
    1285             :                                                                     __func__);
    1286           0 :                         zebra_evpn_nhg_mac_update(es);
    1287           0 :                         kernel_del_mac_nhg(es->nhg_id);
    1288             :                 }
    1289             :         }
    1290             : 
    1291             : }
    1292             : 
    1293           0 : static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh *nh,
    1294             :                                            struct vty *vty,
    1295             :                                            json_object *json_array)
    1296             : {
    1297           0 :         if (json_array) {
    1298           0 :                 json_object *json = NULL;
    1299             : 
    1300           0 :                 json = json_object_new_object();
    1301           0 :                 json_object_string_addf(json, "vtep", "%pI4", &nh->vtep_ip);
    1302           0 :                 json_object_int_add(json, "nhId", nh->nh_id);
    1303           0 :                 json_object_int_add(json, "refCnt", nh->ref_cnt);
    1304             : 
    1305           0 :                 json_object_array_add(json_array, json);
    1306             :         } else {
    1307           0 :                 vty_out(vty, "%-16pI4 %-10u %u\n", &nh->vtep_ip, nh->nh_id,
    1308             :                         nh->ref_cnt);
    1309             :         }
    1310           0 : }
    1311             : 
    1312           0 : static void zebra_evpn_l2_nh_show_cb(struct hash_bucket *bucket, void *ctxt)
    1313             : {
    1314           0 :         struct zebra_evpn_l2_nh *nh = (struct zebra_evpn_l2_nh *)bucket->data;
    1315           0 :         struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
    1316             : 
    1317           0 :         zebra_evpn_es_l2_nh_show_entry(nh, wctx->vty, wctx->json);
    1318           0 : }
    1319             : 
    1320           0 : void zebra_evpn_l2_nh_show(struct vty *vty, bool uj)
    1321             : {
    1322           0 :         struct evpn_mh_show_ctx wctx;
    1323           0 :         json_object *json_array = NULL;
    1324             : 
    1325           0 :         if (uj) {
    1326           0 :                 json_array = json_object_new_array();
    1327             :         } else {
    1328           0 :                 vty_out(vty, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
    1329             :         }
    1330             : 
    1331           0 :         memset(&wctx, 0, sizeof(wctx));
    1332           0 :         wctx.vty = vty;
    1333           0 :         wctx.json = json_array;
    1334             : 
    1335           0 :         hash_iterate(zmh_info->nh_ip_table, zebra_evpn_l2_nh_show_cb, &wctx);
    1336             : 
    1337           0 :         if (uj)
    1338           0 :                 vty_json(vty, json_array);
    1339           0 : }
    1340             : 
    1341           0 : static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_find(struct in_addr vtep_ip)
    1342             : {
    1343           0 :         struct zebra_evpn_l2_nh *nh;
    1344           0 :         struct zebra_evpn_l2_nh tmp;
    1345             : 
    1346           0 :         tmp.vtep_ip.s_addr = vtep_ip.s_addr;
    1347           0 :         nh = hash_lookup(zmh_info->nh_ip_table, &tmp);
    1348             : 
    1349           0 :         return nh;
    1350             : }
    1351             : 
    1352           0 : static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip)
    1353             : {
    1354           0 :         struct zebra_evpn_l2_nh *nh;
    1355             : 
    1356           0 :         nh = XCALLOC(MTYPE_L2_NH, sizeof(*nh));
    1357           0 :         nh->vtep_ip = vtep_ip;
    1358           0 :         (void)hash_get(zmh_info->nh_ip_table, nh, hash_alloc_intern);
    1359             : 
    1360           0 :         nh->nh_id = zebra_evpn_nhid_alloc(NULL);
    1361           0 :         if (!nh->nh_id) {
    1362           0 :                 hash_release(zmh_info->nh_ip_table, nh);
    1363           0 :                 XFREE(MTYPE_L2_NH, nh);
    1364           0 :                 return NULL;
    1365             :         }
    1366             : 
    1367             :         /* install the NH in the dataplane */
    1368           0 :         kernel_upd_mac_nh(nh->nh_id, nh->vtep_ip);
    1369             : 
    1370           0 :         return nh;
    1371             : }
    1372             : 
    1373           0 : static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh *nh)
    1374             : {
    1375             :         /* delete the NH from the dataplane */
    1376           0 :         kernel_del_mac_nh(nh->nh_id);
    1377             : 
    1378           0 :         zebra_evpn_nhid_free(nh->nh_id, NULL);
    1379           0 :         hash_release(zmh_info->nh_ip_table, nh);
    1380           0 :         XFREE(MTYPE_L2_NH, nh);
    1381           0 : }
    1382             : 
    1383           0 : static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep *es_vtep)
    1384             : {
    1385           0 :         if (es_vtep->nh)
    1386             :                 return;
    1387             : 
    1388           0 :         es_vtep->nh = zebra_evpn_l2_nh_find(es_vtep->vtep_ip);
    1389           0 :         if (!es_vtep->nh)
    1390           0 :                 es_vtep->nh = zebra_evpn_l2_nh_alloc(es_vtep->vtep_ip);
    1391             : 
    1392           0 :         if (!es_vtep->nh) {
    1393           0 :                 zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep->es->esi_str,
    1394             :                           &es_vtep->vtep_ip);
    1395           0 :                 return;
    1396             :         }
    1397             : 
    1398           0 :         ++es_vtep->nh->ref_cnt;
    1399             : 
    1400           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
    1401           0 :                 zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep->es->esi_str,
    1402             :                            &es_vtep->vtep_ip, es_vtep->nh->nh_id,
    1403             :                            es_vtep->nh->ref_cnt);
    1404             : 
    1405             :         /* add the NH to the parent NHG */
    1406           0 :         zebra_evpn_nhg_update(es_vtep->es);
    1407             : }
    1408             : 
    1409           0 : static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep *es_vtep)
    1410             : {
    1411           0 :         struct zebra_evpn_l2_nh *nh = es_vtep->nh;
    1412             : 
    1413           0 :         if (!nh)
    1414             :                 return;
    1415             : 
    1416           0 :         es_vtep->nh = NULL;
    1417           0 :         if (nh->ref_cnt)
    1418           0 :                 --nh->ref_cnt;
    1419             : 
    1420           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
    1421           0 :                 zlog_debug("es %s vtep %pI4 nh %u deref %u",
    1422             :                            es_vtep->es->esi_str, &es_vtep->vtep_ip, nh->nh_id,
    1423             :                            nh->ref_cnt);
    1424             : 
    1425             :         /* remove the NH from the parent NHG */
    1426           0 :         zebra_evpn_nhg_update(es_vtep->es);
    1427             : 
    1428             :         /* uninstall the NH */
    1429           0 :         if (!nh->ref_cnt)
    1430           0 :                 zebra_evpn_l2_nh_free(nh);
    1431             : }
    1432             : 
    1433             : /*****************************************************************************/
    1434             : /* Ethernet Segment Management
    1435             :  * 1. Ethernet Segment is a collection of links attached to the same
    1436             :  *    server (MHD) or switch (MHN)
    1437             :  * 2. An Ethernet Segment can span multiple PEs and is identified by the
    1438             :  *    10-byte ES-ID.
    1439             :  * 3. Zebra manages the local ESI configuration.
    1440             :  * 4. It also maintains the aliasing that maps an ESI (local or remote)
    1441             :  *    to one or more PEs/VTEPs.
    1442             :  * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
    1443             :  */
    1444             : /* A list of remote VTEPs is maintained for each ES. This list includes -
    1445             :  * 1. VTEPs for which we have imported the ESR i.e. ES-peers
    1446             :  * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
    1447             :  *    have been imported into one or more EVPNs
    1448             :  */
    1449           0 : static int zebra_evpn_es_vtep_cmp(void *p1, void *p2)
    1450             : {
    1451           0 :         const struct zebra_evpn_es_vtep *es_vtep1 = p1;
    1452           0 :         const struct zebra_evpn_es_vtep *es_vtep2 = p2;
    1453             : 
    1454           0 :         return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
    1455             : }
    1456             : 
    1457           0 : static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_new(
    1458             :                 struct zebra_evpn_es *es, struct in_addr vtep_ip)
    1459             : {
    1460           0 :         struct zebra_evpn_es_vtep *es_vtep;
    1461             : 
    1462           0 :         es_vtep = XCALLOC(MTYPE_ZES_VTEP, sizeof(*es_vtep));
    1463             : 
    1464           0 :         es_vtep->es = es;
    1465           0 :         es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
    1466           0 :         listnode_init(&es_vtep->es_listnode, es_vtep);
    1467           0 :         listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
    1468             : 
    1469           0 :         return es_vtep;
    1470             : }
    1471             : 
    1472           0 : static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep *es_vtep)
    1473             : {
    1474           0 :         struct zebra_evpn_es *es = es_vtep->es;
    1475             : 
    1476           0 :         list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
    1477             :         /* update the L2-NHG associated with the ES */
    1478           0 :         zebra_evpn_l2_nh_es_vtep_deref(es_vtep);
    1479           0 :         XFREE(MTYPE_ZES_VTEP, es_vtep);
    1480           0 : }
    1481             : 
    1482             : 
    1483             : /* check if VTEP is already part of the list */
    1484           0 : static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_find(
    1485             :                 struct zebra_evpn_es *es, struct in_addr vtep_ip)
    1486             : {
    1487           0 :         struct listnode *node = NULL;
    1488           0 :         struct zebra_evpn_es_vtep *es_vtep;
    1489             : 
    1490           0 :         for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
    1491           0 :                 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
    1492           0 :                         return es_vtep;
    1493             :         }
    1494             :         return NULL;
    1495             : }
    1496             : 
    1497             : /* flush all the dataplane br-port info associated with the ES */
    1498           0 : static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es *es)
    1499             : {
    1500           0 :         struct in_addr sph_filters[ES_VTEP_MAX_CNT];
    1501             : 
    1502           0 :         if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
    1503             :                 return false;
    1504             : 
    1505           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1506           0 :                 zlog_debug("es %s br-port dplane clear", es->esi_str);
    1507             : 
    1508           0 :         memset(&sph_filters, 0, sizeof(sph_filters));
    1509           0 :         dplane_br_port_update(es->zif->ifp, false /* non_df */, 0, sph_filters,
    1510             :                               0 /* backup_nhg_id */);
    1511           0 :         return true;
    1512             : }
    1513             : 
    1514             : static inline bool
    1515           0 : zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es *es)
    1516             : {
    1517           0 :         return (es->flags & ZEBRA_EVPNES_NON_DF)
    1518           0 :                || (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
    1519           0 :                || listcount(es->es_vtep_list);
    1520             : }
    1521             : 
    1522             : /* returns TRUE if dplane entry was updated */
    1523           0 : static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
    1524             :                                                 const char *caller)
    1525             : {
    1526           0 :         uint32_t backup_nhg_id;
    1527           0 :         struct in_addr sph_filters[ES_VTEP_MAX_CNT];
    1528           0 :         struct listnode *node = NULL;
    1529           0 :         struct zebra_evpn_es_vtep *es_vtep;
    1530           0 :         uint32_t sph_filter_cnt = 0;
    1531             : 
    1532           0 :         if (!(es->flags & ZEBRA_EVPNES_LOCAL))
    1533           0 :                 return zebra_evpn_es_br_port_dplane_clear(es);
    1534             : 
    1535             :         /* If the ES is not a bridge port there is nothing
    1536             :          * in the dataplane
    1537             :          */
    1538           0 :         if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
    1539             :                 return false;
    1540             : 
    1541           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1542           0 :                 zlog_debug("es %s br-port dplane update by %s", es->esi_str,
    1543             :                            caller);
    1544           0 :         backup_nhg_id = (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) ? es->nhg_id : 0;
    1545             : 
    1546           0 :         memset(&sph_filters, 0, sizeof(sph_filters));
    1547           0 :         if (es->flags & ZEBRA_EVPNES_BYPASS) {
    1548           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1549           0 :                         zlog_debug(
    1550             :                                 "es %s SPH filter disabled as it is in bypass",
    1551             :                                 es->esi_str);
    1552             :         } else {
    1553           0 :                 if (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT) {
    1554           0 :                         zlog_warn("es %s vtep count %d exceeds filter cnt %d",
    1555             :                                   es->esi_str, listcount(es->es_vtep_list),
    1556             :                                   ES_VTEP_MAX_CNT);
    1557             :                 } else {
    1558           0 :                         for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node,
    1559             :                                                   es_vtep)) {
    1560           0 :                                 if (es_vtep->flags
    1561           0 :                                     & ZEBRA_EVPNES_VTEP_DEL_IN_PROG)
    1562           0 :                                         continue;
    1563           0 :                                 sph_filters[sph_filter_cnt] = es_vtep->vtep_ip;
    1564           0 :                                 ++sph_filter_cnt;
    1565             :                         }
    1566             :                 }
    1567             :         }
    1568             : 
    1569           0 :         dplane_br_port_update(es->zif->ifp, !!(es->flags & ZEBRA_EVPNES_NON_DF),
    1570             :                               sph_filter_cnt, sph_filters, backup_nhg_id);
    1571             : 
    1572           0 :         return true;
    1573             : }
    1574             : 
    1575             : /* returns TRUE if dplane entry was updated */
    1576           0 : static bool zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
    1577             :                                     const char *caller, const char *reason)
    1578             : {
    1579           0 :         bool old_non_df;
    1580             : 
    1581           0 :         old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
    1582             : 
    1583           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1584           0 :                 zlog_debug("df-change es %s %s to %s; %s: %s", es->esi_str,
    1585             :                            old_non_df ? "non-df" : "df",
    1586             :                            new_non_df ? "non-df" : "df", caller, reason);
    1587             : 
    1588           0 :         if (old_non_df == new_non_df)
    1589             :                 return false;
    1590             : 
    1591           0 :         if (new_non_df)
    1592           0 :                 es->flags |= ZEBRA_EVPNES_NON_DF;
    1593             :         else
    1594           0 :                 es->flags &= ~ZEBRA_EVPNES_NON_DF;
    1595             : 
    1596             :         /* update non-DF block filter in the dataplane */
    1597           0 :         return zebra_evpn_es_br_port_dplane_update(es, __func__);
    1598             : }
    1599             : 
    1600             : 
    1601             : /* returns TRUE if dplane entry was updated */
    1602           0 : static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
    1603             :                                           const char *caller)
    1604             : {
    1605           0 :         struct listnode *node = NULL;
    1606           0 :         struct zebra_evpn_es_vtep *es_vtep;
    1607           0 :         bool new_non_df = false;
    1608             : 
    1609             :         /* If the ES is not ready (i.e. not completely configured) there
    1610             :          * is no need to setup the BUM block filter
    1611             :          */
    1612           0 :         if (!(es->flags & ZEBRA_EVPNES_LOCAL)
    1613           0 :             || (es->flags & ZEBRA_EVPNES_BYPASS)
    1614           0 :             || !zmh_info->es_originator_ip.s_addr)
    1615           0 :                 return zebra_evpn_es_df_change(es, new_non_df, caller,
    1616             :                                                "not-ready");
    1617             : 
    1618             :         /* if oper-state is down DF filtering must be on. when the link comes
    1619             :          * up again dataplane should block BUM till FRR has had the chance
    1620             :          * to run DF election again
    1621             :          */
    1622           0 :         if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
    1623           0 :                 new_non_df = true;
    1624           0 :                 return zebra_evpn_es_df_change(es, new_non_df, caller,
    1625             :                                                "oper-down");
    1626             :         }
    1627             : 
    1628             :         /* ES was just created; we need to wait for the peers to rx the
    1629             :          * our Type-4 routes and for the switch to import the peers' Type-4
    1630             :          * routes
    1631             :          */
    1632           0 :         if (es->df_delay_timer) {
    1633           0 :                 new_non_df = true;
    1634           0 :                 return zebra_evpn_es_df_change(es, new_non_df, caller,
    1635             :                                                "df-delay");
    1636             :         }
    1637             : 
    1638           0 :         for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
    1639             :                 /* Only VTEPs that have advertised the ESR can participate
    1640             :                  * in DF election
    1641             :                  */
    1642           0 :                 if (!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR))
    1643           0 :                         continue;
    1644             : 
    1645             :                 /* If the DF alg is not the same we should fall back to
    1646             :                  * service-carving. But as service-carving is not supported
    1647             :                  * we will stop forwarding BUM
    1648             :                  */
    1649           0 :                 if (es_vtep->df_alg != EVPN_MH_DF_ALG_PREF) {
    1650             :                         new_non_df = true;
    1651             :                         break;
    1652             :                 }
    1653             : 
    1654             :                 /* Peer VTEP wins DF election if -
    1655             :                  * the peer-VTEP has higher preference (or)
    1656             :                  * the pref is the same but peer's IP address is lower
    1657             :                  */
    1658           0 :                 if ((es_vtep->df_pref > es->df_pref)
    1659           0 :                     || ((es_vtep->df_pref == es->df_pref)
    1660           0 :                         && (es_vtep->vtep_ip.s_addr
    1661             :                             < zmh_info->es_originator_ip.s_addr))) {
    1662             :                         new_non_df = true;
    1663             :                         break;
    1664             :                 }
    1665             :         }
    1666             : 
    1667           0 :         return zebra_evpn_es_df_change(es, new_non_df, caller, "elected");
    1668             : }
    1669             : 
    1670           0 : static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
    1671             :                                    struct in_addr vtep_ip, bool esr_rxed,
    1672             :                                    uint8_t df_alg, uint16_t df_pref)
    1673             : {
    1674           0 :         struct zebra_evpn_es_vtep *es_vtep;
    1675           0 :         bool old_esr_rxed;
    1676           0 :         bool dplane_updated = false;
    1677             : 
    1678           0 :         es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
    1679             : 
    1680           0 :         if (!es_vtep) {
    1681           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1682           0 :                         zlog_debug("es %s vtep %pI4 add",
    1683             :                                         es->esi_str, &vtep_ip);
    1684           0 :                 es_vtep = zebra_evpn_es_vtep_new(es, vtep_ip);
    1685             :                 /* update the L2-NHG associated with the ES */
    1686           0 :                 zebra_evpn_l2_nh_es_vtep_ref(es_vtep);
    1687             :         }
    1688             : 
    1689           0 :         old_esr_rxed = !!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR);
    1690           0 :         if ((old_esr_rxed != esr_rxed) || (es_vtep->df_alg != df_alg)
    1691           0 :             || (es_vtep->df_pref != df_pref)) {
    1692             :                 /* If any of the DF election params changed we need to re-run
    1693             :                  * DF election
    1694             :                  */
    1695           0 :                 if (esr_rxed)
    1696           0 :                         es_vtep->flags |= ZEBRA_EVPNES_VTEP_RXED_ESR;
    1697             :                 else
    1698           0 :                         es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
    1699           0 :                 es_vtep->df_alg = df_alg;
    1700           0 :                 es_vtep->df_pref = df_pref;
    1701           0 :                 dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
    1702             :         }
    1703             :         /* add the vtep to the SPH list */
    1704           0 :         if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
    1705           0 :                 zebra_evpn_es_br_port_dplane_update(es, __func__);
    1706           0 : }
    1707             : 
    1708           0 : static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
    1709             :                 struct in_addr vtep_ip)
    1710             : {
    1711           0 :         struct zebra_evpn_es_vtep *es_vtep;
    1712           0 :         bool dplane_updated = false;
    1713             : 
    1714           0 :         es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
    1715             : 
    1716           0 :         if (es_vtep) {
    1717           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1718           0 :                         zlog_debug("es %s vtep %pI4 del",
    1719             :                                         es->esi_str, &vtep_ip);
    1720           0 :                 es_vtep->flags |= ZEBRA_EVPNES_VTEP_DEL_IN_PROG;
    1721           0 :                 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
    1722           0 :                         es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
    1723           0 :                         dplane_updated =
    1724           0 :                                 zebra_evpn_es_run_df_election(es, __func__);
    1725             :                 }
    1726             :                 /* remove the vtep from the SPH list */
    1727           0 :                 if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
    1728           0 :                         zebra_evpn_es_br_port_dplane_update(es, __func__);
    1729           0 :                 zebra_evpn_es_vtep_free(es_vtep);
    1730             :         }
    1731           0 : }
    1732             : 
    1733             : /* compare ES-IDs for the global ES RB tree */
    1734           0 : static int zebra_es_rb_cmp(const struct zebra_evpn_es *es1,
    1735             :                 const struct zebra_evpn_es *es2)
    1736             : {
    1737           0 :         return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
    1738             : }
    1739           0 : RB_GENERATE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
    1740             : 
    1741             : /* Lookup ES */
    1742           0 : struct zebra_evpn_es *zebra_evpn_es_find(const esi_t *esi)
    1743             : {
    1744           0 :         struct zebra_evpn_es tmp;
    1745             : 
    1746           0 :         memcpy(&tmp.esi, esi, sizeof(esi_t));
    1747           0 :         return RB_FIND(zebra_es_rb_head, &zmh_info->es_rb_tree, &tmp);
    1748             : }
    1749             : 
    1750             : /* A new local es is created when a local-es-id and sysmac is configured
    1751             :  * against an interface.
    1752             :  */
    1753           0 : static struct zebra_evpn_es *zebra_evpn_es_new(const esi_t *esi)
    1754             : {
    1755           0 :         struct zebra_evpn_es *es;
    1756             : 
    1757           0 :         if (!memcmp(esi, zero_esi, sizeof(esi_t)))
    1758             :                 return NULL;
    1759             : 
    1760           0 :         es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
    1761             : 
    1762             :         /* fill in ESI */
    1763           0 :         memcpy(&es->esi, esi, sizeof(esi_t));
    1764           0 :         esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
    1765             : 
    1766             :         /* Add to rb_tree */
    1767           0 :         RB_INSERT(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
    1768             : 
    1769             :         /* Initialise the ES-EVI list */
    1770           0 :         es->es_evi_list = list_new();
    1771           0 :         listset_app_node_mem(es->es_evi_list);
    1772             : 
    1773             :         /* Initialise the VTEP list */
    1774           0 :         es->es_vtep_list = list_new();
    1775           0 :         listset_app_node_mem(es->es_vtep_list);
    1776           0 :         es->es_vtep_list->cmp = zebra_evpn_es_vtep_cmp;
    1777             : 
    1778             :         /* mac entries associated with the ES */
    1779           0 :         es->mac_list = list_new();
    1780           0 :         listset_app_node_mem(es->mac_list);
    1781             : 
    1782             :         /* reserve a NHG  */
    1783           0 :         es->nhg_id = zebra_evpn_nhid_alloc(es);
    1784             : 
    1785           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1786           0 :                 zlog_debug("es %s nhg %u new", es->esi_str, es->nhg_id);
    1787             : 
    1788             :         return es;
    1789             : }
    1790             : 
    1791             : /* Free a given ES -
    1792             :  * This just frees appropriate memory, caller should have taken other
    1793             :  * needed actions.
    1794             :  */
    1795           0 : static void zebra_evpn_es_free(struct zebra_evpn_es **esp)
    1796             : {
    1797           0 :         struct zebra_evpn_es *es = *esp;
    1798             : 
    1799             :         /* If the ES has a local or remote reference it cannot be freed.
    1800             :          * Free is also prevented if there are MAC entries referencing
    1801             :          * it.
    1802             :          */
    1803           0 :         if ((es->flags & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE)) ||
    1804           0 :                         listcount(es->mac_list))
    1805             :                 return;
    1806             : 
    1807           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1808           0 :                 zlog_debug("es %s free", es->esi_str);
    1809             : 
    1810             :         /* If the NHG is still installed uninstall it and free the id */
    1811           0 :         if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
    1812           0 :                 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
    1813           0 :                 kernel_del_mac_nhg(es->nhg_id);
    1814             :         }
    1815           0 :         zebra_evpn_nhid_free(es->nhg_id, es);
    1816             : 
    1817             :         /* cleanup resources maintained against the ES */
    1818           0 :         list_delete(&es->es_evi_list);
    1819           0 :         list_delete(&es->es_vtep_list);
    1820           0 :         list_delete(&es->mac_list);
    1821             : 
    1822             :         /* remove from the VNI-ESI rb tree */
    1823           0 :         RB_REMOVE(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
    1824             : 
    1825           0 :         XFREE(MTYPE_ZES, es);
    1826             : 
    1827           0 :         *esp = NULL;
    1828             : }
    1829             : 
    1830             : /* Inform BGP about local ES addition */
    1831           0 : static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es)
    1832             : {
    1833           0 :         struct zserv *client;
    1834           0 :         struct stream *s;
    1835           0 :         uint8_t oper_up;
    1836           0 :         bool bypass;
    1837             : 
    1838           0 :         client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
    1839             :         /* BGP may not be running. */
    1840           0 :         if (!client)
    1841             :                 return 0;
    1842             : 
    1843           0 :         s = stream_new(ZEBRA_MAX_PACKET_SIZ);
    1844             : 
    1845           0 :         zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id());
    1846           0 :         stream_put(s, &es->esi, sizeof(esi_t));
    1847           0 :         stream_put_ipv4(s, zmh_info->es_originator_ip.s_addr);
    1848           0 :         oper_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
    1849           0 :         stream_putc(s, oper_up);
    1850           0 :         stream_putw(s, es->df_pref);
    1851           0 :         bypass = !!(es->flags & ZEBRA_EVPNES_BYPASS);
    1852           0 :         stream_putc(s, bypass);
    1853             : 
    1854             :         /* Write packet size. */
    1855           0 :         stream_putw_at(s, 0, stream_get_endp(s));
    1856             : 
    1857           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1858           0 :                 zlog_debug(
    1859             :                         "send add local es %s %pI4 active %u df_pref %u%s to %s",
    1860             :                         es->esi_str, &zmh_info->es_originator_ip, oper_up,
    1861             :                         es->df_pref, bypass ? " bypass" : "",
    1862             :                         zebra_route_string(client->proto));
    1863             : 
    1864           0 :         client->local_es_add_cnt++;
    1865           0 :         return zserv_send_message(client, s);
    1866             : }
    1867             : 
    1868             : /* Inform BGP about local ES deletion */
    1869           0 : static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es)
    1870             : {
    1871           0 :         struct zserv *client;
    1872           0 :         struct stream *s;
    1873             : 
    1874           0 :         client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
    1875             :         /* BGP may not be running. */
    1876           0 :         if (!client)
    1877             :                 return 0;
    1878             : 
    1879           0 :         s = stream_new(ZEBRA_MAX_PACKET_SIZ);
    1880           0 :         stream_reset(s);
    1881             : 
    1882           0 :         zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id());
    1883           0 :         stream_put(s, &es->esi, sizeof(esi_t));
    1884             : 
    1885             :         /* Write packet size. */
    1886           0 :         stream_putw_at(s, 0, stream_get_endp(s));
    1887             : 
    1888           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    1889           0 :                 zlog_debug("send del local es %s to %s", es->esi_str,
    1890             :                                 zebra_route_string(client->proto));
    1891             : 
    1892           0 :         client->local_es_del_cnt++;
    1893           0 :         return zserv_send_message(client, s);
    1894             : }
    1895             : 
    1896           0 : static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es *es,
    1897             :                 bool es_evi_re_reval)
    1898             : {
    1899           0 :         bool old_ready;
    1900           0 :         bool new_ready;
    1901           0 :         struct listnode *node;
    1902           0 :         struct zebra_evpn_es_evi *es_evi;
    1903             : 
    1904           0 :         old_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
    1905             : 
    1906           0 :         if ((es->flags & ZEBRA_EVPNES_LOCAL) &&
    1907           0 :                         zmh_info->es_originator_ip.s_addr)
    1908           0 :                 es->flags |= ZEBRA_EVPNES_READY_FOR_BGP;
    1909             :         else
    1910           0 :                 es->flags &= ~ZEBRA_EVPNES_READY_FOR_BGP;
    1911             : 
    1912           0 :         new_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
    1913           0 :         if (old_ready == new_ready)
    1914             :                 return;
    1915             : 
    1916           0 :         if (new_ready)
    1917           0 :                 zebra_evpn_es_send_add_to_client(es);
    1918             :         else
    1919           0 :                 zebra_evpn_es_send_del_to_client(es);
    1920             : 
    1921             :         /* re-eval associated EVIs */
    1922           0 :         if (es_evi_re_reval) {
    1923           0 :                 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, node, es_evi)) {
    1924           0 :                         if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
    1925           0 :                                 continue;
    1926           0 :                         zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
    1927             :                 }
    1928             :         }
    1929             : }
    1930             : 
    1931           0 : void zebra_evpn_es_send_all_to_client(bool add)
    1932             : {
    1933           0 :         struct listnode *es_node;
    1934           0 :         struct listnode *evi_node;
    1935           0 :         struct zebra_evpn_es *es;
    1936           0 :         struct zebra_evpn_es_evi *es_evi;
    1937             : 
    1938           0 :         if (!zmh_info)
    1939             :                 return;
    1940             : 
    1941           0 :         for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, es_node, es)) {
    1942           0 :                 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) {
    1943           0 :                         if (add)
    1944           0 :                                 zebra_evpn_es_send_add_to_client(es);
    1945           0 :                         for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
    1946             :                                                 evi_node, es_evi)) {
    1947           0 :                                 if (!(es_evi->flags &
    1948             :                                         ZEBRA_EVPNES_EVI_READY_FOR_BGP))
    1949           0 :                                         continue;
    1950             : 
    1951           0 :                                 if (add)
    1952           0 :                                         zebra_evpn_es_evi_send_to_client(
    1953             :                                                 es, es_evi->zevpn,
    1954             :                                                 true /* add */);
    1955             :                                 else
    1956           0 :                                         zebra_evpn_es_evi_send_to_client(
    1957             :                                                 es, es_evi->zevpn,
    1958             :                                                 false /* add */);
    1959             :                         }
    1960           0 :                         if (!add)
    1961           0 :                                 zebra_evpn_es_send_del_to_client(es);
    1962             :                 }
    1963             :         }
    1964             : }
    1965             : 
    1966             : /* walk the vlan bitmap associated with the zif and create or delete
    1967             :  * es_evis for all vlans associated with a VNI.
    1968             :  * XXX: This API is really expensive. optimize later if possible.
    1969             :  */
    1970           0 : static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
    1971             : {
    1972           0 :         struct zebra_if *zif = es->zif;
    1973           0 :         uint16_t vid;
    1974           0 :         struct zebra_evpn_access_bd *acc_bd;
    1975             : 
    1976           0 :         if (!bf_is_inited(zif->vlan_bitmap))
    1977             :                 return;
    1978             : 
    1979           0 :         bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
    1980           0 :                 acc_bd = zebra_evpn_acc_vl_find(vid);
    1981           0 :                 if (acc_bd->zevpn)
    1982           0 :                         zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
    1983             :         }
    1984             : }
    1985             : 
    1986           0 : static void zebra_evpn_flush_local_mac(struct zebra_mac *mac,
    1987             :                                        struct interface *ifp)
    1988             : {
    1989           0 :         struct zebra_if *zif;
    1990           0 :         struct interface *br_ifp;
    1991           0 :         vlanid_t vid;
    1992             : 
    1993           0 :         zif = ifp->info;
    1994           0 :         br_ifp = zif->brslave_info.br_if;
    1995           0 :         if (!br_ifp)
    1996             :                 return;
    1997             : 
    1998           0 :         if (mac->zevpn->vxlan_if) {
    1999           0 :                 zif = mac->zevpn->vxlan_if->info;
    2000           0 :                 vid = zif->l2info.vxl.access_vlan;
    2001             :         } else {
    2002             :                 vid = 0;
    2003             :         }
    2004             : 
    2005             :         /* delete the local mac from the dataplane */
    2006           0 :         dplane_local_mac_del(ifp, br_ifp, vid, &mac->macaddr);
    2007             :         /* delete the local mac in zebra */
    2008           0 :         zebra_evpn_del_local_mac(mac->zevpn, mac, true);
    2009             : }
    2010             : 
    2011           0 : static void zebra_evpn_es_flush_local_macs(struct zebra_evpn_es *es,
    2012             :                                            struct interface *ifp, bool add)
    2013             : {
    2014           0 :         struct zebra_mac *mac;
    2015           0 :         struct listnode *node;
    2016           0 :         struct listnode *nnode;
    2017             : 
    2018           0 :         for (ALL_LIST_ELEMENTS(es->mac_list, node, nnode, mac)) {
    2019           0 :                 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
    2020           0 :                         continue;
    2021             : 
    2022             :                 /* If ES is being attached/detached from the access port we
    2023             :                  * need to clear local activity and peer activity and start
    2024             :                  * over */
    2025           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    2026           0 :                         zlog_debug("VNI %u mac %pEA update; local ES %s %s",
    2027             :                                    mac->zevpn->vni,
    2028             :                                    &mac->macaddr,
    2029             :                                    es->esi_str, add ? "add" : "del");
    2030           0 :                 zebra_evpn_flush_local_mac(mac, ifp);
    2031             :         }
    2032           0 : }
    2033             : 
    2034           0 : void zebra_evpn_es_local_br_port_update(struct zebra_if *zif)
    2035             : {
    2036           0 :         struct zebra_evpn_es *es = zif->es_info.es;
    2037           0 :         bool old_br_port = !!(es->flags & ZEBRA_EVPNES_BR_PORT);
    2038           0 :         bool new_br_port;
    2039             : 
    2040           0 :         if (zif->brslave_info.bridge_ifindex != IFINDEX_INTERNAL)
    2041           0 :                 es->flags |= ZEBRA_EVPNES_BR_PORT;
    2042             :         else
    2043           0 :                 es->flags &= ~ZEBRA_EVPNES_BR_PORT;
    2044             : 
    2045           0 :         new_br_port = !!(es->flags & ZEBRA_EVPNES_BR_PORT);
    2046           0 :         if (old_br_port == new_br_port)
    2047             :                 return;
    2048             : 
    2049           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2050           0 :                 zlog_debug("es %s br_port change old %u new %u", es->esi_str,
    2051             :                            old_br_port, new_br_port);
    2052             : 
    2053             :         /* update the dataplane br_port attrs */
    2054           0 :         if (new_br_port && zebra_evpn_es_br_port_dplane_update_needed(es))
    2055           0 :                 zebra_evpn_es_br_port_dplane_update(es, __func__);
    2056             : }
    2057             : 
    2058             : /* On config of first local-ES turn off DAD */
    2059           0 : static void zebra_evpn_mh_dup_addr_detect_off(void)
    2060             : {
    2061           0 :         struct zebra_vrf *zvrf;
    2062           0 :         bool old_detect;
    2063           0 :         bool new_detect;
    2064             : 
    2065           0 :         if (zmh_info->flags & ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF)
    2066             :                 return;
    2067             : 
    2068           0 :         zvrf = zebra_vrf_get_evpn();
    2069           0 :         old_detect = zebra_evpn_do_dup_addr_detect(zvrf);
    2070           0 :         zmh_info->flags |= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF;
    2071           0 :         new_detect = zebra_evpn_do_dup_addr_detect(zvrf);
    2072             : 
    2073           0 :         if (old_detect && !new_detect) {
    2074           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2075           0 :                         zlog_debug(
    2076             :                                 "evpn-mh config caused DAD addr detect chg from %s to %s",
    2077             :                                 old_detect ? "on" : "off",
    2078             :                                 new_detect ? "on" : "off");
    2079           0 :                 zebra_vxlan_clear_dup_detect_vni_all(zvrf);
    2080             :         }
    2081             : }
    2082             : 
    2083             : /* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
    2084             :  * neighbors
    2085             :  */
    2086           0 : static void zebra_evpn_mh_advertise_reach_neigh_only(void)
    2087             : {
    2088           0 :         if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY)
    2089             :                 return;
    2090             : 
    2091           0 :         zmh_info->flags |= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY;
    2092           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2093           0 :                 zlog_debug("evpn-mh: only REACHABLE neigh advertised");
    2094             : 
    2095             :         /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
    2096             :          * need to withdraw them
    2097             :          */
    2098             : }
    2099             : 
    2100             : /* On config of first local-ES turn on advertisement of local SVI-MAC */
    2101           0 : static void zebra_evpn_mh_advertise_svi_mac(void)
    2102             : {
    2103           0 :         if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_SVI_MAC)
    2104             :                 return;
    2105             : 
    2106           0 :         zmh_info->flags |= ZEBRA_EVPN_MH_ADV_SVI_MAC;
    2107           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2108           0 :                 zlog_debug("evpn-mh: advertise SVI MAC");
    2109             : 
    2110             :         /* walk through all SVIs and see if we need to advertise the MAC */
    2111           0 :         zebra_evpn_acc_vl_adv_svi_mac_all();
    2112             : }
    2113             : 
    2114           0 : static void zebra_evpn_es_df_delay_exp_cb(struct thread *t)
    2115             : {
    2116           0 :         struct zebra_evpn_es *es;
    2117             : 
    2118           0 :         es = THREAD_ARG(t);
    2119             : 
    2120           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2121           0 :                 zlog_debug("es %s df-delay expired", es->esi_str);
    2122             : 
    2123           0 :         zebra_evpn_es_run_df_election(es, __func__);
    2124           0 : }
    2125             : 
    2126             : /* currently there is no global config to turn on MH instead we use
    2127             :  * the addition of the first local Ethernet Segment as the trigger to
    2128             :  * init MH specific processing
    2129             :  */
    2130           0 : static void zebra_evpn_mh_on_first_local_es(void)
    2131             : {
    2132           0 :         zebra_evpn_mh_dup_addr_detect_off();
    2133           0 :         zebra_evpn_mh_advertise_reach_neigh_only();
    2134           0 :         zebra_evpn_mh_advertise_svi_mac();
    2135           0 : }
    2136             : 
    2137           0 : static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
    2138             :                 struct zebra_if *zif)
    2139             : {
    2140           0 :         if (es->flags & ZEBRA_EVPNES_LOCAL)
    2141             :                 return;
    2142             : 
    2143           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2144           0 :                 zlog_debug("local es %s add; nhg %u if %s", es->esi_str,
    2145             :                            es->nhg_id, zif->ifp->name);
    2146             : 
    2147           0 :         zebra_evpn_mh_on_first_local_es();
    2148             : 
    2149           0 :         es->flags |= ZEBRA_EVPNES_LOCAL;
    2150           0 :         listnode_init(&es->local_es_listnode, es);
    2151           0 :         listnode_add(zmh_info->local_es_list, &es->local_es_listnode);
    2152             : 
    2153             :         /* attach es to interface */
    2154           0 :         zif->es_info.es = es;
    2155           0 :         es->df_pref = zif->es_info.df_pref ? zif->es_info.df_pref
    2156             :                                            : EVPN_MH_DF_PREF_DEFAULT;
    2157             : 
    2158             :         /* attach interface to es */
    2159           0 :         es->zif = zif;
    2160           0 :         if (if_is_operative(zif->ifp))
    2161           0 :                 es->flags |= ZEBRA_EVPNES_OPER_UP;
    2162             : 
    2163           0 :         if (zif->brslave_info.bridge_ifindex != IFINDEX_INTERNAL)
    2164           0 :                 es->flags |= ZEBRA_EVPNES_BR_PORT;
    2165             : 
    2166             :         /* inherit the bypass flag from the interface */
    2167           0 :         if (zif->flags & ZIF_FLAG_LACP_BYPASS)
    2168           0 :                 es->flags |= ZEBRA_EVPNES_BYPASS;
    2169             : 
    2170             :         /* setup base-vni if one doesn't already exist; the ES will get sent
    2171             :          * to BGP as a part of that process
    2172             :          */
    2173           0 :         if (!zmh_info->es_base_evpn)
    2174           0 :                 zebra_evpn_es_get_one_base_evpn();
    2175             :         else
    2176             :                 /* send notification to bgp */
    2177           0 :                 zebra_evpn_es_re_eval_send_to_client(es,
    2178             :                         false /* es_evi_re_reval */);
    2179             : 
    2180             :         /* Start the DF delay timer on the local ES */
    2181           0 :         if (!es->df_delay_timer)
    2182           0 :                 thread_add_timer(zrouter.master, zebra_evpn_es_df_delay_exp_cb,
    2183             :                                  es, ZEBRA_EVPN_MH_DF_DELAY_TIME,
    2184             :                                  &es->df_delay_timer);
    2185             : 
    2186             :         /* See if the local VTEP can function as DF on the ES */
    2187           0 :         if (!zebra_evpn_es_run_df_election(es, __func__)) {
    2188             :                 /* check if the dplane entry needs to be re-programmed as a
    2189             :                  * result of some thing other than DF status change
    2190             :                  */
    2191           0 :                 if (zebra_evpn_es_br_port_dplane_update_needed(es))
    2192           0 :                         zebra_evpn_es_br_port_dplane_update(es, __func__);
    2193             :         }
    2194             : 
    2195             : 
    2196             :         /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
    2197             :          * the zif
    2198             :          */
    2199           0 :         zebra_evpn_es_setup_evis(es);
    2200             :         /* if there any local macs referring to the ES as dest we
    2201             :          * need to clear the contents and start over
    2202             :          */
    2203           0 :         zebra_evpn_es_flush_local_macs(es, zif->ifp, true);
    2204             : 
    2205             :         /* inherit EVPN protodown flags on the access port */
    2206           0 :         zebra_evpn_mh_update_protodown_es(es, true /*resync_dplane*/);
    2207             : }
    2208             : 
    2209           0 : static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
    2210             : {
    2211           0 :         struct zebra_if *zif;
    2212           0 :         struct zebra_evpn_es *es = *esp;
    2213           0 :         bool dplane_updated = false;
    2214             : 
    2215           0 :         if (!(es->flags & ZEBRA_EVPNES_LOCAL))
    2216             :                 return;
    2217             : 
    2218           0 :         zif = es->zif;
    2219             : 
    2220             :         /* if there any local macs referring to the ES as dest we
    2221             :          * need to clear the contents and start over
    2222             :          */
    2223           0 :         zebra_evpn_es_flush_local_macs(es, zif->ifp, false);
    2224             : 
    2225           0 :         es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
    2226             : 
    2227           0 :         THREAD_OFF(es->df_delay_timer);
    2228             : 
    2229             :         /* clear EVPN protodown flags on the access port */
    2230           0 :         zebra_evpn_mh_clear_protodown_es(es);
    2231             : 
    2232             :         /* remove the DF filter */
    2233           0 :         dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
    2234             : 
    2235             :         /* flush the BUM filters and backup NHG */
    2236           0 :         if (!dplane_updated)
    2237           0 :                 zebra_evpn_es_br_port_dplane_clear(es);
    2238             : 
    2239             :         /* clear the es from the parent interface */
    2240           0 :         zif->es_info.es = NULL;
    2241           0 :         es->zif = NULL;
    2242             : 
    2243             :         /* clear all local flags associated with the ES */
    2244           0 :         es->flags &= ~(ZEBRA_EVPNES_OPER_UP | ZEBRA_EVPNES_BR_PORT
    2245             :                        | ZEBRA_EVPNES_BYPASS);
    2246             : 
    2247             :         /* remove from the ES list */
    2248           0 :         list_delete_node(zmh_info->local_es_list, &es->local_es_listnode);
    2249             : 
    2250             :         /* free up the ES if there is no remote reference */
    2251           0 :         zebra_evpn_es_free(esp);
    2252             : }
    2253             : 
    2254             : /* Delete an ethernet segment and inform BGP */
    2255           0 : static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp)
    2256             : {
    2257           0 :         struct zebra_evpn_es_evi *es_evi;
    2258           0 :         struct listnode *node = NULL;
    2259           0 :         struct listnode *nnode = NULL;
    2260           0 :         struct zebra_if *zif;
    2261           0 :         struct zebra_evpn_es *es = *esp;
    2262             : 
    2263           0 :         if (!CHECK_FLAG(es->flags, ZEBRA_EVPNES_LOCAL))
    2264             :                 return;
    2265             : 
    2266           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
    2267           0 :                 zif = es->zif;
    2268           0 :                 zlog_debug("local es %s del; nhg %u if %s", es->esi_str,
    2269             :                            es->nhg_id, zif ? zif->ifp->name : "-");
    2270             :         }
    2271             : 
    2272             :         /* remove all ES-EVIs associated with the ES */
    2273           0 :         for (ALL_LIST_ELEMENTS(es->es_evi_list, node, nnode, es_evi))
    2274           0 :                 zebra_evpn_local_es_evi_do_del(es_evi);
    2275             : 
    2276             :         /* send a del if the ES had been sent to BGP earlier */
    2277           0 :         if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
    2278           0 :                 zebra_evpn_es_send_del_to_client(es);
    2279             : 
    2280           0 :         zebra_evpn_es_local_info_clear(esp);
    2281             : }
    2282             : 
    2283             : /* eval remote info associated with the ES */
    2284           0 : static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
    2285             : {
    2286           0 :         struct zebra_evpn_es *es = *esp;
    2287             : 
    2288             :         /* if there are remote VTEPs the ES-EVI is classified as "remote" */
    2289           0 :         if (listcount(es->es_vtep_list)) {
    2290           0 :                 if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
    2291           0 :                         es->flags |= ZEBRA_EVPNES_REMOTE;
    2292           0 :                         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2293           0 :                                 zlog_debug("remote es %s add; nhg %u",
    2294             :                                            es->esi_str, es->nhg_id);
    2295             :                 }
    2296             :         } else {
    2297           0 :                 if (es->flags & ZEBRA_EVPNES_REMOTE) {
    2298           0 :                         es->flags &= ~ZEBRA_EVPNES_REMOTE;
    2299           0 :                         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2300           0 :                                 zlog_debug("remote es %s del; nhg %u",
    2301             :                                            es->esi_str, es->nhg_id);
    2302           0 :                         zebra_evpn_es_free(esp);
    2303             :                 }
    2304             :         }
    2305           0 : }
    2306             : 
    2307             : /* A new local es is created when a local-es-id and sysmac is configured
    2308             :  * against an interface.
    2309             :  */
    2310           0 : static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi)
    2311             : {
    2312           0 :         struct zebra_evpn_es *old_es = zif->es_info.es;
    2313           0 :         struct zebra_evpn_es *es;
    2314             : 
    2315           0 :         if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi)))
    2316             :                 /* dup - nothing to be done */
    2317             :                 return 0;
    2318             : 
    2319             :         /* release the old_es against the zif */
    2320           0 :         if (old_es)
    2321           0 :                 zebra_evpn_local_es_del(&old_es);
    2322             : 
    2323           0 :         es = zebra_evpn_es_find(esi);
    2324           0 :         if (es) {
    2325             :                 /* if it exists against another interface flag an error */
    2326           0 :                 if (es->zif && es->zif != zif)
    2327             :                         return -1;
    2328             :         } else {
    2329             :                 /* create new es */
    2330           0 :                 es = zebra_evpn_es_new(esi);
    2331             :         }
    2332             : 
    2333           0 :         memcpy(&zif->es_info.esi, esi, sizeof(*esi));
    2334           0 :         if (es)
    2335           0 :                 zebra_evpn_es_local_info_set(es, zif);
    2336             : 
    2337             :         return 0;
    2338             : }
    2339             : 
    2340           0 : static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid,
    2341             :                                        struct ethaddr *sysmac)
    2342             : {
    2343           0 :         struct zebra_evpn_es *old_es = zif->es_info.es;
    2344           0 :         esi_t esi;
    2345           0 :         int offset = 0;
    2346           0 :         int field_bytes = 0;
    2347             : 
    2348             :         /* Complete config of the ES-ID bootstraps the ES */
    2349           0 :         if (!lid || is_zero_mac(sysmac)) {
    2350             :                 /* clear old esi */
    2351           0 :                 memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi));
    2352             :                 /* if in ES is attached to zif delete it */
    2353           0 :                 if (old_es)
    2354           0 :                         zebra_evpn_local_es_del(&old_es);
    2355           0 :                 return 0;
    2356             :         }
    2357             : 
    2358             :         /* build 10-byte type-3-ESI -
    2359             :          * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
    2360             :          */
    2361           0 :         field_bytes = 1;
    2362           0 :         esi.val[offset] = ESI_TYPE_MAC;
    2363           0 :         offset += field_bytes;
    2364             : 
    2365           0 :         field_bytes = ETH_ALEN;
    2366           0 :         memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes);
    2367           0 :         offset += field_bytes;
    2368             : 
    2369           0 :         esi.val[offset++] = (uint8_t)(lid >> 16);
    2370           0 :         esi.val[offset++] = (uint8_t)(lid >> 8);
    2371           0 :         esi.val[offset++] = (uint8_t)lid;
    2372             : 
    2373           0 :         return zebra_evpn_local_es_update(zif, &esi);
    2374             : }
    2375             : 
    2376           0 : int zebra_evpn_remote_es_del(const esi_t *esi, struct in_addr vtep_ip)
    2377             : {
    2378           0 :         char buf[ESI_STR_LEN];
    2379           0 :         struct zebra_evpn_es *es;
    2380             : 
    2381           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2382           0 :                 zlog_debug("remote es %s vtep %pI4 del",
    2383             :                            esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
    2384             : 
    2385           0 :         es = zebra_evpn_es_find(esi);
    2386           0 :         if (!es) {
    2387           0 :                 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
    2388             :                           esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
    2389           0 :                 return -1;
    2390             :         }
    2391             : 
    2392           0 :         zebra_evpn_es_vtep_del(es, vtep_ip);
    2393           0 :         zebra_evpn_es_remote_info_re_eval(&es);
    2394             : 
    2395           0 :         return 0;
    2396             : }
    2397             : 
    2398             : /* force delete a remote ES on the way down */
    2399           0 : static void zebra_evpn_remote_es_flush(struct zebra_evpn_es **esp)
    2400             : {
    2401           0 :         struct zebra_evpn_es_vtep *es_vtep;
    2402           0 :         struct listnode *node;
    2403           0 :         struct listnode *nnode;
    2404           0 :         struct zebra_evpn_es *es = *esp;
    2405             : 
    2406           0 :         for (ALL_LIST_ELEMENTS(es->es_vtep_list, node, nnode, es_vtep)) {
    2407           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2408           0 :                         zlog_debug("es %s vtep %pI4 flush",
    2409             :                                         es->esi_str,
    2410             :                                         &es_vtep->vtep_ip);
    2411           0 :                 zebra_evpn_es_vtep_free(es_vtep);
    2412             :         }
    2413           0 :         zebra_evpn_es_remote_info_re_eval(esp);
    2414           0 : }
    2415             : 
    2416           0 : int zebra_evpn_remote_es_add(const esi_t *esi, struct in_addr vtep_ip,
    2417             :                              bool esr_rxed, uint8_t df_alg, uint16_t df_pref)
    2418             : {
    2419           0 :         char buf[ESI_STR_LEN];
    2420           0 :         struct zebra_evpn_es *es;
    2421             : 
    2422           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2423           0 :                 zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
    2424             :                            esi_to_str(esi, buf, sizeof(buf)),
    2425             :                            &vtep_ip, esr_rxed ? "esr" : "", df_alg,
    2426             :                            df_pref);
    2427             : 
    2428           0 :         es = zebra_evpn_es_find(esi);
    2429           0 :         if (!es) {
    2430           0 :                 es = zebra_evpn_es_new(esi);
    2431           0 :                 if (!es) {
    2432           0 :                         zlog_warn(
    2433             :                                 "remote es %s vtep %pI4 add failed, es missing",
    2434             :                                 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
    2435           0 :                         return -1;
    2436             :                 }
    2437             :         }
    2438             : 
    2439           0 :         if (df_alg != EVPN_MH_DF_ALG_PREF)
    2440           0 :                 zlog_warn(
    2441             :                         "remote es %s vtep %pI4 add %s with unsupported df_alg %d",
    2442             :                         esi_to_str(esi, buf, sizeof(buf)), &vtep_ip,
    2443             :                         esr_rxed ? "esr" : "", df_alg);
    2444             : 
    2445           0 :         zebra_evpn_es_vtep_add(es, vtep_ip, esr_rxed, df_alg, df_pref);
    2446           0 :         zebra_evpn_es_remote_info_re_eval(&es);
    2447             : 
    2448           0 :         return 0;
    2449             : }
    2450             : 
    2451           0 : void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS)
    2452             : {
    2453           0 :         struct stream *s;
    2454           0 :         struct in_addr vtep_ip;
    2455           0 :         esi_t esi;
    2456             : 
    2457           0 :         if (!is_evpn_enabled()) {
    2458           0 :                 zlog_debug(
    2459             :                         "%s: EVPN not enabled yet we received a es_add zapi call",
    2460             :                         __func__);
    2461           0 :                 return;
    2462             :         }
    2463             : 
    2464           0 :         memset(&esi, 0, sizeof(esi_t));
    2465           0 :         s = msg;
    2466             : 
    2467           0 :         STREAM_GET(&esi, s, sizeof(esi_t));
    2468           0 :         STREAM_GET(&vtep_ip.s_addr, s, sizeof(vtep_ip.s_addr));
    2469             : 
    2470           0 :         if (hdr->command == ZEBRA_REMOTE_ES_VTEP_ADD) {
    2471           0 :                 uint32_t zapi_flags;
    2472           0 :                 uint8_t df_alg;
    2473           0 :                 uint16_t df_pref;
    2474           0 :                 bool esr_rxed;
    2475             : 
    2476           0 :                 STREAM_GETL(s, zapi_flags);
    2477           0 :                 esr_rxed = (zapi_flags & ZAPI_ES_VTEP_FLAG_ESR_RXED) ? true
    2478             :                                                                      : false;
    2479           0 :                 STREAM_GETC(s, df_alg);
    2480           0 :                 STREAM_GETW(s, df_pref);
    2481           0 :                 zebra_rib_queue_evpn_rem_es_add(&esi, &vtep_ip, esr_rxed,
    2482             :                                                 df_alg, df_pref);
    2483             :         } else {
    2484           0 :                 zebra_rib_queue_evpn_rem_es_del(&esi, &vtep_ip);
    2485             :         }
    2486             : 
    2487           0 : stream_failure:
    2488             :         return;
    2489             : }
    2490             : 
    2491           0 : void zebra_evpn_es_mac_deref_entry(struct zebra_mac *mac)
    2492             : {
    2493           0 :         struct zebra_evpn_es *es = mac->es;
    2494             : 
    2495           0 :         mac->es = NULL;
    2496           0 :         if (!es)
    2497           0 :                 return;
    2498             : 
    2499           0 :         list_delete_node(es->mac_list, &mac->es_listnode);
    2500           0 :         if (!listcount(es->mac_list))
    2501           0 :                 zebra_evpn_es_free(&es);
    2502             : }
    2503             : 
    2504             : /* Associate a MAC entry with a local or remote ES. Returns false if there
    2505             :  * was no ES change.
    2506             :  */
    2507           0 : bool zebra_evpn_es_mac_ref_entry(struct zebra_mac *mac,
    2508             :                                  struct zebra_evpn_es *es)
    2509             : {
    2510           0 :         if (mac->es == es)
    2511             :                 return false;
    2512             : 
    2513           0 :         if (mac->es)
    2514           0 :                 zebra_evpn_es_mac_deref_entry(mac);
    2515             : 
    2516           0 :         if (!es)
    2517             :                 return true;
    2518             : 
    2519           0 :         mac->es = es;
    2520           0 :         listnode_init(&mac->es_listnode, mac);
    2521           0 :         listnode_add(es->mac_list, &mac->es_listnode);
    2522             : 
    2523           0 :         return true;
    2524             : }
    2525             : 
    2526           0 : bool zebra_evpn_es_mac_ref(struct zebra_mac *mac, const esi_t *esi)
    2527             : {
    2528           0 :         struct zebra_evpn_es *es;
    2529             : 
    2530           0 :         es = zebra_evpn_es_find(esi);
    2531           0 :         if (!es) {
    2532             :                 /* If non-zero esi implicitly create a new ES */
    2533           0 :                 if (memcmp(esi, zero_esi, sizeof(esi_t))) {
    2534           0 :                         es = zebra_evpn_es_new(esi);
    2535           0 :                         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2536           0 :                                 zlog_debug("auto es %s add on mac ref",
    2537             :                                            es->esi_str);
    2538             :                 }
    2539             :         }
    2540             : 
    2541           0 :         return zebra_evpn_es_mac_ref_entry(mac, es);
    2542             : }
    2543             : 
    2544             : /* Inform BGP about local ES-EVI add or del */
    2545           0 : static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
    2546             :                                             struct zebra_evpn *zevpn, bool add)
    2547             : {
    2548           0 :         struct zserv *client;
    2549           0 :         struct stream *s;
    2550             : 
    2551           0 :         client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
    2552             :         /* BGP may not be running. */
    2553           0 :         if (!client)
    2554             :                 return 0;
    2555             : 
    2556           0 :         s = stream_new(ZEBRA_MAX_PACKET_SIZ);
    2557             : 
    2558           0 :         zclient_create_header(s,
    2559             :                         add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL,
    2560             :                         zebra_vrf_get_evpn_id());
    2561           0 :         stream_put(s, &es->esi, sizeof(esi_t));
    2562           0 :         stream_putl(s, zevpn->vni);
    2563             : 
    2564             :         /* Write packet size. */
    2565           0 :         stream_putw_at(s, 0, stream_get_endp(s));
    2566             : 
    2567           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2568           0 :                 zlog_debug("send %s local es %s evi %u to %s",
    2569             :                                 add ? "add" : "del",
    2570             :                                 es->esi_str, zevpn->vni,
    2571             :                                 zebra_route_string(client->proto));
    2572             : 
    2573           0 :         client->local_es_add_cnt++;
    2574           0 :         return zserv_send_message(client, s);
    2575             : }
    2576             : 
    2577             : /* sysmac part of a local ESI has changed */
    2578           0 : static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
    2579             :                 struct ethaddr *sysmac)
    2580             : {
    2581           0 :         int rv;
    2582             : 
    2583           0 :         rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac);
    2584           0 :         if (!rv)
    2585           0 :                 memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
    2586             : 
    2587           0 :         return rv;
    2588             : }
    2589             : 
    2590             : /* local-ID part of ESI has changed */
    2591           0 : static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
    2592             : {
    2593           0 :         int rv;
    2594             : 
    2595           0 :         rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac);
    2596           0 :         if (!rv)
    2597           0 :                 zif->es_info.lid = lid;
    2598             : 
    2599           0 :         return rv;
    2600             : }
    2601             : 
    2602             : /* type-0 esi has changed */
    2603           0 : static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi)
    2604             : {
    2605           0 :         int rv;
    2606             : 
    2607           0 :         rv = zebra_evpn_local_es_update(zif, esi);
    2608             : 
    2609             :         /* clear the old es_lid, es_sysmac - type-0 is being set so old
    2610             :          * type-3 params need to be flushed
    2611             :          */
    2612           0 :         memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr));
    2613           0 :         zif->es_info.lid = 0;
    2614             : 
    2615           0 :         return rv;
    2616             : }
    2617             : 
    2618           1 : void zebra_evpn_es_cleanup(void)
    2619             : {
    2620           1 :         struct zebra_evpn_es *es;
    2621           1 :         struct zebra_evpn_es *es_next;
    2622             : 
    2623           1 :         RB_FOREACH_SAFE(es, zebra_es_rb_head,
    2624             :                         &zmh_info->es_rb_tree, es_next) {
    2625           0 :                 zebra_evpn_local_es_del(&es);
    2626           0 :                 if (es)
    2627           0 :                         zebra_evpn_remote_es_flush(&es);
    2628             :         }
    2629           1 : }
    2630             : 
    2631           0 : static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref)
    2632             : {
    2633           0 :         struct zebra_evpn_es *es;
    2634           0 :         uint16_t tmp_pref;
    2635             : 
    2636           0 :         if (zif->es_info.df_pref == df_pref)
    2637             :                 return;
    2638             : 
    2639           0 :         zif->es_info.df_pref = df_pref;
    2640           0 :         es = zif->es_info.es;
    2641             : 
    2642           0 :         if (!es)
    2643             :                 return;
    2644             : 
    2645           0 :         tmp_pref = zif->es_info.df_pref ? zif->es_info.df_pref
    2646             :                                         : EVPN_MH_DF_PREF_DEFAULT;
    2647             : 
    2648           0 :         if (es->df_pref == tmp_pref)
    2649             :                 return;
    2650             : 
    2651           0 :         es->df_pref = tmp_pref;
    2652             :         /* run df election */
    2653           0 :         zebra_evpn_es_run_df_election(es, __func__);
    2654             :         /* notify bgp */
    2655           0 :         if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
    2656           0 :                 zebra_evpn_es_send_add_to_client(es);
    2657             : }
    2658             : 
    2659             : /* If bypass mode on an es changed we set all local macs to
    2660             :  * inactive and drop the sync info
    2661             :  */
    2662           0 : static void zebra_evpn_es_bypass_update_macs(struct zebra_evpn_es *es,
    2663             :                                              struct interface *ifp, bool bypass)
    2664             : {
    2665           0 :         struct zebra_mac *mac;
    2666           0 :         struct listnode *node;
    2667           0 :         struct listnode *nnode;
    2668           0 :         struct zebra_if *zif;
    2669             : 
    2670             :         /* Flush all MACs linked to the ES */
    2671           0 :         for (ALL_LIST_ELEMENTS(es->mac_list, node, nnode, mac)) {
    2672           0 :                 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
    2673           0 :                         continue;
    2674             : 
    2675           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    2676           0 :                         zlog_debug("VNI %u mac %pEA %s update es %s",
    2677             :                                    mac->zevpn->vni,
    2678             :                                    &mac->macaddr,
    2679             :                                    bypass ? "bypass" : "non-bypass",
    2680             :                                    es->esi_str);
    2681           0 :                 zebra_evpn_flush_local_mac(mac, ifp);
    2682             :         }
    2683             : 
    2684             :         /* While in bypass-mode locally learnt MACs are linked
    2685             :          * to the access port instead of the ES
    2686             :          */
    2687           0 :         zif = ifp->info;
    2688           0 :         if (!zif->mac_list)
    2689             :                 return;
    2690             : 
    2691           0 :         for (ALL_LIST_ELEMENTS(zif->mac_list, node, nnode, mac)) {
    2692           0 :                 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
    2693           0 :                         continue;
    2694             : 
    2695           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    2696           0 :                         zlog_debug("VNI %u mac %pEA %s update ifp %s",
    2697             :                                    mac->zevpn->vni,
    2698             :                                    &mac->macaddr,
    2699             :                                    bypass ? "bypass" : "non-bypass", ifp->name);
    2700           0 :                 zebra_evpn_flush_local_mac(mac, ifp);
    2701             :         }
    2702             : }
    2703             : 
    2704           0 : void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es,
    2705             :                                  struct interface *ifp, bool bypass)
    2706             : {
    2707           0 :         bool old_bypass;
    2708           0 :         bool dplane_updated;
    2709             : 
    2710           0 :         old_bypass = !!(es->flags & ZEBRA_EVPNES_BYPASS);
    2711           0 :         if (old_bypass == bypass)
    2712             :                 return;
    2713             : 
    2714           0 :         if (bypass)
    2715           0 :                 es->flags |= ZEBRA_EVPNES_BYPASS;
    2716             :         else
    2717           0 :                 es->flags &= ~ZEBRA_EVPNES_BYPASS;
    2718             : 
    2719           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2720           0 :                 zlog_debug("bond %s es %s lacp bypass changed to %s", ifp->name,
    2721             :                            es->esi_str, bypass ? "on" : "off");
    2722             : 
    2723             :         /* send bypass update to BGP */
    2724           0 :         if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
    2725           0 :                 zebra_evpn_es_send_add_to_client(es);
    2726             : 
    2727           0 :         zebra_evpn_es_bypass_update_macs(es, ifp, bypass);
    2728             : 
    2729             :         /* re-run DF election */
    2730           0 :         dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
    2731             : 
    2732             :         /* disable SPH filter */
    2733           0 :         if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL)
    2734           0 :             && (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT))
    2735           0 :                 zebra_evpn_es_br_port_dplane_update(es, __func__);
    2736             : }
    2737             : 
    2738           0 : static void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass)
    2739             : {
    2740           0 :         bool old_bypass = !!(zif->es_info.flags & ZIF_CFG_ES_FLAG_BYPASS);
    2741             : 
    2742           0 :         if (old_bypass == bypass)
    2743             :                 return;
    2744             : 
    2745           0 :         if (bypass)
    2746           0 :                 zif->es_info.flags |= ZIF_CFG_ES_FLAG_BYPASS;
    2747             :         else
    2748           0 :                 zif->es_info.flags &= ~ZIF_CFG_ES_FLAG_BYPASS;
    2749             : 
    2750             : 
    2751           0 :         if (zif->es_info.es)
    2752           0 :                 zebra_evpn_es_bypass_update(zif->es_info.es, zif->ifp, bypass);
    2753             : }
    2754             : 
    2755             : 
    2756             : /* Only certain types of access ports can be setup as an Ethernet Segment */
    2757           7 : bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
    2758             : {
    2759           7 :         if (zif->zif_type == ZEBRA_IF_BOND)
    2760             :                 return true;
    2761             : 
    2762             :         /* relax the checks to allow config to be applied in zebra
    2763             :          * before interface is rxed from the kernel
    2764             :          */
    2765           7 :         if (zif->ifp->ifindex == IFINDEX_INTERNAL)
    2766           0 :                 return true;
    2767             : 
    2768             :         /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
    2769             :         return false;
    2770             : }
    2771             : 
    2772           0 : void zebra_evpn_if_es_print(struct vty *vty, json_object *json,
    2773             :                             struct zebra_if *zif)
    2774             : {
    2775           0 :         char buf[ETHER_ADDR_STRLEN];
    2776           0 :         char esi_buf[ESI_STR_LEN];
    2777             : 
    2778           0 :         if (json) {
    2779           0 :                 json_object *json_evpn;
    2780             : 
    2781           0 :                 json_evpn = json_object_new_object();
    2782           0 :                 json_object_object_add(json, "evpnMh", json_evpn);
    2783             : 
    2784           0 :                 if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
    2785           0 :                         json_object_int_add(json_evpn, "esId",
    2786           0 :                                             zif->es_info.lid);
    2787           0 :                         json_object_string_add(
    2788             :                                 json_evpn, "esSysmac",
    2789           0 :                                 prefix_mac2str(&zif->es_info.sysmac, buf,
    2790             :                                                sizeof(buf)));
    2791           0 :                 } else if (memcmp(&zif->es_info.esi, zero_esi,
    2792             :                                   sizeof(*zero_esi))) {
    2793           0 :                         json_object_string_add(json_evpn, "esId",
    2794           0 :                                                esi_to_str(&zif->es_info.esi,
    2795             :                                                           esi_buf,
    2796             :                                                           sizeof(esi_buf)));
    2797             :                 }
    2798             : 
    2799           0 :                 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
    2800           0 :                         json_object_string_add(
    2801             :                                 json_evpn, "uplink",
    2802           0 :                                 CHECK_FLAG(zif->flags,
    2803             :                                            ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
    2804             :                                         ? "up"
    2805             :                                         : "down");
    2806             :         } else {
    2807           0 :                 char mh_buf[80];
    2808           0 :                 bool vty_print = false;
    2809             : 
    2810           0 :                 mh_buf[0] = '\0';
    2811           0 :                 strlcat(mh_buf, "  EVPN-MH:", sizeof(mh_buf));
    2812           0 :                 if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
    2813           0 :                         vty_print = true;
    2814           0 :                         snprintf(mh_buf + strlen(mh_buf),
    2815           0 :                                  sizeof(mh_buf) - strlen(mh_buf),
    2816             :                                  " ES id %u ES sysmac %s", zif->es_info.lid,
    2817           0 :                                  prefix_mac2str(&zif->es_info.sysmac, buf,
    2818             :                                                 sizeof(buf)));
    2819           0 :                 } else if (memcmp(&zif->es_info.esi, zero_esi,
    2820             :                                   sizeof(*zero_esi))) {
    2821           0 :                         vty_print = true;
    2822           0 :                         snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
    2823             :                                  sizeof(mh_buf)
    2824           0 :                                          - strnlen(mh_buf, sizeof(mh_buf)),
    2825             :                                  " ES id %s",
    2826             :                                  esi_to_str(&zif->es_info.esi, esi_buf,
    2827             :                                             sizeof(esi_buf)));
    2828             :                 }
    2829             : 
    2830           0 :                 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
    2831           0 :                         vty_print = true;
    2832           0 :                         if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
    2833           0 :                                 strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
    2834             :                         else
    2835           0 :                                 strlcat(mh_buf, " uplink (down)",
    2836             :                                         sizeof(mh_buf));
    2837             :                 }
    2838             : 
    2839           0 :                 if (vty_print)
    2840           0 :                         vty_out(vty, "%s\n", mh_buf);
    2841             :         }
    2842           0 : }
    2843             : 
    2844           0 : static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es *es)
    2845             : {
    2846           0 :         struct zebra_mac *mac;
    2847           0 :         struct listnode *node;
    2848             : 
    2849             :         /* If fast-failover is supported by the dataplane via the use
    2850             :          * of an ES backup NHG there is nothing to be done in the
    2851             :          * control plane
    2852             :          */
    2853           0 :         if (!(zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF))
    2854             :                 return;
    2855             : 
    2856           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    2857           0 :                 zlog_debug("mac slow-fail on es %s %s ", es->esi_str,
    2858             :                            (es->flags & ZEBRA_EVPNES_OPER_UP) ? "up" : "down");
    2859             : 
    2860           0 :         for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
    2861           0 :                 if (!(mac->flags & ZEBRA_MAC_LOCAL)
    2862           0 :                     || !zebra_evpn_mac_is_static(mac))
    2863           0 :                         continue;
    2864             : 
    2865           0 :                 if (es->flags & ZEBRA_EVPNES_OPER_UP) {
    2866           0 :                         if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    2867           0 :                                 zlog_debug(
    2868             :                                         "VNI %u mac %pEA move to acc %s es %s %s ",
    2869             :                                         mac->zevpn->vni,
    2870             :                                         &mac->macaddr,
    2871             :                                         es->zif->ifp->name, es->esi_str,
    2872             :                                         (es->flags & ZEBRA_EVPNES_OPER_UP)
    2873             :                                                 ? "up"
    2874             :                                                 : "down");
    2875             :                         /* switch the local macs to access port */
    2876           0 :                         if (zebra_evpn_sync_mac_dp_install(
    2877             :                                     mac, false /*set_inactive*/,
    2878             :                                     false /*force_clear_static*/, __func__)
    2879             :                             < 0)
    2880             :                                 /* if the local mac install fails get rid of the
    2881             :                                  * old rem entry
    2882             :                                  */
    2883           0 :                                 zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
    2884             :                                                              true /*force*/);
    2885             :                 } else {
    2886             :                         /* switch the local macs to network port. if there
    2887             :                          * is no active NHG we don't bother deleting the MAC;
    2888             :                          * that is left up to the dataplane to handle.
    2889             :                          */
    2890           0 :                         if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
    2891           0 :                                 continue;
    2892           0 :                         if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
    2893           0 :                                 zlog_debug(
    2894             :                                         "VNI %u mac %pEA move to nhg %u es %s %s ",
    2895             :                                         mac->zevpn->vni,
    2896             :                                         &mac->macaddr,
    2897             :                                         es->nhg_id, es->esi_str,
    2898             :                                         (es->flags & ZEBRA_EVPNES_OPER_UP)
    2899             :                                                 ? "up"
    2900             :                                                 : "down");
    2901           0 :                         zebra_evpn_rem_mac_install(mac->zevpn, mac,
    2902             :                                                    true /*was_static*/);
    2903             :                 }
    2904             :         }
    2905             : }
    2906             : 
    2907           0 : void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
    2908             : {
    2909           0 :         struct zebra_evpn_es *es = zif->es_info.es;
    2910           0 :         bool old_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
    2911             : 
    2912           0 :         if (old_up == up)
    2913             :                 return;
    2914             : 
    2915           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    2916           0 :                 zlog_debug("es %s state changed to %s ",
    2917             :                                 es->esi_str,
    2918             :                                 up ? "up" : "down");
    2919           0 :         if (up)
    2920           0 :                 es->flags |= ZEBRA_EVPNES_OPER_UP;
    2921             :         else
    2922           0 :                 es->flags &= ~ZEBRA_EVPNES_OPER_UP;
    2923             : 
    2924           0 :         zebra_evpn_es_run_df_election(es, __func__);
    2925           0 :         zebra_evpn_local_mac_oper_state_change(es);
    2926             : 
    2927             :         /* inform BGP of the ES oper state change */
    2928           0 :         if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
    2929           0 :                 zebra_evpn_es_send_add_to_client(es);
    2930             : }
    2931             : 
    2932           0 : static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es,
    2933             :                                     uint8_t vtep_str_size)
    2934             : {
    2935           0 :         struct zebra_evpn_es_vtep *zvtep;
    2936           0 :         struct listnode *node;
    2937           0 :         bool first = true;
    2938           0 :         char ip_buf[INET6_ADDRSTRLEN];
    2939             : 
    2940           0 :         vtep_str[0] = '\0';
    2941           0 :         for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep)) {
    2942           0 :                 if (first) {
    2943           0 :                         first = false;
    2944           0 :                         strlcat(vtep_str,
    2945           0 :                                 inet_ntop(AF_INET, &zvtep->vtep_ip, ip_buf,
    2946             :                                           sizeof(ip_buf)),
    2947             :                                 vtep_str_size);
    2948             :                 } else {
    2949           0 :                         strlcat(vtep_str, ",", vtep_str_size);
    2950           0 :                         strlcat(vtep_str,
    2951           0 :                                 inet_ntop(AF_INET, &zvtep->vtep_ip, ip_buf,
    2952             :                                           sizeof(ip_buf)),
    2953             :                                 vtep_str_size);
    2954             :                 }
    2955             :         }
    2956           0 :         return vtep_str;
    2957             : }
    2958             : 
    2959           0 : static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es *es,
    2960             :                                          json_object *json_vteps)
    2961             : {
    2962           0 :         struct zebra_evpn_es_vtep *es_vtep;
    2963           0 :         struct listnode *node;
    2964           0 :         json_object *json_vtep_entry;
    2965           0 :         char alg_buf[EVPN_DF_ALG_STR_LEN];
    2966             : 
    2967           0 :         for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
    2968           0 :                 json_vtep_entry = json_object_new_object();
    2969           0 :                 json_object_string_addf(json_vtep_entry, "vtep", "%pI4",
    2970             :                                         &es_vtep->vtep_ip);
    2971           0 :                 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
    2972           0 :                         json_object_string_add(
    2973             :                                 json_vtep_entry, "dfAlgorithm",
    2974           0 :                                 evpn_es_df_alg2str(es_vtep->df_alg, alg_buf,
    2975             :                                                    sizeof(alg_buf)));
    2976           0 :                         json_object_int_add(json_vtep_entry, "dfPreference",
    2977           0 :                                             es_vtep->df_pref);
    2978             :                 }
    2979           0 :                 if (es_vtep->nh)
    2980           0 :                         json_object_int_add(json_vtep_entry, "nexthopId",
    2981           0 :                                             es_vtep->nh->nh_id);
    2982           0 :                 json_object_array_add(json_vteps, json_vtep_entry);
    2983             :         }
    2984           0 : }
    2985             : 
    2986           0 : static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es,
    2987             :                                      json_object *json_array)
    2988             : {
    2989           0 :         char type_str[5];
    2990           0 :         char vtep_str[ES_VTEP_LIST_STR_SZ];
    2991             : 
    2992           0 :         if (json_array) {
    2993           0 :                 json_object *json = NULL;
    2994           0 :                 json_object *json_vteps;
    2995           0 :                 json_object *json_flags;
    2996             : 
    2997           0 :                 json = json_object_new_object();
    2998           0 :                 json_object_string_add(json, "esi", es->esi_str);
    2999             : 
    3000           0 :                 if (es->flags
    3001           0 :                     & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE
    3002             :                        | ZEBRA_EVPNES_NON_DF)) {
    3003           0 :                         json_flags = json_object_new_array();
    3004           0 :                         if (es->flags & ZEBRA_EVPNES_LOCAL)
    3005           0 :                                 json_array_string_add(json_flags, "local");
    3006           0 :                         if (es->flags & ZEBRA_EVPNES_REMOTE)
    3007           0 :                                 json_array_string_add(json_flags, "remote");
    3008           0 :                         if (es->flags & ZEBRA_EVPNES_NON_DF)
    3009           0 :                                 json_array_string_add(json_flags, "nonDF");
    3010           0 :                         if (es->flags & ZEBRA_EVPNES_BYPASS)
    3011           0 :                                 json_array_string_add(json_flags, "bypass");
    3012           0 :                         json_object_object_add(json, "flags", json_flags);
    3013             :                 }
    3014             : 
    3015           0 :                 if (es->zif)
    3016           0 :                         json_object_string_add(json, "accessPort",
    3017           0 :                                                es->zif->ifp->name);
    3018             : 
    3019           0 :                 if (listcount(es->es_vtep_list)) {
    3020           0 :                         json_vteps = json_object_new_array();
    3021           0 :                         zebra_evpn_es_json_vtep_fill(es, json_vteps);
    3022           0 :                         json_object_object_add(json, "vteps", json_vteps);
    3023             :                 }
    3024           0 :                 json_object_array_add(json_array, json);
    3025             :         } else {
    3026           0 :                 type_str[0] = '\0';
    3027           0 :                 if (es->flags & ZEBRA_EVPNES_LOCAL)
    3028           0 :                         strlcat(type_str, "L", sizeof(type_str));
    3029           0 :                 if (es->flags & ZEBRA_EVPNES_REMOTE)
    3030           0 :                         strlcat(type_str, "R", sizeof(type_str));
    3031           0 :                 if (es->flags & ZEBRA_EVPNES_NON_DF)
    3032           0 :                         strlcat(type_str, "N", sizeof(type_str));
    3033           0 :                 if (es->flags & ZEBRA_EVPNES_BYPASS)
    3034           0 :                         strlcat(type_str, "B", sizeof(type_str));
    3035             : 
    3036           0 :                 zebra_evpn_es_vtep_str(vtep_str, es, sizeof(vtep_str));
    3037             : 
    3038           0 :                 vty_out(vty, "%-30s %-4s %-21s %s\n",
    3039           0 :                                 es->esi_str, type_str,
    3040           0 :                                 es->zif ? es->zif->ifp->name : "-",
    3041             :                                 vtep_str);
    3042             :         }
    3043           0 : }
    3044             : 
    3045           0 : static void zebra_evpn_es_show_entry_detail(struct vty *vty,
    3046             :                 struct zebra_evpn_es *es, json_object *json)
    3047             : {
    3048           0 :         char type_str[80];
    3049           0 :         char alg_buf[EVPN_DF_ALG_STR_LEN];
    3050           0 :         struct zebra_evpn_es_vtep *es_vtep;
    3051           0 :         struct listnode *node;
    3052           0 :         char thread_buf[THREAD_TIMER_STRLEN];
    3053             : 
    3054           0 :         if (json) {
    3055           0 :                 json_object *json_vteps;
    3056           0 :                 json_object *json_flags;
    3057             : 
    3058           0 :                 json_object_string_add(json, "esi", es->esi_str);
    3059           0 :                 if (es->zif)
    3060           0 :                         json_object_string_add(json, "accessPort",
    3061           0 :                                                es->zif->ifp->name);
    3062             : 
    3063             : 
    3064           0 :                 if (es->flags) {
    3065           0 :                         json_flags = json_object_new_array();
    3066           0 :                         if (es->flags & ZEBRA_EVPNES_LOCAL)
    3067           0 :                                 json_array_string_add(json_flags, "local");
    3068           0 :                         if (es->flags & ZEBRA_EVPNES_REMOTE)
    3069           0 :                                 json_array_string_add(json_flags, "remote");
    3070           0 :                         if (es->flags & ZEBRA_EVPNES_NON_DF)
    3071           0 :                                 json_array_string_add(json_flags, "nonDF");
    3072           0 :                         if (es->flags & ZEBRA_EVPNES_BYPASS)
    3073           0 :                                 json_array_string_add(json_flags, "bypass");
    3074           0 :                         if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
    3075           0 :                                 json_array_string_add(json_flags,
    3076             :                                                       "readyForBgp");
    3077           0 :                         if (es->flags & ZEBRA_EVPNES_BR_PORT)
    3078           0 :                                 json_array_string_add(json_flags, "bridgePort");
    3079           0 :                         if (es->flags & ZEBRA_EVPNES_OPER_UP)
    3080           0 :                                 json_array_string_add(json_flags, "operUp");
    3081           0 :                         if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
    3082           0 :                                 json_array_string_add(json_flags,
    3083             :                                                       "nexthopGroupActive");
    3084           0 :                         json_object_object_add(json, "flags", json_flags);
    3085             :                 }
    3086             : 
    3087           0 :                 json_object_int_add(json, "vniCount",
    3088           0 :                                     listcount(es->es_evi_list));
    3089           0 :                 json_object_int_add(json, "macCount", listcount(es->mac_list));
    3090           0 :                 json_object_int_add(json, "dfPreference", es->df_pref);
    3091           0 :                 if (es->df_delay_timer)
    3092           0 :                         json_object_string_add(
    3093             :                                 json, "dfDelayTimer",
    3094           0 :                                 thread_timer_to_hhmmss(thread_buf,
    3095             :                                                        sizeof(thread_buf),
    3096             :                                                        es->df_delay_timer));
    3097           0 :                 json_object_int_add(json, "nexthopGroup", es->nhg_id);
    3098           0 :                 if (listcount(es->es_vtep_list)) {
    3099           0 :                         json_vteps = json_object_new_array();
    3100           0 :                         zebra_evpn_es_json_vtep_fill(es, json_vteps);
    3101           0 :                         json_object_object_add(json, "vteps", json_vteps);
    3102             :                 }
    3103             :         } else {
    3104           0 :                 type_str[0] = '\0';
    3105           0 :                 if (es->flags & ZEBRA_EVPNES_LOCAL)
    3106           0 :                         strlcat(type_str, "Local", sizeof(type_str));
    3107           0 :                 if (es->flags & ZEBRA_EVPNES_REMOTE) {
    3108           0 :                         if (strnlen(type_str, sizeof(type_str)))
    3109           0 :                                 strlcat(type_str, ",", sizeof(type_str));
    3110           0 :                         strlcat(type_str, "Remote", sizeof(type_str));
    3111             :                 }
    3112             : 
    3113           0 :                 vty_out(vty, "ESI: %s\n", es->esi_str);
    3114           0 :                 vty_out(vty, " Type: %s\n", type_str);
    3115           0 :                 vty_out(vty, " Interface: %s\n",
    3116           0 :                                 (es->zif) ?
    3117           0 :                                 es->zif->ifp->name : "-");
    3118           0 :                 if (es->flags & ZEBRA_EVPNES_LOCAL) {
    3119           0 :                         vty_out(vty, " State: %s\n",
    3120           0 :                                 (es->flags & ZEBRA_EVPNES_OPER_UP) ? "up"
    3121             :                                                                    : "down");
    3122           0 :                         vty_out(vty, " Bridge port: %s\n",
    3123           0 :                                 (es->flags & ZEBRA_EVPNES_BR_PORT) ? "yes"
    3124             :                                                                    : "no");
    3125             :                 }
    3126           0 :                 vty_out(vty, " Ready for BGP: %s\n",
    3127           0 :                                 (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ?
    3128             :                                 "yes" : "no");
    3129           0 :                 if (es->flags & ZEBRA_EVPNES_BYPASS)
    3130           0 :                         vty_out(vty, " LACP bypass: on\n");
    3131           0 :                 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
    3132           0 :                 vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
    3133           0 :                 if (es->flags & ZEBRA_EVPNES_LOCAL)
    3134           0 :                         vty_out(vty, " DF status: %s \n",
    3135           0 :                                 (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
    3136             :                                                                   : "df");
    3137           0 :                 if (es->df_delay_timer)
    3138           0 :                         vty_out(vty, " DF delay: %s\n",
    3139             :                                 thread_timer_to_hhmmss(thread_buf,
    3140             :                                                        sizeof(thread_buf),
    3141             :                                                        es->df_delay_timer));
    3142           0 :                 vty_out(vty, " DF preference: %u\n", es->df_pref);
    3143           0 :                 vty_out(vty, " Nexthop group: %u\n", es->nhg_id);
    3144           0 :                 vty_out(vty, " VTEPs:\n");
    3145           0 :                 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
    3146           0 :                         vty_out(vty, "     %pI4",
    3147             :                                         &es_vtep->vtep_ip);
    3148           0 :                         if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR)
    3149           0 :                                 vty_out(vty, " df_alg: %s df_pref: %d",
    3150           0 :                                         evpn_es_df_alg2str(es_vtep->df_alg,
    3151             :                                                            alg_buf,
    3152             :                                                            sizeof(alg_buf)),
    3153             :                                         es_vtep->df_pref);
    3154           0 :                         vty_out(vty, " nh: %u\n",
    3155           0 :                                 es_vtep->nh ? es_vtep->nh->nh_id : 0);
    3156             :                 }
    3157             : 
    3158           0 :                 vty_out(vty, "\n");
    3159             :         }
    3160           0 : }
    3161             : 
    3162           0 : void zebra_evpn_es_show(struct vty *vty, bool uj)
    3163             : {
    3164           0 :         struct zebra_evpn_es *es;
    3165           0 :         json_object *json_array = NULL;
    3166             : 
    3167           0 :         if (uj) {
    3168           0 :                 json_array = json_object_new_array();
    3169             :         } else {
    3170           0 :                 vty_out(vty, "Type: B bypass, L local, R remote, N non-DF\n");
    3171           0 :                 vty_out(vty, "%-30s %-4s %-21s %s\n",
    3172             :                                 "ESI", "Type", "ES-IF", "VTEPs");
    3173             :         }
    3174             : 
    3175           0 :         RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
    3176           0 :                 zebra_evpn_es_show_entry(vty, es, json_array);
    3177             : 
    3178           0 :         if (uj)
    3179           0 :                 vty_json(vty, json_array);
    3180           0 : }
    3181             : 
    3182           0 : void zebra_evpn_es_show_detail(struct vty *vty, bool uj)
    3183             : {
    3184           0 :         struct zebra_evpn_es *es;
    3185           0 :         json_object *json_array = NULL;
    3186             : 
    3187           0 :         if (uj)
    3188           0 :                 json_array = json_object_new_array();
    3189             : 
    3190           0 :         RB_FOREACH (es, zebra_es_rb_head, &zmh_info->es_rb_tree) {
    3191           0 :                 json_object *json = NULL;
    3192             : 
    3193           0 :                 if (uj)
    3194           0 :                         json = json_object_new_object();
    3195           0 :                 zebra_evpn_es_show_entry_detail(vty, es, json);
    3196           0 :                 if (uj)
    3197           0 :                         json_object_array_add(json_array, json);
    3198             :         }
    3199             : 
    3200           0 :         if (uj)
    3201           0 :                 vty_json(vty, json_array);
    3202           0 : }
    3203             : 
    3204           0 : void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi)
    3205             : {
    3206           0 :         struct zebra_evpn_es *es;
    3207           0 :         char esi_str[ESI_STR_LEN];
    3208           0 :         json_object *json = NULL;
    3209             : 
    3210           0 :         if (uj)
    3211           0 :                 json = json_object_new_object();
    3212             : 
    3213           0 :         es = zebra_evpn_es_find(esi);
    3214             : 
    3215           0 :         if (es) {
    3216           0 :                 zebra_evpn_es_show_entry_detail(vty, es, json);
    3217             :         } else {
    3218           0 :                 if (!uj) {
    3219           0 :                         esi_to_str(esi, esi_str, sizeof(esi_str));
    3220           0 :                         vty_out(vty, "ESI %s does not exist\n", esi_str);
    3221             :                 }
    3222             :         }
    3223             : 
    3224           0 :         if (uj)
    3225           0 :                 vty_json(vty, json);
    3226           0 : }
    3227             : 
    3228           0 : int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
    3229             : {
    3230           0 :         struct zebra_if *zif = ifp->info;
    3231           0 :         char buf[ETHER_ADDR_STRLEN];
    3232           0 :         bool type_3_esi = false;
    3233           0 :         char esi_buf[ESI_STR_LEN];
    3234             : 
    3235           0 :         if (zif->es_info.lid) {
    3236           0 :                 vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
    3237           0 :                 type_3_esi = true;
    3238             :         }
    3239             : 
    3240           0 :         if (!is_zero_mac(&zif->es_info.sysmac)) {
    3241           0 :                 vty_out(vty, " evpn mh es-sys-mac %s\n",
    3242             :                                 prefix_mac2str(&zif->es_info.sysmac,
    3243             :                                         buf, sizeof(buf)));
    3244           0 :                 type_3_esi = true;
    3245             :         }
    3246             : 
    3247           0 :         if (!type_3_esi
    3248           0 :             && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
    3249           0 :                 vty_out(vty, " evpn mh es-id %s\n",
    3250             :                                 esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf)));
    3251             : 
    3252           0 :         if (zif->es_info.df_pref)
    3253           0 :                 vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
    3254             : 
    3255           0 :         if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
    3256           0 :                 vty_out(vty, " evpn mh uplink\n");
    3257             : 
    3258           0 :         return 0;
    3259             : }
    3260             : 
    3261             : #include "zebra/zebra_evpn_mh_clippy.c"
    3262             : /* CLI for setting an ES in bypass mode */
    3263           0 : DEFPY_HIDDEN(zebra_evpn_es_bypass, zebra_evpn_es_bypass_cmd,
    3264             :              "[no] evpn mh bypass",
    3265             :              NO_STR "EVPN\n" EVPN_MH_VTY_STR "set bypass mode\n")
    3266             : {
    3267           0 :         VTY_DECLVAR_CONTEXT(interface, ifp);
    3268           0 :         struct zebra_if *zif;
    3269             : 
    3270           0 :         zif = ifp->info;
    3271             : 
    3272           0 :         if (no) {
    3273           0 :                 zebra_evpn_es_bypass_cfg_update(zif, false);
    3274             :         } else {
    3275           0 :                 if (!zebra_evpn_is_if_es_capable(zif)) {
    3276           0 :                         vty_out(vty,
    3277             :                                 "%% DF bypass cannot be associated with this interface type\n");
    3278           0 :                         return CMD_WARNING;
    3279             :                 }
    3280           0 :                 zebra_evpn_es_bypass_cfg_update(zif, true);
    3281             :         }
    3282             :         return CMD_SUCCESS;
    3283             : }
    3284             : 
    3285             : /* CLI for configuring DF preference part for an ES */
    3286           0 : DEFPY(zebra_evpn_es_pref, zebra_evpn_es_pref_cmd,
    3287             :       "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
    3288             :       NO_STR "EVPN\n" EVPN_MH_VTY_STR
    3289             :              "preference value used for DF election\n"
    3290             :              "pref\n")
    3291             : {
    3292           0 :         VTY_DECLVAR_CONTEXT(interface, ifp);
    3293           0 :         struct zebra_if *zif;
    3294             : 
    3295           0 :         zif = ifp->info;
    3296             : 
    3297           0 :         if (no) {
    3298           0 :                 zebra_evpn_es_df_pref_update(zif, 0);
    3299             :         } else {
    3300           0 :                 if (!zebra_evpn_is_if_es_capable(zif)) {
    3301           0 :                         vty_out(vty,
    3302             :                                 "%% DF preference cannot be associated with this interface type\n");
    3303           0 :                         return CMD_WARNING;
    3304             :                 }
    3305           0 :                 zebra_evpn_es_df_pref_update(zif, df_pref);
    3306             :         }
    3307             :         return CMD_SUCCESS;
    3308             : }
    3309             : 
    3310             : /* CLI for setting up sysmac part of ESI on an access port */
    3311           0 : DEFPY(zebra_evpn_es_sys_mac,
    3312             :       zebra_evpn_es_sys_mac_cmd,
    3313             :       "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
    3314             :       NO_STR
    3315             :       "EVPN\n"
    3316             :       EVPN_MH_VTY_STR
    3317             :       "Ethernet segment system MAC\n"
    3318             :       MAC_STR
    3319             : )
    3320             : {
    3321           0 :         VTY_DECLVAR_CONTEXT(interface, ifp);
    3322           0 :         struct zebra_if *zif;
    3323           0 :         int ret = 0;
    3324             : 
    3325           0 :         zif = ifp->info;
    3326             : 
    3327           0 :         if (no) {
    3328           0 :                 static struct ethaddr zero_mac;
    3329             : 
    3330           0 :                 ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac);
    3331           0 :                 if (ret == -1) {
    3332           0 :                         vty_out(vty, "%% Failed to clear ES sysmac\n");
    3333           0 :                         return CMD_WARNING;
    3334             :                 }
    3335             :         } else {
    3336             : 
    3337           0 :                 if (!zebra_evpn_is_if_es_capable(zif)) {
    3338           0 :                         vty_out(vty,
    3339             :                                 "%% ESI cannot be associated with this interface type\n");
    3340           0 :                         return CMD_WARNING;
    3341             :                 }
    3342             : 
    3343           0 :                 if  (!mac || is_zero_mac(&mac->eth_addr)) {
    3344           0 :                         vty_out(vty, "%% ES sysmac value is invalid\n");
    3345           0 :                         return CMD_WARNING;
    3346             :                 }
    3347             : 
    3348           0 :                 ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr);
    3349           0 :                 if (ret == -1) {
    3350           0 :                         vty_out(vty,
    3351             :                                 "%% ESI already exists on a different interface\n");
    3352           0 :                         return CMD_WARNING;
    3353             :                 }
    3354             :         }
    3355             :         return CMD_SUCCESS;
    3356             : }
    3357             : 
    3358             : /* CLI for setting up local-ID part of ESI on an access port */
    3359           0 : DEFPY(zebra_evpn_es_id,
    3360             :       zebra_evpn_es_id_cmd,
    3361             :       "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
    3362             :       NO_STR
    3363             :       "EVPN\n"
    3364             :       EVPN_MH_VTY_STR
    3365             :       "Ethernet segment identifier\n"
    3366             :       "local discriminator\n"
    3367             :       "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
    3368             : )
    3369             : {
    3370           0 :         VTY_DECLVAR_CONTEXT(interface, ifp);
    3371           0 :         struct zebra_if *zif;
    3372           0 :         int ret = 0;
    3373           0 :         esi_t esi;
    3374             : 
    3375           0 :         zif = ifp->info;
    3376             : 
    3377           0 :         if (no) {
    3378           0 :                 if (zif->es_info.lid)
    3379           0 :                         ret = zebra_evpn_es_lid_update(zif, 0);
    3380           0 :                 else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
    3381           0 :                         ret = zebra_evpn_es_type0_esi_update(zif, zero_esi);
    3382             : 
    3383           0 :                 if (ret == -1) {
    3384           0 :                         vty_out(vty,
    3385             :                                 "%% Failed to clear ES local id or ESI name\n");
    3386           0 :                         return CMD_WARNING;
    3387             :                 }
    3388             :         } else {
    3389           0 :                 if (!zebra_evpn_is_if_es_capable(zif)) {
    3390           0 :                         vty_out(vty,
    3391             :                                 "%% ESI cannot be associated with this interface type\n");
    3392           0 :                         return CMD_WARNING;
    3393             :                 }
    3394             : 
    3395           0 :                 if (esi_str) {
    3396           0 :                         if (!str_to_esi(esi_str, &esi)) {
    3397           0 :                                 vty_out(vty, "%% Malformed ESI name\n");
    3398           0 :                                 return CMD_WARNING;
    3399             :                         }
    3400           0 :                         ret = zebra_evpn_es_type0_esi_update(zif, &esi);
    3401             :                 } else {
    3402           0 :                         if (!es_lid) {
    3403           0 :                                 vty_out(vty,
    3404             :                                         "%% Specify ES local id or ESI name\n");
    3405           0 :                                 return CMD_WARNING;
    3406             :                         }
    3407           0 :                         ret = zebra_evpn_es_lid_update(zif, es_lid);
    3408             :                 }
    3409             : 
    3410           0 :                 if (ret == -1) {
    3411           0 :                         vty_out(vty,
    3412             :                                 "%% ESI already exists on a different interface\n");
    3413           0 :                         return CMD_WARNING;
    3414             :                 }
    3415             :         }
    3416             :         return CMD_SUCCESS;
    3417             : }
    3418             : 
    3419             : /* CLI for tagging an interface as an uplink */
    3420           0 : DEFPY(zebra_evpn_mh_uplink, zebra_evpn_mh_uplink_cmd, "[no] evpn mh uplink",
    3421             :       NO_STR "EVPN\n" EVPN_MH_VTY_STR "uplink to the VxLAN core\n")
    3422             : {
    3423           0 :         VTY_DECLVAR_CONTEXT(interface, ifp);
    3424           0 :         struct zebra_if *zif;
    3425             : 
    3426           0 :         zif = ifp->info;
    3427           0 :         zebra_evpn_mh_uplink_cfg_update(zif, no ? false : true);
    3428             : 
    3429           0 :         return CMD_SUCCESS;
    3430             : }
    3431             : 
    3432           0 : void zebra_evpn_mh_json(json_object *json)
    3433             : {
    3434           0 :         json_object *json_array;
    3435           0 :         char thread_buf[THREAD_TIMER_STRLEN];
    3436             : 
    3437           0 :         json_object_int_add(json, "macHoldtime", zmh_info->mac_hold_time);
    3438           0 :         json_object_int_add(json, "neighHoldtime", zmh_info->neigh_hold_time);
    3439           0 :         json_object_int_add(json, "startupDelay", zmh_info->startup_delay_time);
    3440           0 :         json_object_string_add(
    3441             :                 json, "startupDelayTimer",
    3442           0 :                 thread_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
    3443           0 :                                        zmh_info->startup_delay_timer));
    3444           0 :         json_object_int_add(json, "uplinkConfigCount",
    3445           0 :                             zmh_info->uplink_cfg_cnt);
    3446           0 :         json_object_int_add(json, "uplinkActiveCount",
    3447           0 :                             zmh_info->uplink_oper_up_cnt);
    3448             : 
    3449           0 :         if (zmh_info->protodown_rc) {
    3450           0 :                 json_array = json_object_new_array();
    3451           0 :                 if (CHECK_FLAG(zmh_info->protodown_rc,
    3452             :                                ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY))
    3453           0 :                         json_object_array_add(
    3454             :                                 json_array,
    3455             :                                 json_object_new_string("startupDelay"));
    3456           0 :                 if (CHECK_FLAG(zmh_info->protodown_rc,
    3457             :                                ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN))
    3458           0 :                         json_object_array_add(
    3459             :                                 json_array,
    3460             :                                 json_object_new_string("uplinkDown"));
    3461           0 :                 json_object_object_add(json, "protodownReasons", json_array);
    3462             :         }
    3463           0 : }
    3464             : 
    3465           0 : void zebra_evpn_mh_print(struct vty *vty)
    3466             : {
    3467           0 :         char pd_buf[ZEBRA_PROTODOWN_RC_STR_LEN];
    3468           0 :         char thread_buf[THREAD_TIMER_STRLEN];
    3469             : 
    3470           0 :         vty_out(vty, "EVPN MH:\n");
    3471           0 :         vty_out(vty, "  mac-holdtime: %ds, neigh-holdtime: %ds\n",
    3472           0 :                 zmh_info->mac_hold_time, zmh_info->neigh_hold_time);
    3473           0 :         vty_out(vty, "  startup-delay: %ds, start-delay-timer: %s\n",
    3474           0 :                 zmh_info->startup_delay_time,
    3475             :                 thread_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
    3476           0 :                                        zmh_info->startup_delay_timer));
    3477           0 :         vty_out(vty, "  uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
    3478           0 :                 zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
    3479           0 :         if (zmh_info->protodown_rc)
    3480           0 :                 vty_out(vty, "  protodown reasons: %s\n",
    3481             :                         zebra_protodown_rc_str(zmh_info->protodown_rc, pd_buf,
    3482             :                                                sizeof(pd_buf)));
    3483           0 : }
    3484             : 
    3485             : /*****************************************************************************/
    3486             : /* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
    3487             :  * XXX: once single vxlan device model becomes available this will not be
    3488             :  * necessary
    3489             :  */
    3490             : /* called when a new vni is added or becomes oper up or becomes a bridge port */
    3491           0 : void zebra_evpn_es_set_base_evpn(struct zebra_evpn *zevpn)
    3492             : {
    3493           0 :         struct listnode *node;
    3494           0 :         struct zebra_evpn_es *es;
    3495             : 
    3496           0 :         if (zmh_info->es_base_evpn) {
    3497           0 :                 if (zmh_info->es_base_evpn != zevpn) {
    3498             :                         /* unrelated EVPN; ignore it */
    3499             :                         return;
    3500             :                 }
    3501             :                 /* check if the local vtep-ip has changed */
    3502             :         } else {
    3503             :                 /* check if the EVPN can be used as base EVPN */
    3504           0 :                 if (!zebra_evpn_send_to_client_ok(zevpn))
    3505             :                         return;
    3506             : 
    3507           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3508           0 :                         zlog_debug("es base vni set to %d",
    3509             :                                         zevpn->vni);
    3510           0 :                 zmh_info->es_base_evpn = zevpn;
    3511             :         }
    3512             : 
    3513             :         /* update local VTEP-IP */
    3514           0 :         if (zmh_info->es_originator_ip.s_addr ==
    3515           0 :                         zmh_info->es_base_evpn->local_vtep_ip.s_addr)
    3516             :                 return;
    3517             : 
    3518           0 :         zmh_info->es_originator_ip.s_addr =
    3519             :                 zmh_info->es_base_evpn->local_vtep_ip.s_addr;
    3520             : 
    3521           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3522           0 :                 zlog_debug("es originator ip set to %pI4",
    3523             :                         &zmh_info->es_base_evpn->local_vtep_ip);
    3524             : 
    3525             :         /* if originator ip changes we need to update bgp */
    3526           0 :         for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
    3527           0 :                 zebra_evpn_es_run_df_election(es, __func__);
    3528             : 
    3529           0 :                 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
    3530           0 :                         zebra_evpn_es_send_add_to_client(es);
    3531             :                 else
    3532           0 :                         zebra_evpn_es_re_eval_send_to_client(es,
    3533             :                                         true /* es_evi_re_reval */);
    3534             :         }
    3535             : }
    3536             : 
    3537             : /* called when a vni is removed or becomes oper down or is removed from a
    3538             :  * bridge
    3539             :  */
    3540           0 : void zebra_evpn_es_clear_base_evpn(struct zebra_evpn *zevpn)
    3541             : {
    3542           0 :         struct listnode *node;
    3543           0 :         struct zebra_evpn_es *es;
    3544             : 
    3545           0 :         if (zmh_info->es_base_evpn != zevpn)
    3546             :                 return;
    3547             : 
    3548           0 :         zmh_info->es_base_evpn = NULL;
    3549             :         /* lost current base EVPN; try to find a new one */
    3550           0 :         zebra_evpn_es_get_one_base_evpn();
    3551             : 
    3552             :         /* couldn't locate an eligible base evpn */
    3553           0 :         if (!zmh_info->es_base_evpn && zmh_info->es_originator_ip.s_addr) {
    3554           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3555           0 :                         zlog_debug("es originator ip cleared");
    3556             : 
    3557           0 :                 zmh_info->es_originator_ip.s_addr = 0;
    3558             :                 /* lost originator ip */
    3559           0 :                 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
    3560           0 :                         zebra_evpn_es_re_eval_send_to_client(es,
    3561             :                                         true /* es_evi_re_reval */);
    3562             :                 }
    3563             :         }
    3564             : }
    3565             : 
    3566             : /* Locate an "eligible" L2-VNI to follow */
    3567           0 : static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket *b, void *data)
    3568             : {
    3569           0 :         struct zebra_evpn *zevpn = b->data;
    3570             : 
    3571           0 :         zebra_evpn_es_set_base_evpn(zevpn);
    3572             : 
    3573           0 :         if (zmh_info->es_base_evpn)
    3574           0 :                 return HASHWALK_ABORT;
    3575             : 
    3576             :         return HASHWALK_CONTINUE;
    3577             : }
    3578             : 
    3579             : /* locate a base_evpn to follow for the purposes of common params like
    3580             :  * originator IP
    3581             :  */
    3582           0 : static void zebra_evpn_es_get_one_base_evpn(void)
    3583             : {
    3584           0 :         struct zebra_vrf *zvrf;
    3585             : 
    3586           0 :         zvrf = zebra_vrf_get_evpn();
    3587           0 :         hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
    3588           0 : }
    3589             : 
    3590             : /*****************************************************************************
    3591             :  * local ethernet segments can be error-disabled if the switch is not
    3592             :  * ready to start transmitting traffic via the VxLAN overlay
    3593             :  */
    3594           0 : bool zebra_evpn_is_es_bond(struct interface *ifp)
    3595             : {
    3596           0 :         struct zebra_if *zif = ifp->info;
    3597             : 
    3598           0 :         return !!(struct zebra_if *)zif->es_info.es;
    3599             : }
    3600             : 
    3601           0 : bool zebra_evpn_is_es_bond_member(struct interface *ifp)
    3602             : {
    3603           0 :         struct zebra_if *zif = ifp->info;
    3604             : 
    3605           0 :         return IS_ZEBRA_IF_BOND_SLAVE(zif->ifp) && zif->bondslave_info.bond_if
    3606           0 :                && ((struct zebra_if *)zif->bondslave_info.bond_if->info)
    3607           0 :                           ->es_info.es;
    3608             : }
    3609             : 
    3610           0 : void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
    3611             :                                              const char *caller)
    3612             : {
    3613           0 :         bool new_protodown;
    3614           0 :         uint32_t old_protodown_rc = 0;
    3615           0 :         uint32_t new_protodown_rc = 0;
    3616           0 :         uint32_t protodown_rc = 0;
    3617             : 
    3618           0 :         if (!clear) {
    3619           0 :                 struct zebra_if *bond_zif;
    3620             : 
    3621           0 :                 bond_zif = zif->bondslave_info.bond_if->info;
    3622           0 :                 protodown_rc = bond_zif->protodown_rc;
    3623             :         }
    3624             : 
    3625           0 :         old_protodown_rc = zif->protodown_rc;
    3626           0 :         new_protodown_rc = (old_protodown_rc & ~ZEBRA_PROTODOWN_EVPN_ALL);
    3627           0 :         new_protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
    3628           0 :         new_protodown = !!new_protodown_rc;
    3629             : 
    3630           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES && (new_protodown_rc != old_protodown_rc))
    3631           0 :                 zlog_debug(
    3632             :                         "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
    3633             :                         caller, zif->ifp->name, old_protodown_rc,
    3634             :                         new_protodown_rc);
    3635             : 
    3636           0 :         if (zebra_if_update_protodown_rc(zif->ifp, new_protodown,
    3637             :                                          new_protodown_rc) == 0) {
    3638           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3639           0 :                         zlog_debug("%s protodown %s", zif->ifp->name,
    3640             :                                    new_protodown ? "on" : "off");
    3641             :         }
    3642           0 : }
    3643             : 
    3644             : /* The bond members inherit the protodown reason code from the bond */
    3645           0 : static void zebra_evpn_mh_update_protodown_bond(struct zebra_if *bond_zif)
    3646             : {
    3647           0 :         struct zebra_if *zif;
    3648           0 :         struct listnode *node;
    3649             : 
    3650           0 :         if (!bond_zif->bond_info.mbr_zifs)
    3651             :                 return;
    3652             : 
    3653           0 :         for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, zif)) {
    3654           0 :                 zebra_evpn_mh_update_protodown_bond_mbr(zif, false /*clear*/,
    3655             :                                                         __func__);
    3656             :         }
    3657             : }
    3658             : 
    3659             : /* The global EVPN MH protodown rc is applied to all local ESs */
    3660           0 : static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
    3661             :                                               bool resync_dplane)
    3662             : {
    3663           0 :         struct zebra_if *zif;
    3664           0 :         uint32_t old_protodown_rc;
    3665             : 
    3666           0 :         zif = es->zif;
    3667             :         /* if the reason code is the same bail unless it is a new
    3668             :          * ES bond in that case we would need to ensure that the
    3669             :          * dplane is really in sync with zebra
    3670             :          */
    3671           0 :         if (!resync_dplane
    3672           0 :             && (zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
    3673           0 :                        == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
    3674             :                 return;
    3675             : 
    3676           0 :         old_protodown_rc = zif->protodown_rc;
    3677           0 :         zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
    3678           0 :         zif->protodown_rc |=
    3679           0 :                 (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
    3680             : 
    3681           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES
    3682           0 :             && (old_protodown_rc != zif->protodown_rc))
    3683           0 :                 zlog_debug(
    3684             :                         "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
    3685             :                         es->esi_str, zif->ifp->name, old_protodown_rc,
    3686             :                         zif->protodown_rc);
    3687             : 
    3688             :         /* update dataplane with the new protodown setting */
    3689           0 :         zebra_evpn_mh_update_protodown_bond(zif);
    3690             : }
    3691             : 
    3692           0 : static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es)
    3693             : {
    3694           0 :         struct zebra_if *zif;
    3695           0 :         uint32_t old_protodown_rc;
    3696             : 
    3697           0 :         zif = es->zif;
    3698           0 :         if (!(zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
    3699             :                 return;
    3700             : 
    3701           0 :         old_protodown_rc = zif->protodown_rc;
    3702           0 :         zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
    3703             : 
    3704           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3705           0 :                 zlog_debug(
    3706             :                         "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
    3707             :                         es->esi_str, zif->ifp->name, old_protodown_rc,
    3708             :                         zif->protodown_rc);
    3709             : 
    3710             :         /* update dataplane with the new protodown setting */
    3711           0 :         zebra_evpn_mh_update_protodown_bond(zif);
    3712             : }
    3713             : 
    3714           1 : static void zebra_evpn_mh_update_protodown_es_all(void)
    3715             : {
    3716           1 :         struct listnode *node;
    3717           1 :         struct zebra_evpn_es *es;
    3718             : 
    3719           2 :         for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es))
    3720           0 :                 zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
    3721           1 : }
    3722             : 
    3723           1 : static void zebra_evpn_mh_update_protodown(uint32_t protodown_rc, bool set)
    3724             : {
    3725           1 :         uint32_t old_protodown_rc = zmh_info->protodown_rc;
    3726             : 
    3727           1 :         if (set) {
    3728           1 :                 if ((protodown_rc & zmh_info->protodown_rc) == protodown_rc)
    3729             :                         return;
    3730             : 
    3731           1 :                 zmh_info->protodown_rc |= protodown_rc;
    3732             :         } else {
    3733           0 :                 if (!(protodown_rc & zmh_info->protodown_rc))
    3734             :                         return;
    3735           0 :                 zmh_info->protodown_rc &= ~protodown_rc;
    3736             :         }
    3737             : 
    3738           1 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3739           0 :                 zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
    3740             :                            old_protodown_rc, zmh_info->protodown_rc);
    3741           1 :         zebra_evpn_mh_update_protodown_es_all();
    3742             : }
    3743             : 
    3744           0 : static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
    3745             : {
    3746           0 :         return zmh_info->uplink_cfg_cnt && !zmh_info->uplink_oper_up_cnt;
    3747             : }
    3748             : 
    3749           0 : static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if *zif,
    3750             :                                                    bool set)
    3751             : {
    3752           0 :         if (set && if_is_operative(zif->ifp)) {
    3753           0 :                 if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)) {
    3754           0 :                         zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
    3755           0 :                         ++zmh_info->uplink_oper_up_cnt;
    3756             :                 }
    3757             :         } else {
    3758           0 :                 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
    3759           0 :                         zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
    3760           0 :                         if (zmh_info->uplink_oper_up_cnt)
    3761           0 :                                 --zmh_info->uplink_oper_up_cnt;
    3762             :                 }
    3763             :         }
    3764           0 : }
    3765             : 
    3766           0 : static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set)
    3767             : {
    3768           0 :         bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
    3769           0 :         bool new_protodown;
    3770             : 
    3771           0 :         if (set) {
    3772           0 :                 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
    3773             :                         return;
    3774             : 
    3775           0 :                 zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK;
    3776           0 :                 ++zmh_info->uplink_cfg_cnt;
    3777             :         } else {
    3778           0 :                 if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK))
    3779             :                         return;
    3780             : 
    3781           0 :                 zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK;
    3782           0 :                 if (zmh_info->uplink_cfg_cnt)
    3783           0 :                         --zmh_info->uplink_cfg_cnt;
    3784             :         }
    3785             : 
    3786           0 :         zebra_evpn_mh_uplink_oper_flags_update(zif, set);
    3787           0 :         new_protodown = zebra_evpn_mh_is_all_uplinks_down();
    3788           0 :         if (old_protodown == new_protodown)
    3789             :                 return;
    3790             : 
    3791           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3792           0 :                 zlog_debug(
    3793             :                         "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
    3794             :                         zif->ifp->name, zif->ifp->ifindex, set ? "set" : "down",
    3795             :                         zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
    3796             : 
    3797           0 :         zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
    3798             :                                        new_protodown);
    3799             : }
    3800             : 
    3801           0 : void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif)
    3802             : {
    3803           0 :         bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
    3804           0 :         bool new_protodown;
    3805             : 
    3806           0 :         zebra_evpn_mh_uplink_oper_flags_update(zif, true /*set*/);
    3807             : 
    3808           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3809           0 :                 zlog_debug(
    3810             :                         "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
    3811             :                         zif->ifp->name, zif->ifp->ifindex,
    3812             :                         if_is_operative(zif->ifp) ? "up" : "down",
    3813             :                         zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
    3814             : 
    3815           0 :         new_protodown = zebra_evpn_mh_is_all_uplinks_down();
    3816           0 :         if (old_protodown == new_protodown)
    3817             :                 return;
    3818             : 
    3819             :         /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
    3820             :          * fire up the start-up delay timer to allow the EVPN network
    3821             :          * to converge (Type-2 routes need to be advertised and processed)
    3822             :          */
    3823           0 :         if (!new_protodown && (zmh_info->uplink_oper_up_cnt == 1))
    3824           0 :                 zebra_evpn_mh_startup_delay_timer_start("uplink-up");
    3825             : 
    3826           0 :         zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
    3827             :                                        new_protodown);
    3828             : }
    3829             : 
    3830           0 : static void zebra_evpn_mh_startup_delay_exp_cb(struct thread *t)
    3831             : {
    3832           0 :         if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3833           0 :                 zlog_debug("startup-delay expired");
    3834             : 
    3835           0 :         zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY,
    3836             :                                        false /* set */);
    3837           0 : }
    3838             : 
    3839           1 : static void zebra_evpn_mh_startup_delay_timer_start(const char *rc)
    3840             : {
    3841           1 :         if (zmh_info->startup_delay_timer) {
    3842           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3843           0 :                         zlog_debug("startup-delay timer cancelled");
    3844           0 :                 THREAD_OFF(zmh_info->startup_delay_timer);
    3845             :         }
    3846             : 
    3847           1 :         if (zmh_info->startup_delay_time) {
    3848           1 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3849           0 :                         zlog_debug(
    3850             :                                 "startup-delay timer started for %d sec on %s",
    3851             :                                 zmh_info->startup_delay_time, rc);
    3852           1 :                 thread_add_timer(zrouter.master,
    3853             :                                  zebra_evpn_mh_startup_delay_exp_cb, NULL,
    3854             :                                  zmh_info->startup_delay_time,
    3855             :                                  &zmh_info->startup_delay_timer);
    3856           1 :                 zebra_evpn_mh_update_protodown(
    3857             :                         ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, true /* set */);
    3858             :         } else {
    3859           0 :                 zebra_evpn_mh_update_protodown(
    3860             :                         ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, false /* set */);
    3861             :         }
    3862           1 : }
    3863             : 
    3864             : /*****************************************************************************
    3865             :  * Nexthop management: nexthops associated with Type-2 routes that have
    3866             :  * an ES as destination are consolidated by BGP into a per-VRF nh->rmac
    3867             :  * mapping which is the installed as a remote neigh/fdb entry with a
    3868             :  * dummy (type-1) prefix referencing it.
    3869             :  * This handling is needed because Type-2 routes with ES as dest use NHG
    3870             :  * that are setup using EAD routes (i.e. such NHGs do not include the
    3871             :  * RMAC info).
    3872             :  ****************************************************************************/
    3873           0 : void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS)
    3874             : {
    3875           0 :         struct stream *s;
    3876           0 :         vrf_id_t vrf_id;
    3877           0 :         struct ipaddr nh;
    3878           0 :         struct ethaddr rmac;
    3879           0 :         struct prefix_evpn dummy_prefix;
    3880           0 :         size_t min_len = 4 + sizeof(nh);
    3881             : 
    3882           0 :         s = msg;
    3883             : 
    3884             :         /*
    3885             :          * Ensure that the stream sent to us is long enough
    3886             :          */
    3887           0 :         if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD)
    3888           0 :                 min_len += sizeof(rmac);
    3889           0 :         if (hdr->length < min_len)
    3890           0 :                 return;
    3891             : 
    3892           0 :         vrf_id = stream_getl(s);
    3893           0 :         stream_get(&nh, s, sizeof(nh));
    3894             : 
    3895           0 :         memset(&dummy_prefix, 0, sizeof(dummy_prefix));
    3896           0 :         dummy_prefix.family = AF_EVPN;
    3897           0 :         dummy_prefix.prefixlen = (sizeof(struct evpn_addr) * 8);
    3898           0 :         dummy_prefix.prefix.route_type = 1; /* XXX - fixup to type-1 def */
    3899           0 :         dummy_prefix.prefix.ead_addr.ip.ipa_type = nh.ipa_type;
    3900             : 
    3901           0 :         if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD) {
    3902           0 :                 stream_get(&rmac, s, sizeof(rmac));
    3903           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3904           0 :                         zlog_debug(
    3905             :                                 "evpn remote nh %d %pIA rmac %pEA add pfx %pFX",
    3906             :                                 vrf_id, &nh, &rmac, &dummy_prefix);
    3907           0 :                 zebra_rib_queue_evpn_route_add(vrf_id, &rmac, &nh,
    3908             :                                                (struct prefix *)&dummy_prefix);
    3909             :         } else {
    3910           0 :                 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
    3911           0 :                         zlog_debug("evpn remote nh %d %pIA del pfx %pFX",
    3912             :                                    vrf_id, &nh, &dummy_prefix);
    3913           0 :                 zebra_rib_queue_evpn_route_del(vrf_id, &nh,
    3914             :                                                (struct prefix *)&dummy_prefix);
    3915             :         }
    3916             : }
    3917             : 
    3918             : /*****************************************************************************/
    3919           0 : void zebra_evpn_mh_config_write(struct vty *vty)
    3920             : {
    3921           0 :         if (zmh_info->mac_hold_time != ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF)
    3922           0 :                 vty_out(vty, "evpn mh mac-holdtime %d\n",
    3923             :                         zmh_info->mac_hold_time);
    3924             : 
    3925           0 :         if (zmh_info->neigh_hold_time != ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF)
    3926           0 :                 vty_out(vty, "evpn mh neigh-holdtime %d\n",
    3927             :                         zmh_info->neigh_hold_time);
    3928             : 
    3929           0 :         if (zmh_info->startup_delay_time != ZEBRA_EVPN_MH_STARTUP_DELAY_DEF)
    3930           0 :                 vty_out(vty, "evpn mh startup-delay %d\n",
    3931             :                         zmh_info->startup_delay_time);
    3932             : 
    3933           0 :         if (zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF)
    3934           0 :                 vty_out(vty, "evpn mh redirect-off\n");
    3935           0 : }
    3936             : 
    3937           0 : int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
    3938             :                 uint32_t duration, bool set_default)
    3939             : {
    3940           0 :         if (set_default)
    3941           0 :                 duration = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
    3942             : 
    3943           0 :         zmh_info->neigh_hold_time = duration;
    3944             : 
    3945           0 :         return 0;
    3946             : }
    3947             : 
    3948           0 : int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
    3949             :                 uint32_t duration, bool set_default)
    3950             : {
    3951           0 :         if (set_default)
    3952           0 :                 duration = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
    3953             : 
    3954           0 :         zmh_info->mac_hold_time = duration;
    3955             : 
    3956           0 :         return 0;
    3957             : }
    3958             : 
    3959           0 : int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
    3960             :                                        bool set_default)
    3961             : {
    3962           0 :         if (set_default)
    3963           0 :                 duration = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
    3964             : 
    3965           0 :         zmh_info->startup_delay_time = duration;
    3966             : 
    3967             :         /* if startup_delay_timer is running allow it to be adjusted
    3968             :          * up or down
    3969             :          */
    3970           0 :         if (zmh_info->startup_delay_timer)
    3971           0 :                 zebra_evpn_mh_startup_delay_timer_start("config");
    3972             : 
    3973           0 :         return 0;
    3974             : }
    3975             : 
    3976           0 : int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off)
    3977             : {
    3978             :         /* This knob needs to be set before ESs are configured
    3979             :          * i.e. cannot be changed on the fly
    3980             :          */
    3981           0 :         if (redirect_off)
    3982           0 :                 zmh_info->flags |= ZEBRA_EVPN_MH_REDIRECT_OFF;
    3983             :         else
    3984           0 :                 zmh_info->flags &= ~ZEBRA_EVPN_MH_REDIRECT_OFF;
    3985             : 
    3986           0 :         return 0;
    3987             : }
    3988             : 
    3989           1 : void zebra_evpn_interface_init(void)
    3990             : {
    3991           1 :         install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
    3992           1 :         install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd);
    3993           1 :         install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd);
    3994           1 :         install_element(INTERFACE_NODE, &zebra_evpn_es_bypass_cmd);
    3995           1 :         install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd);
    3996           1 : }
    3997             : 
    3998           1 : void zebra_evpn_mh_init(void)
    3999             : {
    4000           1 :         zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info));
    4001             : 
    4002           1 :         zmh_info->mac_hold_time = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
    4003           1 :         zmh_info->neigh_hold_time = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
    4004             :         /* setup ES tables */
    4005           1 :         RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree);
    4006           1 :         zmh_info->local_es_list = list_new();
    4007           1 :         listset_app_node_mem(zmh_info->local_es_list);
    4008             : 
    4009           1 :         bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
    4010           5 :         bf_assign_zero_index(zmh_info->nh_id_bitmap);
    4011           1 :         zmh_info->nhg_table = hash_create(zebra_evpn_nhg_hash_keymake,
    4012             :                                           zebra_evpn_nhg_cmp, "l2 NHG table");
    4013           2 :         zmh_info->nh_ip_table =
    4014           1 :                 hash_create(zebra_evpn_nh_ip_hash_keymake, zebra_evpn_nh_ip_cmp,
    4015             :                             "l2 NH IP table");
    4016             : 
    4017             :         /* setup broadcast domain tables */
    4018           1 :         zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
    4019             :                         zebra_evpn_acc_vl_cmp, "access VLAN hash table");
    4020             : 
    4021           1 :         zmh_info->startup_delay_time = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
    4022           1 :         zebra_evpn_mh_startup_delay_timer_start("init");
    4023           1 : }
    4024             : 
    4025           1 : void zebra_evpn_mh_terminate(void)
    4026             : {
    4027           1 :         list_delete(&zmh_info->local_es_list);
    4028             : 
    4029           1 :         hash_iterate(zmh_info->evpn_vlan_table,
    4030             :                         zebra_evpn_acc_vl_cleanup_all, NULL);
    4031           1 :         hash_free(zmh_info->evpn_vlan_table);
    4032           1 :         hash_free(zmh_info->nhg_table);
    4033           1 :         hash_free(zmh_info->nh_ip_table);
    4034           1 :         bf_free(zmh_info->nh_id_bitmap);
    4035             : 
    4036           1 :         XFREE(MTYPE_ZMH_INFO, zrouter.mh_info);
    4037           1 : }

Generated by: LCOV version v1.16-topotato