diff options
-rw-r--r-- | isisd/fabricd.c | 1 | ||||
-rw-r--r-- | isisd/isis_adjacency.c | 4 | ||||
-rw-r--r-- | isisd/isis_circuit.c | 105 | ||||
-rw-r--r-- | isisd/isis_circuit.h | 16 | ||||
-rw-r--r-- | isisd/isis_lsp.c | 99 | ||||
-rw-r--r-- | isisd/isis_lsp.h | 4 | ||||
-rw-r--r-- | isisd/isis_lsp_hash.c | 89 | ||||
-rw-r--r-- | isisd/isis_pdu.c | 77 | ||||
-rw-r--r-- | isisd/isis_pdu.h | 4 | ||||
-rw-r--r-- | isisd/isis_tx_queue.c | 182 | ||||
-rw-r--r-- | isisd/isis_tx_queue.h (renamed from isisd/isis_lsp_hash.h) | 43 | ||||
-rw-r--r-- | isisd/subdir.am | 4 |
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 \ |