]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: per-instance dynamic hostname cache
authorIgor Ryzhov <iryzhov@nfware.com>
Fri, 11 Jun 2021 15:27:46 +0000 (18:27 +0300)
committerIgor Ryzhov <iryzhov@nfware.com>
Fri, 18 Jun 2021 14:00:15 +0000 (17:00 +0300)
Currently, the dynamic hostname cache is global. It is incorrect because
neighbors in different VRFs may have the same system ID and different
hostnames.

This also fixes a memory leak - when the instance is deleted, the cache
must be cleaned up and the cleanup thread must be cancelled.

Fixes #8832.

Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
isisd/isis_adjacency.c
isisd/isis_dynhn.c
isisd/isis_dynhn.h
isisd/isis_lsp.c
isisd/isis_misc.c
isisd/isis_nb_notifications.c
isisd/isis_snmp.c
isisd/isisd.c
isisd/isisd.h
tests/isisd/test_common.c
tests/isisd/test_isis_spf.c

index c1f5e49ecaf0296a2b3385b38853b8f2dd482ebd..ffda0f8643bc5932d8d12874ade83a61bac6ccc6 100644 (file)
@@ -270,7 +270,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj)
 
        struct isis_dynhn *dyn;
 
-       dyn = dynhn_find_by_id(adj->sysid);
+       dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
        if (dyn)
                return dyn->hostname;
        else
@@ -401,7 +401,7 @@ void isis_adj_print(struct isis_adjacency *adj)
 
        if (!adj)
                return;
-       dyn = dynhn_find_by_id(adj->sysid);
+       dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
        if (dyn)
                zlog_debug("%s", dyn->hostname);
 
@@ -537,7 +537,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                vty_out(vty, "    SNPA: %s", snpa_print(adj->snpa));
                if (adj->circuit
                    && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
-                       dyn = dynhn_find_by_id(adj->lanid);
+                       dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
                        if (dyn)
                                vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
                                        adj->lanid[ISIS_SYS_ID_LEN]);
index decd3e8922810f3947ff92d86575a094b9ed36c5..ade6e8222023a715c61640eea949d01e2a88d168 100644 (file)
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_DYNHN, "ISIS dyn hostname");
 
-extern struct host host;
-
-struct list *dyn_cache = NULL;
 static int dyn_cache_cleanup(struct thread *);
 
 void dyn_cache_init(struct isis *isis)
 {
-       if (dyn_cache == NULL)
-               dyn_cache = list_new();
+       isis->dyn_cache = list_new();
        if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
                thread_add_timer(master, dyn_cache_cleanup, isis, 120,
                                 &isis->t_dync_clean);
-       return;
 }
 
-void dyn_cache_cleanup_all(void)
+void dyn_cache_finish(struct isis *isis)
 {
        struct listnode *node, *nnode;
        struct isis_dynhn *dyn;
 
-       for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) {
-               list_delete_node(dyn_cache, node);
+       thread_cancel(&isis->t_dync_clean);
+
+       for (ALL_LIST_ELEMENTS(isis->dyn_cache, node, nnode, dyn)) {
+               list_delete_node(isis->dyn_cache, node);
                XFREE(MTYPE_ISIS_DYNHN, dyn);
        }
+
+       list_delete(&isis->dyn_cache);
 }
 
 static int dyn_cache_cleanup(struct thread *thread)
@@ -79,10 +78,10 @@ static int dyn_cache_cleanup(struct thread *thread)
 
        isis->t_dync_clean = NULL;
 
-       for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) {
+       for (ALL_LIST_ELEMENTS(isis->dyn_cache, node, nnode, dyn)) {
                if ((now - dyn->refresh) < MAX_LSP_LIFETIME)
                        continue;
-               list_delete_node(dyn_cache, node);
+               list_delete_node(isis->dyn_cache, node);
                XFREE(MTYPE_ISIS_DYNHN, dyn);
        }
 
@@ -92,54 +91,55 @@ static int dyn_cache_cleanup(struct thread *thread)
        return ISIS_OK;
 }
 
-struct isis_dynhn *dynhn_find_by_id(const uint8_t *id)
+struct isis_dynhn *dynhn_find_by_id(struct isis *isis, const uint8_t *id)
 {
        struct listnode *node = NULL;
        struct isis_dynhn *dyn = NULL;
 
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn))
                if (memcmp(dyn->id, id, ISIS_SYS_ID_LEN) == 0)
                        return dyn;
 
        return NULL;
 }
 
