]> git.puffer.fish Git - matthieu/frr.git/commitdiff
fabricd: reimplement LSP transmission logic
authorChristian Franke <chris@opensourcerouting.org>
Thu, 10 May 2018 15:37:05 +0000 (17:37 +0200)
committerChristian Franke <chris@opensourcerouting.org>
Wed, 5 Sep 2018 09:38:13 +0000 (11:38 +0200)
Before this commit, isisd/fabricd maintained a bitfield for each LSP
to track the SRM bit for each circuit, which specifies whether an LSP
needs to be sent on that circuit. Every second, it would scan over all
LSPs in `lsp_tick` and queue them up for transmission accordingly.

This design has two drawbacks: a) it scales poorly b) it adds
unacceptable latency to the update process: each router takes a random
amount of time between 0 and 1 seconds to forward an update. In a
network with a diamter of 10, it might already take 10 seconds for an
update to traverse the network.

To mitigate this, a new design was chosen. Instead of tracking SRM in a
bitfield, have one tx_queue per circuit and declare that an LSP is in
that queue if and only if it would have SRM set for that circuit.

This way, we can track SRM similarly as we did before, however, on
insertion into the LSP queue, we can add a timer for (re)transmission,
alleviating the need for a periodic scan with LSP tick and reducing the
latency for forwarding of updates.

Signed-off-by: Christian Franke <chris@opensourcerouting.org>
13 files changed:
isisd/fabricd.c
isisd/isis_adjacency.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_lsp_hash.c [deleted file]
isisd/isis_lsp_hash.h [deleted file]
isisd/isis_pdu.c
isisd/isis_pdu.h
isisd/isis_tx_queue.c [new file with mode: 0644]
isisd/isis_tx_queue.h [new file with mode: 0644]
isisd/subdir.am

index 5effcd83df8b98c7b27935abbf5781e2c72ff237..fe8731c8d09a7a84f25be7b0a7079d82fcc8940e 100644 (file)
@@ -29,6 +29,7 @@
 #include "isisd/isis_spf.h"
 #include "isisd/isis_tlvs.h"
 #include "isisd/isis_lsp.h"
+#include "isisd/isis_tx_queue.h"
 
 DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
 
