back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_mpls.c (source / functions) Hit Total Coverage
Test: test_pim6_prune_propagate.py::PIM6PrunePropagate Lines: 53 1779 3.0 %
Date: 2023-02-24 18:39:23 Functions: 12 103 11.7 %

          Line data    Source code
       1             : /* Zebra MPLS code
       2             :  * Copyright (C) 2013 Cumulus Networks, Inc.
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "prefix.h"
      24             : #include "table.h"
      25             : #include "memory.h"
      26             : #include "command.h"
      27             : #include "if.h"
      28             : #include "log.h"
      29             : #include "sockunion.h"
      30             : #include "linklist.h"
      31             : #include "thread.h"
      32             : #include "workqueue.h"
      33             : #include "prefix.h"
      34             : #include "routemap.h"
      35             : #include "stream.h"
      36             : #include "nexthop.h"
      37             : #include "termtable.h"
      38             : #include "lib/json.h"
      39             : 
      40             : #include "zebra/rib.h"
      41             : #include "zebra/rt.h"
      42             : #include "zebra/interface.h"
      43             : #include "zebra/zserv.h"
      44             : #include "zebra/zebra_router.h"
      45             : #include "zebra/redistribute.h"
      46             : #include "zebra/debug.h"
      47             : #include "zebra/zebra_vrf.h"
      48             : #include "zebra/zebra_mpls.h"
      49             : #include "zebra/zebra_srte.h"
      50             : #include "zebra/zebra_errors.h"
      51             : 
      52          12 : DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
      53          12 : DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
      54          12 : DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
      55             : 
      56             : bool mpls_enabled;
      57             : bool mpls_pw_reach_strict; /* Strict reachability checking */
      58             : 
      59             : /* static function declarations */
      60             : 
      61             : static void fec_evaluate(struct zebra_vrf *zvrf);
      62             : static uint32_t fec_derive_label_from_index(struct zebra_vrf *vrf,
      63             :                                             struct zebra_fec *fec);
      64             : static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
      65             :                        struct route_node *rn, struct route_entry *re);
      66             : static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label);
      67             : static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
      68             :                                  mpls_label_t old_label);
      69             : static int fec_send(struct zebra_fec *fec, struct zserv *client);
      70             : static void fec_update_clients(struct zebra_fec *fec);
      71             : static void fec_print(struct zebra_fec *fec, struct vty *vty);
      72             : static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p);
      73             : static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
      74             :                                  mpls_label_t label, uint32_t flags,
      75             :                                  uint32_t label_index);
      76             : static int fec_del(struct zebra_fec *fec);
      77             : 
      78             : static unsigned int label_hash(const void *p);
      79             : static bool label_cmp(const void *p1, const void *p2);
      80             : static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
      81             :                                      struct nexthop *nexthop);
      82             : static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
      83             :                                      struct nexthop *nexthop);
      84             : static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe);
      85             : 
      86             : static void lsp_select_best_nhlfe(struct zebra_lsp *lsp);
      87             : static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt);
      88             : static void lsp_schedule(struct hash_bucket *bucket, void *ctxt);
      89             : static wq_item_status lsp_process(struct work_queue *wq, void *data);
      90             : static void lsp_processq_del(struct work_queue *wq, void *data);
      91             : static void lsp_processq_complete(struct work_queue *wq);
      92             : static int lsp_processq_add(struct zebra_lsp *lsp);
      93             : static void *lsp_alloc(void *p);
      94             : 
      95             : /* Check whether lsp can be freed - no nhlfes, e.g., and call free api */
      96             : static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp);
      97             : 
      98             : /* Free lsp; sets caller's pointer to NULL */
      99             : static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp);
     100             : 
     101             : static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size);
     102             : static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
     103             :                               int size);
     104             : static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
     105             :                             enum nexthop_types_t gtype,
     106             :                             const union g_addr *gate, ifindex_t ifindex);
     107             : static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
     108             :                                       enum lsp_types_t lsp_type,
     109             :                                       enum nexthop_types_t gtype,
     110             :                                       const union g_addr *gate,
     111             :                                       ifindex_t ifindex);
     112             : static struct zebra_nhlfe *
     113             : nhlfe_add(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
     114             :           enum nexthop_types_t gtype, const union g_addr *gate,
     115             :           ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels,
     116             :           bool is_backup);
     117             : static int nhlfe_del(struct zebra_nhlfe *nhlfe);
     118             : static void nhlfe_free(struct zebra_nhlfe *nhlfe);
     119             : static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
     120             :                                    struct mpls_label_stack *nh_label);
     121             : static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
     122             :                                   enum lsp_types_t type);
     123             : static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
     124             :                                          mpls_label_t in_label);
     125             : static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
     126             :                         const char *indent);
     127             : static void lsp_print(struct vty *vty, struct zebra_lsp *lsp);
     128             : static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt);
     129             : static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
     130             :                                    int afi, enum lsp_types_t lsp_type);
     131             : static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
     132             :                            const struct zapi_nexthop *znh);
     133             : static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
     134             :                                   const struct zapi_nexthop *znh);
     135             : 
     136             : /* Static functions */
     137             : 
     138             : /*
     139             :  * Handle failure in LSP install, clear flags for NHLFE.
     140             :  */
     141           0 : static void clear_nhlfe_installed(struct zebra_lsp *lsp)
     142             : {
     143           0 :         struct zebra_nhlfe *nhlfe;
     144           0 :         struct nexthop *nexthop;
     145             : 
     146           0 :         frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
     147           0 :                 nexthop = nhlfe->nexthop;
     148           0 :                 if (!nexthop)
     149           0 :                         continue;
     150             : 
     151           0 :                 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
     152           0 :                 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
     153             :         }
     154             : 
     155           0 :         frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
     156           0 :                 nexthop = nhlfe->nexthop;
     157           0 :                 if (!nexthop)
     158           0 :                         continue;
     159             : 
     160           0 :                 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
     161           0 :                 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
     162             :         }
     163           0 : }
     164             : 
     165             : /*
     166             :  * Install label forwarding entry based on labeled-route entry.
     167             :  */
     168           0 : static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label,
     169             :                        struct route_node *rn, struct route_entry *re)
     170             : {
     171           0 :         struct hash *lsp_table;
     172           0 :         struct zebra_ile tmp_ile;
     173           0 :         struct zebra_lsp *lsp;
     174           0 :         struct zebra_nhlfe *nhlfe;
     175           0 :         struct nexthop *nexthop;
     176           0 :         enum lsp_types_t lsp_type;
     177           0 :         char buf[BUFSIZ];
     178           0 :         int added, changed;
     179             : 
     180             :         /* Lookup table. */
     181           0 :         lsp_table = zvrf->lsp_table;
     182           0 :         if (!lsp_table)
     183             :                 return -1;
     184             : 
     185           0 :         lsp_type = lsp_type_from_re_type(re->type);
     186           0 :         added = changed = 0;
     187             : 
     188             :         /* Locate or allocate LSP entry. */
     189           0 :         tmp_ile.in_label = label;
     190           0 :         lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
     191             : 
     192             :         /* For each active nexthop, create NHLFE. Note that we deliberately skip
     193             :          * recursive nexthops right now, because intermediate hops won't
     194             :          * understand
     195             :          * the label advertised by the recursive nexthop (plus we don't have the
     196             :          * logic yet to push multiple labels).
     197             :          */
     198           0 :         for (nexthop = re->nhe->nhg.nexthop;
     199           0 :              nexthop; nexthop = nexthop->next) {
     200             :                 /* Skip inactive and recursive entries. */
     201           0 :                 if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
     202           0 :                         continue;
     203           0 :                 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
     204           0 :                         continue;
     205             : 
     206           0 :                 nhlfe = nhlfe_find(&lsp->nhlfe_list, lsp_type,
     207           0 :                                    nexthop->type, &nexthop->gate,
     208             :                                    nexthop->ifindex);
     209           0 :                 if (nhlfe) {
     210             :                         /* Clear deleted flag (in case it was set) */
     211           0 :                         UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
     212           0 :                         if (nexthop_labels_match(nhlfe->nexthop, nexthop))
     213             :                                 /* No change */
     214           0 :                                 continue;
     215             : 
     216             : 
     217           0 :                         if (IS_ZEBRA_DEBUG_MPLS) {
     218           0 :                                 nhlfe2str(nhlfe, buf, BUFSIZ);
     219           0 :                                 zlog_debug(
     220             :                                         "LSP in-label %u type %d nexthop %s out-label changed",
     221             :                                         lsp->ile.in_label, lsp_type, buf);
     222             :                         }
     223             : 
     224             :                         /* Update out label, trigger processing. */
     225           0 :                         nhlfe_out_label_update(nhlfe, nexthop->nh_label);
     226           0 :                         SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
     227           0 :                         changed++;
     228             :                 } else {
     229             :                         /* Add LSP entry to this nexthop */
     230           0 :                         nhlfe = nhlfe_add(lsp, lsp_type, nexthop->type,
     231             :                                           &nexthop->gate, nexthop->ifindex,
     232           0 :                                           nexthop->nh_label->num_labels,
     233           0 :                                           nexthop->nh_label->label,
     234             :                                           false /*backup*/);
     235           0 :                         if (!nhlfe)
     236             :                                 return -1;
     237             : 
     238           0 :                         if (IS_ZEBRA_DEBUG_MPLS) {
     239           0 :                                 nhlfe2str(nhlfe, buf, BUFSIZ);
     240           0 :                                 zlog_debug(
     241             :                                         "Add LSP in-label %u type %d nexthop %s out-label %u",
     242             :                                         lsp->ile.in_label, lsp_type, buf,
     243             :                                         nexthop->nh_label->label[0]);
     244             :                         }
     245             : 
     246           0 :                         lsp->addr_family = NHLFE_FAMILY(nhlfe);
     247             : 
     248             :                         /* Mark NHLFE as changed. */
     249           0 :                         SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
     250           0 :                         added++;
     251             :                 }
     252             :         }
     253             : 
     254             :         /* Queue LSP for processing if necessary. If no NHLFE got added (special
     255             :          * case), delete the LSP entry; this case results in somewhat ugly
     256             :          * logging.
     257             :          */
     258           0 :         if (added || changed) {
     259           0 :                 if (lsp_processq_add(lsp))
     260             :                         return -1;
     261             :         } else {
     262           0 :                 lsp_check_free(lsp_table, &lsp);
     263             :         }
     264             : 
     265             :         return 0;
     266             : }
     267             : 
     268             : /*
     269             :  * Uninstall all non-static NHLFEs of a label forwarding entry. If all
     270             :  * NHLFEs are removed, the entire entry is deleted.
     271             :  */
     272           0 : static int lsp_uninstall(struct zebra_vrf *zvrf, mpls_label_t label)
     273             : {
     274           0 :         struct hash *lsp_table;
     275           0 :         struct zebra_ile tmp_ile;
     276           0 :         struct zebra_lsp *lsp;
     277           0 :         struct zebra_nhlfe *nhlfe;
     278           0 :         char buf[BUFSIZ];
     279             : 
     280             :         /* Lookup table. */
     281           0 :         lsp_table = zvrf->lsp_table;
     282           0 :         if (!lsp_table)
     283             :                 return -1;
     284             : 
     285             :         /* If entry is not present, exit. */
     286           0 :         tmp_ile.in_label = label;
     287           0 :         lsp = hash_lookup(lsp_table, &tmp_ile);
     288           0 :         if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
     289             :                 return 0;
     290             : 
     291             :         /* Mark NHLFEs for delete or directly delete, as appropriate. */
     292           0 :         frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
     293             : 
     294             :                 /* Skip static NHLFEs */
     295           0 :                 if (nhlfe->type == ZEBRA_LSP_STATIC)
     296           0 :                         continue;
     297             : 
     298           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
     299           0 :                         nhlfe2str(nhlfe, buf, BUFSIZ);
     300           0 :                         zlog_debug(
     301             :                                 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
     302             :                                 label, nhlfe->type, buf, nhlfe->flags);
     303             :                 }
     304             : 
     305           0 :                 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)) {
     306           0 :                         UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
     307           0 :                         SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
     308             :                 } else {
     309           0 :                         nhlfe_del(nhlfe);
     310             :                 }
     311             :         }
     312             : 
     313             :         /* Queue LSP for processing, if needed, else delete. */
     314           0 :         if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
     315           0 :                 if (lsp_processq_add(lsp))
     316             :                         return -1;
     317             :         } else {
     318           0 :                 lsp_check_free(lsp_table, &lsp);
     319             :         }
     320             : 
     321             :         return 0;
     322             : }
     323             : 
     324             : /*
     325             :  * This function is invoked upon change to label block configuration; it
     326             :  * will walk all registered FECs with label-index and appropriately update
     327             :  * their local labels and trigger client updates.
     328             :  */
     329           0 : static void fec_evaluate(struct zebra_vrf *zvrf)
     330             : {
     331           0 :         struct route_node *rn;
     332           0 :         struct zebra_fec *fec;
     333           0 :         uint32_t old_label, new_label;
     334           0 :         int af;
     335             : 
     336           0 :         for (af = AFI_IP; af < AFI_MAX; af++) {
     337           0 :                 if (zvrf->fec_table[af] == NULL)
     338           0 :                         continue;
     339             : 
     340           0 :                 for (rn = route_top(zvrf->fec_table[af]); rn;
     341           0 :                      rn = route_next(rn)) {
     342           0 :                         if ((fec = rn->info) == NULL)
     343           0 :                                 continue;
     344             : 
     345             :                         /* Skip configured FECs and those without a label index.
     346             :                          */
     347           0 :                         if (fec->flags & FEC_FLAG_CONFIGURED
     348           0 :                             || fec->label_index == MPLS_INVALID_LABEL_INDEX)
     349           0 :                                 continue;
     350             : 
     351             :                         /* Save old label, determine new label. */
     352           0 :                         old_label = fec->label;
     353           0 :                         new_label =
     354           0 :                                 zvrf->mpls_srgb.start_label + fec->label_index;
     355           0 :                         if (new_label >= zvrf->mpls_srgb.end_label)
     356           0 :                                 new_label = MPLS_INVALID_LABEL;
     357             : 
     358             :                         /* If label has changed, update FEC and clients. */
     359           0 :                         if (new_label == old_label)
     360           0 :                                 continue;
     361             : 
     362           0 :                         if (IS_ZEBRA_DEBUG_MPLS)
     363           0 :                                 zlog_debug(
     364             :                                         "Update fec %pRN new label %u upon label block",
     365             :                                         rn, new_label);
     366             : 
     367           0 :                         fec->label = new_label;
     368           0 :                         fec_update_clients(fec);
     369             : 
     370             :                         /* Update label forwarding entries appropriately */
     371           0 :                         fec_change_update_lsp(zvrf, fec, old_label);
     372             :                 }
     373             :         }
     374           0 : }
     375             : 
     376             : /*
     377             :  * Derive (if possible) and update the local label for the FEC based on
     378             :  * its label index. The index is "acceptable" if it falls within the
     379             :  * globally configured label block (SRGB).
     380             :  */
     381           0 : static uint32_t fec_derive_label_from_index(struct zebra_vrf *zvrf,
     382             :                                             struct zebra_fec *fec)
     383             : {
     384           0 :         uint32_t label;
     385             : 
     386           0 :         if (fec->label_index != MPLS_INVALID_LABEL_INDEX
     387           0 :             && zvrf->mpls_srgb.start_label
     388           0 :             && ((label = zvrf->mpls_srgb.start_label + fec->label_index)
     389           0 :                 < zvrf->mpls_srgb.end_label))
     390           0 :                 fec->label = label;
     391             :         else
     392           0 :                 fec->label = MPLS_INVALID_LABEL;
     393             : 
     394           0 :         return fec->label;
     395             : }
     396             : 
     397             : /*
     398             :  * There is a change for this FEC. Install or uninstall label forwarding
     399             :  * entries, as appropriate.
     400             :  */
     401           0 : static int fec_change_update_lsp(struct zebra_vrf *zvrf, struct zebra_fec *fec,
     402             :                                  mpls_label_t old_label)
     403             : {
     404           0 :         struct route_table *table;
     405           0 :         struct route_node *rn;
     406           0 :         struct route_entry *re;
     407           0 :         afi_t afi;
     408             : 
     409             :         /* Uninstall label forwarding entry, if previously installed. */
     410           0 :         if (old_label != MPLS_INVALID_LABEL
     411           0 :             && old_label != MPLS_LABEL_IMPLICIT_NULL)
     412           0 :                 lsp_uninstall(zvrf, old_label);
     413             : 
     414             :         /* Install label forwarding entry corr. to new label, if needed. */
     415           0 :         if (fec->label == MPLS_INVALID_LABEL
     416           0 :             || fec->label == MPLS_LABEL_IMPLICIT_NULL)
     417             :                 return 0;
     418             : 
     419           0 :         afi = family2afi(PREFIX_FAMILY(&fec->rn->p));
     420           0 :         table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
     421           0 :         if (!table)
     422             :                 return 0;
     423             : 
     424             :         /* See if labeled route exists. */
     425           0 :         rn = route_node_lookup(table, &fec->rn->p);
     426           0 :         if (!rn)
     427             :                 return 0;
     428             : 
     429           0 :         RNODE_FOREACH_RE (rn, re) {
     430           0 :                 if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
     431             :                         break;
     432             :         }
     433             : 
     434           0 :         if (!re || !zebra_rib_labeled_unicast(re))
     435           0 :                 return 0;
     436             : 
     437           0 :         if (lsp_install(zvrf, fec->label, rn, re))
     438             :                 return -1;
     439             : 
     440             :         return 0;
     441             : }
     442             : 
     443             : /*
     444             :  * Inform about FEC to a registered client.
     445             :  */
     446           0 : static int fec_send(struct zebra_fec *fec, struct zserv *client)
     447             : {
     448           0 :         struct stream *s;
     449           0 :         struct route_node *rn;
     450             : 
     451           0 :         rn = fec->rn;
     452             : 
     453             :         /* Get output stream. */
     454           0 :         s = stream_new(ZEBRA_MAX_PACKET_SIZ);
     455             : 
     456           0 :         zclient_create_header(s, ZEBRA_FEC_UPDATE, VRF_DEFAULT);
     457             : 
     458           0 :         stream_putw(s, rn->p.family);
     459           0 :         stream_put_prefix(s, &rn->p);
     460           0 :         stream_putl(s, fec->label);
     461           0 :         stream_putw_at(s, 0, stream_get_endp(s));
     462           0 :         return zserv_send_message(client, s);
     463             : }
     464             : 
     465             : /*
     466             :  * Update all registered clients about this FEC. Caller should've updated
     467             :  * FEC and ensure no duplicate updates.
     468             :  */
     469           0 : static void fec_update_clients(struct zebra_fec *fec)
     470             : {
     471           0 :         struct listnode *node;
     472           0 :         struct zserv *client;
     473             : 
     474           0 :         for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client)) {
     475           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
     476           0 :                         zlog_debug("Update client %s",
     477             :                                    zebra_route_string(client->proto));
     478           0 :                 fec_send(fec, client);
     479             :         }
     480           0 : }
     481             : 
     482             : 
     483             : /*
     484             :  * Print a FEC-label binding entry.
     485             :  */
     486           0 : static void fec_print(struct zebra_fec *fec, struct vty *vty)
     487             : {
     488           0 :         struct route_node *rn;
     489           0 :         struct listnode *node;
     490           0 :         struct zserv *client;
     491           0 :         char buf[BUFSIZ];
     492             : 
     493           0 :         rn = fec->rn;
     494           0 :         vty_out(vty, "%pRN\n", rn);
     495           0 :         vty_out(vty, "  Label: %s", label2str(fec->label, buf, BUFSIZ));
     496           0 :         if (fec->label_index != MPLS_INVALID_LABEL_INDEX)
     497           0 :                 vty_out(vty, ", Label Index: %u", fec->label_index);
     498           0 :         vty_out(vty, "\n");
     499           0 :         if (!list_isempty(fec->client_list)) {
     500           0 :                 vty_out(vty, "  Client list:");
     501           0 :                 for (ALL_LIST_ELEMENTS_RO(fec->client_list, node, client))
     502           0 :                         vty_out(vty, " %s(fd %d)",
     503           0 :                                 zebra_route_string(client->proto),
     504             :                                 client->sock);
     505           0 :                 vty_out(vty, "\n");
     506             :         }
     507           0 : }
     508             : 
     509             : /*
     510             :  * Locate FEC-label binding that matches with passed info.
     511             :  */
     512           0 : static struct zebra_fec *fec_find(struct route_table *table, struct prefix *p)
     513             : {
     514           0 :         struct route_node *rn;
     515             : 
     516           0 :         apply_mask(p);
     517           0 :         rn = route_node_lookup(table, p);
     518           0 :         if (!rn)
     519             :                 return NULL;
     520             : 
     521           0 :         route_unlock_node(rn);
     522           0 :         return (rn->info);
     523             : }
     524             : 
     525             : /*
     526             :  * Add a FEC. This may be upon a client registering for a binding
     527             :  * or when a binding is configured.
     528             :  */
     529           0 : static struct zebra_fec *fec_add(struct route_table *table, struct prefix *p,
     530             :                                  mpls_label_t label, uint32_t flags,
     531             :                                  uint32_t label_index)
     532             : {
     533           0 :         struct route_node *rn;
     534           0 :         struct zebra_fec *fec;
     535             : 
     536           0 :         apply_mask(p);
     537             : 
     538             :         /* Lookup (or add) route node.*/
     539           0 :         rn = route_node_get(table, p);
     540           0 :         if (!rn)
     541             :                 return NULL;
     542             : 
     543           0 :         fec = rn->info;
     544             : 
     545           0 :         if (!fec) {
     546           0 :                 fec = XCALLOC(MTYPE_FEC, sizeof(struct zebra_fec));
     547             : 
     548           0 :                 rn->info = fec;
     549           0 :                 fec->rn = rn;
     550           0 :                 fec->label = label;
     551           0 :                 fec->client_list = list_new();
     552             :         } else
     553           0 :                 route_unlock_node(rn); /* for the route_node_get */
     554             : 
     555           0 :         fec->label_index = label_index;
     556           0 :         fec->flags = flags;
     557             : 
     558           0 :         return fec;
     559             : }
     560             : 
     561             : /*
     562             :  * Delete a FEC. This may be upon the last client deregistering for
     563             :  * a FEC and no binding exists or when the binding is deleted and there
     564             :  * are no registered clients.
     565             :  */
     566           0 : static int fec_del(struct zebra_fec *fec)
     567             : {
     568           0 :         list_delete(&fec->client_list);
     569           0 :         fec->rn->info = NULL;
     570           0 :         route_unlock_node(fec->rn);
     571           0 :         XFREE(MTYPE_FEC, fec);
     572           0 :         return 0;
     573             : }
     574             : 
     575             : /*
     576             :  * Hash function for label.
     577             :  */
     578           0 : static unsigned int label_hash(const void *p)
     579             : {
     580           0 :         const struct zebra_ile *ile = p;
     581             : 
     582           0 :         return (jhash_1word(ile->in_label, 0));
     583             : }
     584             : 
     585             : /*
     586             :  * Compare 2 LSP hash entries based on in-label.
     587             :  */
     588           0 : static bool label_cmp(const void *p1, const void *p2)
     589             : {
     590           0 :         const struct zebra_ile *ile1 = p1;
     591           0 :         const struct zebra_ile *ile2 = p2;
     592             : 
     593           0 :         return (ile1->in_label == ile2->in_label);
     594             : }
     595             : 
     596             : /*
     597             :  * Check if an IPv4 nexthop for a NHLFE is active. Update nexthop based on
     598             :  * the passed flag.
     599             :  * NOTE: Looking only for connected routes right now.
     600             :  */
     601           0 : static int nhlfe_nexthop_active_ipv4(struct zebra_nhlfe *nhlfe,
     602             :                                      struct nexthop *nexthop)
     603             : {
     604           0 :         struct route_table *table;
     605           0 :         struct prefix_ipv4 p;
     606           0 :         struct route_node *rn;
     607           0 :         struct route_entry *match;
     608           0 :         struct nexthop *match_nh;
     609             : 
     610           0 :         table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, nexthop->vrf_id);
     611           0 :         if (!table)
     612             :                 return 0;
     613             : 
     614             :         /* Lookup nexthop in IPv4 routing table. */
     615           0 :         memset(&p, 0, sizeof(p));
     616           0 :         p.family = AF_INET;
     617           0 :         p.prefixlen = IPV4_MAX_BITLEN;
     618           0 :         p.prefix = nexthop->gate.ipv4;
     619             : 
     620           0 :         rn = route_node_match(table, (struct prefix *)&p);
     621           0 :         if (!rn)
     622             :                 return 0;
     623             : 
     624           0 :         route_unlock_node(rn);
     625             : 
     626             :         /* Locate a valid connected route. */
     627           0 :         RNODE_FOREACH_RE (rn, match) {
     628           0 :                 if (CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
     629           0 :                     || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
     630           0 :                         continue;
     631             : 
     632           0 :                 for (match_nh = match->nhe->nhg.nexthop; match_nh;
     633           0 :                      match_nh = match_nh->next) {
     634           0 :                         if (match->type == ZEBRA_ROUTE_CONNECT
     635           0 :                             || nexthop->ifindex == match_nh->ifindex) {
     636           0 :                                 nexthop->ifindex = match_nh->ifindex;
     637           0 :                                 return 1;
     638             :                         }
     639             :                 }
     640             :         }
     641             : 
     642             :         return 0;
     643             : }
     644             : 
     645             : 
     646             : /*
     647             :  * Check if an IPv6 nexthop for a NHLFE is active. Update nexthop based on
     648             :  * the passed flag.
     649             :  * NOTE: Looking only for connected routes right now.
     650             :  */
     651           0 : static int nhlfe_nexthop_active_ipv6(struct zebra_nhlfe *nhlfe,
     652             :                                      struct nexthop *nexthop)
     653             : {
     654           0 :         struct route_table *table;
     655           0 :         struct prefix_ipv6 p;
     656           0 :         struct route_node *rn;
     657           0 :         struct route_entry *match;
     658             : 
     659           0 :         table = zebra_vrf_table(AFI_IP6, SAFI_UNICAST, nexthop->vrf_id);
     660           0 :         if (!table)
     661             :                 return 0;
     662             : 
     663             :         /* Lookup nexthop in IPv6 routing table. */
     664           0 :         memset(&p, 0, sizeof(p));
     665           0 :         p.family = AF_INET6;
     666           0 :         p.prefixlen = IPV6_MAX_BITLEN;
     667           0 :         p.prefix = nexthop->gate.ipv6;
     668             : 
     669           0 :         rn = route_node_match(table, (struct prefix *)&p);
     670           0 :         if (!rn)
     671             :                 return 0;
     672             : 
     673           0 :         route_unlock_node(rn);
     674             : 
     675             :         /* Locate a valid connected route. */
     676           0 :         RNODE_FOREACH_RE (rn, match) {
     677           0 :                 if ((match->type == ZEBRA_ROUTE_CONNECT)
     678             :                     && !CHECK_FLAG(match->status, ROUTE_ENTRY_REMOVED)
     679           0 :                     && CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED))
     680             :                         break;
     681             :         }
     682             : 
     683           0 :         if (!match || !match->nhe->nhg.nexthop)
     684             :                 return 0;
     685             : 
     686           0 :         nexthop->ifindex = match->nhe->nhg.nexthop->ifindex;
     687           0 :         return 1;
     688             : }
     689             : 
     690             : 
     691             : /*
     692             :  * Check the nexthop reachability for a NHLFE and return if valid (reachable)
     693             :  * or not.
     694             :  * NOTE: Each NHLFE points to only 1 nexthop.
     695             :  */
     696           0 : static int nhlfe_nexthop_active(struct zebra_nhlfe *nhlfe)
     697             : {
     698           0 :         struct nexthop *nexthop;
     699           0 :         struct interface *ifp;
     700           0 :         struct zebra_ns *zns;
     701             : 
     702           0 :         nexthop = nhlfe->nexthop;
     703           0 :         if (!nexthop) // unexpected
     704             :                 return 0;
     705             : 
     706             :         /* Check on nexthop based on type. */
     707           0 :         switch (nexthop->type) {
     708           0 :         case NEXTHOP_TYPE_IFINDEX:
     709             :                 /*
     710             :                  * Lookup if this type is special.  The
     711             :                  * NEXTHOP_TYPE_IFINDEX is a pop and
     712             :                  * forward into a different table for
     713             :                  * processing.  As such this ifindex
     714             :                  * passed to us may be a VRF device
     715             :                  * which will not be in the default
     716             :                  * VRF.  So let's look in all of them
     717             :                  */
     718           0 :                 zns = zebra_ns_lookup(NS_DEFAULT);
     719           0 :                 ifp = if_lookup_by_index_per_ns(zns, nexthop->ifindex);
     720           0 :                 if (ifp && if_is_operative(ifp))
     721           0 :                         SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     722             :                 else
     723           0 :                         UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     724             :                 break;
     725           0 :         case NEXTHOP_TYPE_IPV4:
     726             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
     727           0 :                 if (nhlfe_nexthop_active_ipv4(nhlfe, nexthop))
     728           0 :                         SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     729             :                 else
     730           0 :                         UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     731             :                 break;
     732             : 
     733           0 :         case NEXTHOP_TYPE_IPV6:
     734           0 :                 if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
     735           0 :                         SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     736             :                 else
     737           0 :                         UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     738             :                 break;
     739             : 
     740           0 :         case NEXTHOP_TYPE_IPV6_IFINDEX:
     741           0 :                 if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
     742           0 :                         ifp = if_lookup_by_index(nexthop->ifindex,
     743             :                                                  nexthop->vrf_id);
     744           0 :                         if (ifp && if_is_operative(ifp))
     745           0 :                                 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     746             :                         else
     747           0 :                                 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     748             :                 } else {
     749           0 :                         if (nhlfe_nexthop_active_ipv6(nhlfe, nexthop))
     750           0 :                                 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     751             :                         else
     752           0 :                                 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     753             :                 }
     754             :                 break;
     755             : 
     756             :         case NEXTHOP_TYPE_BLACKHOLE:
     757             :                 break;
     758             :         }
     759             : 
     760           0 :         return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
     761             : }
     762             : 
     763             : /*
     764             :  * Walk through NHLFEs for a LSP forwarding entry, verify nexthop
     765             :  * reachability and select the best. Multipath entries are also
     766             :  * marked. This is invoked when an LSP scheduled for processing (due
     767             :  * to some change) is examined.
     768             :  */
     769           0 : static void lsp_select_best_nhlfe(struct zebra_lsp *lsp)
     770             : {
     771           0 :         struct zebra_nhlfe *nhlfe;
     772           0 :         struct zebra_nhlfe *best;
     773           0 :         struct nexthop *nexthop;
     774           0 :         int changed = 0;
     775             : 
     776           0 :         if (!lsp)
     777             :                 return;
     778             : 
     779           0 :         best = NULL;
     780           0 :         lsp->num_ecmp = 0;
     781           0 :         UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
     782             : 
     783             :         /*
     784             :          * First compute the best path, after checking nexthop status. We are
     785             :          * only concerned with non-deleted NHLFEs.
     786             :          */
     787           0 :         frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
     788             :                 /* Clear selection flags. */
     789           0 :                 UNSET_FLAG(nhlfe->flags,
     790             :                            (NHLFE_FLAG_SELECTED | NHLFE_FLAG_MULTIPATH));
     791             : 
     792           0 :                 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
     793           0 :                     && nhlfe_nexthop_active(nhlfe)) {
     794           0 :                         if (!best || (nhlfe->distance < best->distance))
     795           0 :                                 best = nhlfe;
     796             :                 }
     797             :         }
     798             : 
     799           0 :         lsp->best_nhlfe = best;
     800           0 :         if (!lsp->best_nhlfe)
     801             :                 return;
     802             : 
     803             :         /*
     804             :          * Check the active status of backup nhlfes also
     805             :          */
     806           0 :         frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
     807           0 :                 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
     808           0 :                         (void)nhlfe_nexthop_active(nhlfe);
     809             :         }
     810             : 
     811             :         /* Mark best NHLFE as selected. */
     812           0 :         SET_FLAG(lsp->best_nhlfe->flags, NHLFE_FLAG_SELECTED);
     813             : 
     814             :         /*
     815             :          * If best path exists, see if there is ECMP. While doing this, note if
     816             :          * a
     817             :          * new (uninstalled) NHLFE has been selected, an installed entry that is
     818             :          * still selected has a change or an installed entry is to be removed.
     819             :          */
     820           0 :         frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
     821           0 :                 int nh_chg, nh_sel, nh_inst;
     822             : 
     823           0 :                 nexthop = nhlfe->nexthop;
     824           0 :                 if (!nexthop) // unexpected
     825           0 :                         continue;
     826             : 
     827           0 :                 if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)
     828           0 :                     && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
     829           0 :                     && (nhlfe->distance == lsp->best_nhlfe->distance)) {
     830           0 :                         SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
     831           0 :                         SET_FLAG(nhlfe->flags, NHLFE_FLAG_MULTIPATH);
     832           0 :                         lsp->num_ecmp++;
     833             :                 }
     834             : 
     835           0 :                 if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) && !changed) {
     836           0 :                         nh_chg = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
     837           0 :                         nh_sel = CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
     838           0 :                         nh_inst =
     839             :                                 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
     840             : 
     841           0 :                         if ((nh_sel && !nh_inst)
     842           0 :                             || (nh_sel && nh_inst && nh_chg)
     843           0 :                             || (nh_inst && !nh_sel))
     844           0 :                                 changed = 1;
     845             :                 }
     846             : 
     847             :                 /* We have finished examining, clear changed flag. */
     848           0 :                 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
     849             :         }
     850             : 
     851           0 :         if (changed)
     852           0 :                 SET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
     853             : }
     854             : 
     855             : /*
     856             :  * Delete LSP forwarding entry from kernel, if installed. Called upon
     857             :  * process exit.
     858             :  */
     859           0 : static void lsp_uninstall_from_kernel(struct hash_bucket *bucket, void *ctxt)
     860             : {
     861           0 :         struct zebra_lsp *lsp;
     862             : 
     863           0 :         lsp = (struct zebra_lsp *)bucket->data;
     864           0 :         if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
     865           0 :                 (void)dplane_lsp_delete(lsp);
     866           0 : }
     867             : 
     868             : /*
     869             :  * Schedule LSP forwarding entry for processing. Called upon changes
     870             :  * that may impact LSPs such as nexthop / connected route changes.
     871             :  */
     872           0 : static void lsp_schedule(struct hash_bucket *bucket, void *ctxt)
     873             : {
     874           0 :         struct zebra_lsp *lsp;
     875             : 
     876           0 :         lsp = (struct zebra_lsp *)bucket->data;
     877             : 
     878             :         /* In the common flow, this is used when external events occur. For
     879             :          * LSPs with backup nhlfes, we'll assume that the forwarding
     880             :          * plane will use the backups to handle these events, until the
     881             :          * owning protocol can react.
     882             :          */
     883           0 :         if (ctxt == NULL) {
     884             :                 /* Skip LSPs with backups */
     885           0 :                 if (nhlfe_list_first(&lsp->backup_nhlfe_list) != NULL) {
     886           0 :                         if (IS_ZEBRA_DEBUG_MPLS_DETAIL)
     887           0 :                                 zlog_debug("%s: skip LSP in-label %u",
     888             :                                            __func__, lsp->ile.in_label);
     889           0 :                         return;
     890             :                 }
     891             :         }
     892             : 
     893           0 :         (void)lsp_processq_add(lsp);
     894             : }
     895             : 
     896             : /*
     897             :  * Process a LSP entry that is in the queue. Recalculate best NHLFE and
     898             :  * any multipaths and update or delete from the kernel, as needed.
     899             :  */
     900           0 : static wq_item_status lsp_process(struct work_queue *wq, void *data)
     901             : {
     902           0 :         struct zebra_lsp *lsp;
     903           0 :         struct zebra_nhlfe *oldbest, *newbest;
     904           0 :         char buf[BUFSIZ], buf2[BUFSIZ];
     905           0 :         struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
     906           0 :         enum zebra_dplane_result res;
     907             : 
     908           0 :         lsp = (struct zebra_lsp *)data;
     909           0 :         if (!lsp) // unexpected
     910             :                 return WQ_SUCCESS;
     911             : 
     912           0 :         oldbest = lsp->best_nhlfe;
     913             : 
     914             :         /* Select best NHLFE(s) */
     915           0 :         lsp_select_best_nhlfe(lsp);
     916             : 
     917           0 :         newbest = lsp->best_nhlfe;
     918             : 
     919           0 :         if (IS_ZEBRA_DEBUG_MPLS) {
     920           0 :                 if (oldbest)
     921           0 :                         nhlfe2str(oldbest, buf, sizeof(buf));
     922           0 :                 if (newbest)
     923           0 :                         nhlfe2str(newbest, buf2, sizeof(buf2));
     924           0 :                 zlog_debug(
     925             :                         "Process LSP in-label %u oldbest %s newbest %s flags 0x%x ecmp# %d",
     926             :                         lsp->ile.in_label, oldbest ? buf : "NULL",
     927             :                         newbest ? buf2 : "NULL", lsp->flags, lsp->num_ecmp);
     928             :         }
     929             : 
     930           0 :         if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED)) {
     931             :                 /* Not already installed */
     932           0 :                 if (newbest) {
     933             : 
     934           0 :                         UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
     935             : 
     936           0 :                         switch (dplane_lsp_add(lsp)) {
     937           0 :                         case ZEBRA_DPLANE_REQUEST_QUEUED:
     938             :                                 /* Set 'installed' flag so we will know
     939             :                                  * that an install is in-flight.
     940             :                                  */
     941           0 :                                 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
     942             : 
     943           0 :                                 zvrf->lsp_installs_queued++;
     944           0 :                                 break;
     945           0 :                         case ZEBRA_DPLANE_REQUEST_FAILURE:
     946           0 :                                 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
     947             :                                           "LSP Install Failure: %u",
     948             :                                           lsp->ile.in_label);
     949           0 :                                 break;
     950           0 :                         case ZEBRA_DPLANE_REQUEST_SUCCESS:
     951           0 :                                 zvrf->lsp_installs++;
     952           0 :                                 break;
     953             :                         }
     954             :                 }
     955             :         } else {
     956             :                 /* Installed, may need an update and/or delete. */
     957           0 :                 if (!newbest) {
     958           0 :                         res = dplane_lsp_delete(lsp);
     959             : 
     960             :                         /* We do some of the lsp cleanup immediately for
     961             :                          * deletes.
     962             :                          */
     963           0 :                         UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
     964           0 :                         clear_nhlfe_installed(lsp);
     965             : 
     966           0 :                         switch (res) {
     967           0 :                         case ZEBRA_DPLANE_REQUEST_QUEUED:
     968           0 :                                 zvrf->lsp_removals_queued++;
     969           0 :                                 break;
     970           0 :                         case ZEBRA_DPLANE_REQUEST_FAILURE:
     971           0 :                                 flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
     972             :                                           "LSP Deletion Failure: %u",
     973             :                                           lsp->ile.in_label);
     974           0 :                                 break;
     975           0 :                         case ZEBRA_DPLANE_REQUEST_SUCCESS:
     976           0 :                                 zvrf->lsp_removals++;
     977           0 :                                 break;
     978             :                         }
     979           0 :                 } else if (CHECK_FLAG(lsp->flags, LSP_FLAG_CHANGED)) {
     980           0 :                         struct zebra_nhlfe *nhlfe;
     981           0 :                         struct nexthop *nexthop;
     982             : 
     983           0 :                         UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
     984             : 
     985             :                         /* We leave the INSTALLED flag set here
     986             :                          * so we know an update is in-flight.
     987             :                          */
     988             : 
     989             :                         /*
     990             :                          * Any NHLFE that was installed but is not
     991             :                          * selected now needs to have its flags updated.
     992             :                          */
     993           0 :                         frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
     994           0 :                                 nexthop = nhlfe->nexthop;
     995           0 :                                 if (!nexthop)
     996           0 :                                         continue;
     997             : 
     998           0 :                                 if (CHECK_FLAG(nhlfe->flags,
     999             :                                                NHLFE_FLAG_INSTALLED)
    1000           0 :                                     && !CHECK_FLAG(nhlfe->flags,
    1001             :                                                    NHLFE_FLAG_SELECTED)) {
    1002           0 :                                         UNSET_FLAG(nhlfe->flags,
    1003             :                                                    NHLFE_FLAG_INSTALLED);
    1004           0 :                                         UNSET_FLAG(nexthop->flags,
    1005             :                                                    NEXTHOP_FLAG_FIB);
    1006             :                                 }
    1007             :                         }
    1008             : 
    1009           0 :                         switch (dplane_lsp_update(lsp)) {
    1010           0 :                         case ZEBRA_DPLANE_REQUEST_QUEUED:
    1011           0 :                                 zvrf->lsp_installs_queued++;
    1012           0 :                                 break;
    1013           0 :                         case ZEBRA_DPLANE_REQUEST_FAILURE:
    1014           0 :                                 flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
    1015             :                                           "LSP Update Failure: %u",
    1016             :                                           lsp->ile.in_label);
    1017           0 :                                 break;
    1018           0 :                         case ZEBRA_DPLANE_REQUEST_SUCCESS:
    1019           0 :                                 zvrf->lsp_installs++;
    1020           0 :                                 break;
    1021             :                         }
    1022             :                 }
    1023             :         }
    1024             : 
    1025             :         return WQ_SUCCESS;
    1026             : }
    1027             : 
    1028             : 
    1029             : /*
    1030             :  * Callback upon processing completion of a LSP forwarding entry.
    1031             :  */
    1032           0 : static void lsp_processq_del(struct work_queue *wq, void *data)
    1033             : {
    1034           0 :         struct zebra_vrf *zvrf;
    1035           0 :         struct zebra_lsp *lsp;
    1036           0 :         struct hash *lsp_table;
    1037           0 :         struct zebra_nhlfe *nhlfe;
    1038             : 
    1039             :         /* If zebra is shutting down, don't delete any structs,
    1040             :          * just ignore this callback. The LSPs will be cleaned up
    1041             :          * during the shutdown processing.
    1042             :          */
    1043           0 :         if (zebra_router_in_shutdown())
    1044           0 :                 return;
    1045             : 
    1046           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
    1047           0 :         assert(zvrf);
    1048             : 
    1049           0 :         lsp_table = zvrf->lsp_table;
    1050           0 :         if (!lsp_table) // unexpected
    1051             :                 return;
    1052             : 
    1053           0 :         lsp = (struct zebra_lsp *)data;
    1054           0 :         if (!lsp) // unexpected
    1055             :                 return;
    1056             : 
    1057             :         /* Clear flag, remove any NHLFEs marked for deletion. If no NHLFEs
    1058             :          * exist,
    1059             :          * delete LSP entry also.
    1060             :          */
    1061           0 :         UNSET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
    1062             : 
    1063           0 :         frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
    1064           0 :                 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
    1065           0 :                         nhlfe_del(nhlfe);
    1066             :         }
    1067             : 
    1068           0 :         frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
    1069           0 :                 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
    1070           0 :                         nhlfe_del(nhlfe);
    1071             :         }
    1072             : 
    1073           0 :         lsp_check_free(lsp_table, &lsp);
    1074             : }
    1075             : 
    1076             : /*
    1077             :  * Callback upon finishing the processing of all scheduled
    1078             :  * LSP forwarding entries.
    1079             :  */
    1080           0 : static void lsp_processq_complete(struct work_queue *wq)
    1081             : {
    1082             :         /* Nothing to do for now. */
    1083           0 : }
    1084             : 
    1085             : /*
    1086             :  * Add LSP forwarding entry to queue for subsequent processing.
    1087             :  */
    1088           0 : static int lsp_processq_add(struct zebra_lsp *lsp)
    1089             : {
    1090             :         /* If already scheduled, exit. */
    1091           0 :         if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
    1092             :                 return 0;
    1093             : 
    1094           0 :         if (zrouter.lsp_process_q == NULL) {
    1095           0 :                 flog_err(EC_ZEBRA_WQ_NONEXISTENT,
    1096             :                          "%s: work_queue does not exist!", __func__);
    1097           0 :                 return -1;
    1098             :         }
    1099             : 
    1100           0 :         work_queue_add(zrouter.lsp_process_q, lsp);
    1101           0 :         SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
    1102           0 :         return 0;
    1103             : }
    1104             : 
    1105             : /*
    1106             :  * Callback to allocate LSP forwarding table entry.
    1107             :  */
    1108           0 : static void *lsp_alloc(void *p)
    1109             : {
    1110           0 :         const struct zebra_ile *ile = p;
    1111           0 :         struct zebra_lsp *lsp;
    1112             : 
    1113           0 :         lsp = XCALLOC(MTYPE_LSP, sizeof(struct zebra_lsp));
    1114           0 :         lsp->ile = *ile;
    1115           0 :         nhlfe_list_init(&lsp->nhlfe_list);
    1116           0 :         nhlfe_list_init(&lsp->backup_nhlfe_list);
    1117             : 
    1118           0 :         if (IS_ZEBRA_DEBUG_MPLS)
    1119           0 :                 zlog_debug("Alloc LSP in-label %u", lsp->ile.in_label);
    1120             : 
    1121           0 :         return ((void *)lsp);
    1122             : }
    1123             : 
    1124             : /*
    1125             :  * Check whether lsp can be freed - no nhlfes, e.g., and call free api
    1126             :  */
    1127           0 : static void lsp_check_free(struct hash *lsp_table, struct zebra_lsp **plsp)
    1128             : {
    1129           0 :         struct zebra_lsp *lsp;
    1130             : 
    1131           0 :         if (plsp == NULL || *plsp == NULL)
    1132             :                 return;
    1133             : 
    1134           0 :         lsp = *plsp;
    1135             : 
    1136           0 :         if ((nhlfe_list_first(&lsp->nhlfe_list) == NULL) &&
    1137           0 :             (nhlfe_list_first(&lsp->backup_nhlfe_list) == NULL) &&
    1138           0 :             !CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
    1139           0 :                 lsp_free(lsp_table, plsp);
    1140             : }
    1141             : 
    1142           0 : static void lsp_free_nhlfe(struct zebra_lsp *lsp)
    1143             : {
    1144           0 :         struct zebra_nhlfe *nhlfe;
    1145             : 
    1146           0 :         while ((nhlfe = nhlfe_list_first(&lsp->nhlfe_list))) {
    1147           0 :                 nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
    1148           0 :                 nhlfe_free(nhlfe);
    1149             :         }
    1150             : 
    1151           0 :         while ((nhlfe = nhlfe_list_first(&lsp->backup_nhlfe_list))) {
    1152           0 :                 nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
    1153           0 :                 nhlfe_free(nhlfe);
    1154             :         }
    1155           0 : }
    1156             : 
    1157             : /*
    1158             :  * Dtor for an LSP: remove from ile hash, release any internal allocations,
    1159             :  * free LSP object.
    1160             :  */
    1161           0 : static void lsp_free(struct hash *lsp_table, struct zebra_lsp **plsp)
    1162             : {
    1163           0 :         struct zebra_lsp *lsp;
    1164             : 
    1165           0 :         if (plsp == NULL || *plsp == NULL)
    1166             :                 return;
    1167             : 
    1168           0 :         lsp = *plsp;
    1169             : 
    1170           0 :         if (IS_ZEBRA_DEBUG_MPLS)
    1171           0 :                 zlog_debug("Free LSP in-label %u flags 0x%x",
    1172             :                            lsp->ile.in_label, lsp->flags);
    1173             : 
    1174           0 :         lsp_free_nhlfe(lsp);
    1175             : 
    1176           0 :         hash_release(lsp_table, &lsp->ile);
    1177           0 :         XFREE(MTYPE_LSP, lsp);
    1178             : 
    1179           0 :         *plsp = NULL;
    1180             : }
    1181             : 
    1182             : /*
    1183             :  * Create printable string for NHLFE entry.
    1184             :  */
    1185           0 : static char *nhlfe2str(const struct zebra_nhlfe *nhlfe, char *buf, int size)
    1186             : {
    1187           0 :         const struct nexthop *nexthop;
    1188             : 
    1189           0 :         buf[0] = '\0';
    1190           0 :         nexthop = nhlfe->nexthop;
    1191           0 :         switch (nexthop->type) {
    1192           0 :         case NEXTHOP_TYPE_IPV4:
    1193             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
    1194           0 :                 inet_ntop(AF_INET, &nexthop->gate.ipv4, buf, size);
    1195           0 :                 break;
    1196           0 :         case NEXTHOP_TYPE_IPV6:
    1197             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
    1198           0 :                 inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, size);
    1199           0 :                 break;
    1200           0 :         case NEXTHOP_TYPE_IFINDEX:
    1201           0 :                 snprintf(buf, size, "Ifindex: %u", nexthop->ifindex);
    1202             :         case NEXTHOP_TYPE_BLACKHOLE:
    1203             :                 break;
    1204             :         }
    1205             : 
    1206           0 :         return buf;
    1207             : }
    1208             : 
    1209             : /*
    1210             :  * Check if NHLFE matches with search info passed.
    1211             :  */
    1212           0 : static int nhlfe_nhop_match(struct zebra_nhlfe *nhlfe,
    1213             :                             enum nexthop_types_t gtype,
    1214             :                             const union g_addr *gate, ifindex_t ifindex)
    1215             : {
    1216           0 :         struct nexthop *nhop;
    1217           0 :         int cmp = 1;
    1218             : 
    1219           0 :         nhop = nhlfe->nexthop;
    1220           0 :         if (!nhop)
    1221             :                 return 1;
    1222             : 
    1223           0 :         if (nhop->type != gtype)
    1224             :                 return 1;
    1225             : 
    1226           0 :         switch (nhop->type) {
    1227           0 :         case NEXTHOP_TYPE_IPV4:
    1228             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
    1229           0 :                 cmp = memcmp(&(nhop->gate.ipv4), &(gate->ipv4),
    1230             :                              sizeof(struct in_addr));
    1231           0 :                 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
    1232           0 :                         cmp = !(nhop->ifindex == ifindex);
    1233             :                 break;
    1234           0 :         case NEXTHOP_TYPE_IPV6:
    1235             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
    1236           0 :                 cmp = memcmp(&(nhop->gate.ipv6), &(gate->ipv6),
    1237             :                              sizeof(struct in6_addr));
    1238           0 :                 if (!cmp && nhop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
    1239           0 :                         cmp = !(nhop->ifindex == ifindex);
    1240             :                 break;
    1241           0 :         case NEXTHOP_TYPE_IFINDEX:
    1242           0 :                 cmp = !(nhop->ifindex == ifindex);
    1243           0 :                 break;
    1244             :         case NEXTHOP_TYPE_BLACKHOLE:
    1245             :                 break;
    1246             :         }
    1247             : 
    1248             :         return cmp;
    1249             : }
    1250             : 
    1251             : 
    1252             : /*
    1253             :  * Locate NHLFE that matches with passed info.
    1254             :  */
    1255           0 : static struct zebra_nhlfe *nhlfe_find(struct nhlfe_list_head *list,
    1256             :                                       enum lsp_types_t lsp_type,
    1257             :                                       enum nexthop_types_t gtype,
    1258             :                                       const union g_addr *gate,
    1259             :                                       ifindex_t ifindex)
    1260             : {
    1261           0 :         struct zebra_nhlfe *nhlfe;
    1262             : 
    1263           0 :         frr_each_safe(nhlfe_list, list, nhlfe) {
    1264           0 :                 if (nhlfe->type != lsp_type)
    1265           0 :                         continue;
    1266           0 :                 if (!nhlfe_nhop_match(nhlfe, gtype, gate, ifindex))
    1267             :                         break;
    1268             :         }
    1269             : 
    1270           0 :         return nhlfe;
    1271             : }
    1272             : 
    1273             : /*
    1274             :  * Allocate and init new NHLFE.
    1275             :  */
    1276             : static struct zebra_nhlfe *
    1277           0 : nhlfe_alloc(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
    1278             :             enum nexthop_types_t gtype, const union g_addr *gate,
    1279             :             ifindex_t ifindex, uint8_t num_labels, const mpls_label_t *labels)
    1280             : {
    1281           0 :         struct zebra_nhlfe *nhlfe;
    1282           0 :         struct nexthop *nexthop;
    1283             : 
    1284           0 :         assert(lsp);
    1285             : 
    1286           0 :         nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(struct zebra_nhlfe));
    1287             : 
    1288           0 :         nhlfe->lsp = lsp;
    1289           0 :         nhlfe->type = lsp_type;
    1290           0 :         nhlfe->distance = lsp_distance(lsp_type);
    1291             : 
    1292           0 :         nexthop = nexthop_new();
    1293             : 
    1294           0 :         nexthop_add_labels(nexthop, lsp_type, num_labels, labels);
    1295             : 
    1296           0 :         nexthop->vrf_id = VRF_DEFAULT;
    1297           0 :         nexthop->type = gtype;
    1298           0 :         switch (nexthop->type) {
    1299           0 :         case NEXTHOP_TYPE_IPV4:
    1300             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
    1301           0 :                 nexthop->gate.ipv4 = gate->ipv4;
    1302           0 :                 if (ifindex)
    1303           0 :                         nexthop->ifindex = ifindex;
    1304             :                 break;
    1305           0 :         case NEXTHOP_TYPE_IPV6:
    1306             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
    1307           0 :                 nexthop->gate.ipv6 = gate->ipv6;
    1308           0 :                 if (ifindex)
    1309           0 :                         nexthop->ifindex = ifindex;
    1310             :                 break;
    1311           0 :         case NEXTHOP_TYPE_IFINDEX:
    1312           0 :                 nexthop->ifindex = ifindex;
    1313           0 :                 break;
    1314           0 :         case NEXTHOP_TYPE_BLACKHOLE:
    1315           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    1316           0 :                         zlog_debug("%s: invalid: blackhole nexthop", __func__);
    1317             : 
    1318           0 :                 nexthop_free(nexthop);
    1319           0 :                 XFREE(MTYPE_NHLFE, nhlfe);
    1320           0 :                 return NULL;
    1321             :         }
    1322           0 :         nhlfe->nexthop = nexthop;
    1323             : 
    1324           0 :         return nhlfe;
    1325             : }
    1326             : 
    1327             : /*
    1328             :  * Add primary or backup NHLFE. Base entry must have been created and
    1329             :  * duplicate check done.
    1330             :  */
    1331           0 : static struct zebra_nhlfe *nhlfe_add(struct zebra_lsp *lsp,
    1332             :                                      enum lsp_types_t lsp_type,
    1333             :                                      enum nexthop_types_t gtype,
    1334             :                                      const union g_addr *gate,
    1335             :                                      ifindex_t ifindex, uint8_t num_labels,
    1336             :                                      const mpls_label_t *labels, bool is_backup)
    1337             : {
    1338           0 :         struct zebra_nhlfe *nhlfe;
    1339             : 
    1340           0 :         if (!lsp)
    1341             :                 return NULL;
    1342             : 
    1343             :         /* Must have labels */
    1344           0 :         if (num_labels == 0 || labels == NULL) {
    1345           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    1346           0 :                         zlog_debug("%s: invalid nexthop: no labels", __func__);
    1347             : 
    1348           0 :                 return NULL;
    1349             :         }
    1350             : 
    1351             :         /* Allocate new object */
    1352           0 :         nhlfe = nhlfe_alloc(lsp, lsp_type, gtype, gate, ifindex, num_labels,
    1353             :                             labels);
    1354             : 
    1355           0 :         if (!nhlfe)
    1356             :                 return NULL;
    1357             : 
    1358             :         /* Enqueue to LSP: primaries at head of list, backups at tail */
    1359           0 :         if (is_backup) {
    1360           0 :                 SET_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP);
    1361           0 :                 nhlfe_list_add_tail(&lsp->backup_nhlfe_list, nhlfe);
    1362             :         } else
    1363           0 :                 nhlfe_list_add_head(&lsp->nhlfe_list, nhlfe);
    1364             : 
    1365             :         return nhlfe;
    1366             : }
    1367             : 
    1368             : /*
    1369             :  * Common delete for NHLFEs.
    1370             :  */
    1371           0 : static void nhlfe_free(struct zebra_nhlfe *nhlfe)
    1372             : {
    1373           0 :         if (!nhlfe)
    1374             :                 return;
    1375             : 
    1376             :         /* Free nexthop. */
    1377           0 :         if (nhlfe->nexthop)
    1378           0 :                 nexthop_free(nhlfe->nexthop);
    1379             : 
    1380           0 :         nhlfe->nexthop = NULL;
    1381             : 
    1382           0 :         XFREE(MTYPE_NHLFE, nhlfe);
    1383             : }
    1384             : 
    1385             : 
    1386             : /*
    1387             :  * Disconnect NHLFE from LSP, and free. Entry must be present on LSP's list.
    1388             :  */
    1389           0 : static int nhlfe_del(struct zebra_nhlfe *nhlfe)
    1390             : {
    1391           0 :         struct zebra_lsp *lsp;
    1392             : 
    1393           0 :         if (!nhlfe)
    1394             :                 return -1;
    1395             : 
    1396           0 :         lsp = nhlfe->lsp;
    1397           0 :         if (!lsp)
    1398             :                 return -1;
    1399             : 
    1400           0 :         if (nhlfe == lsp->best_nhlfe)
    1401           0 :                 lsp->best_nhlfe = NULL;
    1402             : 
    1403             :         /* Unlink from LSP */
    1404           0 :         if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP))
    1405           0 :                 nhlfe_list_del(&lsp->backup_nhlfe_list, nhlfe);
    1406             :         else
    1407           0 :                 nhlfe_list_del(&lsp->nhlfe_list, nhlfe);
    1408             : 
    1409           0 :         nhlfe->lsp = NULL;
    1410             : 
    1411           0 :         nhlfe_free(nhlfe);
    1412             : 
    1413           0 :         return 0;
    1414             : }
    1415             : 
    1416             : /*
    1417             :  * Update label for NHLFE entry.
    1418             :  */
    1419           0 : static void nhlfe_out_label_update(struct zebra_nhlfe *nhlfe,
    1420             :                                    struct mpls_label_stack *nh_label)
    1421             : {
    1422           0 :         nhlfe->nexthop->nh_label->label[0] = nh_label->label[0];
    1423             : }
    1424             : 
    1425           0 : static int mpls_lsp_uninstall_all(struct hash *lsp_table, struct zebra_lsp *lsp,
    1426             :                                   enum lsp_types_t type)
    1427             : {
    1428           0 :         struct zebra_nhlfe *nhlfe;
    1429           0 :         int schedule_lsp = 0;
    1430           0 :         char buf[BUFSIZ];
    1431             : 
    1432           0 :         if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
    1433           0 :                 schedule_lsp = 1;
    1434             : 
    1435             :         /* Mark NHLFEs for delete or directly delete, as appropriate. */
    1436           0 :         frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
    1437             :                 /* Skip non-static NHLFEs */
    1438           0 :                 if (nhlfe->type != type)
    1439           0 :                         continue;
    1440             : 
    1441           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    1442           0 :                         nhlfe2str(nhlfe, buf, sizeof(buf));
    1443           0 :                         zlog_debug(
    1444             :                                 "Del LSP in-label %u type %d nexthop %s flags 0x%x",
    1445             :                                 lsp->ile.in_label, type, buf, nhlfe->flags);
    1446             :                 }
    1447             : 
    1448           0 :                 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
    1449           0 :                         UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
    1450           0 :                         SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
    1451           0 :                         schedule_lsp = 1;
    1452             :                 } else {
    1453           0 :                         nhlfe_del(nhlfe);
    1454             :                 }
    1455             :         }
    1456             : 
    1457           0 :         frr_each_safe(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
    1458             :                 /* Skip non-static NHLFEs */
    1459           0 :                 if (nhlfe->type != type)
    1460           0 :                         continue;
    1461             : 
    1462           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    1463           0 :                         nhlfe2str(nhlfe, buf, sizeof(buf));
    1464           0 :                         zlog_debug(
    1465             :                                 "Del backup LSP in-label %u type %d nexthop %s flags 0x%x",
    1466             :                                 lsp->ile.in_label, type, buf, nhlfe->flags);
    1467             :                 }
    1468             : 
    1469           0 :                 if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)) {
    1470           0 :                         UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
    1471           0 :                         SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
    1472           0 :                         schedule_lsp = 1;
    1473             :                 } else {
    1474           0 :                         nhlfe_del(nhlfe);
    1475             :                 }
    1476             :         }
    1477             : 
    1478             :         /* Queue LSP for processing, if needed, else delete. */
    1479           0 :         if (schedule_lsp) {
    1480           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    1481           0 :                         zlog_debug("Schedule LSP in-label %u flags 0x%x",
    1482             :                                    lsp->ile.in_label, lsp->flags);
    1483             :                 }
    1484           0 :                 if (lsp_processq_add(lsp))
    1485             :                         return -1;
    1486             :         } else {
    1487           0 :                 lsp_check_free(lsp_table, &lsp);
    1488             :         }
    1489             : 
    1490             :         return 0;
    1491             : }
    1492             : 
    1493             : /*
    1494             :  * Uninstall all static NHLFEs for a particular LSP forwarding entry.
    1495             :  * If no other NHLFEs exist, the entry would be deleted.
    1496             :  */
    1497           0 : static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf,
    1498             :                                          mpls_label_t in_label)
    1499             : {
    1500           0 :         struct hash *lsp_table;
    1501           0 :         struct zebra_ile tmp_ile;
    1502           0 :         struct zebra_lsp *lsp;
    1503             : 
    1504             :         /* Lookup table. */
    1505           0 :         lsp_table = zvrf->lsp_table;
    1506           0 :         if (!lsp_table)
    1507             :                 return -1;
    1508             : 
    1509             :         /* If entry is not present, exit. */
    1510           0 :         tmp_ile.in_label = in_label;
    1511           0 :         lsp = hash_lookup(lsp_table, &tmp_ile);
    1512           0 :         if (!lsp || (nhlfe_list_first(&lsp->nhlfe_list) == NULL))
    1513             :                 return 0;
    1514             : 
    1515           0 :         return mpls_lsp_uninstall_all(lsp_table, lsp, ZEBRA_LSP_STATIC);
    1516             : }
    1517             : 
    1518           0 : static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe)
    1519             : {
    1520           0 :         json_object *json_nhlfe = NULL;
    1521           0 :         json_object *json_backups = NULL;
    1522           0 :         json_object *json_label_stack;
    1523           0 :         struct nexthop *nexthop = nhlfe->nexthop;
    1524           0 :         int i;
    1525             : 
    1526           0 :         json_nhlfe = json_object_new_object();
    1527           0 :         json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
    1528           0 :         json_object_int_add(json_nhlfe, "outLabel",
    1529           0 :                             nexthop->nh_label->label[0]);
    1530             : 
    1531           0 :         json_label_stack = json_object_new_array();
    1532           0 :         json_object_object_add(json_nhlfe, "outLabelStack", json_label_stack);
    1533           0 :         for (i = 0; i < nexthop->nh_label->num_labels; i++)
    1534           0 :                 json_object_array_add(
    1535             :                         json_label_stack,
    1536           0 :                         json_object_new_int(nexthop->nh_label->label[i]));
    1537             : 
    1538           0 :         json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
    1539             : 
    1540           0 :         if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
    1541           0 :                 json_object_boolean_true_add(json_nhlfe, "installed");
    1542             : 
    1543           0 :         switch (nexthop->type) {
    1544           0 :         case NEXTHOP_TYPE_IPV4:
    1545             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
    1546           0 :                 json_object_string_addf(json_nhlfe, "nexthop", "%pI4",
    1547             :                                         &nexthop->gate.ipv4);
    1548           0 :                 break;
    1549           0 :         case NEXTHOP_TYPE_IPV6:
    1550             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
    1551           0 :                 json_object_string_addf(json_nhlfe, "nexthop", "%pI6",
    1552             :                                         &nexthop->gate.ipv6);
    1553             : 
    1554           0 :                 if (nexthop->ifindex)
    1555           0 :                         json_object_string_add(json_nhlfe, "interface",
    1556             :                                                ifindex2ifname(nexthop->ifindex,
    1557             :                                                               nexthop->vrf_id));
    1558             :                 break;
    1559           0 :         case NEXTHOP_TYPE_IFINDEX:
    1560           0 :                 if (nexthop->ifindex)
    1561           0 :                         json_object_string_add(json_nhlfe, "interface",
    1562             :                                                ifindex2ifname(nexthop->ifindex,
    1563             :                                                               nexthop->vrf_id));
    1564             :                 break;
    1565             :         case NEXTHOP_TYPE_BLACKHOLE:
    1566             :                 break;
    1567             :         }
    1568             : 
    1569           0 :         if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
    1570           0 :                 json_backups = json_object_new_array();
    1571           0 :                 for (i = 0; i < nexthop->backup_num; i++) {
    1572           0 :                         json_object_array_add(
    1573             :                                 json_backups,
    1574           0 :                                 json_object_new_int(nexthop->backup_idx[i]));
    1575             :                 }
    1576             : 
    1577           0 :                 json_object_object_add(json_nhlfe, "backupIndex",
    1578             :                                        json_backups);
    1579             :         }
    1580             : 
    1581           0 :         return json_nhlfe;
    1582             : }
    1583             : 
    1584             : /*
    1585             :  * Print the NHLFE for a LSP forwarding entry.
    1586             :  */
    1587           0 : static void nhlfe_print(struct zebra_nhlfe *nhlfe, struct vty *vty,
    1588             :                         const char *indent)
    1589             : {
    1590           0 :         struct nexthop *nexthop;
    1591           0 :         char buf[MPLS_LABEL_STRLEN];
    1592             : 
    1593           0 :         nexthop = nhlfe->nexthop;
    1594           0 :         if (!nexthop || !nexthop->nh_label) // unexpected
    1595           0 :                 return;
    1596             : 
    1597           0 :         vty_out(vty, " type: %s remote label: %s distance: %d\n",
    1598             :                 nhlfe_type2str(nhlfe->type),
    1599           0 :                 mpls_label2str(nexthop->nh_label->num_labels,
    1600           0 :                                nexthop->nh_label->label,
    1601             :                                buf, sizeof(buf), 0),
    1602           0 :                 nhlfe->distance);
    1603             : 
    1604           0 :         if (indent)
    1605           0 :                 vty_out(vty, "%s", indent);
    1606             : 
    1607           0 :         switch (nexthop->type) {
    1608           0 :         case NEXTHOP_TYPE_IPV4:
    1609             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
    1610           0 :                 vty_out(vty, "  via %pI4", &nexthop->gate.ipv4);
    1611           0 :                 if (nexthop->ifindex)
    1612           0 :                         vty_out(vty, " dev %s",
    1613             :                                 ifindex2ifname(nexthop->ifindex,
    1614             :                                                nexthop->vrf_id));
    1615             :                 break;
    1616           0 :         case NEXTHOP_TYPE_IPV6:
    1617             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
    1618           0 :                 vty_out(vty, "  via %s",
    1619           0 :                         inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
    1620             :                                   sizeof(buf)));
    1621           0 :                 if (nexthop->ifindex)
    1622           0 :                         vty_out(vty, " dev %s",
    1623             :                                 ifindex2ifname(nexthop->ifindex,
    1624             :                                                nexthop->vrf_id));
    1625             :                 break;
    1626           0 :         case NEXTHOP_TYPE_IFINDEX:
    1627           0 :                 if (nexthop->ifindex)
    1628           0 :                         vty_out(vty, "  dev %s",
    1629             :                                 ifindex2ifname(nexthop->ifindex,
    1630             :                                                nexthop->vrf_id));
    1631             :                 break;
    1632             :         case NEXTHOP_TYPE_BLACKHOLE:
    1633             :                 break;
    1634             :         }
    1635           0 :         vty_out(vty, "%s",
    1636           0 :                 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_IS_BACKUP) ? " (backup)"
    1637             :                                                                : "");
    1638           0 :         vty_out(vty, "%s",
    1639           0 :                 CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)"
    1640             :                                                                : "");
    1641           0 :         vty_out(vty, "\n");
    1642             : }
    1643             : 
    1644             : /*
    1645             :  * Print an LSP forwarding entry.
    1646             :  */
    1647           0 : static void lsp_print(struct vty *vty, struct zebra_lsp *lsp)
    1648             : {
    1649           0 :         struct zebra_nhlfe *nhlfe, *backup;
    1650           0 :         int i, j;
    1651             : 
    1652           0 :         vty_out(vty, "Local label: %u%s\n", lsp->ile.in_label,
    1653           0 :                 CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ? " (installed)"
    1654             :                                                            : "");
    1655             : 
    1656           0 :         frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
    1657           0 :                 nhlfe_print(nhlfe, vty, NULL);
    1658             : 
    1659           0 :                 if (nhlfe->nexthop == NULL ||
    1660           0 :                     !CHECK_FLAG(nhlfe->nexthop->flags,
    1661             :                                 NEXTHOP_FLAG_HAS_BACKUP))
    1662           0 :                         continue;
    1663             : 
    1664             :                 /* Backup nhlfes: find backups in backup list */
    1665             : 
    1666           0 :                 for (j = 0; j < nhlfe->nexthop->backup_num; j++) {
    1667           0 :                         i = 0;
    1668           0 :                         backup = NULL;
    1669           0 :                         frr_each(nhlfe_list, &lsp->backup_nhlfe_list, backup) {
    1670           0 :                                 if (i == nhlfe->nexthop->backup_idx[j])
    1671             :                                         break;
    1672           0 :                                 i++;
    1673             :                         }
    1674             : 
    1675           0 :                         if (backup) {
    1676           0 :                                 vty_out(vty, "   [backup %d]", i);
    1677           0 :                                 nhlfe_print(backup, vty, "   ");
    1678             :                         }
    1679             :                 }
    1680             :         }
    1681           0 : }
    1682             : 
    1683             : /*
    1684             :  * JSON objects for an LSP forwarding entry.
    1685             :  */
    1686           0 : static json_object *lsp_json(struct zebra_lsp *lsp)
    1687             : {
    1688           0 :         struct zebra_nhlfe *nhlfe = NULL;
    1689           0 :         json_object *json = json_object_new_object();
    1690           0 :         json_object *json_nhlfe_list = json_object_new_array();
    1691             : 
    1692           0 :         json_object_int_add(json, "inLabel", lsp->ile.in_label);
    1693             : 
    1694           0 :         if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
    1695           0 :                 json_object_boolean_true_add(json, "installed");
    1696             : 
    1697           0 :         frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe)
    1698           0 :                 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
    1699             : 
    1700           0 :         json_object_object_add(json, "nexthops", json_nhlfe_list);
    1701           0 :         json_nhlfe_list = NULL;
    1702             : 
    1703             : 
    1704           0 :         frr_each(nhlfe_list, &lsp->backup_nhlfe_list, nhlfe) {
    1705           0 :                 if (json_nhlfe_list == NULL)
    1706           0 :                         json_nhlfe_list = json_object_new_array();
    1707             : 
    1708           0 :                 json_object_array_add(json_nhlfe_list, nhlfe_json(nhlfe));
    1709             :         }
    1710             : 
    1711           0 :         if (json_nhlfe_list)
    1712           0 :                 json_object_object_add(json, "backupNexthops", json_nhlfe_list);
    1713             : 
    1714           0 :         return json;
    1715             : }
    1716             : 
    1717             : 
    1718             : /* Return a sorted linked list of the hash contents */
    1719           0 : static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
    1720             : {
    1721           0 :         unsigned int i;
    1722           0 :         struct hash_bucket *hb;
    1723           0 :         struct list *sorted_list = list_new();
    1724             : 
    1725           0 :         sorted_list->cmp = (int (*)(void *, void *))cmp;
    1726             : 
    1727           0 :         for (i = 0; i < hash->size; i++)
    1728           0 :                 for (hb = hash->index[i]; hb; hb = hb->next)
    1729           0 :                         listnode_add_sort(sorted_list, hb->data);
    1730             : 
    1731           0 :         return sorted_list;
    1732             : }
    1733             : 
    1734             : /*
    1735             :  * Compare two LSPs based on their label values.
    1736             :  */
    1737           0 : static int lsp_cmp(const struct zebra_lsp *lsp1, const struct zebra_lsp *lsp2)
    1738             : {
    1739           0 :         if (lsp1->ile.in_label < lsp2->ile.in_label)
    1740             :                 return -1;
    1741             : 
    1742           0 :         if (lsp1->ile.in_label > lsp2->ile.in_label)
    1743           0 :                 return 1;
    1744             : 
    1745             :         return 0;
    1746             : }
    1747             : 
    1748             : /*
    1749             :  * Initialize work queue for processing changed LSPs.
    1750             :  */
    1751           0 : static void mpls_processq_init(void)
    1752             : {
    1753           0 :         zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
    1754             : 
    1755           0 :         zrouter.lsp_process_q->spec.workfunc = &lsp_process;
    1756           0 :         zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
    1757           0 :         zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
    1758           0 :         zrouter.lsp_process_q->spec.max_retries = 0;
    1759           0 :         zrouter.lsp_process_q->spec.hold = 10;
    1760           0 : }
    1761             : 
    1762             : 
    1763             : /*
    1764             :  * Process LSP update results from zebra dataplane.
    1765             :  */
    1766           0 : void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
    1767             : {
    1768           0 :         struct zebra_vrf *zvrf;
    1769           0 :         mpls_label_t label;
    1770           0 :         struct zebra_ile tmp_ile;
    1771           0 :         struct hash *lsp_table;
    1772           0 :         struct zebra_lsp *lsp;
    1773           0 :         struct zebra_nhlfe *nhlfe;
    1774           0 :         struct nexthop *nexthop;
    1775           0 :         enum dplane_op_e op;
    1776           0 :         enum zebra_dplane_result status;
    1777           0 :         enum zebra_sr_policy_update_label_mode update_mode;
    1778             : 
    1779           0 :         op = dplane_ctx_get_op(ctx);
    1780           0 :         status = dplane_ctx_get_status(ctx);
    1781             : 
    1782           0 :         if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
    1783           0 :                 zlog_debug("LSP dplane ctx %p, op %s, in-label %u, result %s",
    1784             :                            ctx, dplane_op2str(op),
    1785             :                            dplane_ctx_get_in_label(ctx),
    1786             :                            dplane_res2str(status));
    1787             : 
    1788           0 :         label = dplane_ctx_get_in_label(ctx);
    1789             : 
    1790           0 :         switch (op) {
    1791           0 :         case DPLANE_OP_LSP_INSTALL:
    1792             :         case DPLANE_OP_LSP_UPDATE:
    1793             :                 /* Look for zebra LSP object */
    1794           0 :                 zvrf = vrf_info_lookup(VRF_DEFAULT);
    1795           0 :                 if (zvrf == NULL)
    1796             :                         break;
    1797             : 
    1798           0 :                 lsp_table = zvrf->lsp_table;
    1799             : 
    1800           0 :                 tmp_ile.in_label = label;
    1801           0 :                 lsp = hash_lookup(lsp_table, &tmp_ile);
    1802           0 :                 if (lsp == NULL) {
    1803           0 :                         if (IS_ZEBRA_DEBUG_DPLANE)
    1804           0 :                                 zlog_debug("LSP ctx %p: in-label %u not found",
    1805             :                                            ctx, dplane_ctx_get_in_label(ctx));
    1806             :                         break;
    1807             :                 }
    1808             : 
    1809             :                 /* TODO -- Confirm that this result is still 'current' */
    1810             : 
    1811           0 :                 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
    1812           0 :                         UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
    1813           0 :                         clear_nhlfe_installed(lsp);
    1814           0 :                         flog_warn(EC_ZEBRA_LSP_INSTALL_FAILURE,
    1815             :                                   "LSP Install Failure: in-label %u",
    1816             :                                   lsp->ile.in_label);
    1817           0 :                         break;
    1818             :                 }
    1819             : 
    1820             :                 /* Update zebra object */
    1821           0 :                 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
    1822           0 :                 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
    1823           0 :                         nexthop = nhlfe->nexthop;
    1824           0 :                         if (!nexthop)
    1825           0 :                                 continue;
    1826             : 
    1827           0 :                         if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) &&
    1828           0 :                             CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
    1829           0 :                                 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
    1830           0 :                                 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
    1831             :                         }
    1832             :                 }
    1833             : 
    1834           0 :                 update_mode = (op == DPLANE_OP_LSP_INSTALL)
    1835             :                                       ? ZEBRA_SR_POLICY_LABEL_CREATED
    1836           0 :                                       : ZEBRA_SR_POLICY_LABEL_UPDATED;
    1837           0 :                 zebra_sr_policy_label_update(label, update_mode);
    1838           0 :                 break;
    1839             : 
    1840           0 :         case DPLANE_OP_LSP_DELETE:
    1841           0 :                 if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
    1842           0 :                         flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
    1843             :                                   "LSP Deletion Failure: in-label %u",
    1844             :                                   dplane_ctx_get_in_label(ctx));
    1845           0 :                         break;
    1846             :                 }
    1847           0 :                 zebra_sr_policy_label_update(label,
    1848             :                                              ZEBRA_SR_POLICY_LABEL_REMOVED);
    1849           0 :                 break;
    1850             : 
    1851             :         case DPLANE_OP_LSP_NOTIFY:
    1852             :         case DPLANE_OP_NONE:
    1853             :         case DPLANE_OP_ROUTE_INSTALL:
    1854             :         case DPLANE_OP_ROUTE_UPDATE:
    1855             :         case DPLANE_OP_ROUTE_DELETE:
    1856             :         case DPLANE_OP_ROUTE_NOTIFY:
    1857             :         case DPLANE_OP_NH_INSTALL:
    1858             :         case DPLANE_OP_NH_UPDATE:
    1859             :         case DPLANE_OP_NH_DELETE:
    1860             :         case DPLANE_OP_PW_INSTALL:
    1861             :         case DPLANE_OP_PW_UNINSTALL:
    1862             :         case DPLANE_OP_SYS_ROUTE_ADD:
    1863             :         case DPLANE_OP_SYS_ROUTE_DELETE:
    1864             :         case DPLANE_OP_ADDR_INSTALL:
    1865             :         case DPLANE_OP_ADDR_UNINSTALL:
    1866             :         case DPLANE_OP_MAC_INSTALL:
    1867             :         case DPLANE_OP_MAC_DELETE:
    1868             :         case DPLANE_OP_NEIGH_INSTALL:
    1869             :         case DPLANE_OP_NEIGH_UPDATE:
    1870             :         case DPLANE_OP_NEIGH_DELETE:
    1871             :         case DPLANE_OP_VTEP_ADD:
    1872             :         case DPLANE_OP_VTEP_DELETE:
    1873             :         case DPLANE_OP_RULE_ADD:
    1874             :         case DPLANE_OP_RULE_DELETE:
    1875             :         case DPLANE_OP_RULE_UPDATE:
    1876             :         case DPLANE_OP_NEIGH_DISCOVER:
    1877             :         case DPLANE_OP_BR_PORT_UPDATE:
    1878             :         case DPLANE_OP_IPTABLE_ADD:
    1879             :         case DPLANE_OP_IPTABLE_DELETE:
    1880             :         case DPLANE_OP_IPSET_ADD:
    1881             :         case DPLANE_OP_IPSET_DELETE:
    1882             :         case DPLANE_OP_IPSET_ENTRY_ADD:
    1883             :         case DPLANE_OP_IPSET_ENTRY_DELETE:
    1884             :         case DPLANE_OP_NEIGH_IP_INSTALL:
    1885             :         case DPLANE_OP_NEIGH_IP_DELETE:
    1886             :         case DPLANE_OP_NEIGH_TABLE_UPDATE:
    1887             :         case DPLANE_OP_GRE_SET:
    1888             :         case DPLANE_OP_INTF_ADDR_ADD:
    1889             :         case DPLANE_OP_INTF_ADDR_DEL:
    1890             :         case DPLANE_OP_INTF_NETCONFIG:
    1891             :         case DPLANE_OP_INTF_INSTALL:
    1892             :         case DPLANE_OP_INTF_UPDATE:
    1893             :         case DPLANE_OP_INTF_DELETE:
    1894             :         case DPLANE_OP_TC_QDISC_INSTALL:
    1895             :         case DPLANE_OP_TC_QDISC_UNINSTALL:
    1896             :         case DPLANE_OP_TC_CLASS_ADD:
    1897             :         case DPLANE_OP_TC_CLASS_DELETE:
    1898             :         case DPLANE_OP_TC_CLASS_UPDATE:
    1899             :         case DPLANE_OP_TC_FILTER_ADD:
    1900             :         case DPLANE_OP_TC_FILTER_DELETE:
    1901             :         case DPLANE_OP_TC_FILTER_UPDATE:
    1902             :                 break;
    1903             : 
    1904             :         } /* Switch */
    1905           0 : }
    1906             : 
    1907             : /*
    1908             :  * Process LSP installation info from two sets of nhlfes: a set from
    1909             :  * a dplane notification, and a set from the zebra LSP object. Update
    1910             :  * counters of installed nexthops, and return whether the LSP has changed.
    1911             :  */
    1912           0 : static bool compare_notif_nhlfes(const struct nhlfe_list_head *ctx_head,
    1913             :                                  struct nhlfe_list_head *nhlfe_head,
    1914             :                                  int *start_counter, int *end_counter)
    1915             : {
    1916           0 :         struct zebra_nhlfe *nhlfe;
    1917           0 :         const struct zebra_nhlfe *ctx_nhlfe;
    1918           0 :         struct nexthop *nexthop;
    1919           0 :         const struct nexthop *ctx_nexthop;
    1920           0 :         int start_count = 0, end_count = 0;
    1921           0 :         bool changed_p = false;
    1922           0 :         bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
    1923             : 
    1924           0 :         frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
    1925           0 :                 char buf[NEXTHOP_STRLEN];
    1926             : 
    1927           0 :                 nexthop = nhlfe->nexthop;
    1928           0 :                 if (!nexthop)
    1929           0 :                         continue;
    1930             : 
    1931           0 :                 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
    1932           0 :                         start_count++;
    1933             : 
    1934           0 :                 ctx_nhlfe = NULL;
    1935           0 :                 ctx_nexthop = NULL;
    1936           0 :                 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
    1937           0 :                         ctx_nexthop = ctx_nhlfe->nexthop;
    1938           0 :                         if (!ctx_nexthop)
    1939           0 :                                 continue;
    1940             : 
    1941           0 :                         if ((ctx_nexthop->type == nexthop->type) &&
    1942           0 :                             nexthop_same(ctx_nexthop, nexthop)) {
    1943             :                                 /* Matched */
    1944             :                                 break;
    1945             :                         }
    1946             :                 }
    1947             : 
    1948           0 :                 if (is_debug)
    1949           0 :                         nexthop2str(nexthop, buf, sizeof(buf));
    1950             : 
    1951           0 :                 if (ctx_nhlfe && ctx_nexthop) {
    1952           0 :                         if (is_debug) {
    1953           0 :                                 const char *tstr = "";
    1954             : 
    1955           0 :                                 if (!CHECK_FLAG(ctx_nhlfe->flags,
    1956             :                                                 NHLFE_FLAG_INSTALLED))
    1957           0 :                                         tstr = "not ";
    1958             : 
    1959           0 :                                 zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
    1960             :                                            buf, tstr);
    1961             :                         }
    1962             : 
    1963             :                         /* Test zebra nhlfe install state */
    1964           0 :                         if (CHECK_FLAG(ctx_nhlfe->flags,
    1965             :                                        NHLFE_FLAG_INSTALLED)) {
    1966             : 
    1967           0 :                                 if (!CHECK_FLAG(nhlfe->flags,
    1968             :                                                 NHLFE_FLAG_INSTALLED))
    1969           0 :                                         changed_p = true;
    1970             : 
    1971             :                                 /* Update counter */
    1972           0 :                                 end_count++;
    1973             :                         } else {
    1974             : 
    1975           0 :                                 if (CHECK_FLAG(nhlfe->flags,
    1976             :                                                NHLFE_FLAG_INSTALLED))
    1977           0 :                                         changed_p = true;
    1978             :                         }
    1979             : 
    1980             :                 } else {
    1981             :                         /* Not mentioned in lfib set -> uninstalled */
    1982           0 :                         if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
    1983           0 :                             CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
    1984             :                             CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
    1985           0 :                                 changed_p = true;
    1986             :                         }
    1987             : 
    1988           0 :                         if (is_debug)
    1989           0 :                                 zlog_debug("LSP dplane notif: no match, nh %s",
    1990             :                                            buf);
    1991             :                 }
    1992             :         }
    1993             : 
    1994           0 :         if (start_counter)
    1995           0 :                 *start_counter += start_count;
    1996           0 :         if (end_counter)
    1997           0 :                 *end_counter += end_count;
    1998             : 
    1999           0 :         return changed_p;
    2000             : }
    2001             : 
    2002             : /*
    2003             :  * Update an lsp nhlfe list from a dplane context, typically an async
    2004             :  * notification context. Update the LSP list to match the installed
    2005             :  * status from the context's list.
    2006             :  */
    2007           0 : static int update_nhlfes_from_ctx(struct nhlfe_list_head *nhlfe_head,
    2008             :                                   const struct nhlfe_list_head *ctx_head)
    2009             : {
    2010           0 :         int ret = 0;
    2011           0 :         struct zebra_nhlfe *nhlfe;
    2012           0 :         const struct zebra_nhlfe *ctx_nhlfe;
    2013           0 :         struct nexthop *nexthop;
    2014           0 :         const struct nexthop *ctx_nexthop;
    2015           0 :         bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
    2016             : 
    2017           0 :         frr_each_safe(nhlfe_list, nhlfe_head, nhlfe) {
    2018           0 :                 char buf[NEXTHOP_STRLEN];
    2019             : 
    2020           0 :                 nexthop = nhlfe->nexthop;
    2021           0 :                 if (!nexthop)
    2022           0 :                         continue;
    2023             : 
    2024           0 :                 ctx_nhlfe = NULL;
    2025           0 :                 ctx_nexthop = NULL;
    2026           0 :                 frr_each(nhlfe_list_const, ctx_head, ctx_nhlfe) {
    2027           0 :                         ctx_nexthop = ctx_nhlfe->nexthop;
    2028           0 :                         if (!ctx_nexthop)
    2029           0 :                                 continue;
    2030             : 
    2031           0 :                         if ((ctx_nexthop->type == nexthop->type) &&
    2032           0 :                             nexthop_same(ctx_nexthop, nexthop)) {
    2033             :                                 /* Matched */
    2034             :                                 break;
    2035             :                         }
    2036             :                 }
    2037             : 
    2038           0 :                 if (is_debug)
    2039           0 :                         nexthop2str(nexthop, buf, sizeof(buf));
    2040             : 
    2041           0 :                 if (ctx_nhlfe && ctx_nexthop) {
    2042             : 
    2043             :                         /* Bring zebra nhlfe install state into sync */
    2044           0 :                         if (CHECK_FLAG(ctx_nhlfe->flags,
    2045             :                                        NHLFE_FLAG_INSTALLED)) {
    2046           0 :                                 if (is_debug)
    2047           0 :                                         zlog_debug("%s: matched lsp nhlfe %s (installed)",
    2048             :                                                    __func__, buf);
    2049             : 
    2050           0 :                                 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
    2051           0 :                                 SET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
    2052             : 
    2053             :                         } else {
    2054           0 :                                 if (is_debug)
    2055           0 :                                         zlog_debug("%s: matched lsp nhlfe %s (not installed)",
    2056             :                                                    __func__, buf);
    2057             : 
    2058           0 :                                 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
    2059           0 :                                 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
    2060             :                         }
    2061             : 
    2062           0 :                         if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
    2063             :                                        NEXTHOP_FLAG_FIB)) {
    2064           0 :                                 SET_FLAG(nhlfe->nexthop->flags,
    2065             :                                          NEXTHOP_FLAG_ACTIVE);
    2066           0 :                                 SET_FLAG(nhlfe->nexthop->flags,
    2067             :                                          NEXTHOP_FLAG_FIB);
    2068             :                         } else {
    2069           0 :                                 UNSET_FLAG(nhlfe->nexthop->flags,
    2070             :                                          NEXTHOP_FLAG_ACTIVE);
    2071           0 :                                 UNSET_FLAG(nhlfe->nexthop->flags,
    2072             :                                            NEXTHOP_FLAG_FIB);
    2073             :                         }
    2074             : 
    2075             :                 } else {
    2076             :                         /* Not mentioned in lfib set -> uninstalled */
    2077           0 :                         if (is_debug)
    2078           0 :                                 zlog_debug("%s: no match for lsp nhlfe %s",
    2079             :                                            __func__, buf);
    2080           0 :                         UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
    2081           0 :                         UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED);
    2082           0 :                         UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
    2083           0 :                         UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
    2084             :                 }
    2085             :         }
    2086             : 
    2087           0 :         return ret;
    2088             : }
    2089             : 
    2090             : /*
    2091             :  * Process async dplane notifications.
    2092             :  */
    2093           0 : void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
    2094             : {
    2095           0 :         struct zebra_vrf *zvrf;
    2096           0 :         struct zebra_ile tmp_ile;
    2097           0 :         struct hash *lsp_table;
    2098           0 :         struct zebra_lsp *lsp;
    2099           0 :         const struct nhlfe_list_head *ctx_list;
    2100           0 :         int start_count = 0, end_count = 0; /* Installed counts */
    2101           0 :         bool changed_p = false;
    2102           0 :         bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
    2103           0 :         enum zebra_sr_policy_update_label_mode update_mode;
    2104             : 
    2105           0 :         if (is_debug)
    2106           0 :                 zlog_debug("LSP dplane notif, in-label %u",
    2107             :                            dplane_ctx_get_in_label(ctx));
    2108             : 
    2109             :         /* Look for zebra LSP object */
    2110           0 :         zvrf = vrf_info_lookup(VRF_DEFAULT);
    2111           0 :         if (zvrf == NULL)
    2112           0 :                 return;
    2113             : 
    2114           0 :         lsp_table = zvrf->lsp_table;
    2115             : 
    2116           0 :         tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
    2117           0 :         lsp = hash_lookup(lsp_table, &tmp_ile);
    2118           0 :         if (lsp == NULL) {
    2119           0 :                 if (is_debug)
    2120           0 :                         zlog_debug("dplane LSP notif: in-label %u not found",
    2121             :                                    dplane_ctx_get_in_label(ctx));
    2122           0 :                 return;
    2123             :         }
    2124             : 
    2125             :         /*
    2126             :          * The dataplane/forwarding plane is notifying zebra about the state
    2127             :          * of the nexthops associated with this LSP. First, we take a
    2128             :          * pre-scan pass to determine whether the LSP has transitioned
    2129             :          * from installed -> uninstalled. In that case, we need to have
    2130             :          * the existing state of the LSP objects available before making
    2131             :          * any changes.
    2132             :          */
    2133           0 :         ctx_list = dplane_ctx_get_nhlfe_list(ctx);
    2134             : 
    2135           0 :         changed_p = compare_notif_nhlfes(ctx_list, &lsp->nhlfe_list,
    2136             :                                          &start_count, &end_count);
    2137             : 
    2138           0 :         if (is_debug)
    2139           0 :                 zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
    2140             :                            start_count, end_count,
    2141             :                            changed_p ? ", changed" : "");
    2142             : 
    2143           0 :         ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
    2144             : 
    2145           0 :         if (compare_notif_nhlfes(ctx_list, &lsp->backup_nhlfe_list,
    2146             :                                  &start_count, &end_count))
    2147             :                 /* Avoid accidentally setting back to 'false' */
    2148           0 :                 changed_p = true;
    2149             : 
    2150           0 :         if (is_debug)
    2151           0 :                 zlog_debug("LSP dplane notif: lfib backups, start_count %d, end_count %d%s",
    2152             :                            start_count, end_count,
    2153             :                            changed_p ? ", changed" : "");
    2154             : 
    2155             :         /*
    2156             :          * Has the LSP become uninstalled? We need the existing state of the
    2157             :          * nexthops/nhlfes at this point so we know what to delete.
    2158             :          */
    2159           0 :         if (start_count > 0 && end_count == 0) {
    2160             :                 /* Inform other lfibs */
    2161           0 :                 dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
    2162             :         }
    2163             : 
    2164             :         /*
    2165             :          * Now we take a second pass and bring the zebra
    2166             :          * nexthop state into sync with the forwarding-plane state.
    2167             :          */
    2168           0 :         ctx_list = dplane_ctx_get_nhlfe_list(ctx);
    2169           0 :         update_nhlfes_from_ctx(&lsp->nhlfe_list, ctx_list);
    2170             : 
    2171           0 :         ctx_list = dplane_ctx_get_backup_nhlfe_list(ctx);
    2172           0 :         update_nhlfes_from_ctx(&lsp->backup_nhlfe_list, ctx_list);
    2173             : 
    2174           0 :         if (end_count > 0) {
    2175           0 :                 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
    2176             : 
    2177             :                 /* SR-TE update too */
    2178           0 :                 if (start_count == 0)
    2179             :                         update_mode = ZEBRA_SR_POLICY_LABEL_CREATED;
    2180             :                 else
    2181           0 :                         update_mode = ZEBRA_SR_POLICY_LABEL_UPDATED;
    2182           0 :                 zebra_sr_policy_label_update(lsp->ile.in_label, update_mode);
    2183             : 
    2184           0 :                 if (changed_p)
    2185           0 :                         dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
    2186             : 
    2187             :         } else {
    2188             :                 /* SR-TE update too */
    2189           0 :                 zebra_sr_policy_label_update(lsp->ile.in_label,
    2190             :                                              ZEBRA_SR_POLICY_LABEL_REMOVED);
    2191             : 
    2192           0 :                 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
    2193           0 :                 clear_nhlfe_installed(lsp);
    2194             :         }
    2195             : }
    2196             : 
    2197             : /*
    2198             :  * Install dynamic LSP entry.
    2199             :  */
    2200           0 : int zebra_mpls_lsp_install(struct zebra_vrf *zvrf, struct route_node *rn,
    2201             :                            struct route_entry *re)
    2202             : {
    2203           0 :         struct route_table *table;
    2204           0 :         struct zebra_fec *fec;
    2205             : 
    2206           0 :         table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
    2207           0 :         if (!table)
    2208             :                 return -1;
    2209             : 
    2210             :         /* See if there is a configured label binding for this FEC. */
    2211           0 :         fec = fec_find(table, &rn->p);
    2212           0 :         if (!fec || fec->label == MPLS_INVALID_LABEL)
    2213             :                 return 0;
    2214             : 
    2215             :         /* We cannot install a label forwarding entry if local label is the
    2216             :          * implicit-null label.
    2217             :          */
    2218           0 :         if (fec->label == MPLS_LABEL_IMPLICIT_NULL)
    2219             :                 return 0;
    2220             : 
    2221           0 :         if (lsp_install(zvrf, fec->label, rn, re))
    2222             :                 return -1;
    2223             : 
    2224             :         return 0;
    2225             : }
    2226             : 
    2227             : /*
    2228             :  * Uninstall dynamic LSP entry, if any.
    2229             :  */
    2230           0 : int zebra_mpls_lsp_uninstall(struct zebra_vrf *zvrf, struct route_node *rn,
    2231             :                              struct route_entry *re)
    2232             : {
    2233           0 :         struct route_table *table;
    2234           0 :         struct zebra_fec *fec;
    2235             : 
    2236           0 :         table = zvrf->fec_table[family2afi(PREFIX_FAMILY(&rn->p))];
    2237           0 :         if (!table)
    2238             :                 return -1;
    2239             : 
    2240             :         /* See if there is a configured label binding for this FEC. */
    2241           0 :         fec = fec_find(table, &rn->p);
    2242           0 :         if (!fec || fec->label == MPLS_INVALID_LABEL)
    2243             :                 return 0;
    2244             : 
    2245             :         /* Uninstall always removes all dynamic NHLFEs. */
    2246           0 :         return lsp_uninstall(zvrf, fec->label);
    2247             : }
    2248             : 
    2249             : /*
    2250             :  * Add an NHLFE to an LSP, return the newly-added object. This path only changes
    2251             :  * the LSP object - nothing is scheduled for processing, for example.
    2252             :  */
    2253             : struct zebra_nhlfe *
    2254           0 : zebra_mpls_lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
    2255             :                          enum nexthop_types_t gtype, const union g_addr *gate,
    2256             :                          ifindex_t ifindex, uint8_t num_labels,
    2257             :                          const mpls_label_t *out_labels)
    2258             : {
    2259             :         /* Just a public pass-through to the internal implementation */
    2260           0 :         return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
    2261             :                          out_labels, false /*backup*/);
    2262             : }
    2263             : 
    2264             : /*
    2265             :  * Add a backup NHLFE to an LSP, return the newly-added object.
    2266             :  * This path only changes the LSP object - nothing is scheduled for
    2267             :  * processing, for example.
    2268             :  */
    2269           0 : struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nhlfe(
    2270             :         struct zebra_lsp *lsp, enum lsp_types_t lsp_type,
    2271             :         enum nexthop_types_t gtype, const union g_addr *gate, ifindex_t ifindex,
    2272             :         uint8_t num_labels, const mpls_label_t *out_labels)
    2273             : {
    2274             :         /* Just a public pass-through to the internal implementation */
    2275           0 :         return nhlfe_add(lsp, lsp_type, gtype, gate, ifindex, num_labels,
    2276             :                          out_labels, true);
    2277             : }
    2278             : 
    2279             : /*
    2280             :  * Add an NHLFE to an LSP based on a nexthop; return the newly-added object
    2281             :  */
    2282           0 : struct zebra_nhlfe *zebra_mpls_lsp_add_nh(struct zebra_lsp *lsp,
    2283             :                                           enum lsp_types_t lsp_type,
    2284             :                                           const struct nexthop *nh)
    2285             : {
    2286           0 :         struct zebra_nhlfe *nhlfe;
    2287             : 
    2288           0 :         if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
    2289             :                 return NULL;
    2290             : 
    2291           0 :         nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate, nh->ifindex,
    2292           0 :                           nh->nh_label->num_labels, nh->nh_label->label,
    2293             :                           false /*backup*/);
    2294             : 
    2295           0 :         return nhlfe;
    2296             : }
    2297             : 
    2298             : /*
    2299             :  * Add a backup NHLFE to an LSP based on a nexthop;
    2300             :  * return the newly-added object.
    2301             :  */
    2302           0 : struct zebra_nhlfe *zebra_mpls_lsp_add_backup_nh(struct zebra_lsp *lsp,
    2303             :                                                  enum lsp_types_t lsp_type,
    2304             :                                                  const struct nexthop *nh)
    2305             : {
    2306           0 :         struct zebra_nhlfe *nhlfe;
    2307             : 
    2308           0 :         if (nh->nh_label == NULL || nh->nh_label->num_labels == 0)
    2309             :                 return NULL;
    2310             : 
    2311           0 :         nhlfe = nhlfe_add(lsp, lsp_type, nh->type, &nh->gate,
    2312           0 :                                  nh->ifindex, nh->nh_label->num_labels,
    2313           0 :                                  nh->nh_label->label, true);
    2314             : 
    2315           0 :         return nhlfe;
    2316             : }
    2317             : 
    2318             : /*
    2319             :  * Free an allocated NHLFE
    2320             :  */
    2321           0 : void zebra_mpls_nhlfe_free(struct zebra_nhlfe *nhlfe)
    2322             : {
    2323             :         /* Just a pass-through to the internal implementation */
    2324           0 :         nhlfe_free(nhlfe);
    2325           0 : }
    2326             : 
    2327             : /*
    2328             :  * Registration from a client for the label binding for a FEC. If a binding
    2329             :  * already exists, it is informed to the client.
    2330             :  * NOTE: If there is a manually configured label binding, that is used.
    2331             :  * Otherwise, if a label index is specified, it means we have to allocate the
    2332             :  * label from a locally configured label block (SRGB), if one exists and index
    2333             :  * is acceptable. If no label index then just register the specified label.
    2334             :  * NOTE2: Either label or label_index is expected to be set to MPLS_INVALID_*
    2335             :  * by the calling function. Register requests with both will be rejected.
    2336             :  */
    2337           0 : int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
    2338             :                             uint32_t label, uint32_t label_index,
    2339             :                             struct zserv *client)
    2340             : {
    2341           0 :         struct route_table *table;
    2342           0 :         struct zebra_fec *fec;
    2343           0 :         bool new_client;
    2344           0 :         bool label_change = false;
    2345           0 :         uint32_t old_label;
    2346           0 :         bool have_label_index = (label_index != MPLS_INVALID_LABEL_INDEX);
    2347           0 :         bool is_configured_fec = false; /* indicate statically configured FEC */
    2348             : 
    2349           0 :         table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
    2350           0 :         if (!table)
    2351             :                 return -1;
    2352             : 
    2353           0 :         if (label != MPLS_INVALID_LABEL && have_label_index) {
    2354           0 :                 flog_err(
    2355             :                         EC_ZEBRA_FEC_LABEL_INDEX_LABEL_CONFLICT,
    2356             :                         "Rejecting FEC register for %pFX with both label %u and Label Index %u specified, client %s",
    2357             :                         p, label, label_index,
    2358             :                         zebra_route_string(client->proto));
    2359           0 :                 return -1;
    2360             :         }
    2361             : 
    2362             :         /* Locate FEC */
    2363           0 :         fec = fec_find(table, p);
    2364           0 :         if (!fec) {
    2365           0 :                 fec = fec_add(table, p, label, 0, label_index);
    2366           0 :                 if (!fec) {
    2367           0 :                         flog_err(
    2368             :                                 EC_ZEBRA_FEC_ADD_FAILED,
    2369             :                                 "Failed to add FEC %pFX upon register, client %s",
    2370             :                                 p, zebra_route_string(client->proto));
    2371           0 :                         return -1;
    2372             :                 }
    2373             : 
    2374             :                 old_label = MPLS_INVALID_LABEL;
    2375             :                 new_client = true;
    2376             :         } else {
    2377             :                 /* Check if the FEC has been statically defined in the config */
    2378           0 :                 is_configured_fec = fec->flags & FEC_FLAG_CONFIGURED;
    2379             :                 /* Client may register same FEC with different label index. */
    2380           0 :                 new_client =
    2381           0 :                         (listnode_lookup(fec->client_list, client) == NULL);
    2382           0 :                 if (!new_client && fec->label_index == label_index
    2383           0 :                     && fec->label == label)
    2384             :                         /* Duplicate register */
    2385             :                         return 0;
    2386             : 
    2387             :                 /* Save current label, update the FEC */
    2388           0 :                 old_label = fec->label;
    2389           0 :                 fec->label_index = label_index;
    2390             :         }
    2391             : 
    2392           0 :         if (new_client)
    2393           0 :                 listnode_add(fec->client_list, client);
    2394             : 
    2395           0 :         if (IS_ZEBRA_DEBUG_MPLS)
    2396           0 :                 zlog_debug("FEC %pFX label%s %u %s by client %s%s", p,
    2397             :                            have_label_index ? " index" : "",
    2398             :                            have_label_index ? label_index : label,
    2399             :                            new_client ? "registered" : "updated",
    2400             :                            zebra_route_string(client->proto),
    2401             :                            is_configured_fec
    2402             :                                    ? ", but using statically configured label"
    2403             :                                    : "");
    2404             : 
    2405             :         /* If not a statically configured FEC, derive the local label
    2406             :          * from label index or use the provided label
    2407             :          */
    2408           0 :         if (!is_configured_fec) {
    2409           0 :                 if (have_label_index)
    2410           0 :                         fec_derive_label_from_index(zvrf, fec);
    2411             :                 else
    2412           0 :                         fec->label = label;
    2413             : 
    2414             :                 /* If no label change, exit. */
    2415           0 :                 if (fec->label == old_label)
    2416             :                         return 0;
    2417             : 
    2418             :                 label_change = true;
    2419             :         }
    2420             : 
    2421             :         /* If new client or label change, update client and install or uninstall
    2422             :          * label forwarding entry as needed.
    2423             :          */
    2424             :         /* Inform client of label, if needed. */
    2425           0 :         if ((new_client && fec->label != MPLS_INVALID_LABEL) || label_change) {
    2426           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    2427           0 :                         zlog_debug("Update client label %u", fec->label);
    2428           0 :                 fec_send(fec, client);
    2429             :         }
    2430             : 
    2431           0 :         if (new_client || label_change)
    2432           0 :                 return fec_change_update_lsp(zvrf, fec, old_label);
    2433             : 
    2434             :         return 0;
    2435             : }
    2436             : 
    2437             : /*
    2438             :  * Deregistration from a client for the label binding for a FEC. The FEC
    2439             :  * itself is deleted if no other registered clients exist and there is no
    2440             :  * label bound to the FEC.
    2441             :  */
    2442           0 : int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
    2443             :                               struct zserv *client)
    2444             : {
    2445           0 :         struct route_table *table;
    2446           0 :         struct zebra_fec *fec;
    2447             : 
    2448           0 :         table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
    2449           0 :         if (!table)
    2450             :                 return -1;
    2451             : 
    2452           0 :         fec = fec_find(table, p);
    2453           0 :         if (!fec) {
    2454           0 :                 flog_err(EC_ZEBRA_FEC_RM_FAILED,
    2455             :                          "Failed to find FEC %pFX upon unregister, client %s",
    2456             :                          p, zebra_route_string(client->proto));
    2457           0 :                 return -1;
    2458             :         }
    2459             : 
    2460           0 :         listnode_delete(fec->client_list, client);
    2461             : 
    2462           0 :         if (IS_ZEBRA_DEBUG_MPLS)
    2463           0 :                 zlog_debug("FEC %pFX unregistered by client %s", p,
    2464             :                            zebra_route_string(client->proto));
    2465             : 
    2466             :         /* If not a configured entry, delete the FEC if no other clients. Before
    2467             :          * deleting, see if any LSP needs to be uninstalled.
    2468             :          */
    2469           0 :         if (!(fec->flags & FEC_FLAG_CONFIGURED)
    2470           0 :             && list_isempty(fec->client_list)) {
    2471           0 :                 mpls_label_t old_label = fec->label;
    2472           0 :                 fec->label = MPLS_INVALID_LABEL; /* reset */
    2473           0 :                 fec_change_update_lsp(zvrf, fec, old_label);
    2474           0 :                 fec_del(fec);
    2475             :         }
    2476             : 
    2477             :         return 0;
    2478             : }
    2479             : 
    2480             : /*
    2481             :  * Cleanup any FECs registered by this client.
    2482             :  */
    2483           0 : static int zebra_mpls_cleanup_fecs_for_client(struct zserv *client)
    2484             : {
    2485           0 :         struct zebra_vrf *zvrf = vrf_info_lookup(VRF_DEFAULT);
    2486           0 :         struct route_node *rn;
    2487           0 :         struct zebra_fec *fec;
    2488           0 :         struct listnode *node;
    2489           0 :         struct zserv *fec_client;
    2490           0 :         int af;
    2491             : 
    2492           0 :         for (af = AFI_IP; af < AFI_MAX; af++) {
    2493           0 :                 if (zvrf->fec_table[af] == NULL)
    2494           0 :                         continue;
    2495             : 
    2496           0 :                 for (rn = route_top(zvrf->fec_table[af]); rn;
    2497           0 :                      rn = route_next(rn)) {
    2498           0 :                         fec = rn->info;
    2499           0 :                         if (!fec || list_isempty(fec->client_list))
    2500           0 :                                 continue;
    2501             : 
    2502           0 :                         for (ALL_LIST_ELEMENTS_RO(fec->client_list, node,
    2503             :                                                   fec_client)) {
    2504           0 :                                 if (fec_client == client) {
    2505           0 :                                         listnode_delete(fec->client_list,
    2506             :                                                         fec_client);
    2507           0 :                                         if (!(fec->flags & FEC_FLAG_CONFIGURED)
    2508           0 :                                             && list_isempty(fec->client_list))
    2509           0 :                                                 fec_del(fec);
    2510             :                                         break;
    2511             :                                 }
    2512             :                         }
    2513             :                 }
    2514             :         }
    2515             : 
    2516           0 :         return 0;
    2517             : }
    2518             : 
    2519             : struct lsp_uninstall_args {
    2520             :         struct hash *lsp_table;
    2521             :         enum lsp_types_t type;
    2522             : };
    2523             : 
    2524             : /*
    2525             :  * Cleanup MPLS labels registered by this client.
    2526             :  */
    2527           0 : static int zebra_mpls_cleanup_zclient_labels(struct zserv *client)
    2528             : {
    2529           0 :         struct vrf *vrf;
    2530           0 :         struct zebra_vrf *zvrf;
    2531             : 
    2532           0 :         RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
    2533           0 :                 struct lsp_uninstall_args args;
    2534             : 
    2535           0 :                 zvrf = vrf->info;
    2536           0 :                 if (!zvrf)
    2537           0 :                         continue;
    2538             : 
    2539             :                 /* Cleanup LSPs. */
    2540           0 :                 args.lsp_table = zvrf->lsp_table;
    2541           0 :                 args.type = lsp_type_from_re_type(client->proto);
    2542           0 :                 hash_iterate(zvrf->lsp_table, mpls_lsp_uninstall_all_type,
    2543             :                              &args);
    2544             : 
    2545             :                 /* Cleanup FTNs. */
    2546           0 :                 mpls_ftn_uninstall_all(zvrf, AFI_IP,
    2547           0 :                                        lsp_type_from_re_type(client->proto));
    2548           0 :                 mpls_ftn_uninstall_all(zvrf, AFI_IP6,
    2549           0 :                                        lsp_type_from_re_type(client->proto));
    2550             :         }
    2551             : 
    2552           0 :         return 0;
    2553             : }
    2554             : 
    2555             : /*
    2556             :  * Return FEC (if any) to which this label is bound.
    2557             :  * Note: Only works for per-prefix binding and when the label is not
    2558             :  * implicit-null.
    2559             :  * TODO: Currently walks entire table, can optimize later with another
    2560             :  * hash..
    2561             :  */
    2562           0 : struct zebra_fec *zebra_mpls_fec_for_label(struct zebra_vrf *zvrf,
    2563             :                                            mpls_label_t label)
    2564             : {
    2565           0 :         struct route_node *rn;
    2566           0 :         struct zebra_fec *fec;
    2567           0 :         int af;
    2568             : 
    2569           0 :         for (af = AFI_IP; af < AFI_MAX; af++) {
    2570           0 :                 if (zvrf->fec_table[af] == NULL)
    2571           0 :                         continue;
    2572             : 
    2573           0 :                 for (rn = route_top(zvrf->fec_table[af]); rn;
    2574           0 :                      rn = route_next(rn)) {
    2575           0 :                         if (!rn->info)
    2576           0 :                                 continue;
    2577           0 :                         fec = rn->info;
    2578           0 :                         if (fec->label == label)
    2579           0 :                                 return fec;
    2580             :                 }
    2581             :         }
    2582             : 
    2583             :         return NULL;
    2584             : }
    2585             : 
    2586             : /*
    2587             :  * Inform if specified label is currently bound to a FEC or not.
    2588             :  */
    2589           0 : int zebra_mpls_label_already_bound(struct zebra_vrf *zvrf, mpls_label_t label)
    2590             : {
    2591           0 :         return (zebra_mpls_fec_for_label(zvrf, label) ? 1 : 0);
    2592             : }
    2593             : 
    2594             : /*
    2595             :  * Add static FEC to label binding. If there are clients registered for this
    2596             :  * FEC, notify them. If there are labeled routes for this FEC, install the
    2597             :  * label forwarding entry.
    2598             : */
    2599           0 : int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
    2600             :                               mpls_label_t in_label)
    2601             : {
    2602           0 :         struct route_table *table;
    2603           0 :         struct zebra_fec *fec;
    2604           0 :         mpls_label_t old_label;
    2605           0 :         int ret = 0;
    2606             : 
    2607           0 :         table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
    2608           0 :         if (!table)
    2609             :                 return -1;
    2610             : 
    2611             :         /* Update existing FEC or create a new one. */
    2612           0 :         fec = fec_find(table, p);
    2613           0 :         if (!fec) {
    2614           0 :                 fec = fec_add(table, p, in_label, FEC_FLAG_CONFIGURED,
    2615             :                               MPLS_INVALID_LABEL_INDEX);
    2616           0 :                 if (!fec) {
    2617           0 :                         flog_err(EC_ZEBRA_FEC_ADD_FAILED,
    2618             :                                  "Failed to add FEC %pFX upon config", p);
    2619           0 :                         return -1;
    2620             :                 }
    2621             : 
    2622           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    2623           0 :                         zlog_debug("Add fec %pFX label %u", p, in_label);
    2624             :         } else {
    2625           0 :                 fec->flags |= FEC_FLAG_CONFIGURED;
    2626           0 :                 if (fec->label == in_label)
    2627             :                         /* Duplicate config */
    2628             :                         return 0;
    2629             : 
    2630             :                 /* Label change, update clients. */
    2631           0 :                 old_label = fec->label;
    2632           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    2633           0 :                         zlog_debug("Update fec %pFX new label %u", p, in_label);
    2634             : 
    2635           0 :                 fec->label = in_label;
    2636           0 :                 fec_update_clients(fec);
    2637             : 
    2638             :                 /* Update label forwarding entries appropriately */
    2639           0 :                 ret = fec_change_update_lsp(zvrf, fec, old_label);
    2640             :         }
    2641             : 
    2642             :         return ret;
    2643             : }
    2644             : 
    2645             : /*
    2646             :  * Remove static FEC to label binding. If there are no clients registered
    2647             :  * for this FEC, delete the FEC; else notify clients
    2648             :  * Note: Upon delete of static binding, if label index exists for this FEC,
    2649             :  * client may need to be updated with derived label.
    2650             :  */
    2651           0 : int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
    2652             : {
    2653           0 :         struct route_table *table;
    2654           0 :         struct zebra_fec *fec;
    2655           0 :         mpls_label_t old_label;
    2656             : 
    2657           0 :         table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
    2658           0 :         if (!table)
    2659             :                 return -1;
    2660             : 
    2661           0 :         fec = fec_find(table, p);
    2662           0 :         if (!fec) {
    2663           0 :                 flog_err(EC_ZEBRA_FEC_RM_FAILED,
    2664             :                          "Failed to find FEC %pFX upon delete", p);
    2665           0 :                 return -1;
    2666             :         }
    2667             : 
    2668           0 :         if (IS_ZEBRA_DEBUG_MPLS) {
    2669           0 :                 zlog_debug("Delete fec %pFX label %u label index %u", p,
    2670             :                            fec->label, fec->label_index);
    2671             :         }
    2672             : 
    2673           0 :         old_label = fec->label;
    2674           0 :         fec->flags &= ~FEC_FLAG_CONFIGURED;
    2675           0 :         fec->label = MPLS_INVALID_LABEL;
    2676             : 
    2677             :         /* If no client exists, just delete the FEC. */
    2678           0 :         if (list_isempty(fec->client_list)) {
    2679           0 :                 fec_del(fec);
    2680           0 :                 return 0;
    2681             :         }
    2682             : 
    2683             :         /* Derive the local label (from label index) or reset it. */
    2684           0 :         fec_derive_label_from_index(zvrf, fec);
    2685             : 
    2686             :         /* If there is a label change, update clients. */
    2687           0 :         if (fec->label == old_label)
    2688             :                 return 0;
    2689           0 :         fec_update_clients(fec);
    2690             : 
    2691             :         /* Update label forwarding entries appropriately */
    2692           0 :         return fec_change_update_lsp(zvrf, fec, old_label);
    2693             : }
    2694             : 
    2695             : /*
    2696             :  * Display MPLS FEC to label binding configuration (VTY command handler).
    2697             :  */
    2698           0 : int zebra_mpls_write_fec_config(struct vty *vty, struct zebra_vrf *zvrf)
    2699             : {
    2700           0 :         struct route_node *rn;
    2701           0 :         int af;
    2702           0 :         struct zebra_fec *fec;
    2703           0 :         int write = 0;
    2704             : 
    2705           0 :         for (af = AFI_IP; af < AFI_MAX; af++) {
    2706           0 :                 if (zvrf->fec_table[af] == NULL)
    2707           0 :                         continue;
    2708             : 
    2709           0 :                 for (rn = route_top(zvrf->fec_table[af]); rn;
    2710           0 :                      rn = route_next(rn)) {
    2711           0 :                         if (!rn->info)
    2712           0 :                                 continue;
    2713             : 
    2714           0 :                         char lstr[BUFSIZ];
    2715           0 :                         fec = rn->info;
    2716             : 
    2717           0 :                         if (!(fec->flags & FEC_FLAG_CONFIGURED))
    2718           0 :                                 continue;
    2719             : 
    2720           0 :                         write = 1;
    2721           0 :                         vty_out(vty, "mpls label bind %pFX %s\n", &rn->p,
    2722             :                                 label2str(fec->label, lstr, BUFSIZ));
    2723             :                 }
    2724             :         }
    2725             : 
    2726           0 :         return write;
    2727             : }
    2728             : 
    2729             : /*
    2730             :  * Display MPLS FEC to label binding (VTY command handler).
    2731             :  */
    2732           0 : void zebra_mpls_print_fec_table(struct vty *vty, struct zebra_vrf *zvrf)
    2733             : {
    2734           0 :         struct route_node *rn;
    2735           0 :         int af;
    2736             : 
    2737           0 :         for (af = AFI_IP; af < AFI_MAX; af++) {
    2738           0 :                 if (zvrf->fec_table[af] == NULL)
    2739           0 :                         continue;
    2740             : 
    2741           0 :                 for (rn = route_top(zvrf->fec_table[af]); rn;
    2742           0 :                      rn = route_next(rn)) {
    2743           0 :                         if (!rn->info)
    2744           0 :                                 continue;
    2745           0 :                         fec_print(rn->info, vty);
    2746             :                 }
    2747             :         }
    2748           0 : }
    2749             : 
    2750             : /*
    2751             :  * Display MPLS FEC to label binding for a specific FEC (VTY command handler).
    2752             :  */
    2753           0 : void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
    2754             :                           struct prefix *p)
    2755             : {
    2756           0 :         struct route_table *table;
    2757           0 :         struct route_node *rn;
    2758             : 
    2759           0 :         table = zvrf->fec_table[family2afi(PREFIX_FAMILY(p))];
    2760           0 :         if (!table)
    2761             :                 return;
    2762             : 
    2763           0 :         apply_mask(p);
    2764           0 :         rn = route_node_lookup(table, p);
    2765           0 :         if (!rn)
    2766             :                 return;
    2767             : 
    2768           0 :         route_unlock_node(rn);
    2769           0 :         if (!rn->info)
    2770             :                 return;
    2771             : 
    2772           0 :         fec_print(rn->info, vty);
    2773             : }
    2774             : 
    2775           0 : static void mpls_zebra_nhe_update(struct route_entry *re, afi_t afi,
    2776             :                                   struct nhg_hash_entry *new_nhe)
    2777             : {
    2778           0 :         struct nhg_hash_entry *nhe;
    2779             : 
    2780           0 :         nhe = zebra_nhg_rib_find_nhe(new_nhe, afi);
    2781             : 
    2782           0 :         route_entry_update_nhe(re, nhe);
    2783           0 : }
    2784             : 
    2785           0 : static bool ftn_update_nexthop(bool add_p, struct nexthop *nexthop,
    2786             :                                enum lsp_types_t type,
    2787             :                                const struct zapi_nexthop *znh)
    2788             : {
    2789           0 :         if (add_p && nexthop->nh_label_type == ZEBRA_LSP_NONE)
    2790           0 :                 nexthop_add_labels(nexthop, type, znh->label_num, znh->labels);
    2791           0 :         else if (!add_p && nexthop->nh_label_type == type)
    2792           0 :                 nexthop_del_labels(nexthop);
    2793             :         else
    2794             :                 return false;
    2795             : 
    2796             :         return true;
    2797             : }
    2798             : 
    2799           0 : void zebra_mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
    2800             :                               struct prefix *prefix, uint8_t route_type,
    2801             :                               uint8_t route_instance)
    2802             : {
    2803           0 :         struct route_table *table;
    2804           0 :         struct route_node *rn;
    2805           0 :         struct route_entry *re;
    2806           0 :         struct nexthop *nexthop;
    2807           0 :         struct nhg_hash_entry *new_nhe;
    2808           0 :         afi_t afi = family2afi(prefix->family);
    2809             : 
    2810             :         /* Lookup table.  */
    2811           0 :         table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
    2812           0 :         if (!table)
    2813             :                 return;
    2814             : 
    2815             :         /* Lookup existing route */
    2816           0 :         rn = route_node_get(table, prefix);
    2817           0 :         RNODE_FOREACH_RE (rn, re) {
    2818           0 :                 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
    2819           0 :                         continue;
    2820           0 :                 if (re->type == route_type && re->instance == route_instance)
    2821             :                         break;
    2822             :         }
    2823           0 :         if (re == NULL)
    2824             :                 return;
    2825             : 
    2826             :         /*
    2827             :          * Nexthops are now shared by multiple routes, so we have to make
    2828             :          * a local copy, modify the copy, then update the route.
    2829             :          */
    2830           0 :         new_nhe = zebra_nhe_copy(re->nhe, 0);
    2831             : 
    2832           0 :         for (nexthop = new_nhe->nhg.nexthop; nexthop; nexthop = nexthop->next)
    2833           0 :                 nexthop_del_labels(nexthop);
    2834             : 
    2835             :         /* Update backup routes/nexthops also, if present. */
    2836           0 :         if (zebra_nhg_get_backup_nhg(new_nhe) != NULL) {
    2837           0 :                 for (nexthop = new_nhe->backup_info->nhe->nhg.nexthop; nexthop;
    2838           0 :                      nexthop = nexthop->next)
    2839           0 :                         nexthop_del_labels(nexthop);
    2840             :         }
    2841             : 
    2842           0 :         SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
    2843           0 :         SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
    2844             : 
    2845             :         /* This will create (or ref) a new nhe, so we will discard the local
    2846             :          * temporary nhe
    2847             :          */
    2848           0 :         mpls_zebra_nhe_update(re, afi, new_nhe);
    2849             : 
    2850           0 :         zebra_nhg_free(new_nhe);
    2851             : 
    2852           0 :         rib_queue_add(rn);
    2853             : }
    2854             : 
    2855             : /*
    2856             :  * Iterate through a list of nexthops, for a match for 'znh'. If found,
    2857             :  * update its labels according to 'add_p', and return 'true' if successful.
    2858             :  */
    2859           0 : static bool ftn_update_znh(bool add_p, enum lsp_types_t type,
    2860             :                            struct nexthop *head, const struct zapi_nexthop *znh)
    2861             : {
    2862           0 :         bool found = false, success = false;
    2863           0 :         struct nexthop *nexthop;
    2864             : 
    2865           0 :         for (nexthop = head; nexthop; nexthop = nexthop->next) {
    2866           0 :                 switch (nexthop->type) {
    2867           0 :                 case NEXTHOP_TYPE_IPV4:
    2868             :                 case NEXTHOP_TYPE_IPV4_IFINDEX:
    2869           0 :                         if (znh->type != NEXTHOP_TYPE_IPV4
    2870           0 :                             && znh->type != NEXTHOP_TYPE_IPV4_IFINDEX)
    2871           0 :                                 continue;
    2872           0 :                         if (!IPV4_ADDR_SAME(&nexthop->gate.ipv4,
    2873             :                                             &znh->gate.ipv4))
    2874           0 :                                 continue;
    2875           0 :                         if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
    2876           0 :                             && nexthop->ifindex != znh->ifindex)
    2877           0 :                                 continue;
    2878             : 
    2879           0 :                         found = true;
    2880             : 
    2881           0 :                         if (!ftn_update_nexthop(add_p, nexthop, type, znh))
    2882             :                                 break;
    2883             : 
    2884             :                         success = true;
    2885             :                         break;
    2886           0 :                 case NEXTHOP_TYPE_IPV6:
    2887             :                 case NEXTHOP_TYPE_IPV6_IFINDEX:
    2888           0 :                         if (znh->type != NEXTHOP_TYPE_IPV6
    2889           0 :                             && znh->type != NEXTHOP_TYPE_IPV6_IFINDEX)
    2890           0 :                                 continue;
    2891           0 :                         if (!IPV6_ADDR_SAME(&nexthop->gate.ipv6,
    2892             :                                             &znh->gate.ipv6))
    2893           0 :                                 continue;
    2894           0 :                         if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX
    2895           0 :                             && nexthop->ifindex != znh->ifindex)
    2896           0 :                                 continue;
    2897             : 
    2898           0 :                         found = true;
    2899             : 
    2900           0 :                         if (!ftn_update_nexthop(add_p, nexthop, type, znh))
    2901             :                                 break;
    2902             :                         success = true;
    2903             :                         break;
    2904           0 :                 case NEXTHOP_TYPE_IFINDEX:
    2905           0 :                         if (znh->type != NEXTHOP_TYPE_IFINDEX)
    2906           0 :                                 continue;
    2907           0 :                         if (nexthop->ifindex != znh->ifindex)
    2908           0 :                                 continue;
    2909             : 
    2910           0 :                         found = true;
    2911             : 
    2912           0 :                         if (!ftn_update_nexthop(add_p, nexthop, type, znh))
    2913             :                                 break;
    2914             :                         success = true;
    2915             :                         break;
    2916           0 :                 case NEXTHOP_TYPE_BLACKHOLE:
    2917             :                         /* Not valid */
    2918           0 :                         continue;
    2919             :                 }
    2920             : 
    2921             :                 if (found)
    2922             :                         break;
    2923             :         }
    2924             : 
    2925           0 :         return success;
    2926             : }
    2927             : 
    2928             : /*
    2929             :  * Install/uninstall LSP and (optionally) FEC-To-NHLFE (FTN) bindings,
    2930             :  * using zapi message info.
    2931             :  * There are several changes that need to be made, in several zebra
    2932             :  * data structures, so we want to do all the work required at once.
    2933             :  */
    2934           0 : void zebra_mpls_zapi_labels_process(bool add_p, struct zebra_vrf *zvrf,
    2935             :                                     const struct zapi_labels *zl)
    2936             : {
    2937           0 :         int i, counter, ret = 0;
    2938           0 :         char buf[NEXTHOP_STRLEN];
    2939           0 :         const struct zapi_nexthop *znh;
    2940           0 :         struct route_table *table;
    2941           0 :         struct route_node *rn = NULL;
    2942           0 :         struct route_entry *re = NULL;
    2943           0 :         struct nhg_hash_entry *new_nhe = NULL;
    2944           0 :         bool found;
    2945           0 :         afi_t afi = AFI_IP;
    2946           0 :         const struct prefix *prefix = NULL;
    2947           0 :         struct hash *lsp_table;
    2948           0 :         struct zebra_ile tmp_ile;
    2949           0 :         struct zebra_lsp *lsp = NULL;
    2950             : 
    2951             :         /* Prep LSP for add case */
    2952           0 :         if (add_p) {
    2953             :                 /* Lookup table. */
    2954           0 :                 lsp_table = zvrf->lsp_table;
    2955           0 :                 if (!lsp_table)
    2956           0 :                         return;
    2957             : 
    2958             :                 /* Find or create LSP object */
    2959           0 :                 tmp_ile.in_label = zl->local_label;
    2960           0 :                 lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
    2961             :         }
    2962             : 
    2963             :         /* Prep for route/FEC update if requested */
    2964           0 :         if (CHECK_FLAG(zl->message, ZAPI_LABELS_FTN)) {
    2965           0 :                 prefix = &zl->route.prefix;
    2966             : 
    2967           0 :                 afi = family2afi(prefix->family);
    2968             : 
    2969             :                 /* Lookup table.  */
    2970           0 :                 table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
    2971           0 :                 if (table) {
    2972             :                         /* Lookup existing route */
    2973           0 :                         rn = route_node_get(table, prefix);
    2974           0 :                         RNODE_FOREACH_RE(rn, re) {
    2975           0 :                                 if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED))
    2976           0 :                                         continue;
    2977           0 :                                 if (re->type == zl->route.type &&
    2978           0 :                                     re->instance == zl->route.instance)
    2979             :                                         break;
    2980             :                         }
    2981             :                 }
    2982             : 
    2983           0 :                 if (re) {
    2984             :                         /*
    2985             :                          * Copy over current nexthops into a temporary group.
    2986             :                          * We can't just change the values here since the nhgs
    2987             :                          * are shared and if the labels change, we'll need
    2988             :                          * to find or create a new nhg. We need to create
    2989             :                          * a whole temporary group, make changes to it,
    2990             :                          * then attach that to the route.
    2991             :                          */
    2992           0 :                         new_nhe = zebra_nhe_copy(re->nhe, 0);
    2993             : 
    2994             :                 } else {
    2995             :                         /*
    2996             :                          * The old version of the zapi code
    2997             :                          * attempted to manage LSPs before trying to
    2998             :                          * find a route/FEC, so we'll continue that way.
    2999             :                          */
    3000           0 :                         if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS)
    3001           0 :                                 zlog_debug(
    3002             :                                         "%s: FTN update requested: no route for prefix %pFX",
    3003             :                                         __func__, prefix);
    3004             :                 }
    3005             :         }
    3006             : 
    3007             :         /*
    3008             :          * Use info from the zapi nexthops to add/replace/remove LSP/FECs
    3009             :          */
    3010             : 
    3011           0 :         counter = 0;
    3012           0 :         for (i = 0; i < zl->nexthop_num; i++) {
    3013             : 
    3014           0 :                 znh = &zl->nexthops[i];
    3015             : 
    3016             :                 /* Attempt LSP update */
    3017           0 :                 if (add_p)
    3018           0 :                         ret = lsp_znh_install(lsp, zl->type, znh);
    3019             :                 else
    3020           0 :                         ret = mpls_lsp_uninstall(zvrf, zl->type,
    3021           0 :                                                  zl->local_label, znh->type,
    3022           0 :                                                  &znh->gate, znh->ifindex,
    3023             :                                                  false);
    3024           0 :                 if (ret < 0) {
    3025           0 :                         if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_MPLS) {
    3026           0 :                                 zapi_nexthop2str(znh, buf, sizeof(buf));
    3027           0 :                                 zlog_debug("%s: Unable to %sinstall LSP: label %u, znh %s",
    3028             :                                            __func__, (add_p ? "" : "un"),
    3029             :                                            zl->local_label, buf);
    3030             :                         }
    3031           0 :                         continue;
    3032             :                 }
    3033             : 
    3034             :                 /* Attempt route/FEC update if requested */
    3035           0 :                 if (re == NULL)
    3036           0 :                         continue;
    3037             : 
    3038             :                 /* Search the route's nexthops for a match, and update it. */
    3039           0 :                 found = ftn_update_znh(add_p, zl->type, new_nhe->nhg.nexthop,
    3040             :                                        znh);
    3041           0 :                 if (found) {
    3042           0 :                         counter++;
    3043           0 :                 } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
    3044           0 :                         zapi_nexthop2str(znh, buf, sizeof(buf));
    3045           0 :                         zlog_debug(
    3046             :                                 "%s: Unable to update FEC: prefix %pFX, label %u, znh %s",
    3047             :                                 __func__, prefix, zl->local_label, buf);
    3048             :                 }
    3049             :         }
    3050             : 
    3051             :         /*
    3052             :          * Process backup LSPs/nexthop entries also. We associate backup
    3053             :          * LSP info with backup nexthops.
    3054             :          */
    3055           0 :         if (!CHECK_FLAG(zl->message, ZAPI_LABELS_HAS_BACKUPS))
    3056           0 :                 goto znh_done;
    3057             : 
    3058           0 :         for (i = 0; i < zl->backup_nexthop_num; i++) {
    3059             : 
    3060           0 :                 znh = &zl->backup_nexthops[i];
    3061             : 
    3062           0 :                 if (add_p)
    3063           0 :                         ret = lsp_backup_znh_install(lsp, zl->type, znh);
    3064             :                 else
    3065           0 :                         ret = mpls_lsp_uninstall(zvrf, zl->type,
    3066           0 :                                                  zl->local_label,
    3067           0 :                                                  znh->type, &znh->gate,
    3068           0 :                                                  znh->ifindex, true);
    3069             : 
    3070           0 :                 if (ret < 0) {
    3071           0 :                         if (IS_ZEBRA_DEBUG_RECV ||
    3072           0 :                             IS_ZEBRA_DEBUG_MPLS) {
    3073           0 :                                 zapi_nexthop2str(znh, buf, sizeof(buf));
    3074           0 :                                 zlog_debug("%s: Unable to %sinstall backup LSP: label %u, znh %s",
    3075             :                                            __func__, (add_p ? "" : "un"),
    3076             :                                            zl->local_label, buf);
    3077             :                         }
    3078           0 :                         continue;
    3079             :                 }
    3080             : 
    3081             :                 /* Attempt backup nexthop/FEC update if requested */
    3082           0 :                 if (re == NULL || zebra_nhg_get_backup_nhg(new_nhe) == NULL)
    3083           0 :                         continue;
    3084             : 
    3085             :                 /* Search the route's backup nexthops for a match
    3086             :                  * and update it.
    3087             :                  */
    3088           0 :                 found = ftn_update_znh(add_p, zl->type,
    3089           0 :                                        new_nhe->backup_info->nhe->nhg.nexthop,
    3090             :                                        znh);
    3091           0 :                 if (found) {
    3092           0 :                         counter++;
    3093           0 :                 } else if (IS_ZEBRA_DEBUG_RECV | IS_ZEBRA_DEBUG_MPLS) {
    3094           0 :                         zapi_nexthop2str(znh, buf, sizeof(buf));
    3095           0 :                         zlog_debug(
    3096             :                                 "%s: Unable to update backup FEC: prefix %pFX, label %u, znh %s",
    3097             :                                 __func__, prefix, zl->local_label, buf);
    3098             :                 }
    3099             :         }
    3100             : 
    3101           0 : znh_done:
    3102             : 
    3103             :         /*
    3104             :          * If we made changes, update the route, and schedule it
    3105             :          * for rib processing
    3106             :          */
    3107           0 :         if (re != NULL && counter > 0) {
    3108           0 :                 assert(rn != NULL);
    3109             : 
    3110           0 :                 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
    3111           0 :                 SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
    3112             : 
    3113           0 :                 mpls_zebra_nhe_update(re, afi, new_nhe);
    3114             : 
    3115           0 :                 rib_queue_add(rn);
    3116             :         }
    3117             : 
    3118           0 :         if (new_nhe)
    3119           0 :                 zebra_nhg_free(new_nhe);
    3120             : }
    3121             : 
    3122             : /*
    3123             :  * Install/update a NHLFE for an LSP in the forwarding table. This may be
    3124             :  * a new LSP entry or a new NHLFE for an existing in-label or an update of
    3125             :  * the out-label for an existing NHLFE (update case).
    3126             :  */
    3127             : static struct zebra_nhlfe *
    3128           0 : lsp_add_nhlfe(struct zebra_lsp *lsp, enum lsp_types_t type,
    3129             :               uint8_t num_out_labels, const mpls_label_t *out_labels,
    3130             :               enum nexthop_types_t gtype, const union g_addr *gate,
    3131             :               ifindex_t ifindex, bool is_backup)
    3132             : {
    3133           0 :         struct zebra_nhlfe *nhlfe;
    3134           0 :         char buf[MPLS_LABEL_STRLEN];
    3135           0 :         const char *backup_str;
    3136             : 
    3137           0 :         if (is_backup) {
    3138           0 :                 nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
    3139             :                                    gate, ifindex);
    3140           0 :                 backup_str = "backup ";
    3141             :         } else {
    3142           0 :                 nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
    3143             :                                    ifindex);
    3144           0 :                 backup_str = "";
    3145             :         }
    3146             : 
    3147           0 :         if (nhlfe) {
    3148           0 :                 struct nexthop *nh = nhlfe->nexthop;
    3149             : 
    3150           0 :                 assert(nh);
    3151           0 :                 assert(nh->nh_label);
    3152             : 
    3153             :                 /* Clear deleted flag (in case it was set) */
    3154           0 :                 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
    3155           0 :                 if (nh->nh_label->num_labels == num_out_labels
    3156           0 :                     && !memcmp(nh->nh_label->label, out_labels,
    3157             :                                sizeof(mpls_label_t) * num_out_labels))
    3158             :                         /* No change */
    3159             :                         return nhlfe;
    3160             : 
    3161           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    3162           0 :                         char buf2[MPLS_LABEL_STRLEN];
    3163           0 :                         char buf3[MPLS_LABEL_STRLEN];
    3164             : 
    3165           0 :                         nhlfe2str(nhlfe, buf, sizeof(buf));
    3166           0 :                         mpls_label2str(num_out_labels, out_labels, buf2,
    3167             :                                        sizeof(buf2), 0);
    3168           0 :                         mpls_label2str(nh->nh_label->num_labels,
    3169           0 :                                        nh->nh_label->label, buf3, sizeof(buf3),
    3170             :                                        0);
    3171             : 
    3172           0 :                         zlog_debug("LSP in-label %u type %d %snexthop %s out-label(s) changed to %s (old %s)",
    3173             :                                    lsp->ile.in_label, type, backup_str, buf,
    3174             :                                    buf2, buf3);
    3175             :                 }
    3176             : 
    3177             :                 /* Update out label(s), trigger processing. */
    3178           0 :                 if (nh->nh_label->num_labels == num_out_labels)
    3179           0 :                         memcpy(nh->nh_label->label, out_labels,
    3180             :                                sizeof(mpls_label_t) * num_out_labels);
    3181             :                 else {
    3182           0 :                         nexthop_del_labels(nh);
    3183           0 :                         nexthop_add_labels(nh, type, num_out_labels,
    3184             :                                            out_labels);
    3185             :                 }
    3186             :         } else {
    3187             :                 /* Add LSP entry to this nexthop */
    3188           0 :                 nhlfe = nhlfe_add(lsp, type, gtype, gate, ifindex,
    3189             :                                   num_out_labels, out_labels, is_backup);
    3190           0 :                 if (!nhlfe)
    3191             :                         return NULL;
    3192             : 
    3193           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    3194           0 :                         char buf2[MPLS_LABEL_STRLEN];
    3195             : 
    3196           0 :                         nhlfe2str(nhlfe, buf, sizeof(buf));
    3197           0 :                         mpls_label2str(num_out_labels, out_labels, buf2,
    3198             :                                        sizeof(buf2), 0);
    3199             : 
    3200           0 :                         zlog_debug("Add LSP in-label %u type %d %snexthop %s out-label(s) %s",
    3201             :                                    lsp->ile.in_label, type, backup_str, buf,
    3202             :                                    buf2);
    3203             :                 }
    3204             : 
    3205           0 :                 lsp->addr_family = NHLFE_FAMILY(nhlfe);
    3206             :         }
    3207             : 
    3208             :         /* Mark NHLFE, queue LSP for processing. */
    3209           0 :         SET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
    3210             : 
    3211           0 :         return nhlfe;
    3212             : }
    3213             : 
    3214             : /*
    3215             :  * Install an LSP and forwarding entry; used primarily
    3216             :  * from vrf zapi message processing.
    3217             :  */
    3218           0 : int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
    3219             :                      mpls_label_t in_label, uint8_t num_out_labels,
    3220             :                      const mpls_label_t *out_labels, enum nexthop_types_t gtype,
    3221             :                      const union g_addr *gate, ifindex_t ifindex)
    3222             : {
    3223           0 :         struct hash *lsp_table;
    3224           0 :         struct zebra_ile tmp_ile;
    3225           0 :         struct zebra_lsp *lsp;
    3226           0 :         struct zebra_nhlfe *nhlfe;
    3227             : 
    3228             :         /* Lookup table. */
    3229           0 :         lsp_table = zvrf->lsp_table;
    3230           0 :         if (!lsp_table)
    3231             :                 return -1;
    3232             : 
    3233             :         /* Find or create LSP object */
    3234           0 :         tmp_ile.in_label = in_label;
    3235           0 :         lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
    3236             : 
    3237           0 :         nhlfe = lsp_add_nhlfe(lsp, type, num_out_labels, out_labels, gtype,
    3238             :                               gate, ifindex, false /*backup*/);
    3239           0 :         if (nhlfe == NULL)
    3240             :                 return -1;
    3241             : 
    3242             :         /* Queue LSP for processing. */
    3243           0 :         if (lsp_processq_add(lsp))
    3244             :                 return -1;
    3245             : 
    3246             :         return 0;
    3247             : }
    3248             : 
    3249             : /*
    3250             :  * Install or replace NHLFE, using info from zapi nexthop
    3251             :  */
    3252           0 : static int lsp_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
    3253             :                            const struct zapi_nexthop *znh)
    3254             : {
    3255           0 :         struct zebra_nhlfe *nhlfe;
    3256             : 
    3257           0 :         nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num, znh->labels,
    3258           0 :                               znh->type, &znh->gate, znh->ifindex,
    3259             :                               false /*backup*/);
    3260           0 :         if (nhlfe == NULL)
    3261             :                 return -1;
    3262             : 
    3263             :         /* Update backup info if present */
    3264           0 :         if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
    3265           0 :                 if (znh->backup_num > NEXTHOP_MAX_BACKUPS) {
    3266           0 :                         nhlfe_del(nhlfe);
    3267           0 :                         return -1;
    3268             :                 }
    3269             : 
    3270           0 :                 nhlfe->nexthop->backup_num = znh->backup_num;
    3271           0 :                 memcpy(nhlfe->nexthop->backup_idx, znh->backup_idx,
    3272             :                        znh->backup_num);
    3273           0 :                 SET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
    3274             :         } else {
    3275             :                 /* Ensure there's no stale backup info */
    3276           0 :                 UNSET_FLAG(nhlfe->nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
    3277           0 :                 nhlfe->nexthop->backup_num = 0;
    3278             :         }
    3279             : 
    3280             :         /* Queue LSP for processing. */
    3281           0 :         if (lsp_processq_add(lsp))
    3282             :                 return -1;
    3283             : 
    3284             :         return 0;
    3285             : }
    3286             : 
    3287             : /*
    3288             :  * Install/update backup NHLFE for an LSP, using info from a zapi message.
    3289             :  */
    3290           0 : static int lsp_backup_znh_install(struct zebra_lsp *lsp, enum lsp_types_t type,
    3291             :                                   const struct zapi_nexthop *znh)
    3292             : {
    3293           0 :         struct zebra_nhlfe *nhlfe;
    3294             : 
    3295           0 :         nhlfe = lsp_add_nhlfe(lsp, type, znh->label_num,
    3296           0 :                               znh->labels, znh->type, &znh->gate,
    3297           0 :                               znh->ifindex, true /*backup*/);
    3298           0 :         if (nhlfe == NULL) {
    3299           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    3300           0 :                         zlog_debug("%s: unable to add backup nhlfe, label: %u",
    3301             :                                    __func__, lsp->ile.in_label);
    3302           0 :                 return -1;
    3303             :         }
    3304             : 
    3305             :         /* Queue LSP for processing. */
    3306           0 :         if (lsp_processq_add(lsp))
    3307             :                 return -1;
    3308             : 
    3309             :         return 0;
    3310             : }
    3311             : 
    3312           0 : struct zebra_lsp *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label)
    3313             : {
    3314           0 :         struct hash *lsp_table;
    3315           0 :         struct zebra_ile tmp_ile;
    3316             : 
    3317             :         /* Lookup table. */
    3318           0 :         lsp_table = zvrf->lsp_table;
    3319           0 :         if (!lsp_table)
    3320             :                 return NULL;
    3321             : 
    3322             :         /* If entry is not present, exit. */
    3323           0 :         tmp_ile.in_label = in_label;
    3324           0 :         return hash_lookup(lsp_table, &tmp_ile);
    3325             : }
    3326             : 
    3327             : /*
    3328             :  * Uninstall a particular NHLFE in the forwarding table. If this is
    3329             :  * the only NHLFE, the entire LSP forwarding entry has to be deleted.
    3330             :  */
    3331           0 : int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
    3332             :                        mpls_label_t in_label, enum nexthop_types_t gtype,
    3333             :                        const union g_addr *gate, ifindex_t ifindex,
    3334             :                        bool backup_p)
    3335             : {
    3336           0 :         struct hash *lsp_table;
    3337           0 :         struct zebra_ile tmp_ile;
    3338           0 :         struct zebra_lsp *lsp;
    3339           0 :         struct zebra_nhlfe *nhlfe;
    3340           0 :         char buf[NEXTHOP_STRLEN];
    3341           0 :         bool schedule_lsp = false;
    3342             : 
    3343             :         /* Lookup table. */
    3344           0 :         lsp_table = zvrf->lsp_table;
    3345           0 :         if (!lsp_table)
    3346             :                 return -1;
    3347             : 
    3348             :         /* If entry is not present, exit. */
    3349           0 :         tmp_ile.in_label = in_label;
    3350           0 :         lsp = hash_lookup(lsp_table, &tmp_ile);
    3351           0 :         if (!lsp)
    3352             :                 return 0;
    3353             : 
    3354           0 :         if (backup_p)
    3355           0 :                 nhlfe = nhlfe_find(&lsp->backup_nhlfe_list, type, gtype,
    3356             :                                    gate, ifindex);
    3357             :         else
    3358           0 :                 nhlfe = nhlfe_find(&lsp->nhlfe_list, type, gtype, gate,
    3359             :                                    ifindex);
    3360           0 :         if (!nhlfe)
    3361             :                 return 0;
    3362             : 
    3363           0 :         if (IS_ZEBRA_DEBUG_MPLS) {
    3364           0 :                 nhlfe2str(nhlfe, buf, sizeof(buf));
    3365           0 :                 zlog_debug("Del LSP in-label %u type %d nexthop %s flags 0x%x",
    3366             :                            in_label, type, buf, nhlfe->flags);
    3367             :         }
    3368             : 
    3369           0 :         if (CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED) ||
    3370           0 :             CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
    3371           0 :                 schedule_lsp = true;
    3372             : 
    3373             :         /* Mark NHLFE for delete or directly delete, as appropriate. */
    3374           0 :         if (schedule_lsp) {
    3375           0 :                 SET_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED);
    3376           0 :                 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_CHANGED);
    3377             : 
    3378           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    3379           0 :                         zlog_debug("Schedule LSP in-label %u flags 0x%x",
    3380             :                                    lsp->ile.in_label, lsp->flags);
    3381           0 :                 if (lsp_processq_add(lsp))
    3382             :                         return -1;
    3383             :         } else {
    3384           0 :                 nhlfe_del(nhlfe);
    3385             : 
    3386             :                 /* Free LSP entry if no other NHLFEs and not scheduled. */
    3387           0 :                 lsp_check_free(lsp_table, &lsp);
    3388             :         }
    3389             :         return 0;
    3390             : }
    3391             : 
    3392           0 : int mpls_lsp_uninstall_all_vrf(struct zebra_vrf *zvrf, enum lsp_types_t type,
    3393             :                                mpls_label_t in_label)
    3394             : {
    3395           0 :         struct hash *lsp_table;
    3396           0 :         struct zebra_ile tmp_ile;
    3397           0 :         struct zebra_lsp *lsp;
    3398             : 
    3399             :         /* Lookup table. */
    3400           0 :         lsp_table = zvrf->lsp_table;
    3401           0 :         if (!lsp_table)
    3402             :                 return -1;
    3403             : 
    3404             :         /* If entry is not present, exit. */
    3405           0 :         tmp_ile.in_label = in_label;
    3406           0 :         lsp = hash_lookup(lsp_table, &tmp_ile);
    3407           0 :         if (!lsp)
    3408             :                 return 0;
    3409             : 
    3410           0 :         return mpls_lsp_uninstall_all(lsp_table, lsp, type);
    3411             : }
    3412             : 
    3413             : /*
    3414             :  * Uninstall all NHLFEs for a particular LSP forwarding entry.
    3415             :  * If no other NHLFEs exist, the entry would be deleted.
    3416             :  */
    3417           0 : static void mpls_lsp_uninstall_all_type(struct hash_bucket *bucket, void *ctxt)
    3418             : {
    3419           0 :         struct lsp_uninstall_args *args = ctxt;
    3420           0 :         struct zebra_lsp *lsp;
    3421           0 :         struct hash *lsp_table;
    3422             : 
    3423           0 :         lsp = (struct zebra_lsp *)bucket->data;
    3424           0 :         if (nhlfe_list_first(&lsp->nhlfe_list) == NULL)
    3425             :                 return;
    3426             : 
    3427           0 :         lsp_table = args->lsp_table;
    3428           0 :         if (!lsp_table)
    3429             :                 return;
    3430             : 
    3431           0 :         mpls_lsp_uninstall_all(lsp_table, lsp, args->type);
    3432             : }
    3433             : 
    3434             : /*
    3435             :  * Uninstall all FEC-To-NHLFE (FTN) bindings of the given address-family and
    3436             :  * LSP type.
    3437             :  */
    3438           0 : static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
    3439             :                                    int afi, enum lsp_types_t lsp_type)
    3440             : {
    3441           0 :         struct route_table *table;
    3442           0 :         struct route_node *rn;
    3443           0 :         struct route_entry *re;
    3444           0 :         struct nexthop *nexthop;
    3445           0 :         struct nexthop_group *nhg;
    3446           0 :         bool update;
    3447             : 
    3448             :         /* Process routes of interested address-families. */
    3449           0 :         table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
    3450           0 :         if (!table)
    3451             :                 return;
    3452             : 
    3453           0 :         for (rn = route_top(table); rn; rn = route_next(rn)) {
    3454           0 :                 update = false;
    3455             : 
    3456           0 :                 RNODE_FOREACH_RE (rn, re) {
    3457           0 :                         struct nhg_hash_entry *new_nhe;
    3458             : 
    3459           0 :                         new_nhe = zebra_nhe_copy(re->nhe, 0);
    3460             : 
    3461           0 :                         nhg = &new_nhe->nhg;
    3462           0 :                         for (nexthop = nhg->nexthop; nexthop;
    3463           0 :                              nexthop = nexthop->next) {
    3464           0 :                                 if (nexthop->nh_label_type != lsp_type)
    3465           0 :                                         continue;
    3466             : 
    3467           0 :                                 nexthop_del_labels(nexthop);
    3468           0 :                                 SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
    3469           0 :                                 SET_FLAG(re->status,
    3470             :                                          ROUTE_ENTRY_LABELS_CHANGED);
    3471           0 :                                 update = true;
    3472             :                         }
    3473             : 
    3474             :                         /* Check for backup info and update that also */
    3475           0 :                         nhg = zebra_nhg_get_backup_nhg(new_nhe);
    3476           0 :                         if (nhg != NULL) {
    3477           0 :                                 for (nexthop = nhg->nexthop; nexthop;
    3478           0 :                                      nexthop = nexthop->next) {
    3479           0 :                                         if (nexthop->nh_label_type != lsp_type)
    3480           0 :                                                 continue;
    3481             : 
    3482           0 :                                         nexthop_del_labels(nexthop);
    3483           0 :                                         SET_FLAG(re->status,
    3484             :                                                  ROUTE_ENTRY_CHANGED);
    3485           0 :                                         SET_FLAG(re->status,
    3486             :                                                  ROUTE_ENTRY_LABELS_CHANGED);
    3487           0 :                                         update = true;
    3488             :                                 }
    3489             :                         }
    3490             : 
    3491           0 :                         if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
    3492           0 :                                 mpls_zebra_nhe_update(re, afi, new_nhe);
    3493             : 
    3494           0 :                         zebra_nhg_free(new_nhe);
    3495             :                 }
    3496             : 
    3497           0 :                 if (update)
    3498           0 :                         rib_queue_add(rn);
    3499             :         }
    3500             : }
    3501             : 
    3502             : #if defined(HAVE_CUMULUS)
    3503             : /*
    3504             :  * Check that the label values used in LSP creation are consistent. The
    3505             :  * main criteria is that if there is ECMP, the label operation must still
    3506             :  * be consistent - i.e., all paths either do a swap or do PHP. This is due
    3507             :  * to current HW restrictions.
    3508             :  */
    3509             : int zebra_mpls_lsp_label_consistent(struct zebra_vrf *zvrf,
    3510             :                                     mpls_label_t in_label,
    3511             :                                     mpls_label_t out_label,
    3512             :                                     enum nexthop_types_t gtype,
    3513             :                                     union g_addr *gate, ifindex_t ifindex)
    3514             : {
    3515             :         struct hash *slsp_table;
    3516             :         struct zebra_ile tmp_ile;
    3517             :         struct zebra_lsp *lsp;
    3518             :         struct zebra_nhlfe *nhlfe;
    3519             :         const struct nexthop *nh;
    3520             : 
    3521             :         /* Lookup table. */
    3522             :         slsp_table = zvrf->slsp_table;
    3523             :         if (!slsp_table)
    3524             :                 return 0;
    3525             : 
    3526             :         /* If entry is not present, exit. */
    3527             :         tmp_ile.in_label = in_label;
    3528             :         lsp = hash_lookup(slsp_table, &tmp_ile);
    3529             :         if (!lsp)
    3530             :                 return 1;
    3531             : 
    3532             :         nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
    3533             :                            gtype, gate, ifindex);
    3534             :         if (nhlfe) {
    3535             :                 nh = nhlfe->nexthop;
    3536             : 
    3537             :                 if (nh == NULL || nh->nh_label == NULL)
    3538             :                         return 0;
    3539             : 
    3540             :                 if (nh->nh_label->label[0] == out_label)
    3541             :                         return 1;
    3542             : 
    3543             :                 /* If not only NHLFE, cannot allow label change. */
    3544             :                 if (nhlfe != nhlfe_list_first(&lsp->nhlfe_list) ||
    3545             :                     nhlfe_list_next(&lsp->nhlfe_list, nhlfe) != NULL)
    3546             :                         return 0;
    3547             :         } else {
    3548             :                 /* If other NHLFEs exist, label operation must match. */
    3549             :                 nhlfe = nhlfe_list_first(&lsp->nhlfe_list);
    3550             :                 if (nhlfe != NULL) {
    3551             :                         int cur_op, new_op;
    3552             : 
    3553             :                         nh = nhlfe->nexthop;
    3554             : 
    3555             :                         if (nh == NULL || nh->nh_label == NULL)
    3556             :                                 return 0;
    3557             : 
    3558             :                         cur_op = (nh->nh_label->label[0] ==
    3559             :                                   MPLS_LABEL_IMPLICIT_NULL);
    3560             :                         new_op = (out_label == MPLS_LABEL_IMPLICIT_NULL);
    3561             :                         if (cur_op != new_op)
    3562             :                                 return 0;
    3563             :                 }
    3564             :         }
    3565             : 
    3566             :         /* Label values are good. */
    3567             :         return 1;
    3568             : }
    3569             : #endif /* HAVE_CUMULUS */
    3570             : 
    3571             : /*
    3572             :  * Add static LSP entry. This may be the first entry for this incoming label
    3573             :  * or an additional nexthop; an existing entry may also have outgoing label
    3574             :  * changed.
    3575             :  * Note: The label operation (swap or PHP) is common for the LSP entry (all
    3576             :  * NHLFEs).
    3577             :  */
    3578           0 : int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
    3579             :                               mpls_label_t out_label,
    3580             :                               enum nexthop_types_t gtype, union g_addr *gate,
    3581             :                               ifindex_t ifindex)
    3582             : {
    3583           0 :         struct hash *slsp_table;
    3584           0 :         struct zebra_ile tmp_ile;
    3585           0 :         struct zebra_lsp *lsp;
    3586           0 :         struct zebra_nhlfe *nhlfe;
    3587           0 :         char buf[BUFSIZ];
    3588             : 
    3589             :         /* Lookup table. */
    3590           0 :         slsp_table = zvrf->slsp_table;
    3591           0 :         if (!slsp_table)
    3592             :                 return -1;
    3593             : 
    3594             :         /* Find or create LSP. */
    3595           0 :         tmp_ile.in_label = in_label;
    3596           0 :         lsp = hash_get(slsp_table, &tmp_ile, lsp_alloc);
    3597             : 
    3598           0 :         nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC, gtype, gate,
    3599             :                            ifindex);
    3600           0 :         if (nhlfe) {
    3601           0 :                 struct nexthop *nh = nhlfe->nexthop;
    3602             : 
    3603           0 :                 assert(nh);
    3604           0 :                 assert(nh->nh_label);
    3605             : 
    3606             :                 /* Compare existing nexthop */
    3607           0 :                 if (nh->nh_label->num_labels == 1 &&
    3608           0 :                     nh->nh_label->label[0] == out_label)
    3609             :                         /* No change */
    3610             :                         return 0;
    3611             : 
    3612           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    3613           0 :                         nhlfe2str(nhlfe, buf, sizeof(buf));
    3614           0 :                         zlog_debug(
    3615             :                                 "Upd static LSP in-label %u nexthop %s out-label %u (old %u)",
    3616             :                                 in_label, buf, out_label,
    3617             :                                 nh->nh_label->label[0]);
    3618             :                 }
    3619           0 :                 if (nh->nh_label->num_labels == 1)
    3620           0 :                         nh->nh_label->label[0] = out_label;
    3621             :                 else {
    3622           0 :                         nexthop_del_labels(nh);
    3623           0 :                         nexthop_add_labels(nh, ZEBRA_LSP_STATIC, 1, &out_label);
    3624             :                 }
    3625             : 
    3626             :         } else {
    3627             :                 /* Add static LSP entry to this nexthop */
    3628           0 :                 nhlfe = nhlfe_add(lsp, ZEBRA_LSP_STATIC, gtype, gate,
    3629             :                                   ifindex, 1, &out_label, false /*backup*/);
    3630           0 :                 if (!nhlfe)
    3631             :                         return -1;
    3632             : 
    3633           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    3634           0 :                         nhlfe2str(nhlfe, buf, sizeof(buf));
    3635           0 :                         zlog_debug(
    3636             :                                 "Add static LSP in-label %u nexthop %s out-label %u",
    3637             :                                 in_label, buf, out_label);
    3638             :                 }
    3639             :         }
    3640             : 
    3641             :         /* (Re)Install LSP in the main table. */
    3642           0 :         if (mpls_lsp_install(zvrf, ZEBRA_LSP_STATIC, in_label, 1, &out_label,
    3643             :                              gtype, gate, ifindex))
    3644             :                 return -1;
    3645             : 
    3646             :         return 0;
    3647             : }
    3648             : 
    3649             : /*
    3650             :  * Delete static LSP entry. This may be the delete of one particular
    3651             :  * NHLFE for this incoming label or the delete of the entire entry (i.e.,
    3652             :  * all NHLFEs).
    3653             :  * NOTE: Delete of the only NHLFE will also end up deleting the entire
    3654             :  * LSP configuration.
    3655             :  */
    3656           0 : int zebra_mpls_static_lsp_del(struct zebra_vrf *zvrf, mpls_label_t in_label,
    3657             :                               enum nexthop_types_t gtype, union g_addr *gate,
    3658             :                               ifindex_t ifindex)
    3659             : {
    3660           0 :         struct hash *slsp_table;
    3661           0 :         struct zebra_ile tmp_ile;
    3662           0 :         struct zebra_lsp *lsp;
    3663           0 :         struct zebra_nhlfe *nhlfe;
    3664             : 
    3665             :         /* Lookup table. */
    3666           0 :         slsp_table = zvrf->slsp_table;
    3667           0 :         if (!slsp_table)
    3668             :                 return -1;
    3669             : 
    3670             :         /* If entry is not present, exit. */
    3671           0 :         tmp_ile.in_label = in_label;
    3672           0 :         lsp = hash_lookup(slsp_table, &tmp_ile);
    3673           0 :         if (!lsp)
    3674             :                 return 0;
    3675             : 
    3676             :         /* Is it delete of entire LSP or a specific NHLFE? */
    3677           0 :         if (gtype == NEXTHOP_TYPE_BLACKHOLE) {
    3678           0 :                 if (IS_ZEBRA_DEBUG_MPLS)
    3679           0 :                         zlog_debug("Del static LSP in-label %u", in_label);
    3680             : 
    3681             :                 /* Uninstall entire LSP from the main table. */
    3682           0 :                 mpls_static_lsp_uninstall_all(zvrf, in_label);
    3683             : 
    3684             :                 /* Delete all static NHLFEs */
    3685           0 :                 frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
    3686           0 :                         nhlfe_del(nhlfe);
    3687             :                 }
    3688             :         } else {
    3689             :                 /* Find specific NHLFE, exit if not found. */
    3690           0 :                 nhlfe = nhlfe_find(&lsp->nhlfe_list, ZEBRA_LSP_STATIC,
    3691             :                                    gtype, gate, ifindex);
    3692           0 :                 if (!nhlfe)
    3693             :                         return 0;
    3694             : 
    3695           0 :                 if (IS_ZEBRA_DEBUG_MPLS) {
    3696           0 :                         char buf[BUFSIZ];
    3697           0 :                         nhlfe2str(nhlfe, buf, sizeof(buf));
    3698           0 :                         zlog_debug("Del static LSP in-label %u nexthop %s",
    3699             :                                    in_label, buf);
    3700             :                 }
    3701             : 
    3702             :                 /* Uninstall LSP from the main table. */
    3703           0 :                 mpls_lsp_uninstall(zvrf, ZEBRA_LSP_STATIC, in_label, gtype,
    3704             :                                    gate, ifindex, false);
    3705             : 
    3706             :                 /* Delete static LSP NHLFE */
    3707           0 :                 nhlfe_del(nhlfe);
    3708             :         }
    3709             : 
    3710             :         /* Remove entire static LSP entry if no NHLFE - valid in either case
    3711             :          * above.
    3712             :          */
    3713           0 :         if (nhlfe_list_first(&lsp->nhlfe_list) == NULL) {
    3714           0 :                 lsp = hash_release(slsp_table, &tmp_ile);
    3715           0 :                 lsp_free_nhlfe(lsp);
    3716           0 :                 XFREE(MTYPE_LSP, lsp);
    3717             :         }
    3718             : 
    3719             :         return 0;
    3720             : }
    3721             : 
    3722             : /*
    3723             :  * Schedule all MPLS label forwarding entries for processing.
    3724             :  * Called upon changes that may affect one or more of them such as
    3725             :  * interface or nexthop state changes.
    3726             :  */
    3727           4 : void zebra_mpls_lsp_schedule(struct zebra_vrf *zvrf)
    3728             : {
    3729           4 :         if (!zvrf)
    3730             :                 return;
    3731           4 :         hash_iterate(zvrf->lsp_table, lsp_schedule, NULL);
    3732             : }
    3733             : 
    3734             : /*
    3735             :  * Display MPLS label forwarding table for a specific LSP
    3736             :  * (VTY command handler).
    3737             :  */
    3738           0 : void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf,
    3739             :                           mpls_label_t label, bool use_json)
    3740             : {
    3741           0 :         struct hash *lsp_table;
    3742           0 :         struct zebra_lsp *lsp;
    3743           0 :         struct zebra_ile tmp_ile;
    3744           0 :         json_object *json = NULL;
    3745             : 
    3746             :         /* Lookup table. */
    3747           0 :         lsp_table = zvrf->lsp_table;
    3748           0 :         if (!lsp_table)
    3749           0 :                 return;
    3750             : 
    3751             :         /* If entry is not present, exit. */
    3752           0 :         tmp_ile.in_label = label;
    3753           0 :         lsp = hash_lookup(lsp_table, &tmp_ile);
    3754           0 :         if (!lsp)
    3755             :                 return;
    3756             : 
    3757           0 :         if (use_json) {
    3758           0 :                 json = lsp_json(lsp);
    3759           0 :                 vty_json(vty, json);
    3760             :         } else
    3761           0 :                 lsp_print(vty, lsp);
    3762             : }
    3763             : 
    3764             : /*
    3765             :  * Display MPLS label forwarding table (VTY command handler).
    3766             :  */
    3767           0 : void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf,
    3768             :                                 bool use_json)
    3769             : {
    3770           0 :         char buf[BUFSIZ];
    3771           0 :         json_object *json = NULL;
    3772           0 :         struct zebra_lsp *lsp = NULL;
    3773           0 :         struct zebra_nhlfe *nhlfe = NULL;
    3774           0 :         struct listnode *node = NULL;
    3775           0 :         struct list *lsp_list = hash_get_sorted_list(zvrf->lsp_table, lsp_cmp);
    3776             : 
    3777           0 :         if (use_json) {
    3778           0 :                 json = json_object_new_object();
    3779             : 
    3780           0 :                 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
    3781           0 :                         json_object_object_add(
    3782           0 :                                 json, label2str(lsp->ile.in_label, buf,
    3783             :                                                 sizeof(buf)),
    3784           0 :                                 lsp_json(lsp));
    3785             : 
    3786           0 :                 vty_json(vty, json);
    3787             :         } else {
    3788           0 :                 struct ttable *tt;
    3789             : 
    3790             :                 /* Prepare table. */
    3791           0 :                 tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
    3792           0 :                 ttable_add_row(tt, "Inbound Label|Type|Nexthop|Outbound Label");
    3793           0 :                 tt->style.cell.rpad = 2;
    3794           0 :                 tt->style.corner = '+';
    3795           0 :                 ttable_restyle(tt);
    3796           0 :                 ttable_rowseps(tt, 0, BOTTOM, true, '-');
    3797             : 
    3798           0 :                 for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
    3799           0 :                         frr_each_safe(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
    3800           0 :                                 struct nexthop *nexthop;
    3801           0 :                                 const char *out_label_str;
    3802           0 :                                 char nh_buf[NEXTHOP_STRLEN];
    3803             : 
    3804           0 :                                 nexthop = nhlfe->nexthop;
    3805             : 
    3806           0 :                                 switch (nexthop->type) {
    3807           0 :                                 case NEXTHOP_TYPE_IFINDEX: {
    3808           0 :                                         struct zebra_ns *zns;
    3809           0 :                                         struct interface *ifp;
    3810             : 
    3811           0 :                                         zns = zebra_ns_lookup(NS_DEFAULT);
    3812           0 :                                         ifp = if_lookup_by_index_per_ns(
    3813           0 :                                                 zns, nexthop->ifindex);
    3814           0 :                                         snprintf(nh_buf, sizeof(nh_buf), "%s",
    3815             :                                                  ifp ? ifp->name : "Null");
    3816           0 :                                         break;
    3817             :                                 }
    3818           0 :                                 case NEXTHOP_TYPE_IPV4:
    3819             :                                 case NEXTHOP_TYPE_IPV4_IFINDEX:
    3820           0 :                                         inet_ntop(AF_INET, &nexthop->gate.ipv4,
    3821             :                                                   nh_buf, sizeof(nh_buf));
    3822           0 :                                         break;
    3823           0 :                                 case NEXTHOP_TYPE_IPV6:
    3824             :                                 case NEXTHOP_TYPE_IPV6_IFINDEX:
    3825           0 :                                         inet_ntop(AF_INET6, &nexthop->gate.ipv6,
    3826             :                                                   nh_buf, sizeof(nh_buf));
    3827           0 :                                         break;
    3828             :                                 case NEXTHOP_TYPE_BLACKHOLE:
    3829             :                                         break;
    3830             :                                 }
    3831             : 
    3832           0 :                                 if (nexthop->type != NEXTHOP_TYPE_IFINDEX)
    3833           0 :                                         out_label_str = mpls_label2str(
    3834           0 :                                                 nexthop->nh_label->num_labels,
    3835           0 :                                                 &nexthop->nh_label->label[0],
    3836             :                                                 buf, sizeof(buf), 1);
    3837             :                                 else
    3838             :                                         out_label_str = "-";
    3839             : 
    3840           0 :                                 ttable_add_row(tt, "%u|%s|%s|%s",
    3841             :                                                lsp->ile.in_label,
    3842             :                                                nhlfe_type2str(nhlfe->type),
    3843             :                                                nh_buf, out_label_str);
    3844             :                         }
    3845             :                 }
    3846             : 
    3847             :                 /* Dump the generated table. */
    3848           0 :                 if (tt->nrows > 1) {
    3849           0 :                         char *table = ttable_dump(tt, "\n");
    3850           0 :                         vty_out(vty, "%s\n", table);
    3851           0 :                         XFREE(MTYPE_TMP, table);
    3852             :                 }
    3853           0 :                 ttable_del(tt);
    3854             :         }
    3855             : 
    3856           0 :         list_delete(&lsp_list);
    3857           0 : }
    3858             : 
    3859             : /*
    3860             :  * Create printable string for static LSP configuration.
    3861             :  */
    3862           0 : static char *nhlfe_config_str(const struct zebra_nhlfe *nhlfe, char *buf,
    3863             :                               int size)
    3864             : {
    3865           0 :         const struct nexthop *nh;
    3866             : 
    3867           0 :         nh = nhlfe->nexthop;
    3868             : 
    3869           0 :         buf[0] = '\0';
    3870           0 :         switch (nh->type) {
    3871           0 :         case NEXTHOP_TYPE_IPV4:
    3872             :         case NEXTHOP_TYPE_IPV4_IFINDEX:
    3873           0 :                 inet_ntop(AF_INET, &nh->gate.ipv4, buf, size);
    3874           0 :                 if (nh->ifindex)
    3875           0 :                         strlcat(buf, ifindex2ifname(nh->ifindex, VRF_DEFAULT),
    3876             :                                 size);
    3877             :                 break;
    3878           0 :         case NEXTHOP_TYPE_IPV6:
    3879             :         case NEXTHOP_TYPE_IPV6_IFINDEX:
    3880           0 :                 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, size);
    3881           0 :                 if (nh->ifindex)
    3882           0 :                         strlcat(buf,
    3883             :                                 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
    3884             :                                 size);
    3885             :                 break;
    3886           0 :         case NEXTHOP_TYPE_IFINDEX:
    3887           0 :                 if (nh->ifindex)
    3888           0 :                         strlcat(buf,
    3889             :                                 ifindex2ifname(nh->ifindex, VRF_DEFAULT),
    3890             :                                 size);
    3891             :                 break;
    3892             :         case NEXTHOP_TYPE_BLACKHOLE:
    3893             :                 break;
    3894             :         }
    3895             : 
    3896           0 :         return buf;
    3897             : }
    3898             : 
    3899             : /*
    3900             :  * Display MPLS LSP configuration of all static LSPs (VTY command handler).
    3901             :  */
    3902           0 : int zebra_mpls_write_lsp_config(struct vty *vty, struct zebra_vrf *zvrf)
    3903             : {
    3904           0 :         struct zebra_lsp *lsp;
    3905           0 :         struct zebra_nhlfe *nhlfe;
    3906           0 :         struct nexthop *nh;
    3907           0 :         struct listnode *node;
    3908           0 :         struct list *slsp_list =
    3909           0 :                 hash_get_sorted_list(zvrf->slsp_table, lsp_cmp);
    3910             : 
    3911           0 :         for (ALL_LIST_ELEMENTS_RO(slsp_list, node, lsp)) {
    3912           0 :                 frr_each(nhlfe_list, &lsp->nhlfe_list, nhlfe) {
    3913           0 :                         char buf[BUFSIZ];
    3914           0 :                         char lstr[30];
    3915             : 
    3916           0 :                         nh = nhlfe->nexthop;
    3917           0 :                         if (nh == NULL || nh->nh_label == NULL)
    3918           0 :                                 continue;
    3919             : 
    3920           0 :                         nhlfe_config_str(nhlfe, buf, sizeof(buf));
    3921             : 
    3922           0 :                         switch (nh->nh_label->label[0]) {
    3923           0 :                         case MPLS_LABEL_IPV4_EXPLICIT_NULL:
    3924             :                         case MPLS_LABEL_IPV6_EXPLICIT_NULL:
    3925           0 :                                 strlcpy(lstr, "explicit-null", sizeof(lstr));
    3926           0 :                                 break;
    3927           0 :                         case MPLS_LABEL_IMPLICIT_NULL:
    3928           0 :                                 strlcpy(lstr, "implicit-null", sizeof(lstr));
    3929           0 :                                 break;
    3930           0 :                         default:
    3931           0 :                                 snprintf(lstr, sizeof(lstr), "%u",
    3932             :                                          nh->nh_label->label[0]);
    3933           0 :                                 break;
    3934             :                         }
    3935             : 
    3936           0 :                         vty_out(vty, "mpls lsp %u %s %s\n", lsp->ile.in_label,
    3937             :                                 buf, lstr);
    3938             :                 }
    3939             :         }
    3940             : 
    3941           0 :         list_delete(&slsp_list);
    3942           0 :         return (zvrf->slsp_table->count ? 1 : 0);
    3943             : }
    3944             : 
    3945             : /*
    3946             :  * Add/update global label block.
    3947             :  */
    3948           0 : int zebra_mpls_label_block_add(struct zebra_vrf *zvrf, uint32_t start_label,
    3949             :                                uint32_t end_label)
    3950             : {
    3951           0 :         zvrf->mpls_srgb.start_label = start_label;
    3952           0 :         zvrf->mpls_srgb.end_label = end_label;
    3953             : 
    3954             :         /* Evaluate registered FECs to see if any get a label or not. */
    3955           0 :         fec_evaluate(zvrf);
    3956           0 :         return 0;
    3957             : }
    3958             : 
    3959             : /*
    3960             :  * Delete global label block.
    3961             :  */
    3962           0 : int zebra_mpls_label_block_del(struct zebra_vrf *zvrf)
    3963             : {
    3964           0 :         zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
    3965           0 :         zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
    3966             : 
    3967             :         /* Process registered FECs to clear their local label, if needed. */
    3968           0 :         fec_evaluate(zvrf);
    3969           0 :         return 0;
    3970             : }
    3971             : 
    3972             : /*
    3973             :  * Display MPLS global label block configuration (VTY command handler).
    3974             :  */
    3975           0 : int zebra_mpls_write_label_block_config(struct vty *vty, struct zebra_vrf *zvrf)
    3976             : {
    3977           0 :         if (zvrf->mpls_srgb.start_label == 0)
    3978             :                 return 0;
    3979             : 
    3980           0 :         if ((zvrf->mpls_srgb.start_label != MPLS_DEFAULT_MIN_SRGB_LABEL)
    3981           0 :             || (zvrf->mpls_srgb.end_label != MPLS_DEFAULT_MAX_SRGB_LABEL)) {
    3982           0 :                 vty_out(vty, "mpls label global-block %u %u\n",
    3983             :                         zvrf->mpls_srgb.start_label, zvrf->mpls_srgb.end_label);
    3984             :         }
    3985             : 
    3986             :         return 1;
    3987             : }
    3988             : 
    3989             : /*
    3990             :  * Called when VRF becomes inactive, cleans up information but keeps
    3991             :  * the table itself.
    3992             :  */
    3993           4 : void zebra_mpls_cleanup_tables(struct zebra_vrf *zvrf)
    3994             : {
    3995           4 :         struct zebra_vrf *def_zvrf;
    3996           4 :         afi_t afi;
    3997             : 
    3998           8 :         if (zvrf_id(zvrf) == VRF_DEFAULT)
    3999           4 :                 hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
    4000             :         else {
    4001             :                 /*
    4002             :                  * For other vrfs, we try to remove associated LSPs; we locate
    4003             :                  * the LSPs in the default vrf.
    4004             :                  */
    4005           0 :                 def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
    4006             : 
    4007             :                 /* At shutdown, the default may be gone already */
    4008           0 :                 if (def_zvrf == NULL)
    4009             :                         return;
    4010             : 
    4011           0 :                 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
    4012           0 :                         if (zvrf->label[afi] != MPLS_LABEL_NONE)
    4013           0 :                                 lsp_uninstall(def_zvrf, zvrf->label[afi]);
    4014             :                 }
    4015             :         }
    4016             : }
    4017             : 
    4018             : /*
    4019             :  * When a vrf label is assigned and the client goes away
    4020             :  * we should cleanup the vrf labels associated with
    4021             :  * that zclient.
    4022             :  */
    4023          12 : void zebra_mpls_client_cleanup_vrf_label(uint8_t proto)
    4024             : {
    4025          12 :         struct vrf *vrf;
    4026          12 :         struct zebra_vrf *def_zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
    4027             : 
    4028          12 :         if (def_zvrf == NULL)
    4029             :                 return;
    4030             : 
    4031          36 :         RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
    4032          12 :                 struct zebra_vrf *zvrf = vrf->info;
    4033          12 :                 afi_t afi;
    4034             : 
    4035          12 :                 if (!zvrf)
    4036           0 :                         continue;
    4037             : 
    4038          48 :                 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
    4039          36 :                         if (zvrf->label_proto[afi] == proto
    4040          12 :                             && zvrf->label[afi] != MPLS_LABEL_NONE)
    4041           0 :                                 lsp_uninstall(def_zvrf, zvrf->label[afi]);
    4042             : 
    4043             :                         /*
    4044             :                          * Cleanup data structures by fiat
    4045             :                          */
    4046          36 :                         zvrf->label_proto[afi] = 0;
    4047          36 :                         zvrf->label[afi] = MPLS_LABEL_NONE;
    4048             :                 }
    4049             :         }
    4050             : }
    4051             : 
    4052           0 : static void lsp_table_free(void *p)
    4053             : {
    4054           0 :         struct zebra_lsp *lsp = p;
    4055             : 
    4056           0 :         lsp_free_nhlfe(lsp);
    4057             : 
    4058           0 :         XFREE(MTYPE_LSP, lsp);
    4059           0 : }
    4060             : 
    4061             : /*
    4062             :  * Called upon process exiting, need to delete LSP forwarding
    4063             :  * entries from the kernel.
    4064             :  * NOTE: Currently supported only for default VRF.
    4065             :  */
    4066           4 : void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
    4067             : {
    4068           4 :         hash_iterate(zvrf->lsp_table, lsp_uninstall_from_kernel, NULL);
    4069           4 :         hash_clean(zvrf->lsp_table, lsp_table_free);
    4070           4 :         hash_free(zvrf->lsp_table);
    4071           4 :         hash_clean(zvrf->slsp_table, lsp_table_free);
    4072           4 :         hash_free(zvrf->slsp_table);
    4073           4 :         route_table_finish(zvrf->fec_table[AFI_IP]);
    4074           4 :         route_table_finish(zvrf->fec_table[AFI_IP6]);
    4075           4 : }
    4076             : 
    4077             : /*
    4078             :  * Allocate MPLS tables for this VRF and do other initialization.
    4079             :  * NOTE: Currently supported only for default VRF.
    4080             :  */
    4081           4 : void zebra_mpls_init_tables(struct zebra_vrf *zvrf)
    4082             : {
    4083           4 :         char buffer[80];
    4084             : 
    4085           4 :         if (!zvrf)
    4086           0 :                 return;
    4087             : 
    4088           4 :         snprintf(buffer, sizeof(buffer), "ZEBRA SLSP table: %s",
    4089           4 :                  zvrf->vrf->name);
    4090           4 :         zvrf->slsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
    4091             : 
    4092           4 :         snprintf(buffer, sizeof(buffer), "ZEBRA LSP table: %s",
    4093           4 :                  zvrf->vrf->name);
    4094           4 :         zvrf->lsp_table = hash_create_size(8, label_hash, label_cmp, buffer);
    4095           4 :         zvrf->fec_table[AFI_IP] = route_table_init();
    4096           4 :         zvrf->fec_table[AFI_IP6] = route_table_init();
    4097           4 :         zvrf->mpls_flags = 0;
    4098           4 :         zvrf->mpls_srgb.start_label = MPLS_DEFAULT_MIN_SRGB_LABEL;
    4099           4 :         zvrf->mpls_srgb.end_label = MPLS_DEFAULT_MAX_SRGB_LABEL;
    4100             : }
    4101             : 
    4102           0 : void zebra_mpls_turned_on(void)
    4103             : {
    4104           0 :         if (!mpls_enabled) {
    4105           0 :                 mpls_processq_init();
    4106           0 :                 mpls_enabled = true;
    4107             :         }
    4108             : 
    4109           0 :         hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
    4110           0 :         hook_register(zserv_client_close, zebra_mpls_cleanup_zclient_labels);
    4111           0 : }
    4112             : 
    4113             : /*
    4114             :  * Global MPLS initialization.
    4115             :  */
    4116           4 : void zebra_mpls_init(void)
    4117             : {
    4118           4 :         mpls_enabled = false;
    4119           4 :         mpls_pw_reach_strict = false;
    4120             : 
    4121           4 :         if (mpls_kernel_init() < 0) {
    4122           4 :                 flog_warn(EC_ZEBRA_MPLS_SUPPORT_DISABLED,
    4123             :                           "Disabling MPLS support (no kernel support)");
    4124           4 :                 return;
    4125             :         }
    4126             : 
    4127           0 :         zebra_mpls_turned_on();
    4128             : }

Generated by: LCOV version v1.16-topotato