-struct isis_dynhn *dynhn_find_by_name(const char *hostname)
+struct isis_dynhn *dynhn_find_by_name(struct isis *isis, const char *hostname)
 {
        struct listnode *node = NULL;
        struct isis_dynhn *dyn = NULL;
 
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn))
                if (strncmp(dyn->hostname, hostname, 255) == 0)
                        return dyn;
 
        return NULL;
 }
 
-void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level)
+void isis_dynhn_insert(struct isis *isis, const uint8_t *id,
+                      const char *hostname, int level)
 {
        struct isis_dynhn *dyn;
 
-       dyn = dynhn_find_by_id(id);
+       dyn = dynhn_find_by_id(isis, id);
        if (!dyn) {
                dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn));
                memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
                dyn->level = level;
-               listnode_add(dyn_cache, dyn);
+               listnode_add(isis->dyn_cache, dyn);
        }
 
        snprintf(dyn->hostname, sizeof(dyn->hostname), "%s", hostname);
        dyn->refresh = time(NULL);
 }
 
-void isis_dynhn_remove(const uint8_t *id)
+void isis_dynhn_remove(struct isis *isis, const uint8_t *id)
 {
        struct isis_dynhn *dyn;
 
-       dyn = dynhn_find_by_id(id);
+       dyn = dynhn_find_by_id(isis, id);
        if (!dyn)
                return;
-       listnode_delete(dyn_cache, dyn);
+       listnode_delete(isis->dyn_cache, dyn);
        XFREE(MTYPE_ISIS_DYNHN, dyn);
 }
 
@@ -158,7 +158,7 @@ void dynhn_print_all(struct vty *vty, struct isis *isis)
        if (!isis->sysid_set)
                return;
        vty_out(vty, "Level  System ID      Dynamic Hostname\n");
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn)) {
                vty_out(vty, "%-7d", dyn->level);
                vty_out(vty, "%-15s%-15s\n", sysid_print(dyn->id),
                        dyn->hostname);
@@ -169,14 +169,15 @@ void dynhn_print_all(struct vty *vty, struct isis *isis)
        return;
 }
 
-struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level)
+struct isis_dynhn *dynhn_snmp_next(struct isis *isis, const uint8_t *id,
+                                  int level)
 {
        struct listnode *node = NULL;
        struct isis_dynhn *dyn = NULL;
        struct isis_dynhn *found_dyn = NULL;
        int res;
 
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn)) {
                res = memcmp(dyn->id, id, ISIS_SYS_ID_LEN);
 
                if (res < 0)
index 8d25582e49c3fc635a59d241337de4de5c9853d4..afb8b51b1fbf66a4b825a1fd47e59323f6a19891 100644 (file)
@@ -31,14 +31,16 @@ struct isis_dynhn {
 };
 
 void dyn_cache_init(struct isis *isis);
-void dyn_cache_cleanup_all(void);
-void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level);
-void isis_dynhn_remove(const uint8_t *id);
-struct isis_dynhn *dynhn_find_by_id(const uint8_t *id);
-struct isis_dynhn *dynhn_find_by_name(const char *hostname);
+void dyn_cache_finish(struct isis *isis);
+void isis_dynhn_insert(struct isis *isis, const uint8_t *id,
+                      const char *hostname, int level);
+void isis_dynhn_remove(struct isis *isis, const uint8_t *id);
+struct isis_dynhn *dynhn_find_by_id(struct isis *isis, const uint8_t *id);
+struct isis_dynhn *dynhn_find_by_name(struct isis *isis, const char *hostname);
 void dynhn_print_all(struct vty *vty, struct isis *isis);
 
 /* Snmp support */
-struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level);
+struct isis_dynhn *dynhn_snmp_next(struct isis *isis, const uint8_t *id,
+                                  int level);
 
 #endif /* _ZEBRA_ISIS_DYNHN_H */
index 056e29e8de81c78e34a15604b986f0d5e1ae7638..814ba8fc2a130c4cd802f4e2bdff4da309989d8f 100644 (file)
@@ -533,11 +533,11 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
 
        if (area->dynhostname && lsp->tlvs->hostname
            && lsp->hdr.rem_lifetime) {
-               isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname,
-                                 (lsp->hdr.lsp_bits & LSPBIT_IST)
-                                                 == IS_LEVEL_1_AND_2
-                                         ? IS_LEVEL_2
-                                         : IS_LEVEL_1);
+               isis_dynhn_insert(
+                       area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname,
+                       (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2
+                               ? IS_LEVEL_2
+                               : IS_LEVEL_1);
        }
 
        return;
@@ -700,7 +700,7 @@ void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
        char id[SYSID_STRLEN];
 
        if (dynhost)