index 56dbc25829c850ad19b49105ee1b7ddd237518ad..a41d6ff8152267214bb99680de920d8654d6a8c8 100644 (file)
@@ -268,7 +268,7 @@ void isis_adj_state_change(struct isis_adjacency *adj,
 
                                circuit->upadjcount[level - 1]--;
                                if (circuit->upadjcount[level - 1] == 0)
-                                       isis_circuit_lsp_queue_clean(circuit);
+                                       isis_tx_queue_clean(circuit->tx_queue);
 
                                isis_event_adjacency_state_change(adj,
                                                                  new_state);
@@ -324,7 +324,7 @@ void isis_adj_state_change(struct isis_adjacency *adj,
                                        adj->circuit->u.p2p.neighbor = NULL;
                                circuit->upadjcount[level - 1]--;
                                if (circuit->upadjcount[level - 1] == 0)
-                                       isis_circuit_lsp_queue_clean(circuit);
+                                       isis_tx_queue_clean(circuit->tx_queue);
 
                                isis_event_adjacency_state_change(adj,
                                                                  new_state);
index 7ecc71023f7224090e38858e6e07d7cbd18d77c6..817a44bafe66fad4e2598c7f30d6d8b360a0559c 100644 (file)
@@ -45,7 +45,6 @@
 #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"
@@ -58,6 +57,7 @@
 #include "isisd/isis_te.h"
 #include "isisd/isis_mt.h"
 #include "isisd/isis_errors.h"
+#include "isisd/isis_tx_queue.h"
 
 DEFINE_QOBJ_TYPE(isis_circuit)
 
@@ -495,29 +495,29 @@ static void isis_circuit_update_all_srmflags(struct isis_circuit *circuit,
 {
        struct isis_area *area;
        struct isis_lsp *lsp;
-       dnode_t *dnode, *dnode_next;
+       dnode_t *dnode;
        int level;
 
        assert(circuit);
        area = circuit->area;
        assert(area);
        for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
-               if (level & circuit->is_type) {
-                       if (area->lspdb[level - 1]
-                           && dict_count(area->lspdb[level - 1]) > 0) {
-                               for (dnode = dict_first(area->lspdb[level - 1]);
-                                    dnode != NULL; dnode = dnode_next) {
-                                       dnode_next = dict_next(
-                                               area->lspdb[level - 1], dnode);
-                                       lsp = dnode_get(dnode);
-                                       if (is_set) {
-                                               ISIS_SET_FLAG(lsp->SRMflags,
-                                                             circuit);
-                                       } else {
-                                               ISIS_CLEAR_FLAG(lsp->SRMflags,
-                                                               circuit);
-                                       }
-                               }
+               if (!(level & circuit->is_type))
+                       continue;
+
+               if (!area->lspdb[level - 1]
+                   || !dict_count(area->lspdb[level - 1]))
+                       continue;
+
+               for (dnode = dict_first(area->lspdb[level - 1]);
+                    dnode != NULL;
+                    dnode = dict_next(area->lspdb[level - 1], dnode)) {
+                       lsp = dnode_get(dnode);
+                       if (is_set) {
+                               isis_tx_queue_add(circuit->tx_queue, lsp,
+                                                 TX_LSP_NORMAL);
+                       } else {
+                               isis_tx_queue_del(circuit->tx_queue, lsp);
                        }
                }
        }
@@ -672,10 +672,7 @@ int isis_circuit_up(struct isis_circuit *circuit)
 
        isis_circuit_prepare(circuit);
 
-       circuit->lsp_queue = list_new();
-       circuit->lsp_hash = isis_lsp_hash_new();
-       circuit->lsp_queue_last_push[0] = circuit->lsp_queue_last_push[1] =
-               monotime(NULL);
+       circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp);
 
        return ISIS_OK;
 }
@@ -743,13 +740,9 @@ void isis_circuit_down(struct isis_circuit *circuit)
        THREAD_OFF(circuit->t_send_lsp);
        THREAD_OFF(circuit->t_read);
 
-       if (circuit->lsp_queue) {
-               list_delete_and_null(&circuit->lsp_queue);
-       }
-
-       if (circuit->lsp_hash) {
-               isis_lsp_hash_free(circuit->lsp_hash);
-               circuit->lsp_hash = NULL;
+       if (circuit->tx_queue) {
+               isis_tx_queue_free(circuit->tx_queue);
+               circuit->tx_queue = NULL;
        }
 
        /* send one gratuitous hello to spead up convergence */
@@ -1346,57 +1339,3 @@ void isis_circuit_init()
        install_node(&interface_node, isis_interface_config_write);
        if_cmd_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 c014e4a52eb1fc37d583057dcb308474efd36de5..ea68767fe0fb35c1bfb5b40ff61631df5918a258 100644 (file)
@@ -80,14 +80,8 @@ struct isis_circuit {
        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) */
-       struct isis_lsp_hash *lsp_hash; /* Hashtable synchronized with lsp_queue */
-       time_t lsp_queue_last_push[2]; /* timestamp used to enforce transmit
-                                       * interval;
-                                       * for scalability, use one timestamp per
-                                       * circuit, instead of one per lsp per
-                                       * circuit
-                                       */
+       struct isis_tx_queue *tx_queue;
+
        /* there is no real point in two streams, just for programming kicker */
        int (*rx)(struct isis_circuit *circuit, uint8_t *ssnpa);
        struct stream *rcv_stream; /* Stream for receiving */
@@ -196,10 +190,4 @@ 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 b7e0b4b553ecb409a144335c48df5d4fc9b83cab..2598572248901b371b543461568ba81ff6a7821a 100644 (file)
@@ -57,6 +57,7 @@
 #include "isisd/isis_mt.h"
 #include "isisd/isis_tlvs.h"
 #include "isisd/fabricd.h"
+#include "isisd/isis_tx_queue.h"
 
 static int lsp_l1_refresh(struct thread *thread);
 static int lsp_l2_refresh(struct thread *thread);
@@ -118,10 +119,9 @@ static void lsp_destroy(struct isis_lsp *lsp)
                return;
 
        for (ALL_LIST_ELEMENTS_RO(lsp->area->circuit_list, cnode, circuit))
-               isis_circuit_cancel_queued_lsp(circuit, lsp);
+               isis_tx_queue_del(circuit->tx_queue, lsp);
 
        ISIS_FLAGS_CLEAR_ALL(lsp->SSNflags);
-       ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
 
        lsp_clear_data(lsp);
 
@@ -366,7 +366,7 @@ static void lsp_purge(struct isis_lsp *lsp, int level)
        lsp->age_out = lsp->area->max_lsp_lifetime[level - 1];
 
        lsp_pack_pdu(lsp);
-       lsp_set_all_srmflags(lsp);
+       lsp_flood(lsp, NULL);
 }
 
 /*
@@ -1208,7 +1208,7 @@ int lsp_generate(struct isis_area *area, int level)
        /* time to calculate our checksum */
        lsp_seqno_update(newlsp);
        newlsp->last_generated = time(NULL);
-       lsp_set_all_srmflags(newlsp);
+       lsp_flood(newlsp, NULL);
 
        refresh_time = lsp_refresh_time(newlsp, rem_lifetime);
 
@@ -1239,7 +1239,7 @@ int lsp_generate(struct isis_area *area, int level)
 }
 
 /*
- * Search own LSPs, update holding time and set SRM
+ * Search own LSPs, update holding time and flood
  */
 static int lsp_regenerate(struct isis_area *area, int level)
 {
@@ -1271,7 +1271,7 @@ static int lsp_regenerate(struct isis_area *area, int level)
        rem_lifetime = lsp_rem_lifetime(area, level);
        lsp->hdr.rem_lifetime = rem_lifetime;
        lsp->last_generated = time(NULL);
-       lsp_set_all_srmflags(lsp);
+       lsp_flood(lsp, NULL);
        for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
                frag->hdr.lsp_bits = lsp_bits_generate(
                        level, area->overload_bit, area->attached_bit);
@@ -1281,7 +1281,7 @@ static int lsp_regenerate(struct isis_area *area, int level)
                 */
                frag->hdr.rem_lifetime = rem_lifetime;
                frag->age_out = ZERO_AGE_LIFETIME;
-               lsp_set_all_srmflags(frag);
+               lsp_flood(frag, NULL);
        }
        lsp_seqno_update(lsp);
 
@@ -1581,7 +1581,7 @@ int lsp_generate_pseudo(struct isis_circuit *circuit, int level)
        lsp_pack_pdu(lsp);
        lsp->own_lsp = 1;
        lsp_insert(lsp, lspdb);
-       lsp_set_all_srmflags(lsp);
+       lsp_flood(lsp, NULL);
 
        refresh_time = lsp_refresh_time(lsp, rem_lifetime);
        THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
@@ -1640,7 +1640,7 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
        lsp_build_pseudo(lsp, circuit, level);
        lsp_inc_seqno(lsp, 0);
        lsp->last_generated = time(NULL);
-       lsp_set_all_srmflags(lsp);
+       lsp_flood(lsp, NULL);
 
        refresh_time = lsp_refresh_time(lsp, rem_lifetime);
        if (level == IS_LEVEL_1)
@@ -1816,23 +1816,16 @@ int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level)
 /*
  * Walk through LSPs for an area
  *  - set remaining lifetime
- *  - set LSPs with SRMflag set for sending
  */
 int lsp_tick(struct thread *thread)
 {
        struct isis_area *area;
-       struct isis_circuit *circuit;
        struct isis_lsp *lsp;
-       struct list *lsp_list;
-       struct listnode *lspnode, *cnode;
        dnode_t *dnode, *dnode_next;
        int level;
        uint16_t rem_lifetime;
-       time_t now = monotime(NULL);
        bool fabricd_sync_incomplete = false;
 
-       lsp_list = list_new();
-
        area = THREAD_ARG(thread);
        assert(area);
        area->t_tick = NULL;
@@ -1841,8 +1834,7 @@ int lsp_tick(struct thread *thread)
        struct isis_circuit *fabricd_init_c = fabricd_initial_sync_circuit(area);
 
        /*
-        * Build a list of LSPs with (any) SRMflag set
-        * and removed the ones that have aged out
+        * Remove LSPs which have aged out
         */
        for (level = 0; level < ISIS_LEVELS; level++) {
                if (area->lspdb[level] && dict_count(area->lspdb[level]) > 0) {
@@ -1873,7 +1865,7 @@ int lsp_tick(struct thread *thread)
                                 */
                                if (rem_lifetime == 1 && lsp->hdr.seqno != 0) {
                                        /* 7.3.16.4 a) set SRM flags on all */
-                                       lsp_set_all_srmflags(lsp);
+                                       lsp_flood(lsp, NULL);
                                        /* 7.3.16.4 b) retain only the header
                                         * FIXME  */
                                        /* 7.3.16.4 c) record the time to purge
@@ -1897,56 +1889,22 @@ int lsp_tick(struct thread *thread)
                                        lsp = NULL;
                                        dict_delete_free(area->lspdb[level],
                                                         dnode);
-                               } else if (flags_any_set(lsp->SRMflags))
-                                       listnode_add(lsp_list, lsp);
+                               }
 
                                if (fabricd_init_c) {
                                        fabricd_sync_incomplete |=
                                                ISIS_CHECK_FLAG(lsp->SSNflags,
                                                                fabricd_init_c);
-                                       fabricd_sync_incomplete |=
-                                               ISIS_CHECK_FLAG(lsp->SRMflags,
-                                                               fabricd_init_c);
-                               }
-                       }
-
-                       /*
-                        * Send LSPs on circuits indicated by the SRMflags
-                        */
-                       if (listcount(lsp_list) > 0) {
-                               for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
-                                                         cnode, circuit)) {
-                                       if (!circuit->lsp_queue)
-                                               continue;
-
-                                       if (now - circuit->lsp_queue_last_push[level]
-                                           < MIN_LSP_RETRANS_INTERVAL) {
-                                               continue;
-                                       }
-
-                                       circuit->lsp_queue_last_push[level] = now;
-
-                                       for (ALL_LIST_ELEMENTS_RO(
-                                                    lsp_list, lspnode, lsp)) {
-                                               if (circuit->upadjcount
-                                                           [lsp->level - 1]
-                                                   && ISIS_CHECK_FLAG(
-                                                              lsp->SRMflags,
-                                                              circuit)) {
-                                                       isis_circuit_queue_lsp(
-                                                               circuit, lsp);
-                                               }
-                                       }
                                }
-                               list_delete_all_node(lsp_list);
                        }
                }
        }
 
-       if (fabricd_init_c && !fabricd_sync_incomplete)
+       if (fabricd_init_c
+           && !fabricd_sync_incomplete
+           && !isis_tx_queue_len(fabricd_init_c->tx_queue)) {
                fabricd_initial_sync_finish(area);
-
-       list_delete_and_null(&lsp_list);
+       }
 
        return ISIS_OK;
 }
