]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: optimize per interface lsp send-queue creation
authorChristian Franke <chris@opensourcerouting.org>
Mon, 2 Oct 2017 23:42:22 +0000 (01:42 +0200)
committerChristian Franke <chris@opensourcerouting.org>
Tue, 3 Oct 2017 12:20:30 +0000 (14:20 +0200)
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
isisd/isis_adjacency.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_constants.h
isisd/isis_lsp.c
isisd/isis_lsp_hash.c [new file with mode: 0644]
isisd/isis_lsp_hash.h [new file with mode: 0644]
isisd/isis_pdu.c
isisd/subdir.am

index 0afa65d726914aba336a0074f0d02729860d6191..c8b9a66e294a7ea39a88e183f78b01fc491a0151 100644 (file)
@@ -214,13 +214,11 @@ void isis_adj_state_change(struct isis_adjacency *adj,
                        } else if (new_state == ISIS_ADJ_DOWN) {
                                listnode_delete(circuit->u.bc.adjdb[level - 1],
                                                adj);
+
                                circuit->upadjcount[level - 1]--;
-                               if (circuit->upadjcount[level - 1] == 0) {
-                                       /* Clean lsp_queue when no adj is up. */
-                                       if (circuit->lsp_queue)
-                                               list_delete_all_node(
-                                                       circuit->lsp_queue);
-                               }
+                               if (circuit->upadjcount[level - 1] == 0)
+                                       isis_circuit_lsp_queue_clean(circuit);
+
                                isis_event_adjacency_state_change(adj,
                                                                  new_state);
                                del = true;
@@ -270,12 +268,9 @@ void isis_adj_state_change(struct isis_adjacency *adj,
                                if (adj->circuit->u.p2p.neighbor == adj)
                                        adj->circuit->u.p2p.neighbor = NULL;
                                circuit->upadjcount[level - 1]--;
-                               if (circuit->upadjcount[level - 1] == 0) {
-                                       /* Clean lsp_queue when no adj is up. */
-                                       if (circuit->lsp_queue)
-                                               list_delete_all_node(
-                                                       circuit->lsp_queue);
-                               }
+                               if (circuit->upadjcount[level - 1] == 0)
+                                       isis_circuit_lsp_queue_clean(circuit);
+
                                isis_event_adjacency_state_change(adj,
                                                                  new_state);
                                del = true;
index 1a978ee0423a5553c68c87c2727827b321037075..1c1385ab77a4c72640b617a8a59870ed8a9a4a0e 100644 (file)
@@ -45,6 +45,7 @@
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_lsp.h"
+#include "isisd/isis_lsp_hash.h"
 #include "isisd/isis_pdu.h"
 #include "isisd/isis_network.h"
 #include "isisd/isis_misc.h"
@@ -674,7 +675,8 @@ int isis_circuit_up(struct isis_circuit *circuit)
        isis_circuit_prepare(circuit);
 
        circuit->lsp_queue = list_new();
-       circuit->lsp_queue_last_cleared = time(NULL);
+       circuit->lsp_hash = isis_lsp_hash_new();
+       monotime(&circuit->lsp_queue_last_cleared);
 
        return ISIS_OK;
 }
@@ -739,14 +741,19 @@ void isis_circuit_down(struct isis_circuit *circuit)
        THREAD_TIMER_OFF(circuit->t_send_csnp[1]);
        THREAD_TIMER_OFF(circuit->t_send_psnp[0]);
        THREAD_TIMER_OFF(circuit->t_send_psnp[1]);
+       THREAD_OFF(circuit->t_send_lsp);
        THREAD_OFF(circuit->t_read);
 
        if (circuit->lsp_queue) {
-               circuit->lsp_queue->del = NULL;
                list_delete(circuit->lsp_queue);
                circuit->lsp_queue = NULL;
        }
 
+       if (circuit->lsp_hash) {
+               isis_lsp_hash_free(circuit->lsp_hash);
+               circuit->lsp_hash = NULL;
+       }
+
        /* send one gratuitous hello to spead up convergence */
        if (circuit->is_type & IS_LEVEL_1)
                send_hello(circuit, IS_LEVEL_1);
@@ -1339,3 +1346,56 @@ void isis_circuit_init()
 
        isis_vty_init();
 }
