#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);
+static int lsp_refresh(struct thread *thread);
static int lsp_l1_refresh_pseudo(struct thread *thread);
static int lsp_l2_refresh_pseudo(struct thread *thread);
lsp->tlvs = NULL;
}
+static void lsp_remove_frags(struct list *frags, dict_t *lspdb);
+
static void lsp_destroy(struct isis_lsp *lsp)
{
struct listnode *cnode;
lsp_clear_data(lsp);
- if (LSP_FRAGMENT(lsp->hdr.lsp_id) == 0 && lsp->lspu.frags) {
- list_delete_and_null(&lsp->lspu.frags);
- lsp->lspu.frags = NULL;
+ if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) {
+ if (lsp->lspu.frags) {
+ lsp_remove_frags(lsp->lspu.frags,
+ lsp->area->lspdb[lsp->level - 1]);
+ list_delete(&lsp->lspu.frags);
+ }
+ } else {
+ if (lsp->lspu.zero_lsp
+ && lsp->lspu.zero_lsp->lspu.frags) {
+ listnode_delete(lsp->lspu.zero_lsp->lspu.frags, lsp);
+ }
}
isis_spf_schedule(lsp->area, lsp->level);
lsp_destroy(lsp);
dnode_destroy(dict_delete(lspdb, dnode));
}
-
- list_delete_all_node(frags);
-
- return;
}
void lsp_search_and_destroy(uint8_t *id, dict_t *lspdb)
if (seqno > lsp->hdr.seqno
|| (seqno == lsp->hdr.seqno
&& ((lsp->hdr.rem_lifetime != 0 && rem_lifetime == 0)
- || lsp->hdr.checksum != checksum))) {
+ || (lsp->hdr.checksum != checksum
+ && lsp->hdr.rem_lifetime)))) {
if (isis->debugs & DEBUG_SNP_PACKETS) {
zlog_debug(
"ISIS-Snp (%s): Compare LSP %s seq 0x%08" PRIx32
for (ALL_LIST_ELEMENTS_RO(lsp0->lspu.frags, node, lsp)) {
if (lsp->tlvs)
lsp_inc_seqno(lsp, 0);
- else
+ else if (lsp->hdr.rem_lifetime) {
+ /* Purge should only be applied when the fragment has
+ * non-zero remaining lifetime.
+ */
lsp_purge(lsp, lsp0->level, NULL);
+ }
}
return;
return lsp;
}
+static void lsp_adjust_stream(struct isis_lsp *lsp)
+{
+ if (lsp->pdu) {
+ if (STREAM_SIZE(lsp->pdu) == LLC_LEN + lsp->area->lsp_mtu)
+ return;
+ stream_free(lsp->pdu);
+ }
+
+ lsp->pdu = stream_new(LLC_LEN + lsp->area->lsp_mtu);
+}
+
struct isis_lsp *lsp_new(struct isis_area *area, uint8_t *lsp_id,
uint16_t rem_lifetime, uint32_t seqno,
uint8_t lsp_bits, uint16_t checksum,
lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
lsp->area = area;
- lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
+ lsp_adjust_stream(lsp);
/* Minimal LSP PDU size */
lsp->hdr.pdu_len = ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN;
void lsp_build_list_nonzero_ht(uint8_t *start_id, uint8_t *stop_id,
struct list *list, dict_t *lspdb)
{
- dnode_t *first, *last, *curr;
+ for (dnode_t *curr = dict_lower_bound(lspdb, start_id);
+ curr; curr = dict_next(lspdb, curr)) {
+ struct isis_lsp *lsp = curr->dict_data;
- first = dict_lower_bound(lspdb, start_id);
- if (!first)
- return;
-
- last = dict_upper_bound(lspdb, stop_id);
-
- curr = first;
-
- if (((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime)
- listnode_add(list, first->dict_data);
-
- while (curr) {
- curr = dict_next(lspdb, curr);
- if (curr
- && ((struct isis_lsp *)(curr->dict_data))->hdr.rem_lifetime)
- listnode_add(list, curr->dict_data);
- if (curr == last)
+ if (memcmp(lsp->hdr.lsp_id, stop_id,
+ ISIS_SYS_ID_LEN + 2) > 0)
break;
- }
- return;
+ if (lsp->hdr.rem_lifetime)
+ listnode_add(list, lsp);
+ }
}
static void lsp_set_time(struct isis_lsp *lsp)
uint8_t subtlv_len;
if (IS_MPLS_TE(isisMplsTE)
+ && circuit->interface
&& HAS_LINK_PARAMS(
circuit->interface))
subtlv_len = add_te_subtlvs(
struct isis_tlvs *tlvs = lsp->tlvs;
lsp->tlvs = NULL;
+ lsp_adjust_stream(lsp);
lsp_pack_pdu(lsp);
size_t tlv_space = STREAM_WRITEABLE(lsp->pdu) - LLC_LEN;
lsp_clear_data(lsp);
frag = lsp_next_frag(LSP_FRAGMENT(frag->hdr.lsp_id) + 1,
lsp, area, level);
+ lsp_adjust_stream(frag);
}
frag->tlvs = tlvs;
}
- list_delete_and_null(&fragments);
+ list_delete(&fragments);
lsp_debug("ISIS (%s): LSP construction is complete. Serializing...",
area->area_tag);
return;
THREAD_TIMER_OFF(area->t_lsp_refresh[level - 1]);
area->lsp_regenerate_pending[level - 1] = 0;
- if (level == IS_LEVEL_1)
- thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
- &area->t_lsp_refresh[level - 1]);
- else if (level == IS_LEVEL_2)
- thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
- &area->t_lsp_refresh[level - 1]);
+ thread_add_timer(master, lsp_refresh,
+ &area->lsp_refresh_arg[level - 1], refresh_time,
+ &area->t_lsp_refresh[level - 1]);
if (isis->debugs & DEBUG_UPDATE_PACKETS) {
zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
lsp->last_generated = time(NULL);
lsp_flood(lsp, NULL);
for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
+ if (!frag->tlvs) {
+ /* Updating and flooding should only affect fragments
+ * carrying data
+ */
+ continue;
+ }
+
frag->hdr.lsp_bits = lsp_bits_generate(
level, area->overload_bit, area->attached_bit);
/* Set the lifetime values of all the fragments to the same
lsp_seqno_update(lsp);
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
- if (level == IS_LEVEL_1)
- thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
- &area->t_lsp_refresh[level - 1]);
- else if (level == IS_LEVEL_2)
- thread_add_timer(master, lsp_l2_refresh, area, refresh_time,
- &area->t_lsp_refresh[level - 1]);
+ thread_add_timer(master, lsp_refresh,
+ &area->lsp_refresh_arg[level - 1], refresh_time,
+ &area->t_lsp_refresh[level - 1]);
area->lsp_regenerate_pending[level - 1] = 0;
if (isis->debugs & DEBUG_UPDATE_PACKETS) {
/*
* Something has changed or periodic refresh -> regenerate LSP
*/
-static int lsp_l1_refresh(struct thread *thread)
+static int lsp_refresh(struct thread *thread)
{
- struct isis_area *area;
+ struct lsp_refresh_arg *arg = THREAD_ARG(thread);
- area = THREAD_ARG(thread);
- assert(area);
+ assert(arg);
- area->t_lsp_refresh[0] = NULL;
- area->lsp_regenerate_pending[0] = 0;
+ struct isis_area *area = arg->area;
- if ((area->is_type & IS_LEVEL_1) == 0)
- return ISIS_ERROR;
-
- sched_debug(
- "ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
- area->area_tag);
- return lsp_regenerate(area, IS_LEVEL_1);
-}
-
-static int lsp_l2_refresh(struct thread *thread)
-{
- struct isis_area *area;
-
- area = THREAD_ARG(thread);
assert(area);
- area->t_lsp_refresh[1] = NULL;
- area->lsp_regenerate_pending[1] = 0;
+ int level = arg->level;
+
+ area->t_lsp_refresh[level - 1] = NULL;
+ area->lsp_regenerate_pending[level - 1] = 0;
- if ((area->is_type & IS_LEVEL_2) == 0)
+ if ((area->is_type & level) == 0)
return ISIS_ERROR;
+ if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL) < 100000L) {
+ sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
+ area->area_tag, level);
+ _lsp_regenerate_schedule(area, level, 0, false,
+ __func__, __FILE__, __LINE__);
+ return 0;
+ }
+
sched_debug(
- "ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
- area->area_tag);
- return lsp_regenerate(area, IS_LEVEL_2);
+ "ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
+ area->area_tag, level);
+ return lsp_regenerate(area, level);
}
-int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo)
+int _lsp_regenerate_schedule(struct isis_area *area, int level,
+ int all_pseudo, bool postpone,
+ const char *func, const char *file,
+ int line)
{
struct isis_lsp *lsp;
uint8_t id[ISIS_SYS_ID_LEN + 2];
return ISIS_ERROR;
sched_debug(
- "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs",
+ "ISIS (%s): Scheduling regeneration of %s LSPs, %sincluding PSNs"
+ " Caller: %s %s:%d",
area->area_tag, circuit_t2string(level),
- all_pseudo ? "" : "not ");
+ all_pseudo ? "" : "not ",
+ func, file, line);
memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
if (!((level & lvl) && (area->is_type & lvl)))
continue;
+ if (postpone) {
+ monotime(&area->last_lsp_refresh_event[lvl - 1]);
+ }
+
sched_debug(
"ISIS (%s): Checking whether L%d needs to be scheduled",
area->area_tag, lvl);
}
area->lsp_regenerate_pending[lvl - 1] = 1;
- if (lvl == IS_LEVEL_1) {
- thread_add_timer_msec(master, lsp_l1_refresh, area,
- timeout,
- &area->t_lsp_refresh[lvl - 1]);
- } else if (lvl == IS_LEVEL_2) {
- thread_add_timer_msec(master, lsp_l2_refresh, area,
- timeout,
- &area->t_lsp_refresh[lvl - 1]);
- }
+ thread_add_timer_msec(master, lsp_refresh,
+ &area->lsp_refresh_arg[lvl - 1],
+ timeout,
+ &area->t_lsp_refresh[lvl - 1]);
}
if (all_pseudo) {
LSP_PSEUDO_ID(ne_id));
}
}
- list_delete_and_null(&adj_list);
+ list_delete(&adj_list);
return;
}
lsp = XCALLOC(MTYPE_ISIS_LSP, sizeof(struct isis_lsp));
lsp->area = area;
lsp->level = level;
- lsp->pdu = stream_new(LLC_LEN + area->lsp_mtu);
+ lsp_adjust_stream(lsp);
lsp->age_out = ZERO_AGE_LIFETIME;
memcpy(&lsp->hdr, hdr, sizeof(lsp->hdr));
void lsp_flood(struct isis_lsp *lsp, struct isis_circuit *circuit)
{
- if (!fabricd) {
+ if (!fabricd)
lsp_set_all_srmflags(lsp, true);
- if (circuit)
- isis_tx_queue_del(circuit->tx_queue, lsp);
- } else {
+ else
fabricd_lsp_flood(lsp);
- }
+
+ if (circuit)
+ isis_tx_queue_del(circuit->tx_queue, lsp);
+}
+
+static int lsp_handle_adj_state_change(struct isis_adjacency *adj)
+{
+ lsp_regenerate_schedule(adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+ return 0;
+}
+
+void lsp_init(void)
+{
+ hook_register(isis_adj_state_change_hook,
+ lsp_handle_adj_state_change);
}