@@ -1986,24 +1944,35 @@ 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_set_all_srmflags(lsp);
+       lsp_flood(lsp, NULL);
 
        return;
 }
 
-void lsp_set_all_srmflags(struct isis_lsp *lsp)
+void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set)
 {
        struct listnode *node;
        struct isis_circuit *circuit;
 
        assert(lsp);
 
-       ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
+       if (!lsp->area)
+               return;
 
-       if (lsp->area) {
-               struct list *circuit_list = lsp->area->circuit_list;
-               for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
-                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
+       struct list *circuit_list = lsp->area->circuit_list;
+       for (ALL_LIST_ELEMENTS_RO(circuit_list, node, circuit)) {
+               if (set) {
+                       isis_tx_queue_add(circuit->tx_queue, lsp,
+                                         TX_LSP_NORMAL);
+               } else {
+                       isis_tx_queue_del(circuit->tx_queue, lsp);
                }
        }
 }
+
+void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit)
+{
+       lsp_set_all_srmflags(lsp);
+       if (circuit)
+               isis_tx_queue_del(circuit->tx_queue, lsp);
+}
index d531cb1576c1e7bf710875d4749c728f7afe219f..4e6379447cf5136de7f28ed31a6d95a34812f33d 100644 (file)
@@ -37,7 +37,6 @@ struct isis_lsp {
                struct list *frags;
                struct isis_lsp *zero_lsp;
        } lspu;
