#include "isisd/isis_spf.h"
#include "isisd/isis_events.h"
#include "isisd/isis_mt.h"
+#include "isisd/isis_tlvs.h"
extern struct isis *isis;
adj->level = level;
adj->flaps = 0;
adj->last_flap = time(NULL);
+ adj->threeway_state = ISIS_THREEWAY_DOWN;
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
listnode_add(circuit->u.bc.adjdb[level - 1], adj);
adj->dischanges[level - 1] = 0;
return NULL; /* not reached */
}
+void isis_adj_process_threeway(struct isis_adjacency *adj,
+ struct isis_threeway_adj *tw_adj,
+ enum isis_adj_usage adj_usage)
+{
+ enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN;
+
+ if (tw_adj) {
+ if (tw_adj->state == ISIS_THREEWAY_DOWN) {
+ next_tw_state = ISIS_THREEWAY_INITIALIZING;
+ } else if (tw_adj->state == ISIS_THREEWAY_INITIALIZING) {
+ next_tw_state = ISIS_THREEWAY_UP;
+ } else if (tw_adj->state == ISIS_THREEWAY_UP) {
+ if (adj->threeway_state == ISIS_THREEWAY_DOWN)
+ next_tw_state = ISIS_THREEWAY_DOWN;
+ else
+ next_tw_state = ISIS_THREEWAY_UP;
+ }
+ } else {
+ next_tw_state = ISIS_THREEWAY_UP;
+ }
+
+ if (next_tw_state != adj->threeway_state) {
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_info("ISIS-Adj (%s): Threeway state change %s to %s",
+ adj->circuit->area->area_tag,
+ isis_threeway_state_name(adj->threeway_state),
+ isis_threeway_state_name(next_tw_state));
+ }
+ }
+
+ if (next_tw_state == ISIS_THREEWAY_DOWN) {
+ isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Neighbor restarted");
+ return;
+ }
+
+ if (next_tw_state == ISIS_THREEWAY_UP) {
+ if (adj->adj_state != ISIS_ADJ_UP) {
+ isis_adj_state_change(adj, ISIS_ADJ_UP, NULL);
+ adj->adj_usage = adj_usage;
+ }
+ }
+
+ adj->threeway_state = next_tw_state;
+}
+
void isis_adj_state_change(struct isis_adjacency *adj,
enum isis_adj_state new_state, const char *reason)
{
#ifndef _ZEBRA_ISIS_ADJACENCY_H
#define _ZEBRA_ISIS_ADJACENCY_H
+#include "isisd/isis_tlvs.h"
+
enum isis_adj_usage {
ISIS_ADJ_NONE,
ISIS_ADJ_LEVEL1,
u_int16_t hold_time; /* entryRemainingTime */
u_int32_t last_upd;
u_int32_t last_flap; /* last time the adj flapped */
+ enum isis_threeway_state threeway_state;
+ uint32_t ext_circuit_id;
int flaps; /* number of adjacency flaps */
struct thread *t_expire; /* expire after hold_time */
struct isis_circuit *circuit; /* back pointer */
unsigned int mt_count; /* Number of entries in mt_set */
};
+struct isis_threeway_adj;
+
struct isis_adjacency *isis_adj_lookup(const u_char *sysid, struct list *adjdb);
struct isis_adjacency *isis_adj_lookup_snpa(const u_char *ssnpa,
struct list *adjdb);
struct isis_adjacency *isis_new_adj(const u_char *id, const u_char *snpa,
int level, struct isis_circuit *circuit);
void isis_delete_adj(void *adj);
+void isis_adj_process_threeway(struct isis_adjacency *adj,
+ struct isis_threeway_adj *tw_adj,
+ enum isis_adj_usage adj_usage);
void isis_adj_state_change(struct isis_adjacency *adj,
enum isis_adj_state state, const char *reason);
void isis_adj_print(struct isis_adjacency *adj);
static int process_p2p_hello(struct iih_info *iih)
{
+ struct isis_threeway_adj *tw_adj = iih->tlvs->threeway_adj;
+ if (tw_adj) {
+ if (tw_adj->state > ISIS_THREEWAY_DOWN) {
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with invalid three-way state: %d\n",
+ iih->circuit->area->area_tag,
+ iih->circuit->interface->name,
+ tw_adj->state);
+ }
+ return ISIS_WARNING;
+ }
+
+ if (tw_adj->neighbor_set
+ && (memcmp(tw_adj->neighbor_id, isis->sysid, ISIS_SYS_ID_LEN)
+ || tw_adj->neighbor_circuit_id != (uint32_t) iih->circuit->idx)) {
+
+ if (isis->debugs & DEBUG_ADJ_PACKETS) {
+ zlog_debug("ISIS-Adj (%s): Rcvd P2P IIH from (%s) which lists IS/Circuit different from us as neighbor.\n",
+ iih->circuit->area->area_tag,
+ iih->circuit->interface->name);
+ }
+
+ return ISIS_WARNING;
+ }
+ }
+
/*
* My interpertation of the ISO, if no adj exists we will create one for
* the circuit
adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
}
+ if (tw_adj && adj->threeway_state == ISIS_THREEWAY_DOWN)
+ adj->ext_circuit_id = tw_adj->local_circuit_id;
+
/* 8.2.6 Monitoring point-to-point adjacencies */
adj->hold_time = iih->holdtime;
adj->last_upd = time(NULL);
switch (iih->circ_type) {
case IS_LEVEL_1:
case IS_LEVEL_1_AND_2:
- if (adj->adj_state != ISIS_ADJ_UP) {
- /* (4) adj state up */
- isis_adj_state_change(adj, ISIS_ADJ_UP,
- NULL);
- /* (5) adj usage level 1 */
- adj->adj_usage = ISIS_ADJ_LEVEL1;
- } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
- ; /* accept */
+ if (adj->adj_state != ISIS_ADJ_UP
+ || adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ isis_adj_process_threeway(adj, tw_adj,
+ ISIS_ADJ_LEVEL1);
}
break;
case IS_LEVEL_2:
if (iih->circuit->area->is_type == IS_LEVEL_1_AND_2) {
switch (iih->circ_type) {
case IS_LEVEL_1:
- if (adj->adj_state != ISIS_ADJ_UP) {
- /* (6) adj state up */
- isis_adj_state_change(adj, ISIS_ADJ_UP,
- NULL);
- /* (7) adj usage level 1 */
- adj->adj_usage = ISIS_ADJ_LEVEL1;
- } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
- ; /* accept */
+ if (adj->adj_state != ISIS_ADJ_UP
+ || adj->adj_usage == ISIS_ADJ_LEVEL1) {
+ isis_adj_process_threeway(adj, tw_adj,
+ ISIS_ADJ_LEVEL1);
} else if ((adj->adj_usage
== ISIS_ADJ_LEVEL1AND2)
|| (adj->adj_usage
}
break;
case IS_LEVEL_2:
- if (adj->adj_state != ISIS_ADJ_UP) {
- /* (6) adj state up */
- isis_adj_state_change(adj, ISIS_ADJ_UP,
- NULL);
- /* (9) adj usage level 2 */
- adj->adj_usage = ISIS_ADJ_LEVEL2;
+ if (adj->adj_state != ISIS_ADJ_UP
+ || adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ isis_adj_process_threeway(adj, tw_adj,
+ ISIS_ADJ_LEVEL2);
} else if ((adj->adj_usage == ISIS_ADJ_LEVEL1)
|| (adj->adj_usage
== ISIS_ADJ_LEVEL1AND2)) {
isis_adj_state_change(adj,
ISIS_ADJ_DOWN,
"Wrong System");
- } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
- ; /* Accept */
}
break;
case IS_LEVEL_1_AND_2:
- if (adj->adj_state != ISIS_ADJ_UP) {
- /* (6) adj state up */
- isis_adj_state_change(adj, ISIS_ADJ_UP,
- NULL);
- /* (10) adj usage level 1 */
- adj->adj_usage = ISIS_ADJ_LEVEL1AND2;
+ if (adj->adj_state != ISIS_ADJ_UP
+ || adj->adj_usage == ISIS_ADJ_LEVEL1AND2) {
+ isis_adj_process_threeway(adj, tw_adj,
+ ISIS_ADJ_LEVEL1AND2);
} else if ((adj->adj_usage == ISIS_ADJ_LEVEL1)
|| (adj->adj_usage
== ISIS_ADJ_LEVEL2)) {
isis_adj_state_change(adj,
ISIS_ADJ_DOWN,
"Wrong System");
- } else if (adj->adj_usage
- == ISIS_ADJ_LEVEL1AND2) {
- ; /* Accept */
}
break;
}
break;
case IS_LEVEL_1_AND_2:
case IS_LEVEL_2:
- if (adj->adj_state != ISIS_ADJ_UP) {
- /* (7) adj state up */
- isis_adj_state_change(adj, ISIS_ADJ_UP,
- NULL);
- /* (8) adj usage level 2 */
- adj->adj_usage = ISIS_ADJ_LEVEL2;
+ if (adj->adj_state != ISIS_ADJ_UP
+ || adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ isis_adj_process_threeway(adj, tw_adj,
+ ISIS_ADJ_LEVEL2);
} else if (adj->adj_usage
== ISIS_ADJ_LEVEL1AND2) {
/* (6) down - wrong system */
isis_adj_state_change(adj,
ISIS_ADJ_DOWN,
"Wrong System");
- } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
- ; /* Accept */
}
break;
}
break;
case IS_LEVEL_1_AND_2:
case IS_LEVEL_2:
- if (adj->adj_state != ISIS_ADJ_UP) {
- /* (8) adj state up */
- isis_adj_state_change(adj, ISIS_ADJ_UP,
- NULL);
- /* (9) adj usage level 2 */
- adj->adj_usage = ISIS_ADJ_LEVEL2;
+ if (adj->adj_state != ISIS_ADJ_UP
+ || adj->adj_usage == ISIS_ADJ_LEVEL2) {
+ isis_adj_process_threeway(adj, tw_adj,
+ ISIS_ADJ_LEVEL2);
} else if (adj->adj_usage == ISIS_ADJ_LEVEL1) {
/* (7) down - wrong system */
isis_adj_state_change(adj,
adj, ISIS_ADJ_DOWN,
"Area Mismatch");
}
- } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
- ; /* Accept */
}
break;
}
isis_tlvs_add_area_addresses(tlvs, circuit->area->area_addrs);
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
isis_tlvs_add_lan_neighbors(
tlvs, circuit->u.bc.lan_neighs[level - 1]);
+ } else if (circuit->circ_type == CIRCUIT_T_P2P) {
+ uint32_t ext_circuit_id = circuit->idx;
+ if (circuit->u.p2p.neighbor) {
+ isis_tlvs_add_threeway_adj(tlvs,
+ circuit->u.p2p.neighbor->threeway_state,
+ ext_circuit_id,
+ circuit->u.p2p.neighbor->sysid,
+ circuit->u.p2p.neighbor->ext_circuit_id);
+ } else {
+ isis_tlvs_add_threeway_adj(tlvs,
+ ISIS_THREEWAY_DOWN,
+ ext_circuit_id,
+ NULL, 0);
+ }
+ }
isis_tlvs_set_protocols_supported(tlvs, &circuit->nlpids);