mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-29 12:18:12 +00:00
isisd: implement threeway adjacencies
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
This commit is contained in:
parent
9fe2120814
commit
42fe262197
@ -47,6 +47,7 @@
|
||||
#include "isisd/isis_spf.h"
|
||||
#include "isisd/isis_events.h"
|
||||
#include "isisd/isis_mt.h"
|
||||
#include "isisd/isis_tlvs.h"
|
||||
|
||||
extern struct isis *isis;
|
||||
|
||||
@ -78,6 +79,7 @@ struct isis_adjacency *isis_new_adj(const u_char *id, const u_char *snpa,
|
||||
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;
|
||||
@ -161,6 +163,51 @@ static const char *adj_state2string(int state)
|
||||
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)
|
||||
{
|
||||
|
@ -25,6 +25,8 @@
|
||||
#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,
|
||||
@ -91,6 +93,8 @@ struct isis_adjacency {
|
||||
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 */
|
||||
@ -98,12 +102,17 @@ struct isis_adjacency {
|
||||
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);
|
||||
|
119
isisd/isis_pdu.c
119
isisd/isis_pdu.c
@ -120,6 +120,32 @@ struct iih_info {
|
||||
|
||||
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
|
||||
@ -155,6 +181,9 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
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);
|
||||
@ -183,14 +212,10 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
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:
|
||||
@ -213,14 +238,10 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
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
|
||||
@ -232,12 +253,10 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
}
|
||||
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)) {
|
||||
@ -245,17 +264,13 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
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)) {
|
||||
@ -263,9 +278,6 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
isis_adj_state_change(adj,
|
||||
ISIS_ADJ_DOWN,
|
||||
"Wrong System");
|
||||
} else if (adj->adj_usage
|
||||
== ISIS_ADJ_LEVEL1AND2) {
|
||||
; /* Accept */
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -292,20 +304,16 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
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;
|
||||
}
|
||||
@ -350,12 +358,10 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
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,
|
||||
@ -374,8 +380,6 @@ static int process_p2p_hello(struct iih_info *iih)
|
||||
adj, ISIS_ADJ_DOWN,
|
||||
"Area Mismatch");
|
||||
}
|
||||
} else if (adj->adj_usage == ISIS_ADJ_LEVEL2) {
|
||||
; /* Accept */
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1552,9 +1556,24 @@ int send_hello(struct isis_circuit *circuit, int level)
|
||||
|
||||
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user