-       uint32_t SRMflags[ISIS_MAX_CIRCUITS];
        uint32_t SSNflags[ISIS_MAX_CIRCUITS];
        int level;     /* L1 or L2? */
        int scheduled; /* scheduled for sending */
@@ -100,6 +99,7 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost);
 void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost);
 int lsp_print_all(struct vty *vty, dict_t *lspdb, char detail, char dynhost);
 /* sets SRMflags for all active circuits of an lsp */
-void lsp_set_all_srmflags(struct isis_lsp *lsp);
+void lsp_set_all_srmflags(struct isis_lsp *lsp, bool set);
+void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit);
 
 #endif /* ISIS_LSP */
diff --git a/isisd/isis_lsp_hash.c b/isisd/isis_lsp_hash.c
deleted file mode 100644 (file)
index c521f42..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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
deleted file mode 100644 (file)
index b50aa09..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 8a5db3c6f953aa54960994a6724542f1d2d7577c..c1523a268d17487b00566b7878fe07ace4a03394 100644 (file)
@@ -57,6 +57,7 @@
 #include "isisd/isis_tlvs.h"
 #include "isisd/isis_errors.h"
 #include "isisd/fabricd.h"
+#include "isisd/isis_tx_queue.h"
 
 static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
                   int level)
@@ -707,7 +708,7 @@ out:
  * Section 7.3.15.1 - Action on receipt of a link state PDU
  */
 static int process_lsp(uint8_t pdu_type, struct isis_circuit *circuit,
-                      const uint8_t *ssnpa)
+                      const uint8_t *ssnpa, uint8_t max_area_addrs)
 {
        int level = (pdu_type == L1_LINK_STATE) ? ISIS_LEVEL1 : ISIS_LEVEL2;
 
@@ -906,7 +907,7 @@ dontcheckadj:
                                                   lsp_confusion);
                                        tlvs = NULL;
                                        /* ii */
