forked from Mirror/frr
Merge pull request #3230 from opensourcerouting/feature/isis-improve-lsp-scheduling
Feature: IS-IS improve lsp scheduling
This commit is contained in:
commit
a8afa9e786
|
@ -59,8 +59,7 @@
|
||||||
#include "isisd/fabricd.h"
|
#include "isisd/fabricd.h"
|
||||||
#include "isisd/isis_tx_queue.h"
|
#include "isisd/isis_tx_queue.h"
|
||||||
|
|
||||||
static int lsp_l1_refresh(struct thread *thread);
|
static int lsp_refresh(struct thread *thread);
|
||||||
static int lsp_l2_refresh(struct thread *thread);
|
|
||||||
static int lsp_l1_refresh_pseudo(struct thread *thread);
|
static int lsp_l1_refresh_pseudo(struct thread *thread);
|
||||||
static int lsp_l2_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]);
|
THREAD_TIMER_OFF(area->t_lsp_refresh[level - 1]);
|
||||||
area->lsp_regenerate_pending[level - 1] = 0;
|
area->lsp_regenerate_pending[level - 1] = 0;
|
||||||
if (level == IS_LEVEL_1)
|
thread_add_timer(master, lsp_refresh,
|
||||||
thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
|
&area->lsp_refresh_arg[level - 1], refresh_time,
|
||||||
&area->t_lsp_refresh[level - 1]);
|
&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]);
|
|
||||||
|
|
||||||
if (isis->debugs & DEBUG_UPDATE_PACKETS) {
|
if (isis->debugs & DEBUG_UPDATE_PACKETS) {
|
||||||
zlog_debug("ISIS-Upd (%s): Building L%d LSP %s, len %" PRIu16
|
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);
|
lsp_seqno_update(lsp);
|
||||||
|
|
||||||
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
|
refresh_time = lsp_refresh_time(lsp, rem_lifetime);
|
||||||
if (level == IS_LEVEL_1)
|
thread_add_timer(master, lsp_refresh,
|
||||||
thread_add_timer(master, lsp_l1_refresh, area, refresh_time,
|
&area->lsp_refresh_arg[level - 1], refresh_time,
|
||||||
&area->t_lsp_refresh[level - 1]);
|
&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]);
|
|
||||||
area->lsp_regenerate_pending[level - 1] = 0;
|
area->lsp_regenerate_pending[level - 1] = 0;
|
||||||
|
|
||||||
if (isis->debugs & DEBUG_UPDATE_PACKETS) {
|
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
|
* 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);
|
assert(area);
|
||||||
|
|
||||||
area->t_lsp_refresh[0] = NULL;
|
int level = arg->level;
|
||||||
area->lsp_regenerate_pending[0] = 0;
|
|
||||||
|
|
||||||
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;
|
return ISIS_ERROR;
|
||||||
|
|
||||||
sched_debug(
|
if (monotime_since(&area->last_lsp_refresh_event[level - 1], NULL) < 50000L) {
|
||||||
"ISIS (%s): LSP L1 refresh timer expired. Refreshing LSP...",
|
sched_debug("ISIS (%s): Still unstable, postpone LSP L%d refresh",
|
||||||
area->area_tag);
|
area->area_tag, level);
|
||||||
return lsp_regenerate(area, IS_LEVEL_1);
|
_lsp_regenerate_schedule(area, level, 0, false,
|
||||||
}
|
__func__, __FILE__, __LINE__);
|
||||||
|
return 0;
|
||||||
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;
|
|
||||||
|
|
||||||
sched_debug(
|
sched_debug(
|
||||||
"ISIS (%s): LSP L2 refresh timer expired. Refreshing LSP...",
|
"ISIS (%s): LSP L%d refresh timer expired. Refreshing LSP...",
|
||||||
area->area_tag);
|
area->area_tag, level);
|
||||||
return lsp_regenerate(area, IS_LEVEL_2);
|
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;
|
struct isis_lsp *lsp;
|
||||||
uint8_t id[ISIS_SYS_ID_LEN + 2];
|
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;
|
return ISIS_ERROR;
|
||||||
|
|
||||||
sched_debug(
|
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),
|
area->area_tag, circuit_t2string(level),
|
||||||
all_pseudo ? "" : "not ");
|
all_pseudo ? "" : "not ",
|
||||||
|
func, file, line);
|
||||||
|
|
||||||
memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
|
memcpy(id, isis->sysid, ISIS_SYS_ID_LEN);
|
||||||
LSP_PSEUDO_ID(id) = LSP_FRAGMENT(id) = 0;
|
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)))
|
if (!((level & lvl) && (area->is_type & lvl)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (postpone) {
|
||||||
|
monotime(&area->last_lsp_refresh_event[lvl - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
sched_debug(
|
sched_debug(
|
||||||
"ISIS (%s): Checking whether L%d needs to be scheduled",
|
"ISIS (%s): Checking whether L%d needs to be scheduled",
|
||||||
area->area_tag, lvl);
|
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;
|
area->lsp_regenerate_pending[lvl - 1] = 1;
|
||||||
if (lvl == IS_LEVEL_1) {
|
thread_add_timer_msec(master, lsp_refresh,
|
||||||
thread_add_timer_msec(master, lsp_l1_refresh, area,
|
&area->lsp_refresh_arg[lvl - 1],
|
||||||
timeout,
|
timeout,
|
||||||
&area->t_lsp_refresh[lvl - 1]);
|
&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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all_pseudo) {
|
if (all_pseudo) {
|
||||||
|
|
|
@ -54,7 +54,12 @@ void lsp_db_destroy(dict_t *lspdb);
|
||||||
int lsp_tick(struct thread *thread);
|
int lsp_tick(struct thread *thread);
|
||||||
|
|
||||||
int lsp_generate(struct isis_area *area, int level);
|
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_generate_pseudo(struct isis_circuit *circuit, int level);
|
||||||
int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level);
|
int lsp_regenerate_schedule_pseudo(struct isis_circuit *circuit, int level);
|
||||||
|
|
||||||
|
|
|
@ -1248,7 +1248,8 @@ static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
|
||||||
return run;
|
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];
|
struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1];
|
||||||
time_t now = monotime(NULL);
|
time_t now = monotime(NULL);
|
||||||
|
@ -1257,10 +1258,12 @@ int isis_spf_schedule(struct isis_area *area, int level)
|
||||||
assert(diff >= 0);
|
assert(diff >= 0);
|
||||||
assert(area->is_type & level);
|
assert(area->is_type & level);
|
||||||
|
|
||||||
if (isis->debugs & DEBUG_SPF_EVENTS)
|
if (isis->debugs & DEBUG_SPF_EVENTS) {
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
|
"ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago"
|
||||||
area->area_tag, level, diff);
|
" Caller: %s %s:%d",
|
||||||
|
area->area_tag, level, diff, func, file, line);
|
||||||
|
}
|
||||||
|
|
||||||
if (area->spf_delay_ietf[level - 1]) {
|
if (area->spf_delay_ietf[level - 1]) {
|
||||||
/* Need to call schedule function also if spf delay is running
|
/* Need to call schedule function also if spf delay is running
|
||||||
|
|
|
@ -34,7 +34,11 @@ void isis_spftree_del(struct isis_spftree *spftree);
|
||||||
void spftree_area_init(struct isis_area *area);
|
void spftree_area_init(struct isis_area *area);
|
||||||
void spftree_area_del(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);
|
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_cmds_init(void);
|
||||||
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
|
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
|
||||||
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
|
struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
|
||||||
|
|
|
@ -160,6 +160,13 @@ struct isis_area *isis_area_create(const char *area_tag)
|
||||||
|
|
||||||
if (fabricd)
|
if (fabricd)
|
||||||
area->fabricd = fabricd_new(area);
|
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);
|
QOBJ_REG(area, isis_area);
|
||||||
|
|
||||||
return area;
|
return area;
|
||||||
|
|
|
@ -90,6 +90,11 @@ enum spf_tree_id {
|
||||||
SPFTREE_COUNT
|
SPFTREE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct lsp_refresh_arg {
|
||||||
|
struct isis_area *area;
|
||||||
|
int level;
|
||||||
|
};
|
||||||
|
|
||||||
struct isis_area {
|
struct isis_area {
|
||||||
struct isis *isis; /* back pointer */
|
struct isis *isis; /* back pointer */
|
||||||
dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */
|
dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */
|
||||||
|
@ -100,6 +105,7 @@ struct isis_area {
|
||||||
struct flags flags;
|
struct flags flags;
|
||||||
struct thread *t_tick; /* LSP walker */
|
struct thread *t_tick; /* LSP walker */
|
||||||
struct thread *t_lsp_refresh[ISIS_LEVELS];
|
struct thread *t_lsp_refresh[ISIS_LEVELS];
|
||||||
|
struct timeval last_lsp_refresh_event[ISIS_LEVELS];
|
||||||
/* t_lsp_refresh is used in two ways:
|
/* t_lsp_refresh is used in two ways:
|
||||||
* a) regular refresh of LSPs
|
* a) regular refresh of LSPs
|
||||||
* b) (possibly throttled) updates to LSPs
|
* b) (possibly throttled) updates to LSPs
|
||||||
|
@ -160,6 +166,8 @@ struct isis_area {
|
||||||
parameters*/
|
parameters*/
|
||||||
struct thread *spf_timer[ISIS_LEVELS];
|
struct thread *spf_timer[ISIS_LEVELS];
|
||||||
|
|
||||||
|
struct lsp_refresh_arg lsp_refresh_arg[ISIS_LEVELS];
|
||||||
|
|
||||||
QOBJ_FIELDS
|
QOBJ_FIELDS
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(isis_area)
|
DECLARE_QOBJ_TYPE(isis_area)
|
||||||
|
|
Loading…
Reference in a new issue