+
+void isis_circuit_schedule_lsp_send(struct isis_circuit *circuit)
+{
+       if (circuit->t_send_lsp)
+               return;
+       circuit->t_send_lsp = thread_add_event(master, send_lsp, circuit, 0, NULL);
+}
+
+void isis_circuit_queue_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp)
+{
+       if (isis_lsp_hash_lookup(circuit->lsp_hash, lsp))
+               return;
+
+       listnode_add(circuit->lsp_queue, lsp);
+       isis_lsp_hash_add(circuit->lsp_hash, lsp);
+       isis_circuit_schedule_lsp_send(circuit);
+}
+
+void isis_circuit_lsp_queue_clean(struct isis_circuit *circuit)
+{
+       if (!circuit->lsp_queue)
+               return;
+
+       list_delete_all_node(circuit->lsp_queue);
+       isis_lsp_hash_clean(circuit->lsp_hash);
+}
+
+void isis_circuit_cancel_queued_lsp(struct isis_circuit *circuit,
+                                   struct isis_lsp *lsp)
+{
+       if (!circuit->lsp_queue)
+               return;
+
+       listnode_delete(circuit->lsp_queue, lsp);
+       isis_lsp_hash_release(circuit->lsp_hash, lsp);
+}
+
+struct isis_lsp *isis_circuit_lsp_queue_pop(struct isis_circuit *circuit)
+{
+       if (!circuit->lsp_queue)
+               return NULL;
+
+       struct listnode *node = listhead(circuit->lsp_queue);
+       if (!node)
+               return NULL;
+
+       struct isis_lsp *rv = listgetdata(node);
+
+       list_delete_node(circuit->lsp_queue, node);
+       isis_lsp_hash_release(circuit->lsp_hash, rv);
+
+       return rv;
+}
index 5906efd2b8af205925f2667588555d3f547933f8..29694deb349584ccf6de0ab182566c5520f1472c 100644 (file)
@@ -34,6 +34,8 @@
 
 #define CIRCUIT_MAX 255
 
+struct isis_lsp;
+
 struct password {
        struct password *next;
        int len;
@@ -79,8 +81,10 @@ struct isis_circuit {
        struct thread *t_read;
        struct thread *t_send_csnp[2];
        struct thread *t_send_psnp[2];
+       struct thread *t_send_lsp;
        struct list *lsp_queue; /* LSPs to be txed (both levels) */
-       time_t lsp_queue_last_cleared; /* timestamp used to enforce transmit
+       struct isis_lsp_hash *lsp_hash; /* Hashtable synchronized with lsp_queue */
+       struct timeval lsp_queue_last_cleared; /* timestamp used to enforce transmit
                                        * interval;
                                        * for scalability, use one timestamp per
                                        * circuit, instead of one per lsp per
@@ -195,4 +199,10 @@ ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit,
 int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid,
                                bool enabled);
 
+void isis_circuit_schedule_lsp_send(struct isis_circuit *circuit);
+void isis_circuit_queue_lsp(struct isis_circuit *circuit, struct isis_lsp *lsp);
+void isis_circuit_lsp_queue_clean(struct isis_circuit *circuit);
+void isis_circuit_cancel_queued_lsp(struct isis_circuit *circuit,
+                                   struct isis_lsp *lsp);
+struct isis_lsp *isis_circuit_lsp_queue_pop(struct isis_circuit *circuit);
 #endif /* _ZEBRA_ISIS_CIRCUIT_H */
index f3a5a24dde577b0ca62913837b686c71ce99b431..b7b5d35c2e6df30671caab0c452ed0a406a30f4c 100644 (file)
@@ -73,7 +73,7 @@
 #define MAX_MIN_LSP_GEN_INTERVAL      120  /* RFC 4444 says 65535 */
 #define DEFAULT_MIN_LSP_GEN_INTERVAL  30
 
-#define MIN_LSP_TRANS_INTERVAL        5
+#define MIN_LSP_TRANS_INTERVAL        20000 /* Microseconds */
 
 #define MIN_CSNP_INTERVAL             1
 #define MAX_CSNP_INTERVAL             600
index 33c52804e4a60e0668ec5794c322697c920cf278..bee6abfdab9c182b837ec7eedfb6216c2805a8ea 100644 (file)
@@ -111,25 +111,15 @@ static void lsp_clear_data(struct isis_lsp *lsp)
 
 static void lsp_destroy(struct isis_lsp *lsp)
 {
-       struct listnode *cnode, *lnode, *lnnode;
-       struct isis_lsp *lsp_in_list;
+       struct listnode *cnode;
        struct isis_circuit *circuit;
 
        if (!lsp)
                return;
 
-       if (lsp->area->circuit_list) {
-               for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode,
-                                         circuit)) {
-                       if (circuit->lsp_queue == NULL)
-                               continue;
-                       for (ALL_LIST_ELEMENTS(circuit->lsp_queue, lnode,
-                                              lnnode, lsp_in_list))
-                               if (lsp_in_list == lsp)
-                                       list_delete_node(circuit->lsp_queue,
-                                                        lnode);
-               }
-       }
+       for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode, circuit))
+               isis_circuit_cancel_queued_lsp(circuit, lsp);
+
        ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
        ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
 