-                                       lsp_set_all_srmflags(lsp);
+                                       lsp_flood(lsp, NULL);
                                        /* v */
                                        ISIS_FLAGS_CLEAR_ALL(
                                                lsp->SSNflags); /* FIXME:
@@ -920,9 +921,10 @@ dontcheckadj:
                                         * Otherwise, don't reflood
                                         * through incoming circuit as usual */
                                        if (!lsp_confusion) {
-                                               /* iii */
-                                               ISIS_CLEAR_FLAG(lsp->SRMflags,
-                                                               circuit);
+                                               isis_tx_queue_del(
+                                                       circuit->tx_queue,
+                                                       lsp);
+
                                                /* iv */
                                                if (circuit->circ_type
                                                    != CIRCUIT_T_BROADCAST)
@@ -933,7 +935,8 @@ dontcheckadj:
                                } /* 7.3.16.4 b) 2) */
                                else if (comp == LSP_EQUAL) {
                                        /* i */
-                                       ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+                                       isis_tx_queue_del(circuit->tx_queue,
+                                                         lsp);
                                        /* ii */
                                        if (circuit->circ_type
                                            != CIRCUIT_T_BROADCAST)
@@ -941,16 +944,18 @@ dontcheckadj:
                                                              circuit);
                                } /* 7.3.16.4 b) 3) */
                                else {
-                                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
+                                       isis_tx_queue_add(circuit->tx_queue,
+                                                         lsp, TX_LSP_NORMAL);
                                        ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                                }
                        } else if (lsp->hdr.rem_lifetime != 0) {
                                /* our own LSP -> 7.3.16.4 c) */
                                if (comp == LSP_NEWER) {
                                        lsp_inc_seqno(lsp, hdr.seqno);
-                                       lsp_set_all_srmflags(lsp);
+                                       lsp_flood(lsp, NULL);
                                } else {
-                                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
+                                       isis_tx_queue_add(circuit->tx_queue,
+                                                         lsp, TX_LSP_NORMAL);
                                        ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                                }
                                if (isis->debugs & DEBUG_UPDATE_PACKETS)
@@ -992,7 +997,7 @@ dontcheckadj:
                }
                /* If the received LSP is older or equal,
                 * resend the LSP which will act as ACK */
-               lsp_set_all_srmflags(lsp);
+               lsp_flood(lsp, NULL);
        } else {
                /* 7.3.15.1 e) - This lsp originated on another system */
 
@@ -1030,10 +1035,7 @@ dontcheckadj:
                                           circuit->area, level, false);
                                tlvs = NULL;
                        }
