]> git.proxmox.com Git - mirror_frr.git/blobdiff - isisd/isis_lsp.c
zebra: Fix label manager memory leak (#5680)
[mirror_frr.git] / isisd / isis_lsp.c
index 0a9f13e6dc4d99a4c9de5267f08064611463d664..c0b90e8439cea1436fb88b221a78c53359a11272 100644 (file)
@@ -40,7 +40,6 @@
 #include "srcdest_table.h"
 #include "lib_errors.h"
 
-#include "isisd/dict.h"
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
-#include "isisd/isis_te.h"
 #include "isisd/isis_mt.h"
 #include "isisd/isis_tlvs.h"
+#include "isisd/isis_te.h"
 #include "isisd/fabricd.h"
 #include "isisd/isis_tx_queue.h"
+#include "isisd/isis_nb.h"
 
 static int lsp_refresh(struct thread *thread);
 static int lsp_l1_refresh_pseudo(struct thread *thread);
 static int lsp_l2_refresh_pseudo(struct thread *thread);
 
+static void lsp_destroy(struct isis_lsp *lsp);
+
 int lsp_id_cmp(uint8_t *id1, uint8_t *id2)
 {
        return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
 }
 
-dict_t *lsp_db_init(void)
+int lspdb_compare(const struct isis_lsp *a, const struct isis_lsp *b)
 {
-       dict_t *dict;
-
-       dict = dict_create(DICTCOUNT_T_MAX, (dict_comp_t)lsp_id_cmp);
-
-       return dict;
+       return memcmp(a->hdr.lsp_id, b->hdr.lsp_id, sizeof(a->hdr.lsp_id));
 }
 
-struct isis_lsp *lsp_search(uint8_t *id, dict_t *lspdb)
+void lsp_db_init(struct lspdb_head *head)
 {
-       dnode_t *node;
-
-#ifdef EXTREME_DEBUG
-       dnode_t *dn;
+       lspdb_init(head);
+}
 
-       zlog_debug("searching db");
-       for (dn = dict_first(lspdb); dn; dn = dict_next(lspdb, dn)) {
-               zlog_debug("%s\t%pX",
-                          rawlspid_print((uint8_t *)dnode_getkey(dn)),
-                          dnode_get(dn));
-       }
-#endif /* EXTREME DEBUG */
+void lsp_db_fini(struct lspdb_head *head)
+{
+       struct isis_lsp *lsp;
 
-       node = dict_lookup(lspdb, id);
+       while ((lsp = lspdb_pop(head)))
+               lsp_destroy(lsp);
+       lspdb_fini(head);
+}
 
-       if (node)
-               return (struct isis_lsp *)dnode_get(node);
+struct isis_lsp *lsp_search(struct lspdb_head *head, const uint8_t *id)
+{
+       struct isis_lsp searchfor;
+       memcpy(searchfor.hdr.lsp_id, id, sizeof(searchfor.hdr.lsp_id));
 
-       return NULL;
+       return lspdb_find(head, &searchfor);
 }
 
 static void lsp_clear_data(struct isis_lsp *lsp)
@@ -109,7 +106,7 @@ static void lsp_clear_data(struct isis_lsp *lsp)
        lsp->tlvs = NULL;
 }
 
-static void lsp_remove_frags(struct list *frags, dict_t *lspdb);
+static void lsp_remove_frags(struct lspdb_head *head, struct list *frags);
 
 static void lsp_destroy(struct isis_lsp *lsp)
 {
@@ -128,8 +125,8 @@ static void lsp_destroy(struct isis_lsp *lsp)
 
        if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
                if (lsp->lspu.frags) {
-                       lsp_remove_frags(lsp->lspu.frags,
-                                        lsp->area->lspdb[lsp->level - 1]);
+                       lsp_remove_frags(&lsp->area->lspdb[lsp->level - 1],
+                                       lsp->lspu.frags);
                        list_delete(&lsp->lspu.frags);
                }
        } else {
@@ -148,56 +145,34 @@ static void lsp_destroy(struct isis_lsp *lsp)
        XFREE(MTYPE_ISIS_LSP, lsp);
 }
 