@@ -1890,12 +1880,15 @@ int lsp_tick(struct thread *thread)
                        if (listcount(lsp_list) > 0) {
                                for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
                                                          cnode, circuit)) {
-                                       int diff =
-                                               time(NULL)
-                                               - circuit->lsp_queue_last_cleared;
-                                       if (circuit->lsp_queue == NULL
-                                           || diff < MIN_LSP_TRANS_INTERVAL)
+                                       if (!circuit->lsp_queue)
                                                continue;
+
+                                       if (monotime_since(
+                                                 &circuit->lsp_queue_last_cleared,
+                                                 NULL) < MIN_LSP_TRANS_INTERVAL) {
+                                               continue;
+                                       }
+
                                        for (ALL_LIST_ELEMENTS_RO(
                                                     lsp_list, lspnode, lsp)) {
                                                if (circuit->upadjcount
@@ -1903,23 +1896,7 @@ int lsp_tick(struct thread *thread)
                                                    && ISIS_CHECK_FLAG(
                                                               lsp->SRMflags,
                                                               circuit)) {
-                                                       /* Add the lsp only if
-                                                        * it is not already in
-                                                        * lsp
-                                                        * queue */
-                                                       if (!listnode_lookup(
-                                                                   circuit->lsp_queue,
-                                                                   lsp)) {
-                                                               listnode_add(
-                                                                       circuit->lsp_queue,
-                                                                       lsp);
-                                                               thread_add_event(
-                                                                       master,
-                                                                       send_lsp,
-                                                                       circuit,
-                                                                       0,
-                                                                       NULL);
-                                                       }
+                                                       isis_circuit_queue_lsp(circuit, lsp);
                                                }
                                        }
                                }