-                       /* ii */
-                       lsp_set_all_srmflags(lsp);
-                       /* iii */
-                       ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+                       lsp_flood(lsp, circuit);
 
                        /* iv */
                        if (circuit->circ_type != CIRCUIT_T_BROADCAST)
@@ -1042,7 +1044,7 @@ dontcheckadj:
                }
                /* 7.3.15.1 e) 2) LSP equal to the one in db */
                else if (comp == LSP_EQUAL) {
-                       ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+                       isis_tx_queue_del(circuit->tx_queue, lsp);
                        lsp_update(lsp, &hdr, tlvs, circuit->rcv_stream,
                                   circuit->area, level, false);
                        tlvs = NULL;
@@ -1051,7 +1053,8 @@ dontcheckadj:
                }
                /* 7.3.15.1 e) 3) LSP older than the one in db */
                else {
-                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
+                       isis_tx_queue_add(circuit->tx_queue, lsp,
+                                         TX_LSP_NORMAL);
                        ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
                }
        }
@@ -1228,25 +1231,27 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
                        if (cmp == LSP_EQUAL) {
                                /* if (circuit->circ_type !=
                                 * CIRCUIT_T_BROADCAST) */
-                               ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+                               isis_tx_queue_del(circuit->tx_queue, lsp);
                        }
                        /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM
                           */
                        else if (cmp == LSP_OLDER) {
                                ISIS_CLEAR_FLAG(lsp->SSNflags, circuit);
-                               ISIS_SET_FLAG(lsp->SRMflags, circuit);
+                               isis_tx_queue_add(circuit->tx_queue, lsp,
+                                                 TX_LSP_NORMAL);
                        }
                        /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
                           on p2p */
                        else {
                                if (own_lsp) {
                                        lsp_inc_seqno(lsp, entry->seqno);
-                                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
+                                       isis_tx_queue_add(circuit->tx_queue, lsp,
+                                                       TX_LSP_NORMAL);
                                } else {
                                        ISIS_SET_FLAG(lsp->SSNflags, circuit);
                                        /* if (circuit->circ_type !=
                                         * CIRCUIT_T_BROADCAST) */
-                                       ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+                                       isis_tx_queue_del(circuit->tx_queue, lsp);
                                }
                        }
                } else {
@@ -1278,7 +1283,8 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
                                                entry->checksum, lsp0, level);
                                lsp_insert(lsp,
                                           circuit->area->lspdb[level - 1]);
-                               ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
+
+                               lsp_set_all_srmflags(lsp, false);
                                ISIS_SET_FLAG(lsp->SSNflags, circuit);
                        }
                }
@@ -1310,8 +1316,10 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
                }
 
                /* on remaining LSPs we set SRM (neighbor knew not of) */
-               for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp))
-                       ISIS_SET_FLAG(lsp->SRMflags, circuit);
+               for (ALL_LIST_ELEMENTS_RO(lsp_list, node, lsp)) {
+                       isis_tx_queue_add(circuit->tx_queue, lsp, TX_LSP_NORMAL);
+               }
+
                /* lets free it */
                list_delete_and_null(&lsp_list);
        }
@@ -1451,7 +1459,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
                break;
        case L1_LINK_STATE:
        case L2_LINK_STATE:
-               retval = process_lsp(pdu_type, circuit, ssnpa);
+               retval = process_lsp(pdu_type, circuit, ssnpa, max_area_addrs);
                break;
        case L1_COMPLETE_SEQ_NUM:
        case L2_COMPLETE_SEQ_NUM:
@@ -2102,25 +2110,12 @@ int send_l2_psnp(struct thread *thread)
 /*
  * ISO 10589 - 7.3.14.3
  */
-int send_lsp(struct thread *thread)
+void send_lsp(void *arg, struct isis_lsp *lsp, enum isis_tx_type tx_type)
 {
-       struct isis_circuit *circuit;
-       struct isis_lsp *lsp;
+       struct isis_circuit *circuit = arg;
        int clear_srm = 1;
        int retval = ISIS_OK;
 
-       circuit = THREAD_ARG(thread);
-       assert(circuit);
-       circuit->t_send_lsp = NULL;
-
-       lsp = isis_circuit_lsp_queue_pop(circuit);
-       if (!lsp)
-               return ISIS_OK;
-
-       if (!list_isempty(circuit->lsp_queue)) {
-               isis_circuit_schedule_lsp_send(circuit);
-       }
-
        if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
                goto out;
 
@@ -2197,8 +2192,6 @@ out:
                 * to clear
                 * the fag.
                 */
-               ISIS_CLEAR_FLAG(lsp->SRMflags, circuit);
+               isis_tx_queue_del(circuit->tx_queue, lsp);
        }
