diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 558bc4276b..bb090f42ed 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -59,8 +59,7 @@ #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); @@ -1251,12 +1250,9 @@ int lsp_generate(struct isis_area *area, int level) 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 @@ -1323,12 +1319,9 @@ static int lsp_regenerate(struct isis_area *area, int level) 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) { @@ -1350,45 +1343,42 @@ static int lsp_regenerate(struct isis_area *area, int level) /* * 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); + + assert(arg); + + struct isis_area *area = arg->area; - area = THREAD_ARG(thread); assert(area); - area->t_lsp_refresh[0] = NULL; - area->lsp_regenerate_pending[0] = 0; + int level = arg->level; - if ((area->is_type & IS_LEVEL_1) == 0) + area->t_lsp_refresh[level - 1] = NULL; + area->lsp_regenerate_pending[level - 1] = 0; + + if ((area->is_type & level) == 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; - - if ((area->is_type & IS_LEVEL_2) == 0) - return ISIS_ERROR; + if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL) < 50000L) { + 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]; @@ -1402,9 +1392,11 @@ int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo) 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; @@ -1414,6 +1406,10 @@ int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo) 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); @@ -1468,15 +1464,10 @@ int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo) } 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) { diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 4beee10081..2b45e6994c 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -54,7 +54,12 @@ void lsp_db_destroy(dict_t *lspdb); int lsp_tick(struct thread *thread); int lsp_generate(struct isis_area *area, int level); -int lsp_regenerate_schedule(struct isis_area *area, int level, int all_pseudo); +#define lsp_regenerate_schedule(area, level, all_pseudo) \ + _lsp_regenerate_schedule((area), (level), (all_pseudo), true, \ + __func__, __FILE__, __LINE__) +int _lsp_regenerate_schedule(struct isis_area *area, int level, + int all_pseudo, bool postpone, + const char *func, const char *file, int line); int lsp_generate_pseudo(struct isis_circuit *circuit, int level); int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level); diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 1440a3becf..1c4ca249ee 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1248,7 +1248,8 @@ static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level) return run; } -int isis_spf_schedule(struct isis_area *area, int level) +int _isis_spf_schedule(struct isis_area *area, int level, + const char *func, const char *file, int line) { struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1]; time_t now = monotime(NULL); @@ -1257,10 +1258,12 @@ int isis_spf_schedule(struct isis_area *area, int level) assert(diff >= 0); assert(area->is_type & level); - if (isis->debugs & DEBUG_SPF_EVENTS) + if (isis->debugs & DEBUG_SPF_EVENTS) { zlog_debug( - "ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago", - area->area_tag, level, diff); + "ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago" + " Caller: %s %s:%d", + area->area_tag, level, diff, func, file, line); + } if (area->spf_delay_ietf[level - 1]) { /* Need to call schedule function also if spf delay is running diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index f4db98cfed..8bf9c9978a 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -34,7 +34,11 @@ void isis_spftree_del(struct isis_spftree *spftree); void spftree_area_init(struct isis_area *area); void spftree_area_del(struct isis_area *area); void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj); -int isis_spf_schedule(struct isis_area *area, int level); +#define isis_spf_schedule(area, level) \ + _isis_spf_schedule((area), (level), __func__, \ + __FILE__, __LINE__) +int _isis_spf_schedule(struct isis_area *area, int level, + const char *func, const char *file, int line); void isis_spf_cmds_init(void); void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, diff --git a/isisd/isisd.c b/isisd/isisd.c index 94e6a63855..54bdbf3eb3 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -160,6 +160,13 @@ struct isis_area *isis_area_create(const char *area_tag) if (fabricd) area->fabricd = fabricd_new(area); + + area->lsp_refresh_arg[0].area = area; + area->lsp_refresh_arg[0].level = IS_LEVEL_1; + area->lsp_refresh_arg[1].area = area; + area->lsp_refresh_arg[1].level = IS_LEVEL_2; + + QOBJ_REG(area, isis_area); return area; diff --git a/isisd/isisd.h b/isisd/isisd.h index 7572f55174..51b359aad4 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -90,6 +90,11 @@ enum spf_tree_id { SPFTREE_COUNT }; +struct lsp_refresh_arg { + struct isis_area *area; + int level; +}; + struct isis_area { struct isis *isis; /* back pointer */ dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */ @@ -100,6 +105,7 @@ struct isis_area { struct flags flags; struct thread *t_tick; /* LSP walker */ struct thread *t_lsp_refresh[ISIS_LEVELS]; + struct timeval last_lsp_refresh_event[ISIS_LEVELS]; /* t_lsp_refresh is used in two ways: * a) regular refresh of LSPs * b) (possibly throttled) updates to LSPs @@ -160,6 +166,8 @@ struct isis_area { parameters*/ struct thread *spf_timer[ISIS_LEVELS]; + struct lsp_refresh_arg lsp_refresh_arg[ISIS_LEVELS]; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(isis_area)