Skip to content

Commit

Permalink
fabricd: reimplement LSP transmission logic
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
cfra committed Sep 5, 2018
1 parent a191178 commit 9b39405
Show file tree
Hide file tree
Showing 12 changed files with 314 additions and 314 deletions.
1 change: 1 addition & 0 deletions isisd/fabricd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down
4 changes: 2 additions & 2 deletions isisd/isis_adjacency.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
105 changes: 22 additions & 83 deletions isisd/isis_circuit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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)

Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}
16 changes: 2 additions & 14 deletions isisd/isis_circuit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Loading

0 comments on commit 9b39405

Please sign in to comment.