Skip to content

Commit

Permalink
isisd: implement threeway adjacencies
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
  • Loading branch information
cfra committed Mar 10, 2018
1 parent 9fe2120 commit 42fe262
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 50 deletions.
47 changes: 47 additions & 0 deletions isisd/isis_adjacency.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
9 changes: 9 additions & 0 deletions isisd/isis_adjacency.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -91,19 +93,26 @@ 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 */
uint16_t *mt_set; /* Topologies this adjacency is valid for */
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);
Expand Down
119 changes: 69 additions & 50 deletions isisd/isis_pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -232,40 +253,31 @@ 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)) {
/* (8) down - wrong system */
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)) {
/* (8) down - wrong system */
isis_adj_state_change(adj,
ISIS_ADJ_DOWN,
"Wrong System");
} else if (adj->adj_usage
== ISIS_ADJ_LEVEL1AND2) {
; /* Accept */
}
break;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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,
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 42fe262

Please sign in to comment.