diff --git a/isisd/isis_lsp_hash.c b/isisd/isis_lsp_hash.c
new file mode 100644 (file)
index 0000000..9196128
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * IS-IS Rout(e)ing protocol - LSP Hash
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "hash.h"
+#include "jhash.h"
+
+#include "isisd/isis_memory.h"
+#include "isisd/isis_flags.h"
+#include "dict.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_lsp_hash.h"
+
+DEFINE_MTYPE_STATIC(ISISD, LSP_HASH, "ISIS LSP Hash")
+
+struct isis_lsp_hash {
+       struct hash *h;
+};
+
+static unsigned lsp_hash_key(void *lp)
+{
+       struct isis_lsp *lsp = lp;
+
+       return jhash(lsp->hdr.lsp_id, ISIS_SYS_ID_LEN + 2, 0x55aa5a5a);
+}
+
+static int lsp_hash_cmp(const void *a, const void *b)
+{
+       const struct isis_lsp *la = a, *lb = b;
+
+       return 0 == memcmp(la->hdr.lsp_id, lb->hdr.lsp_id, ISIS_SYS_ID_LEN + 2);
+}
+
+struct isis_lsp_hash *isis_lsp_hash_new(void)
+{
+       struct isis_lsp_hash *rv = XCALLOC(MTYPE_LSP_HASH, sizeof(*rv));
+
+       rv->h = hash_create(lsp_hash_key, lsp_hash_cmp, NULL);
+       return rv;
+}
+
+void isis_lsp_hash_clean(struct isis_lsp_hash *ih)
+{
+       hash_clean(ih->h, NULL);
+}
+
+void isis_lsp_hash_free(struct isis_lsp_hash *ih)
+{
+       isis_lsp_hash_clean(ih);
+       hash_free(ih->h);
+}
+
+struct isis_lsp *isis_lsp_hash_lookup(struct isis_lsp_hash *ih,
+                           struct isis_lsp *lsp)
+{
+       return hash_lookup(ih->h, lsp);
+}
+
+void isis_lsp_hash_add(struct isis_lsp_hash *ih, struct isis_lsp *lsp)
+{
+       struct isis_lsp *inserted;
+       inserted = hash_get(ih->h, lsp, hash_alloc_intern);
+       assert(inserted == lsp);
+}
+
+void isis_lsp_hash_release(struct isis_lsp_hash *ih, struct isis_lsp *lsp)
+{
+       hash_release(ih->h, lsp);
+}
diff --git a/isisd/isis_lsp_hash.h b/isisd/isis_lsp_hash.h
new file mode 100644 (file)
index 0000000..b50aa09
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * IS-IS Rout(e)ing protocol - LSP Hash
+ *
+ * Copyright (C) 2017 Christian Franke
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef ISIS_LSP_HASH_H
+#define ISIS_LSP_HASH_H
+
+struct isis_lsp_hash;
+
+struct isis_lsp_hash *isis_lsp_hash_new(void);
+void isis_lsp_hash_clean(struct isis_lsp_hash *ih);
+void isis_lsp_hash_free(struct isis_lsp_hash *ih);
+struct isis_lsp *isis_lsp_hash_lookup(struct isis_lsp_hash *ih,
+                                     struct isis_lsp *lsp);
+void isis_lsp_hash_add(struct isis_lsp_hash *ih, struct isis_lsp *lsp);
+void isis_lsp_hash_release(struct isis_lsp_hash *ih, struct isis_lsp *lsp);
+#endif
index a20051f8c366f7b4152f689bb554e0086cb1b6be..2f9e3caf1ccb8f3194d01172dbca57d00c38d18c 100644 (file)
@@ -2046,39 +2046,24 @@ int send_lsp(struct thread *thread)
 {
        struct isis_circuit *circuit;
        struct isis_lsp *lsp;
-       struct listnode *node;
        int clear_srm = 1;
        int retval = ISIS_OK;
 
        circuit = THREAD_ARG(thread);
        assert(circuit);
+       circuit->t_send_lsp = NULL;
 
-       if (!circuit->lsp_queue)
+       lsp = isis_circuit_lsp_queue_pop(circuit);
+       if (!lsp)
                return ISIS_OK;
-
-       node = listhead(circuit->lsp_queue);
-
-       /*
-        * Handle case where there are no LSPs on the queue. This can
-        * happen, for instance, if an adjacency goes down before this
-        * thread gets a chance to run.
-        */
-       if (!node)
-               return ISIS_OK;
-
-       /*
-        * Delete LSP from lsp_queue. If it's still in queue, it is assumed
-        * as 'transmit pending', but send_lsp may never be called again.
-        * Retry will happen because SRM flag will not be cleared.
-        */
-       lsp = listgetdata(node);
-       list_delete_node(circuit->lsp_queue, node);
-
        /* Set the last-cleared time if the queue is empty. */
        /* TODO: Is is possible that new lsps keep being added to the queue
         * that the queue is never empty? */
-       if (list_isempty(circuit->lsp_queue))
-               circuit->lsp_queue_last_cleared = time(NULL);
+       if (list_isempty(circuit->lsp_queue)) {
+               monotime(&circuit->lsp_queue_last_cleared);
+       } else {
+               isis_circuit_schedule_lsp_send(circuit);
+       }
 
        if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
                goto out;
index 6e49d4ec80ac0424c571d861df1f37ad3c16e333..7b56715fa917fa504782ecc0385106d0e181ab3c 100644 (file)
@@ -18,6 +18,7 @@ isisd_libisis_a_SOURCES = \
        isisd/isis_events.c \
        isisd/isis_flags.c \
        isisd/isis_lsp.c \
+       isisd/isis_lsp_hash.c \
        isisd/isis_memory.c \
        isisd/isis_misc.c \
        isisd/isis_mt.c \
@@ -46,6 +47,7 @@ noinst_HEADERS += \
        isisd/isis_events.h \
        isisd/isis_flags.h \
        isisd/isis_lsp.h \
+       isisd/isis_lsp_hash.h \
        isisd/isis_memory.h \
        isisd/isis_misc.h \
        isisd/isis_mt.h \