-void lsp_db_destroy(dict_t *lspdb)
-{
-       dnode_t *dnode, *next;
-       struct isis_lsp *lsp;
-
-       dnode = dict_first(lspdb);
-       while (dnode) {
-               next = dict_next(lspdb, dnode);
-               lsp = dnode_get(dnode);
-               lsp_destroy(lsp);
-               dict_delete_free(lspdb, dnode);
-               dnode = next;
-       }
-
-       dict_free(lspdb);
-
-       return;
-}
-
 /*
  * Remove all the frags belonging to the given lsp
  */
-static void lsp_remove_frags(struct list *frags, dict_t *lspdb)
+static void lsp_remove_frags(struct lspdb_head *head, struct list *frags)
 {
-       dnode_t *dnode;
        struct listnode *lnode, *lnnode;
        struct isis_lsp *lsp;
 
        for (ALL_LIST_ELEMENTS(frags, lnode, lnnode, lsp)) {
-               dnode = dict_lookup(lspdb, lsp->hdr.lsp_id);
+               lsp = lsp_search(head, lsp->hdr.lsp_id);
+               lspdb_del(head, lsp);
                lsp_destroy(lsp);
-               dnode_destroy(dict_delete(lspdb, dnode));
        }
 }
 
-void lsp_search_and_destroy(uint8_t *id, dict_t *lspdb)
+void lsp_search_and_destroy(struct lspdb_head *head, const uint8_t *id)
 {
-       dnode_t *node;
        struct isis_lsp *lsp;
 
-       node = dict_lookup(lspdb, id);
-       if (node) {
-               node = dict_delete(lspdb, node);
-               lsp = dnode_get(node);
+       lsp = lsp_search(head, id);
+       if (lsp) {
+               lspdb_del(head, lsp);
                /*
                 * If this is a zero lsp, remove all the frags now
                 */
                if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0) {
                        if (lsp->lspu.frags)
-                               lsp_remove_frags(lsp->lspu.frags, lspdb);
+                               lsp_remove_frags(head, lsp->lspu.frags);
                } else {
                        /*
                         * else just remove this frag, from the zero lsps' frag
@@ -209,7 +184,6 @@ void lsp_search_and_destroy(uint8_t *id, dict_t *lspdb)
                                                lsp);
                }
                lsp_destroy(lsp);
-               dnode_destroy(node);
        }
 }
 
@@ -514,7 +488,7 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
 
                memcpy(lspid, lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
                LSP_FRAGMENT(lspid) = 0;
-               lsp0 = lsp_search(lspid, area->lspdb[level - 1]);
+               lsp0 = lsp_search(&area->lspdb[level - 1], lspid);
                if (lsp0)
                        lsp_link_fragment(lsp, lsp0);
        }
@@ -582,9 +556,9 @@ struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
        return lsp;
 }
 
-void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb)
+void lsp_insert(struct lspdb_head *head, struct isis_lsp *lsp)
 {
-       dict_alloc_insert(lspdb, lsp->hdr.lsp_id, lsp);
+       lspdb_add(head, lsp);
        if (lsp->hdr.seqno)
                isis_spf_schedule(lsp->area, lsp->level);
 }
@@ -592,13 +566,16 @@ void lsp_insert(struct isis_lsp *lsp, dict_t *lspdb)
 /*
  * Build a list of LSPs with non-zero ht bounded by start and stop ids
  */
-void lsp_build_list_nonzero_ht(uint8_t *start_id, uint8_t *stop_id,
-                              struct list *list, dict_t *lspdb)
+void lsp_build_list_nonzero_ht(struct lspdb_head *head, const uint8_t *start_id,
+                              const uint8_t *stop_id, struct list *list)
 {
-       for (dnode_t *curr = dict_lower_bound(lspdb, start_id);
-            curr; curr = dict_next(lspdb, curr)) {
-               struct isis_lsp *lsp = curr->dict_data;
+       struct isis_lsp searchfor;
+       struct isis_lsp *lsp, *start;
+
+       memcpy(&searchfor.hdr.lsp_id, start_id, sizeof(searchfor.hdr.lsp_id));
 
+       start = lspdb_find_gteq(head, &searchfor);
+       frr_each_from (lspdb, head, lsp, start) {
                if (memcmp(lsp->hdr.lsp_id, stop_id,
                           ISIS_SYS_ID_LEN + 2) > 0)
                        break;
@@ -699,26 +676,20 @@ void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost)
 }
 
 /* print all the lsps info in the local lspdb */
-int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost)
+int lsp_print_all(struct vty *vty, struct lspdb_head *head, char detail,
+                 char dynhost)
 {
-
-       dnode_t *node = dict_first(lspdb), *next;
+       struct isis_lsp *lsp;
        int lsp_count = 0;
 
        if (detail == ISIS_UI_LEVEL_BRIEF) {
-               while (node != NULL) {
-                       /* I think it is unnecessary, so I comment it out */
-                       /* dict_contains (lspdb, node); */
-                       next = dict_next(lspdb, node);
-                       lsp_print(dnode_get(node), vty, dynhost);
-                       node = next;
+               frr_each (lspdb, head, lsp) {
+                       lsp_print(lsp, vty, dynhost);
                        lsp_count++;
                }
        } else if (detail == ISIS_UI_LEVEL_DETAIL) {
-               while (node != NULL) {
-                       next = dict_next(lspdb, node);
-                       lsp_print_detail(dnode_get(node), vty, dynhost);
-                       node = next;
+               frr_each (lspdb, head, lsp) {
+                       lsp_print_detail(lsp, vty, dynhost);
                        lsp_count++;
                }
        }
@@ -811,8 +782,8 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
                if (!rn->info)
                        continue;
                struct isis_ext_info *info = rn->info;
-
                struct prefix_ipv6 *p, *src_p;
+
                srcdest_rnode_prefixes(rn, (const struct prefix **)&p,
                                       (const struct prefix **)&src_p);
 
@@ -847,7 +818,7 @@ static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
        memcpy(frag_id, lsp0->hdr.lsp_id, ISIS_SYS_ID_LEN + 1);
        LSP_FRAGMENT(frag_id) = frag_num;
 
-       lsp = lsp_search(frag_id, area->lspdb[level - 1]);
+       lsp = lsp_search(&area->lspdb[level - 1], frag_id);
        if (lsp) {
                lsp_clear_data(lsp);
                if (!lsp->lspu.zero_lsp)
@@ -860,7 +831,7 @@ static struct isis_lsp *lsp_next_frag(uint8_t frag_num, struct isis_lsp *lsp0,
                                        area->attached_bit),
                      0, lsp0, level);
        lsp->own_lsp = 1;
-       lsp_insert(lsp, area->lspdb[level - 1]);
+       lsp_insert(&area->lspdb[level - 1], lsp);
        return lsp;
 }
 
@@ -893,6 +864,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
        /* Protocols Supported */
        if (area->ip_circuits > 0 || area->ipv6_circuits > 0) {
                struct nlpids nlpids = {.count = 0};
+
                if (area->ip_circuits > 0) {
                        lsp_debug(
                                "ISIS (%s): Found IPv4 circuit, adding IPv4 to NLPIDs",
@@ -938,10 +910,12 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                          area->area_tag);
        }
 
-       /* IPv4 address and TE router ID TLVs. In case of the first one we don't
-        * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put
-        * into
-        * LSP and this address is same as router id. */
+       /* IPv4 address and TE router ID TLVs.
+        * In case of the first one we don't follow "C" vendor,
+        * but "J" vendor behavior - one IPv4 address is put
+        * into LSP. TE router ID will be the same if MPLS-TE
+        * is not activate or MPLS-TE router-id not specified
+        */
        if (isis->router_id != 0) {
                struct in_addr id = {.s_addr = isis->router_id};
                inet_ntop(AF_INET, &id, buf, sizeof(buf));
@@ -949,11 +923,14 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                          area->area_tag, buf);
                isis_tlvs_add_ipv4_address(lsp->tlvs, &id);
 
-               /* Exactly same data is put into TE router ID TLV, but only if
-                * new style
-                * TLV's are in use. */
+               /* If new style TLV's are in use, add TE router ID TLV
+                * Check if MPLS-TE is activate and mpls-te router-id set
+                * otherwise add exactly same data as for IPv4 address
+                */
                if (area->newmetric) {
-
+                       if (IS_MPLS_TE(area->mta)
+                           && area->mta->router_id.s_addr != 0)
+                               id.s_addr = area->mta->router_id.s_addr;
                        lsp_debug(
                                "ISIS (%s): Adding router ID also as TE router ID tlv.",
                                area->area_tag);
@@ -1034,6 +1011,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                    && circuit->ipv6_non_link->count > 0) {
                        struct listnode *ipnode;
                        struct prefix_ipv6 *ipv6;
+
                        for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
                                                  ipnode, ipv6)) {
                                lsp_debug(
@@ -1066,25 +1044,10 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                                        lsp->tlvs, ne_id,
                                                        metric);
                                        }
-                                       if (area->newmetric) {
-                                               uint8_t subtlvs[256];
-                                               uint8_t subtlv_len;
-
-                                               if (IS_MPLS_TE(area->mta)
-                                                   && circuit->interface
-                                                   && HAS_LINK_PARAMS(
-                                                              circuit->interface))
-                                                       subtlv_len = add_te_subtlvs(
-                                                               subtlvs,
-                                                               circuit->mtc);
-                                               else
-                                                       subtlv_len = 0;
-
+                                       if (area->newmetric)
                                                tlvs_add_mt_bcast(
                                                        lsp->tlvs, circuit,
-                                                       level, ne_id, metric,
-                                                       subtlvs, subtlv_len);
-                                       }
+                                                       level, ne_id, metric);
                                }
                        } else {
                                lsp_debug(
@@ -1109,36 +1072,6 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                                lsp->tlvs, ne_id, metric);
                                }
                                if (area->newmetric) {
-                                       uint8_t subtlvs[256];
-                                       uint8_t subtlv_len;
-
-                                       if (IS_MPLS_TE(area->mta)
-                                           && circuit->interface != NULL
-                                           && HAS_LINK_PARAMS(
-                                                      circuit->interface))
-                                               /* Update Local and Remote IP
-                                                * address for MPLS TE circuit
-                                                * parameters */
-                                               /* NOTE sure that it is the
-                                                * pertinent place for that
-                                                * updates */
-                                               /* Local IP address could be
-                                                * updated in isis_circuit.c -
-                                                * isis_circuit_add_addr() */
-                                               /* But, where update remote IP
-                                                * address ? in isis_pdu.c -
-                                                * process_p2p_hello() ? */
-
-                                               /* Add SubTLVs & Adjust real
-                                                * size of SubTLVs */
-                                               subtlv_len = add_te_subtlvs(
-                                                       subtlvs, circuit->mtc);
-                                       else
-                                               /* Or keep only TE metric with
-                                                * no SubTLVs if MPLS_TE is off
-                                                */
-                                               subtlv_len = 0;
-
                                        uint32_t neighbor_metric;
                                        if (fabricd_tier(area) == 0) {
                                                neighbor_metric = 0xffe;
@@ -1147,8 +1080,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
                                        }
 
                                        tlvs_add_mt_p2p(lsp->tlvs, circuit,
-                                                       ne_id, neighbor_metric,
-                                                       subtlvs, subtlv_len);
+                                                       ne_id, neighbor_metric);
                                }
                        } else {
                                lsp_debug(
@@ -1228,12 +1160,12 @@ int lsp_generate(struct isis_area *area, int level)
        memcpy(&lspid, isis->sysid, ISIS_SYS_ID_LEN);
 
        /* only builds the lsp if the area shares the level */
-       oldlsp = lsp_search(lspid, area->lspdb[level - 1]);
+       oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
        if (oldlsp) {
                /* FIXME: we should actually initiate a purge */
                seq_num = oldlsp->hdr.seqno;
-               lsp_search_and_destroy(oldlsp->hdr.lsp_id,
-                                      area->lspdb[level - 1]);
+               lsp_search_and_destroy(&area->lspdb[level - 1],
+                                      oldlsp->hdr.lsp_id);
        }
        rem_lifetime = lsp_rem_lifetime(area, level);
        newlsp =
@@ -1243,7 +1175,7 @@ int lsp_generate(struct isis_area *area, int level)
        newlsp->area = area;
        newlsp->own_lsp = 1;
 
-       lsp_insert(newlsp, area->lspdb[level - 1]);
+       lsp_insert(&area->lspdb[level - 1], newlsp);
        /* build_lsp_data (newlsp, area); */
        lsp_build(newlsp, area);
        /* time to calculate our checksum */
@@ -1288,7 +1220,7 @@ int lsp_generate(struct isis_area *area, int level)
  */
 static int lsp_regenerate(struct isis_area *area, int level)
 {
-       dict_t *lspdb;
+       struct lspdb_head *head;
        struct isis_lsp *lsp, *frag;
        struct listnode *node;
        uint8_t lspid[ISIS_SYS_ID_LEN + 2];
@@ -1297,12 +1229,12 @@ static int lsp_regenerate(struct isis_area *area, int level)
        if ((area == NULL) || (area->is_type & level) != level)
                return ISIS_ERROR;
 
-       lspdb = area->lspdb[level - 1];
+       head = &area->lspdb[level - 1];
 
        memset(lspid, 0, ISIS_SYS_ID_LEN + 2);
        memcpy(lspid, isis->sysid, ISIS_SYS_ID_LEN);
 
-       lsp = lsp_search(lspid, lspdb);
+       lsp = lsp_search(head, lspid);
 
        if (!lsp) {
                flog_err(EC_LIB_DEVELOPMENT,
@@ -1445,7 +1377,7 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level,
                        continue;
                }
 
-               lsp = lsp_search(id, area->lspdb[lvl - 1]);
+               lsp = lsp_search(&area->lspdb[lvl - 1], id);
                if (!lsp) {
                        sched_debug(
                                "ISIS (%s): We do not have any LSPs to regenerate, nothing todo.",
@@ -1542,7 +1474,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
        }
        if (circuit->area->newmetric) {
                isis_tlvs_add_extended_reach(lsp->tlvs, ISIS_MT_IPV4_UNICAST,
-                                            ne_id, 0, NULL, 0);
+                                            ne_id, 0, circuit->ext);
                lsp_debug(
                        "ISIS (%s): Adding %s.%02x as te-style neighbor (self)",
                        area->area_tag, sysid_print(ne_id),
@@ -1584,7 +1516,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
                if (circuit->area->newmetric) {
                        isis_tlvs_add_extended_reach(lsp->tlvs,
                                                     ISIS_MT_IPV4_UNICAST,
-                                                    ne_id, 0, NULL, 0);
+                                                    ne_id, 0, circuit->ext);
                        lsp_debug(
                                "ISIS (%s): Adding %s.%02x as te-style neighbor (peer)",
                                area->area_tag, sysid_print(ne_id),
@@ -1597,7 +1529,7 @@ static void lsp_build_pseudo(struct isis_lsp *lsp, struct isis_circuit *circuit,
 
 int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
 {
-       dict_t *lspdb = circuit->area->lspdb[level - 1];
+       struct lspdb_head *head = &circuit->area->lspdb[level - 1];
        struct isis_lsp *lsp;
        uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
        uint16_t rem_lifetime, refresh_time;
@@ -1615,7 +1547,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
        /*
         * If for some reason have a pseudo LSP in the db already -> regenerate
         */
-       if (lsp_search(lsp_id, lspdb))
+       if (lsp_search(head, lsp_id))
                return lsp_regenerate_schedule_pseudo(circuit, level);
 
        rem_lifetime = lsp_rem_lifetime(circuit->area, level);
@@ -1628,7 +1560,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
        lsp_build_pseudo(lsp, circuit, level);
        lsp_pack_pdu(lsp);
        lsp->own_lsp = 1;
-       lsp_insert(lsp, lspdb);
+       lsp_insert(head, lsp);
        lsp_flood(lsp, NULL);
 
        refresh_time = lsp_refresh_time(lsp, rem_lifetime);
@@ -1659,7 +1591,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
 
 static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
 {
-       dict_t *lspdb = circuit->area->lspdb[level - 1];
+       struct lspdb_head *head = &circuit->area->lspdb[level - 1];
        struct isis_lsp *lsp;
        uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
        uint16_t rem_lifetime, refresh_time;
@@ -1674,7 +1606,7 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
        LSP_PSEUDO_ID(lsp_id) = circuit->circuit_id;
        LSP_FRAGMENT(lsp_id) = 0;
 
-       lsp = lsp_search(lsp_id, lspdb);
+       lsp = lsp_search(head, lsp_id);
 
        if (!lsp) {
                flog_err(EC_LIB_DEVELOPMENT,
@@ -1813,7 +1745,7 @@ int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
                        continue;
                }
 
-               lsp = lsp_search(lsp_id, circuit->area->lspdb[lvl - 1]);
+               lsp = lsp_search(&circuit->area->lspdb[lvl - 1], lsp_id);
                if (!lsp) {
                        sched_debug(
                                "ISIS (%s): Pseudonode LSP does not exist yet, nothing to regenerate.",
@@ -1869,7 +1801,6 @@ int lsp_tick(struct thread *thread)
 {
        struct isis_area *area;
        struct isis_lsp *lsp;
-       dnode_t *dnode, *dnode_next;
        int level;
        uint16_t rem_lifetime;
        bool fabricd_sync_incomplete = false;
@@ -1885,83 +1816,69 @@ int lsp_tick(struct thread *thread)
         * Remove LSPs which have aged out
         */
        for (level = 0; level < ISIS_LEVELS; level++) {
-               if (area->lspdb[level] && dict_count(area->lspdb[level]) > 0) {
-                       for (dnode = dict_first(area->lspdb[level]);
-                            dnode != NULL; dnode = dnode_next) {
-                               dnode_next =
-                                       dict_next(area->lspdb[level], dnode);
-                               lsp = dnode_get(dnode);
-
-                               /*
-                                * The lsp rem_lifetime is kept at 0 for MaxAge
-                                * or
-                                * ZeroAgeLifetime depending on explicit purge
-                                * or
-                                * natural age out. So schedule spf only once
-                                * when
-                                * the first time rem_lifetime becomes 0.
-                                */
-                               rem_lifetime = lsp->hdr.rem_lifetime;
-                               lsp_set_time(lsp);
-
-                               /*
-                                * Schedule may run spf which should be done
-                                * only after
-                                * the lsp rem_lifetime becomes 0 for the first
-                                * time.
-                                * ISO 10589 - 7.3.16.4 first paragraph.
-                                */
-                               if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
-                                       /* 7.3.16.4 a) set SRM flags on all */
-                                       /* 7.3.16.4 b) retain only the header */
-                                       if (lsp->area->purge_originator)
-                                               lsp_purge(lsp, lsp->level, NULL);
-                                       else
-                                               lsp_flood(lsp, NULL);
-                                       /* 7.3.16.4 c) record the time to purge
-                                        * FIXME */
-                                       isis_spf_schedule(lsp->area, lsp->level);
-                               }
+               struct isis_lsp *next = lspdb_first(&area->lspdb[level]);
+               frr_each_from (lspdb, &area->lspdb[level], lsp, next) {
+                       /*
+                        * The lsp rem_lifetime is kept at 0 for MaxAge
+                        * or
+                        * ZeroAgeLifetime depending on explicit purge
+                        * or
+                        * natural age out. So schedule spf only once
+                        * when
+                        * the first time rem_lifetime becomes 0.
+                        */
+                       rem_lifetime = lsp->hdr.rem_lifetime;
+                       lsp_set_time(lsp);
 
-                               if (lsp->age_out == 0) {
-                                       zlog_debug(
-                                               "ISIS-Upd (%s): L%u LSP %s seq "
-                                               "0x%08" PRIx32 " aged out",
-                                               area->area_tag, lsp->level,
-                                               rawlspid_print(lsp->hdr.lsp_id),
-                                               lsp->hdr.seqno);
-
-                                       /* if we're aging out fragment 0,
-                                        * lsp_destroy() below will delete all
-                                        * other fragments too, so we need to
-                                        * skip over those
-                                        */
-                                       while (!LSP_FRAGMENT(lsp->hdr.lsp_id)
-                                                       && dnode_next) {
-                                               struct isis_lsp *nextlsp;
-
-                                               nextlsp = dnode_get(dnode_next);
-                                               if (memcmp(nextlsp->hdr.lsp_id,
-                                                          lsp->hdr.lsp_id,
-                                                          ISIS_SYS_ID_LEN + 1))
-                                                       break;
-
-                                               dnode_next = dict_next(
-                                                       area->lspdb[level],
-                                                       dnode_next);
-                                       }
+                       /*
+                        * Schedule may run spf which should be done
+                        * only after
+                        * the lsp rem_lifetime becomes 0 for the first
+                        * time.
+                        * ISO 10589 - 7.3.16.4 first paragraph.
+                        */
+                       if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
+                               /* 7.3.16.4 a) set SRM flags on all */
+                               /* 7.3.16.4 b) retain only the header */
+                               if (lsp->area->purge_originator)
+                                       lsp_purge(lsp, lsp->level, NULL);
+                               else
+                                       lsp_flood(lsp, NULL);
+                               /* 7.3.16.4 c) record the time to purge
+                                * FIXME */
+                               isis_spf_schedule(lsp->area, lsp->level);
+                       }
 
-                                       lsp_destroy(lsp);
-                                       lsp = NULL;
-                                       dict_delete_free(area->lspdb[level],
-                                                        dnode);
-                               }
+                       if (lsp->age_out == 0) {
+                               zlog_debug(
+                                       "ISIS-Upd (%s): L%u LSP %s seq "
+                                       "0x%08" PRIx32 " aged out",
+                                       area->area_tag, lsp->level,
+                                       rawlspid_print(lsp->hdr.lsp_id),
+                                       lsp->hdr.seqno);
+
+                               /* if we're aging out fragment 0, lsp_destroy()
+                                * below will delete all other fragments too,
+                                * so we need to skip over those
+                                */
+                               if (!LSP_FRAGMENT(lsp->hdr.lsp_id))
+                                       while (next &&
+                                               !memcmp(next->hdr.lsp_id,
+                                                       lsp->hdr.lsp_id,
+                                                       ISIS_SYS_ID_LEN + 1))
+                                               next = lspdb_next(
+                                                       &area->lspdb[level],
+                                                       next);
+
+                               lspdb_del(&area->lspdb[level], lsp);
+                               lsp_destroy(lsp);
+                               lsp = NULL;
+                       }
 
-                               if (fabricd_init_c && lsp) {
-                                       fabricd_sync_incomplete |=
-                                               ISIS_CHECK_FLAG(lsp->SSNflags,
-                                                               fabricd_init_c);
-                               }
+                       if (fabricd_init_c && lsp) {
+                               fabricd_sync_incomplete |=
+                                       ISIS_CHECK_FLAG(lsp->SSNflags,
+                                                       fabricd_init_c);
                        }
                }
        }
@@ -1979,7 +1896,7 @@ void lsp_purge_pseudo(uint8_t *id, struct isis_circuit *circuit, int level)
 {
        struct isis_lsp *lsp;
 
-       lsp = lsp_search(id, circuit->area->lspdb[level - 1]);
+       lsp = lsp_search(&circuit->area->lspdb[level - 1], id);
        if (!lsp)
                return;
 
@@ -2012,7 +1929,7 @@ void lsp_purge_non_exist(int level, struct isis_lsp_hdr *hdr,
 
        lsp_pack_pdu(lsp);
 
-       lsp_insert(lsp, area->lspdb[lsp->level - 1]);
+       lsp_insert(&area->lspdb[lsp->level - 1], lsp);
        lsp_flood(lsp, NULL);
 
        return;