summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/control2
-rw-r--r--doc/Building_FRR_on_Ubuntu1604.md4
-rw-r--r--isisd/isis_adjacency.c19
-rw-r--r--isisd/isis_circuit.c64
-rw-r--r--isisd/isis_circuit.h12
-rw-r--r--isisd/isis_constants.h2
-rw-r--r--isisd/isis_lsp.c49
-rw-r--r--isisd/isis_lsp_hash.c89
-rw-r--r--isisd/isis_lsp_hash.h34
-rw-r--r--isisd/isis_pdu.c31
-rw-r--r--isisd/subdir.am2
11 files changed, 230 insertions, 78 deletions
diff --git a/debian/control b/debian/control
index d2b2e7cea..84b04c347 100644
--- a/debian/control
+++ b/debian/control
@@ -10,7 +10,7 @@ XS-Testsuite: autopkgtest
Package: frr
Architecture: any
-Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute, ${misc:Depends}, libc-ares2
+Depends: ${shlibs:Depends}, logrotate (>= 3.2-11), iproute2 | iproute, ${misc:Depends}, libc-ares2
Pre-Depends: adduser
Conflicts: zebra, zebra-pj, quagga
Replaces: zebra, zebra-pj
diff --git a/doc/Building_FRR_on_Ubuntu1604.md b/doc/Building_FRR_on_Ubuntu1604.md
index b33fb6025..bdd0a9624 100644
--- a/doc/Building_FRR_on_Ubuntu1604.md
+++ b/doc/Building_FRR_on_Ubuntu1604.md
@@ -14,7 +14,7 @@ Add packages:
apt-get install git autoconf automake libtool make gawk libreadline-dev \
texinfo dejagnu pkg-config libpam0g-dev libjson-c-dev bison flex \
- python-pytest libc-ares-dev python3-dev libsystemd-dev
+ python-pytest libc-ares-dev python3-dev libsystemd-dev python-ipaddr
Get FRR, compile it and install it (from Git)
---------------------------------------------
@@ -113,7 +113,7 @@ Add the following lines to `/etc/modules-load.d/modules.conf`:
**Reboot** or use `sysctl -p` to apply the same config to the running system
-### Install the systemd service
+### Install the systemd service (if rebooted from last step, change directory back to frr directory)
sudo install -m 644 tools/frr.service /etc/systemd/system/frr.service
sudo install -m 644 tools/etc/default/frr /etc/default/frr
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 0afa65d72..c8b9a66e2 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -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;
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 1a978ee04..1c1385ab7 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -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;
+}
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index 5906efd2b..29694deb3 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -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 */
diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h
index f3a5a24dd..b7b5d35c2 100644
--- a/isisd/isis_constants.h
+++ b/isisd/isis_constants.h
@@ -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
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 33c52804e..bee6abfda 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -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
index 000000000..919612882
--- /dev/null
+++ b/isisd/isis_lsp_hash.c
@@ -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
index 000000000..b50aa09dc
--- /dev/null
+++ b/isisd/isis_lsp_hash.h
@@ -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
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index a20051f8c..2f9e3caf1 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -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;
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 6e49d4ec8..7b56715fa 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -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 \