summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--isisd/fabricd.c1
-rw-r--r--isisd/isis_adjacency.c4
-rw-r--r--isisd/isis_circuit.c105
-rw-r--r--isisd/isis_circuit.h16
-rw-r--r--isisd/isis_lsp.c99
-rw-r--r--isisd/isis_lsp.h4
-rw-r--r--isisd/isis_lsp_hash.c89
-rw-r--r--isisd/isis_pdu.c77
-rw-r--r--isisd/isis_pdu.h4
-rw-r--r--isisd/isis_tx_queue.c182
-rw-r--r--isisd/isis_tx_queue.h (renamed from isisd/isis_lsp_hash.h)43
-rw-r--r--isisd/subdir.am4
12 files changed, 314 insertions, 314 deletions
diff --git a/isisd/fabricd.c b/isisd/fabricd.c
index 5effcd83d..fe8731c8d 100644
--- a/isisd/fabricd.c
+++ b/isisd/fabricd.c
@@ -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")
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 56dbc2582..a41d6ff81 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -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);
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 7ecc71023..817a44baf 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -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;
-}
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index c014e4a52..ea68767fe 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -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 */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index b7e0b4b55..259857224 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -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);
+}
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index d531cb157..4e6379447 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -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
index c521f42b3..000000000
--- a/isisd/isis_lsp_hash.c
+++ /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_pdu.c b/isisd/isis_pdu.c
index 8a5db3c6f..c1523a268 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -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;
}
diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h
index c69bfedea..ea19de259 100644
--- a/isisd/isis_pdu.h
+++ b/isisd/isis_pdu.h
@@ -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
index 000000000..32427628a
--- /dev/null
+++ b/isisd/isis_tx_queue.c
@@ -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_lsp_hash.h b/isisd/isis_tx_queue.h
index b50aa09dc..ddecdf1e4 100644
--- a/isisd/isis_lsp_hash.h
+++ b/isisd/isis_tx_queue.h
@@ -1,7 +1,7 @@
/*
- * IS-IS Rout(e)ing protocol - LSP Hash
+ * IS-IS Rout(e)ing protocol - LSP TX Queuing logic
*
- * Copyright (C) 2017 Christian Franke
+ * Copyright (C) 2018 Christian Franke
*
* This file is part of FreeRangeRouting (FRR)
*
@@ -19,16 +19,31 @@
* 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);
+#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
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 792b0df6c..a45b9ca47 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -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 \