-               dyn = dynhn_find_by_id(lsp_id);
+               dyn = dynhn_find_by_id(isis, lsp_id);
        else
                dyn = NULL;
 
index d3d081d37624c7cc5ec3e4b4b5634c6bd65bcb60..d49ad8485ec7bb2bc80ad3ebd1c4e1577bc2447d 100644 (file)
@@ -458,6 +458,7 @@ const char *print_sys_hostname(const uint8_t *sysid)
 {
        struct isis_dynhn *dyn;
        struct isis *isis = NULL;
+       struct listnode *node;
 
        if (!sysid)
                return "nullsysid";
@@ -467,9 +468,11 @@ const char *print_sys_hostname(const uint8_t *sysid)
        if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
                return cmd_hostname_get();
 
-       dyn = dynhn_find_by_id(sysid);
-       if (dyn)
-               return dyn->hostname;
+       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+               dyn = dynhn_find_by_id(isis, sysid);
+               if (dyn)
+                       return dyn->hostname;
+       }
 
        return sysid_print(sysid);
 }
index 755378a9b7ecde5ef1bd44e246dc14fb400bad56..f219632acf794c0f22d0ed64ffacd5cbdd14a76d 100644 (file)
@@ -315,7 +315,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj,
        struct yang_data *data;
        struct isis_circuit *circuit = adj->circuit;
        struct isis_area *area = circuit->area;
-       struct isis_dynhn *dyn = dynhn_find_by_id(adj->sysid);
+       struct isis_dynhn *dyn = dynhn_find_by_id(circuit->isis, adj->sysid);
 
        notif_prep_instance_hdr(xpath, area, "default", arguments);
        notif_prepr_iface_hdr(xpath, circuit, arguments);
index fa2f9a7669357fe98752fc8fc0553184636a159d..d530faa151856aeb4214da66652a4da1ddc5f1df 100644 (file)
@@ -1654,6 +1654,10 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
        oid *oid_idx;
        size_t oid_idx_len;
        size_t off = 0;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       if (isis == NULL)
+               return NULL;
 
        *write_method = NULL;
 
@@ -1687,7 +1691,7 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
 
                cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
 
-               dyn = dynhn_find_by_id(cmp_buf);
+               dyn = dynhn_find_by_id(isis, cmp_buf);
 
                if (dyn == NULL || dyn->level != cmp_level)
                        return NULL;
@@ -1739,7 +1743,7 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
                 */
                cmp_level = (int)(IS_LEVEL_2 + 1);
 
-       dyn = dynhn_snmp_next(cmp_buf, cmp_level);
+       dyn = dynhn_snmp_next(isis, cmp_buf, cmp_level);
 
        if (dyn == NULL)
                return NULL;
index 05d87419913f5bdfa40e46c6e552deb642910db1..7f56903fc9be3745b6ded94eef59db44c4c6eee0 100644 (file)
@@ -229,6 +229,7 @@ void isis_finish(struct isis *isis)
 
        isis_redist_free(isis);
        list_delete(&isis->area_list);
+       dyn_cache_finish(isis);
        XFREE(MTYPE_ISIS, isis);
 }
 
@@ -1076,6 +1077,23 @@ DEFUN(show_isis_interface_arg,
                                          vrf_name, all_vrf);
 }
 
+static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid)
+{
+       struct isis_dynhn *dynhn;
+
+       memset(sysid, 0, ISIS_SYS_ID_LEN);
+       if (id) {
+               if (sysid2buff(sysid, id) == 0) {
+                       dynhn = dynhn_find_by_name(isis, id);
+                       if (dynhn == NULL)
+                               return -1;
+                       memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
+               }
+       }
+
+       return 0;
+}
+
 static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
                                 struct isis *isis, uint8_t *sysid)
 {
@@ -1131,7 +1149,6 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
                              const char *vrf_name, bool all_vrf)
 {
        struct listnode *node;
-       struct isis_dynhn *dynhn;
        uint8_t sysid[ISIS_SYS_ID_LEN];
        struct isis *isis;
 
@@ -1140,29 +1157,27 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
                return CMD_SUCCESS;
        }
 
-       memset(sysid, 0, ISIS_SYS_ID_LEN);
-       if (id) {
-               if (sysid2buff(sysid, id) == 0) {
-                       dynhn = dynhn_find_by_name(id);
-                       if (dynhn == NULL) {
-                               vty_out(vty, "Invalid system id %s\n", id);
-                               return CMD_SUCCESS;
-                       }
-                       memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
-               }
-       }
-
        if (vrf_name) {
                if (all_vrf) {
                        for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+                               if (id_to_sysid(isis, id, sysid)) {
+                                       vty_out(vty, "Invalid system id %s\n",
+                                               id);
+                                       return CMD_SUCCESS;
+                               }
                                isis_neighbor_common(vty, id, detail, isis,
                                                     sysid);
                        }
                        return CMD_SUCCESS;
                }
                isis = isis_lookup_by_vrfname(vrf_name);