-
-       return retval;
 }
index c69bfedeae78603ebcd3c3852d5f5ead79b063ca..ea19de259121d9f2294040684ece7c95c5c7a154 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef _ZEBRA_ISIS_PDU_H
 #define _ZEBRA_ISIS_PDU_H
 
+#include "isisd/isis_tx_queue.h"
+
 #ifdef __SUNPRO_C
 #pragma pack(1)
 #endif
@@ -212,7 +214,7 @@ int send_l1_csnp(struct thread *thread);
 int send_l2_csnp(struct thread *thread);
 int send_l1_psnp(struct thread *thread);
 int send_l2_psnp(struct thread *thread);
-int send_lsp(struct thread *thread);
+void send_lsp(void *arg, struct isis_lsp *lsp, enum isis_tx_type tx_type);
 void fill_fixed_hdr(uint8_t pdu_type, struct stream *stream);
 int send_hello(struct isis_circuit *circuit, int level);
 int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa);
diff --git a/isisd/isis_tx_queue.c b/isisd/isis_tx_queue.c
new file mode 100644 (file)
index 0000000..3242762
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * IS-IS Rout(e)ing protocol - LSP TX Queuing logic
+ *
+ * Copyright (C) 2018 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/isisd.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_tx_queue.h"
+
+DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue")
+DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry")
+
+struct isis_tx_queue {
+       void *arg;
+       void (*send_event)(void *arg, struct isis_lsp *, enum isis_tx_type);
+       struct hash *hash;
+};
+
+struct isis_tx_queue_entry {
+       struct isis_lsp *lsp;
+       enum isis_tx_type type;
+       struct thread *retry;
+       struct isis_tx_queue *queue;
+};
+
+static unsigned tx_queue_hash_key(void *p)
+{
+       struct isis_tx_queue_entry *e = p;
+
+       uint32_t id_key = jhash(e->lsp->hdr.lsp_id,
+                               ISIS_SYS_ID_LEN + 2, 0x55aa5a5a);
+
+       return jhash_1word(e->lsp->level, id_key);
+}
+
+static int tx_queue_hash_cmp(const void *a, const void *b)
+{
+       const struct isis_tx_queue_entry *ea = a, *eb = b;
+
+       if (ea->lsp->level != eb->lsp->level)
+               return 0;
+
+       if (memcmp(ea->lsp->hdr.lsp_id, eb->lsp->hdr.lsp_id,
+                  ISIS_SYS_ID_LEN + 2))
+               return 0;
+
+       return 1;
+}
+
+struct isis_tx_queue *isis_tx_queue_new(void *arg,
+                                       void(*send_event)(void *arg,
+                                                         struct isis_lsp *,
+                                                         enum isis_tx_type))
+{
+       struct isis_tx_queue *rv = XCALLOC(MTYPE_TX_QUEUE, sizeof(*rv));
+
+       rv->arg = arg;
+       rv->send_event = send_event;
+
+       rv->hash = hash_create(tx_queue_hash_key, tx_queue_hash_cmp, NULL);
+       return rv;
+}
+
+static void tx_queue_element_free(void *element)
+{
+       struct isis_tx_queue_entry *e = element;
+
+       if (e->retry)
+               thread_cancel(e->retry);
+
+       XFREE(MTYPE_TX_QUEUE_ENTRY, e);
+}
+
+void isis_tx_queue_free(struct isis_tx_queue *queue)
+{
+       hash_clean(queue->hash, tx_queue_element_free);
+       hash_free(queue->hash);
+       XFREE(MTYPE_TX_QUEUE, queue);
+}
+
+static struct isis_tx_queue_entry *tx_queue_find(struct isis_tx_queue *queue,
+                                                struct isis_lsp *lsp)
+{
+       struct isis_tx_queue_entry e = {
+               .lsp = lsp
+       };
+
+       return hash_lookup(queue->hash, &e);
+}
+
+static int tx_queue_send_event(struct thread *thread)
+{
+       struct isis_tx_queue_entry *e = THREAD_ARG(thread);
+       struct isis_tx_queue *queue = e->queue;
+
+       e->retry = NULL;
+       thread_add_timer(master, tx_queue_send_event, e, 5, &e->retry);
+
+       queue->send_event(queue->arg, e->lsp, e->type);
+       /* Don't access e here anymore, send_event might have destroyed it */
+
+       return 0;
+}
+
+void isis_tx_queue_add(struct isis_tx_queue *queue,
+                      struct isis_lsp *lsp,
+                      enum isis_tx_type type)
+{
+       if (!queue)
+               return;
+
+       struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
+       if (!e) {
+               e = XCALLOC(MTYPE_TX_QUEUE_ENTRY, sizeof(*e));
+               e->lsp = lsp;
+               e->queue = queue;
+
+               struct isis_tx_queue_entry *inserted;
+               inserted = hash_get(queue->hash, e, hash_alloc_intern);
+               assert(inserted == e);
+       }
+
+       e->type = type;
+
+       if (e->retry)
+               thread_cancel(e->retry);
+       thread_add_event(master, tx_queue_send_event, e, 0, &e->retry);
+}
+
+void isis_tx_queue_del(struct isis_tx_queue *queue, struct isis_lsp *lsp)
+{
+       if (!queue)
+               return;
+
+       struct isis_tx_queue_entry *e = tx_queue_find(queue, lsp);
+       if (!e)
+               return;
+
+       if (e->retry)
+               thread_cancel(e->retry);
+
+       hash_release(queue->hash, e);
+       XFREE(MTYPE_TX_QUEUE_ENTRY, e);
+}
+
+unsigned long isis_tx_queue_len(struct isis_tx_queue *queue)
+{
+       if (!queue)
+               return 0;
+
+       return hashcount(queue->hash);
+}
+
+void isis_tx_queue_clean(struct isis_tx_queue *queue)
+{
+       hash_clean(queue->hash, tx_queue_element_free);
+}
diff --git a/isisd/isis_tx_queue.h b/isisd/isis_tx_queue.h
new file mode 100644 (file)
index 0000000..ddecdf1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * IS-IS Rout(e)ing protocol - LSP TX Queuing logic
+ *
+ * Copyright (C) 2018 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_TX_QUEUE_H
+#define ISIS_TX_QUEUE_H
+
+enum isis_tx_type {
+       TX_LSP_NORMAL = 0,
+       TX_LSP_CIRCUIT_SCOPED
+};
+
+struct isis_tx_queue;
+
+struct isis_tx_queue *isis_tx_queue_new(void *arg,
+                                       void(*send_event)(void *arg,
+                                                         struct isis_lsp *,
+                                                         enum isis_tx_type));
+
+void isis_tx_queue_free(struct isis_tx_queue *queue);
+
+void isis_tx_queue_add(struct isis_tx_queue *queue,
+                      struct isis_lsp *lsp,
+                      enum isis_tx_type type);
+
+void isis_tx_queue_del(struct isis_tx_queue *queue, struct isis_lsp *lsp);
+
+unsigned long isis_tx_queue_len(struct isis_tx_queue *queue);
+
+void isis_tx_queue_clean(struct isis_tx_queue *queue);
+
+#endif
index 792b0df6c29da2e825f2491bdfeb4df80e6ca0a2..a45b9ca47c045bcb106dde551fc2a05ac2481007 100644 (file)
@@ -27,7 +27,6 @@ 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 \
@@ -40,6 +39,7 @@ noinst_HEADERS += \
        isisd/isis_spf_private.h \
        isisd/isis_te.h \
        isisd/isis_tlvs.h \
+       isisd/isis_tx_queue.h \
        isisd/isis_vty_common.h \
        isisd/isis_zebra.h \
        isisd/isisd.h \
@@ -58,7 +58,6 @@ LIBISIS_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 \
@@ -69,6 +68,7 @@ LIBISIS_SOURCES = \
        isisd/isis_spf.c \
        isisd/isis_te.c \
        isisd/isis_tlvs.c \
+       isisd/isis_tx_queue.c \
        isisd/isis_vty_common.c \
        isisd/isis_zebra.c \
        isisd/isisd.c \