}
}
+ if (adj->threeway_state != next_tw_state) {
+ send_hello_sched(adj->circuit, 0, TRIGGERED_IIH_DELAY);
+ }
+
adj->threeway_state = next_tw_state;
}
void isis_adj_state_change(struct isis_adjacency *adj,
enum isis_adj_state new_state, const char *reason)
{
- int old_state;
- int level;
- struct isis_circuit *circuit;
+ enum isis_adj_state old_state = adj->adj_state;
+ struct isis_circuit *circuit = adj->circuit;
bool del;
- old_state = adj->adj_state;
adj->adj_state = new_state;
-
- circuit = adj->circuit;
+ if (new_state != old_state) {
+ send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
+ }
if (isis->debugs & DEBUG_ADJ_PACKETS) {
zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
del = false;
- for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
+ for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
if ((adj->level & level) == 0)
continue;
if (new_state == ISIS_ADJ_UP) {
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
del = false;
- for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
+ for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
if ((adj->level & level) == 0)
continue;
if (new_state == ISIS_ADJ_UP) {
circuit->upadjcount[level - 1]++;
hook_call(isis_adj_state_change_hook, adj);
- if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
- send_hello(circuit, level);
-
/* update counter & timers for debugging
* purposes */
adj->last_flap = time(NULL);
if (del)
isis_delete_adj(adj);
}
-
- return;
}
circuit->priority[i] = DEFAULT_PRIORITY;
circuit->metric[i] = DEFAULT_CIRCUIT_METRIC;
circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
+ circuit->level_arg[i].level = i + 1;
+ circuit->level_arg[i].circuit = circuit;
}
circuit->mtc = mpls_te_circuit_new();
/* 8.4.1 a) commence sending of IIH PDUs */
- if (circuit->is_type & IS_LEVEL_1) {
- thread_add_event(master, send_lan_l1_hello, circuit, 0,
- NULL);
- circuit->u.bc.lan_neighs[0] = list_new();
- }
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
+ if (!(circuit->is_type & level))
+ continue;
- if (circuit->is_type & IS_LEVEL_2) {
- thread_add_event(master, send_lan_l2_hello, circuit, 0,
- NULL);
- circuit->u.bc.lan_neighs[1] = list_new();
+ send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY);
+ circuit->u.bc.lan_neighs[level - 1] = list_new();
+
+ thread_add_timer(master, isis_run_dr,
+ &circuit->level_arg[level - 1],
+ 2 * circuit->hello_interval[level - 1],
+ &circuit->u.bc.t_run_dr[level - 1]);
}
/* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
/* 8.4.1 c) FIXME: listen for ESH PDUs */
-
- /* 8.4.1 d) */
- /* dr election will commence in... */
- if (circuit->is_type & IS_LEVEL_1)
- thread_add_timer(master, isis_run_dr_l1, circuit,
- 2 * circuit->hello_interval[0],
- &circuit->u.bc.t_run_dr[0]);
- if (circuit->is_type & IS_LEVEL_2)
- thread_add_timer(master, isis_run_dr_l2, circuit,
- 2 * circuit->hello_interval[1],
- &circuit->u.bc.t_run_dr[1]);
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
/* initializing the hello send threads
* for a ptp IF
*/
circuit->u.p2p.neighbor = NULL;
- thread_add_event(master, send_p2p_hello, circuit, 0, NULL);
+ send_hello_sched(circuit, 0, TRIGGERED_IIH_DELAY);
}
/* initializing PSNP timers */
struct bfd_info;
+struct isis_circuit_arg {
+ int level;
+ struct isis_circuit *circuit;
+};
+
struct isis_circuit {
int state;
uint8_t circuit_id; /* l1/l2 bcast CircuitID */
struct thread *t_send_psnp[2];
struct thread *t_send_lsp;
struct isis_tx_queue *tx_queue;
+ struct isis_circuit_arg level_arg[2]; /* used as argument for threads */
/* there is no real point in two streams, just for programming kicker */
int (*rx)(struct isis_circuit *circuit, uint8_t *ssnpa);
#define MIN_LSP_RETRANS_INTERVAL 5 /* Seconds */
+#define TRIGGERED_IIH_DELAY 50 /* msec */
+
#define MIN_CSNP_INTERVAL 1
#define MAX_CSNP_INTERVAL 600
#define DEFAULT_CSNP_INTERVAL 10
return NULL; /* not reached */
}
-int isis_run_dr_l1(struct thread *thread)
+int isis_run_dr(struct thread *thread)
{
- struct isis_circuit *circuit;
+ struct isis_circuit_arg *arg = THREAD_ARG(thread);
- circuit = THREAD_ARG(thread);
- assert(circuit);
-
- if (circuit->u.bc.run_dr_elect[0])
- zlog_warn("isis_run_dr(): run_dr_elect already set for l1");
-
- circuit->u.bc.t_run_dr[0] = NULL;
- circuit->u.bc.run_dr_elect[0] = 1;
+ assert(arg);
- return ISIS_OK;
-}
+ struct isis_circuit *circuit = arg->circuit;
+ int level = arg->level;
-int isis_run_dr_l2(struct thread *thread)
-{
- struct isis_circuit *circuit;
-
- circuit = THREAD_ARG(thread);
assert(circuit);
- if (circuit->u.bc.run_dr_elect[1])
- zlog_warn("isis_run_dr(): run_dr_elect already set for l2");
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+ zlog_warn("%s: scheduled for non broadcast circuit from %s:%d",
+ __func__, thread->schedfrom, thread->schedfrom_line);
+ return ISIS_WARNING;
+ }
+ if (circuit->u.bc.run_dr_elect[level - 1])
+ zlog_warn("isis_run_dr(): run_dr_elect already set for l%d", level);
- circuit->u.bc.t_run_dr[1] = NULL;
- circuit->u.bc.run_dr_elect[1] = 1;
+ circuit->u.bc.t_run_dr[level - 1] = NULL;
+ circuit->u.bc.run_dr_elect[level - 1] = 1;
return ISIS_OK;
}
if (level == 1) {
memset(circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
- THREAD_TIMER_OFF(circuit->t_send_csnp[0]);
-
- thread_add_timer(master, isis_run_dr_l1, circuit,
- 2 * circuit->hello_interval[0],
- &circuit->u.bc.t_run_dr[0]);
-
thread_add_timer(master, send_l1_psnp, circuit,
isis_jitter(circuit->psnp_interval[level - 1],
PSNP_JITTER),
} else {
memset(circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
- THREAD_TIMER_OFF(circuit->t_send_csnp[1]);
-
- thread_add_timer(master, isis_run_dr_l2, circuit,
- 2 * circuit->hello_interval[1],
- &circuit->u.bc.t_run_dr[1]);
-
thread_add_timer(master, send_l2_psnp, circuit,
isis_jitter(circuit->psnp_interval[level - 1],
PSNP_JITTER),
&circuit->t_send_psnp[1]);
}
+ THREAD_TIMER_OFF(circuit->t_send_csnp[level - 1]);
+
+ thread_add_timer(master, isis_run_dr,
+ &circuit->level_arg[level - 1],
+ 2 * circuit->hello_interval[level - 1],
+ &circuit->u.bc.t_run_dr[level - 1]);
+
+
thread_add_event(master, isis_event_dis_status_change, circuit, 0,
NULL);
/* Lets keep a pause in DR election */
circuit->u.bc.run_dr_elect[level - 1] = 0;
- if (level == 1)
- thread_add_timer(master, isis_run_dr_l1, circuit,
- 2 * circuit->hello_interval[0],
- &circuit->u.bc.t_run_dr[0]);
- else
- thread_add_timer(master, isis_run_dr_l2, circuit,
- 2 * circuit->hello_interval[1],
- &circuit->u.bc.t_run_dr[1]);
circuit->u.bc.is_dr[level - 1] = 1;
if (level == 1) {
thread_cancel (circuit->t_send_l1_psnp); */
lsp_generate_pseudo(circuit, 1);
- THREAD_TIMER_OFF(circuit->u.bc.t_run_dr[0]);
- thread_add_timer(master, isis_run_dr_l1, circuit,
- 2 * circuit->hello_interval[0],
- &circuit->u.bc.t_run_dr[0]);
-
thread_add_timer(master, send_l1_csnp, circuit,
isis_jitter(circuit->csnp_interval[level - 1],
CSNP_JITTER),
thread_cancel (circuit->t_send_l1_psnp); */
lsp_generate_pseudo(circuit, 2);
- THREAD_TIMER_OFF(circuit->u.bc.t_run_dr[1]);
- thread_add_timer(master, isis_run_dr_l2, circuit,
- 2 * circuit->hello_interval[1],
- &circuit->u.bc.t_run_dr[1]);
-
thread_add_timer(master, send_l2_csnp, circuit,
isis_jitter(circuit->csnp_interval[level - 1],
CSNP_JITTER),
&circuit->t_send_csnp[1]);
}
+ thread_add_timer(master, isis_run_dr,
+ &circuit->level_arg[level - 1],
+ 2 * circuit->hello_interval[level - 1],
+ &circuit->u.bc.t_run_dr[level - 1]);
thread_add_event(master, isis_event_dis_status_change, circuit, 0,
NULL);
#ifndef _ZEBRA_ISIS_DR_H
#define _ZEBRA_ISIS_DR_H
-int isis_run_dr_l1(struct thread *thread);
-int isis_run_dr_l2(struct thread *thread);
+int isis_run_dr(struct thread *thread);
int isis_dr_elect(struct isis_circuit *circuit, int level);
int isis_dr_resign(struct isis_circuit *circuit, int level);
int isis_dr_commence(struct isis_circuit *circuit, int level);
static void circuit_commence_level(struct isis_circuit *circuit, int level)
{
- if (level == 1) {
- if (!circuit->is_passive)
+ if (!circuit->is_passive) {
+ if (level == 1) {
thread_add_timer(master, send_l1_psnp, circuit,
isis_jitter(circuit->psnp_interval[0],
PSNP_JITTER),
&circuit->t_send_psnp[0]);
-
- if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
- thread_add_timer(master, isis_run_dr_l1, circuit,
- 2 * circuit->hello_interval[0],
- &circuit->u.bc.t_run_dr[0]);
-
- thread_add_timer(master, send_lan_l1_hello, circuit,
- isis_jitter(circuit->hello_interval[0],
- IIH_JITTER),
- &circuit->u.bc.t_send_lan_hello[0]);
-
- circuit->u.bc.lan_neighs[0] = list_new();
- }
- } else {
- if (!circuit->is_passive)
+ } else {
thread_add_timer(master, send_l2_psnp, circuit,
isis_jitter(circuit->psnp_interval[1],
PSNP_JITTER),
&circuit->t_send_psnp[1]);
-
- if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
- thread_add_timer(master, isis_run_dr_l2, circuit,
- 2 * circuit->hello_interval[1],
- &circuit->u.bc.t_run_dr[1]);
-
- thread_add_timer(master, send_lan_l2_hello, circuit,
- isis_jitter(circuit->hello_interval[1],
- IIH_JITTER),
- &circuit->u.bc.t_send_lan_hello[1]);
-
- circuit->u.bc.lan_neighs[1] = list_new();
}
}
- return;
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ thread_add_timer(master, isis_run_dr,
+ &circuit->level_arg[level - 1],
+ 2 * circuit->hello_interval[level - 1],
+ &circuit->u.bc.t_run_dr[level - 1]);
+
+ send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY);
+ circuit->u.bc.lan_neighs[level - 1] = list_new();
+ }
}
static void circuit_resign_level(struct isis_circuit *circuit, int level)
return retval;
}
-int send_lan_l1_hello(struct thread *thread)
+static int send_hello_cb(struct thread *thread)
{
- struct isis_circuit *circuit;
- int retval;
+ struct isis_circuit_arg *arg = THREAD_ARG(thread);
+
+ assert(arg);
+
+ struct isis_circuit *circuit = arg->circuit;
+ int level = arg->level;
- circuit = THREAD_ARG(thread);
assert(circuit);
- circuit->u.bc.t_send_lan_hello[0] = NULL;
- if (!(circuit->area->is_type & IS_LEVEL_1)) {
- zlog_warn(
- "ISIS-Hello (%s): Trying to send L1 IIH in L2-only area",
- circuit->area->area_tag);
- return 1;
+ if (circuit->circ_type == CIRCUIT_T_P2P) {
+ circuit->u.p2p.t_send_p2p_hello = NULL;
+ send_hello(circuit, 1);
+ send_hello_sched(circuit, ISIS_LEVEL1,
+ 1000 * circuit->hello_interval[1]);
+ return ISIS_OK;
}
- if (circuit->u.bc.run_dr_elect[0])
- isis_dr_elect(circuit, 1);
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+ zlog_warn("ISIS-Hello (%s): Trying to send hello on unknown circuit type %d",
+ circuit->area->area_tag, circuit->circ_type);
+ return ISIS_WARNING;
+ }
- retval = send_hello(circuit, 1);
+ circuit->u.bc.t_send_lan_hello[level - 1] = NULL;
+ if (!(circuit->is_type & level)) {
+ zlog_warn("ISIS-Hello (%s): Trying to send L%d IIH in L%d-only circuit",
+ circuit->area->area_tag, level, 3 - level);
+ return ISIS_WARNING;
+ }
- /* set next timer thread */
- thread_add_timer(master, send_lan_l1_hello, circuit,
- isis_jitter(circuit->hello_interval[0], IIH_JITTER),
- &circuit->u.bc.t_send_lan_hello[0]);
+ if (circuit->u.bc.run_dr_elect[level - 1])
+ isis_dr_elect(circuit, level);
- return retval;
+ int rv = send_hello(circuit, level);
+
+ /* set next timer thread */
+ send_hello_sched(circuit, level, 1000 * circuit->hello_interval[level - 1]);
+ return rv;
}
-int send_lan_l2_hello(struct thread *thread)
+static void _send_hello_sched(struct isis_circuit *circuit,
+ struct thread **threadp,
+ int level, long delay)
{
- struct isis_circuit *circuit;
- int retval;
-
- circuit = THREAD_ARG(thread);
- assert(circuit);
- circuit->u.bc.t_send_lan_hello[1] = NULL;
+ if (*threadp) {
+ if (thread_timer_remain_msec(*threadp) < (unsigned long)delay)
+ return;
- if (!(circuit->area->is_type & IS_LEVEL_2)) {
- zlog_warn("ISIS-Hello (%s): Trying to send L2 IIH in L1 area",
- circuit->area->area_tag);
- return 1;
+ thread_cancel(*threadp);
}
- if (circuit->u.bc.run_dr_elect[1])
- isis_dr_elect(circuit, 2);
-
- retval = send_hello(circuit, 2);
-
- /* set next timer thread */
- thread_add_timer(master, send_lan_l2_hello, circuit,
- isis_jitter(circuit->hello_interval[1], IIH_JITTER),
- &circuit->u.bc.t_send_lan_hello[1]);
-
- return retval;
+ thread_add_timer_msec(master, send_hello_cb,
+ &circuit->level_arg[level - 1],
+ isis_jitter(delay, IIH_JITTER),
+ threadp);
}
-int send_p2p_hello(struct thread *thread)
+void send_hello_sched(struct isis_circuit *circuit, int level, long delay)
{
- struct isis_circuit *circuit;
-
- circuit = THREAD_ARG(thread);
- assert(circuit);
- circuit->u.p2p.t_send_p2p_hello = NULL;
+ if (circuit->circ_type == CIRCUIT_T_P2P) {
+ _send_hello_sched(circuit, &circuit->u.p2p.t_send_p2p_hello,
+ ISIS_LEVEL1, delay);
+ return;
+ }
- send_hello(circuit, 1);
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
+ zlog_warn("%s: encountered unknown circuit type %d on %s",
+ __func__, circuit->circ_type,
+ circuit->interface->name);
+ return;
+ }
- /* set next timer thread */
- thread_add_timer(master, send_p2p_hello, circuit,
- isis_jitter(circuit->hello_interval[1], IIH_JITTER),
- &circuit->u.p2p.t_send_p2p_hello);
+ for (int loop_level = ISIS_LEVEL1; loop_level <= ISIS_LEVEL2; loop_level++) {
+ if (!(loop_level & level))
+ continue;
- return ISIS_OK;
+ _send_hello_sched(
+ circuit,
+ &circuit->u.bc.t_send_lan_hello[loop_level - 1],
+ loop_level,
+ delay
+ );
+ }
}
+
/*
* Count the maximum number of lsps that can be accomodated by a given size.
*/
/*
* Sending functions
*/
-int send_lan_l1_hello(struct thread *thread);
-int send_lan_l2_hello(struct thread *thread);
-int send_p2p_hello(struct thread *thread);
+void send_hello_sched(struct isis_circuit *circuit, int level, long delay);
int send_csnp(struct isis_circuit *circuit, int level);
int send_l1_csnp(struct thread *thread);
int send_l2_csnp(struct thread *thread);
XFREE(MTYPE_THREAD_MASTER, m);
}
-/* Return remain time in second. */
-unsigned long thread_timer_remain_second(struct thread *thread)
+/* Return remain time in miliseconds. */
+unsigned long thread_timer_remain_msec(struct thread *thread)
{
int64_t remain;
pthread_mutex_lock(&thread->mtx);
{
- remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
+ remain = monotime_until(&thread->u.sands, NULL) / 1000LL;
}
pthread_mutex_unlock(&thread->mtx);
return remain < 0 ? 0 : remain;
}
+/* Return remain time in seconds. */
+unsigned long thread_timer_remain_second(struct thread *thread)
+{
+ return thread_timer_remain_msec(thread) / 1000LL;
+}
+
#define debugargdef const char *funcname, const char *schedfrom, int fromln
#define debugargpass funcname, schedfrom, fromln
extern void thread_call(struct thread *);
extern unsigned long thread_timer_remain_second(struct thread *);
extern struct timeval thread_timer_remain(struct thread *);
+extern unsigned long thread_timer_remain_msec(struct thread *);
extern int thread_should_yield(struct thread *);
/* set yield time for thread */
extern void thread_set_yield_time(struct thread *, unsigned long);
hostname r1
+debug isis adj-packets
+debug isis events
+debug isis update-packets
interface r1-eth0
ip router isis 1
ipv6 router isis 1
hostname r2
+debug isis adj-packets
+debug isis events
+debug isis update-packets
interface r2-eth0
ip router isis 1
ipv6 router isis 1
hostname r3
+debug isis adj-packets
+debug isis events
+debug isis update-packets
interface r3-eth0
ip router isis 1
ipv6 router isis 1
hostname r4
+debug isis adj-packets
+debug isis events
+debug isis update-packets
interface r4-eth0
ip router isis 1
ipv6 router isis 1
hostname r5
+debug isis adj-packets
+debug isis events
+debug isis update-packets
interface r5-eth0
ip router isis 1
ipv6 router isis 1
"Returns True if there were errors, otherwise False."
return len(self.errors) > 0
+ def __str__(self):
+ return '\n'.join(self.errors)
+
def get_test_logdir(node=None, init=False):
"""
Return the current test log directory based on PYTEST_CURRENT_TEST