-               if (isis != NULL)
+               if (isis != NULL) {
+                       if (id_to_sysid(isis, id, sysid)) {
+                               vty_out(vty, "Invalid system id %s\n", id);
+                               return CMD_SUCCESS;
+                       }
                        isis_neighbor_common(vty, id, detail, isis, sysid);
+               }
        }
 
        return CMD_SUCCESS;
@@ -1218,7 +1233,6 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
                               bool all_vrf)
 {
        struct listnode *node;
-       struct isis_dynhn *dynhn;
        uint8_t sysid[ISIS_SYS_ID_LEN];
        struct isis *isis;
 
@@ -1227,27 +1241,27 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
                return CMD_SUCCESS;
        }
 
-       memset(sysid, 0, ISIS_SYS_ID_LEN);
-       if (id) {
-               if (sysid2buff(sysid, id) == 0) {
-                       dynhn = dynhn_find_by_name(id);
-                       if (dynhn == NULL) {
-                               vty_out(vty, "Invalid system id %s\n", id);
-                               return CMD_SUCCESS;
-                       }
-                       memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
-               }
-       }
        if (vrf_name) {
                if (all_vrf) {
-                       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
+                       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+                               if (id_to_sysid(isis, id, sysid)) {
+                                       vty_out(vty, "Invalid system id %s\n",
+                                               id);
+                                       return CMD_SUCCESS;
+                               }
                                isis_neighbor_common_clear(vty, id, sysid,
                                                           isis);
+                       }
                        return CMD_SUCCESS;
                }
                isis = isis_lookup_by_vrfname(vrf_name);
-               if (isis != NULL)
+               if (isis != NULL) {
+                       if (id_to_sysid(isis, id, sysid)) {
+                               vty_out(vty, "Invalid system id %s\n", id);
+                               return CMD_SUCCESS;
+                       }
                        isis_neighbor_common_clear(vty, id, sysid, isis);
+               }
        }
 
        return CMD_SUCCESS;
@@ -2204,7 +2218,7 @@ struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
         */
        if (sysid2buff(lspid, sysid)) {
                lsp = lsp_search(head, lspid);
-       } else if ((dynhn = dynhn_find_by_name(sysid))) {
+       } else if ((dynhn = dynhn_find_by_name(isis, sysid))) {
                memcpy(lspid, dynhn->id, ISIS_SYS_ID_LEN);
                lsp = lsp_search(head, lspid);
        } else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) {
index 9d0b57e9f6834ba4040f02c6da4d3ce5bf0e7eea..b2c9af55b78faf157074d71b5f2cf6edf38531c4 100644 (file)
@@ -95,6 +95,7 @@ struct isis {
        struct thread *t_dync_clean;      /* dynamic hostname cache cleanup thread */
        uint32_t circuit_ids_used[8];     /* 256 bits to track circuit ids 1 through 255 */
        int snmp_notifications;
+       struct list *dyn_cache;
 
        struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
 };
index 5b2028ffd409600a284f97bbf8f5e5060a808190..ade3573535617a40b709282b9118ab4eb35c338e 100644 (file)
@@ -309,7 +309,8 @@ static int topology_load_node(const struct isis_topology *topology,
 {
        int ret;
 
-       isis_dynhn_insert(tnode->sysid, tnode->hostname, tnode->level);
+       isis_dynhn_insert(area->isis, tnode->sysid, tnode->hostname,
+                         tnode->level);
 
        for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
                if ((tnode->level & level) == 0)
index b89a5a008ee7cbf1030d7fae3d0389c07bc47e44..a30f33ccade1797d4f347023f1387674747785f1 100644 (file)
@@ -269,7 +269,7 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
                if (sysid2buff(fail_id, fail_sysid_str) == 0) {
                        struct isis_dynhn *dynhn;
 
-                       dynhn = dynhn_find_by_name(fail_sysid_str);
+                       dynhn = dynhn_find_by_name(area->isis, fail_sysid_str);
                        if (dynhn == NULL) {
                                vty_out(vty, "Invalid system id %s\n",
                                        fail_sysid_str);
@@ -339,9 +339,6 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
        /* Cleanup IS-IS area. */
        isis_area_destroy(area);
 
-       /* Cleanup hostnames. */
-       dyn_cache_cleanup_all();
-
        return CMD_SUCCESS;
 }