mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-06-04 19:31:44 +00:00
Merge pull request #1286 from opensourcerouting/isis-lsp-queue-improv
isisd: optimize per interface lsp send-queue creation
This commit is contained in:
commit
c1c41b0458
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
89
isisd/isis_lsp_hash.c
Normal file
89
isisd/isis_lsp_hash.c
Normal file
@ -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);
|
||||
}
|
34
isisd/isis_lsp_hash.h
Normal file
34
isisd/isis_lsp_hash.h
Normal file
@ -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
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user