summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--isisd/isis_adjacency.c47
-rw-r--r--isisd/isis_adjacency.h9
-rw-r--r--isisd/isis_circuit.c56
-rw-r--r--isisd/isis_circuit.h10
-rw-r--r--isisd/isis_csm.c9
-rw-r--r--isisd/isis_lsp.c10
-rw-r--r--isisd/isis_pdu.c133
-rw-r--r--isisd/isis_route.c40
-rw-r--r--isisd/isis_spf.c42
-rw-r--r--isisd/isis_te.c60
-rw-r--r--isisd/isis_tlvs.c337
-rw-r--r--isisd/isis_tlvs.h24
-rw-r--r--isisd/isis_vty.c17
-rw-r--r--isisd/isisd.h5
-rw-r--r--lib/strlcat.c14
-rw-r--r--lib/strlcpy.c29
-rw-r--r--lib/zebra.h6
-rw-r--r--ospf6d/ospf6_message.c3
-rw-r--r--tests/isisd/test_fuzz_isis_tlv_tests.h.gzbin232370 -> 262877 bytes
-rwxr-xr-xtools/frr-reload.py30
-rw-r--r--zebra/rib.h2
-rw-r--r--zebra/zebra_vrf.c7
-rw-r--r--zebra/zebra_vty.c352
23 files changed, 862 insertions, 380 deletions
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 72e6d4bdb9..a6e1a55a9f 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -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 && !adj->circuit->disable_threeway_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)
{
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 98bb9838fa..2c3bd19af8 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -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);
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 75d4397637..2c443c71f7 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -234,8 +234,8 @@ void isis_circuit_add_addr(struct isis_circuit *circuit,
#ifdef EXTREME_DEBUG
prefix2str(connected->address, buf, sizeof(buf));
- zlog_debug("Added IP address %s to circuit %d", buf,
- circuit->circuit_id);
+ zlog_debug("Added IP address %s to circuit %s", buf,
+ circuit->interface->name);
#endif /* EXTREME_DEBUG */
}
if (connected->address->family == AF_INET6) {
@@ -265,8 +265,8 @@ void isis_circuit_add_addr(struct isis_circuit *circuit,
#ifdef EXTREME_DEBUG
prefix2str(connected->address, buf, sizeof(buf));
- zlog_debug("Added IPv6 address %s to circuit %d", buf,
- circuit->circuit_id);
+ zlog_debug("Added IPv6 address %s to circuit %s", buf,
+ circuit->interface->name);
#endif /* EXTREME_DEBUG */
}
return;
@@ -300,9 +300,9 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
} else {
prefix2str(connected->address, buf, sizeof(buf));
zlog_warn(
- "Nonexistant ip address %s removal attempt from \
- circuit %d",
- buf, circuit->circuit_id);
+ "Nonexistent ip address %s removal attempt from \
+ circuit %s",
+ buf, circuit->interface->name);
zlog_warn("Current ip addresses on %s:",
circuit->interface->name);
for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
@@ -349,9 +349,9 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
if (!found) {
prefix2str(connected->address, buf, sizeof(buf));
zlog_warn(
- "Nonexitant ip address %s removal attempt from \
- circuit %d",
- buf, circuit->circuit_id);
+ "Nonexistent ip address %s removal attempt from \
+ circuit %s",
+ buf, circuit->interface->name);
zlog_warn("Current ip addresses on %s:",
circuit->interface->name);
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
@@ -377,17 +377,15 @@ void isis_circuit_del_addr(struct isis_circuit *circuit,
return;
}
-static uint8_t isis_circuit_id_gen(struct interface *ifp)
+static uint8_t isis_circuit_id_gen(struct isis *isis, struct interface *ifp)
{
/* Circuit ids MUST be unique for any broadcast circuits. Otherwise,
* Pseudo-Node LSPs cannot be generated correctly.
*
- * Currently, allocate one circuit ID for any circuit, limiting the
- * total
+ * Currently, allocate one circuit ID for any circuit, limiting the total
* numer of circuits IS-IS can run on to 255.
*
- * We should revisit this when implementing 3-way adjacencies for p2p,
- * since
+ * We should revisit this when implementing 3-way adjacencies for p2p, since
* we then have extended interface IDs available.
*/
uint8_t id = ifp->ifindex;
@@ -405,6 +403,7 @@ static uint8_t isis_circuit_id_gen(struct interface *ifp)
return 0;
}
+ _ISIS_SET_FLAG(isis->circuit_ids_used, id);
return id;
}
@@ -413,11 +412,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp)
struct listnode *node, *nnode;
struct connected *conn;
- circuit->circuit_id = isis_circuit_id_gen(ifp);
- _ISIS_SET_FLAG(isis->circuit_ids_used, circuit->circuit_id);
-
isis_circuit_if_bind(circuit, ifp);
- /* isis_circuit_update_addrs (circuit, ifp); */
if (if_is_broadcast(ifp)) {
if (circuit->circ_type_config == CIRCUIT_T_P2P)
@@ -442,8 +437,6 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp)
for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn))
isis_circuit_add_addr(circuit, conn);
-
- return;
}
void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp)
@@ -460,26 +453,19 @@ void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp)
if (circuit->ip_addrs) {
assert(listcount(circuit->ip_addrs) == 0);
list_delete_and_null(&circuit->ip_addrs);
- circuit->ip_addrs = NULL;
}
if (circuit->ipv6_link) {
assert(listcount(circuit->ipv6_link) == 0);
list_delete_and_null(&circuit->ipv6_link);
- circuit->ipv6_link = NULL;
}
if (circuit->ipv6_non_link) {
assert(listcount(circuit->ipv6_non_link) == 0);
list_delete_and_null(&circuit->ipv6_non_link);
- circuit->ipv6_non_link = NULL;
}
circuit->circ_type = CIRCUIT_T_UNKNOWN;
- _ISIS_CLEAR_FLAG(isis->circuit_ids_used, circuit->circuit_id);
- circuit->circuit_id = 0;
-
- return;
}
void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp)
@@ -593,6 +579,12 @@ int isis_circuit_up(struct isis_circuit *circuit)
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ circuit->circuit_id = isis_circuit_id_gen(isis, circuit->interface);
+ if (!circuit->circuit_id) {
+ zlog_err("There are already 255 broadcast circuits active!");
+ return ISIS_ERROR;
+ }
+
/*
* Get the Hardware Address
*/
@@ -737,6 +729,9 @@ void isis_circuit_down(struct isis_circuit *circuit)
THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[1]);
circuit->lsp_regenerate_pending[0] = 0;
circuit->lsp_regenerate_pending[1] = 0;
+
+ _ISIS_CLEAR_FLAG(isis->circuit_ids_used, circuit->circuit_id);
+ circuit->circuit_id = 0;
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
isis_delete_adj(circuit->u.p2p.neighbor);
circuit->u.p2p.neighbor = NULL;
@@ -1046,6 +1041,11 @@ int isis_interface_config_write(struct vty *vty)
write++;
}
+ if (circuit->disable_threeway_adj) {
+ vty_out(vty, " no isis three-way-handshake\n");
+ write++;
+ }
+
/* ISIS - Hello interval */
if (circuit->hello_interval[0]
== circuit->hello_interval[1]) {
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index 0d392036e9..246279c6f3 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -32,8 +32,6 @@
#include "isis_constants.h"
#include "isis_common.h"
-#define CIRCUIT_MAX 255
-
struct isis_lsp;
struct password {
@@ -69,7 +67,7 @@ struct isis_p2p_info {
struct isis_circuit {
int state;
- u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */
+ u_char circuit_id; /* l1/l2 bcast CircuitID */
struct isis_area *area; /* back pointer to the area */
struct interface *interface; /* interface info from z */
int fd; /* IS-IS l1/2 socket */
@@ -82,9 +80,8 @@ struct isis_circuit {
struct thread *t_send_csnp[2];
struct thread *t_send_psnp[2];
struct thread *t_send_lsp;
- struct list *lsp_queue; /* LSPs to be txed (both levels) */
- struct isis_lsp_hash
- *lsp_hash; /* Hashtable synchronized with lsp_queue */
+ struct list *lsp_queue; /* LSPs to be txed (both levels) */
+ struct isis_lsp_hash *lsp_hash; /* Hashtable synchronized with lsp_queue */
time_t lsp_queue_last_push[2]; /* timestamp used to enforce transmit
* interval;
* for scalability, use one timestamp per
@@ -135,6 +132,7 @@ struct isis_circuit {
u_int16_t upadjcount[2];
#define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01
u_char flags;
+ bool disable_threeway_adj;
/*
* Counters as in 10589--11.2.5.9
*/
diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c
index a283260d92..10870d5c50 100644
--- a/isisd/isis_csm.c
+++ b/isisd/isis_csm.c
@@ -86,13 +86,6 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
case IF_UP_FROM_Z:
circuit = isis_circuit_new();
isis_circuit_if_add(circuit, (struct interface *)arg);
- if (!circuit->circuit_id) {
- isis_circuit_if_del(circuit,
- (struct interface *)arg);
- isis_circuit_del(circuit);
- circuit = NULL;
- break;
- }
listnode_add(isis->init_circ_list, circuit);
circuit->state = C_STATE_INIT;
break;
@@ -143,8 +136,6 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
break;
case IF_UP_FROM_Z:
isis_circuit_if_add(circuit, (struct interface *)arg);
- if (!circuit->circuit_id)
- break;
if (isis_circuit_up(circuit) != ISIS_OK) {
zlog_err(
"Could not bring up %s because of invalid config.",
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 55888bd389..b2ba8b3932 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -1034,7 +1034,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
break;
case CIRCUIT_T_P2P: {
struct isis_adjacency *nei = circuit->u.p2p.neighbor;
- if (nei && (level & nei->circuit_t)) {
+ if (nei && nei->adj_state == ISIS_ADJ_UP
+ && (level & nei->circuit_t)) {
uint8_t ne_id[7];
memcpy(ne_id, nei->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(ne_id) = 0;
@@ -1875,15 +1876,12 @@ int lsp_tick(struct thread *thread)
if (!circuit->lsp_queue)
continue;
- if (now
- - circuit->lsp_queue_last_push
- [level]
+ if (now - circuit->lsp_queue_last_push[level]
< MIN_LSP_RETRANS_INTERVAL) {
continue;
}
- circuit->lsp_queue_last_push[level] =
- now;
+ circuit->lsp_queue_last_push[level] = now;
for (ALL_LIST_ELEMENTS_RO(
lsp_list, lspnode, lsp)) {
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 20c39a624f..bcbda33088 100644
--- a/isisd/isis_pdu.c
+++ b/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;
}
@@ -415,7 +419,7 @@ static int process_p2p_hello(struct iih_info *iih)
if (isis->debugs & DEBUG_ADJ_PACKETS) {
zlog_debug(
"ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
- " cir id %02d, length %d",
+ " cir id %hhu, length %" PRIu16,
iih->circuit->area->area_tag,
iih->circuit->interface->name,
circuit_t2string(iih->circuit->is_type),
@@ -1184,8 +1188,7 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
entry = entry->next) {
zlog_debug(
"ISIS-Snp (%s): %cSNP entry %s, seq 0x%08" PRIx32
- ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
- "s",
+ ", cksum 0x%04" PRIx16 ", lifetime %" PRIu16 "s",
circuit->area->area_tag, typechar,
rawlspid_print(entry->id), entry->seqno,
entry->checksum, entry->rem_lifetime);
@@ -1244,12 +1247,10 @@ static int process_snp(uint8_t pdu_type, struct isis_circuit *circuit,
ISIS_SYS_ID_LEN + 1);
LSP_FRAGMENT(lspid) = 0;
lsp0 = lsp_search(
- lspid,
- circuit->area
- ->lspdb[level - 1]);
+ lspid,
+ circuit->area->lspdb[level - 1]);
if (!lsp0) {
- zlog_debug(
- "Got lsp frag in snp, while zero not in database");
+ zlog_debug("Got lsp frag in snp, while zero not in database");
continue;
}
}
@@ -1555,9 +1556,25 @@ 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
+ && !circuit->disable_threeway_adj) {
+ 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);
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index b9605018ed..ad769f9886 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -100,26 +100,6 @@ static int nexthoplookup(struct list *nexthops, struct in_addr *ip,
return 0;
}
-#ifdef EXTREME_DEBUG
-static void nexthop_print(struct isis_nexthop *nh)
-{
- u_char buf[BUFSIZ];
-
- inet_ntop(AF_INET, &nh->ip, (char *)buf, BUFSIZ);
-
- zlog_debug(" %s %u", buf, nh->ifindex);
-}
-
-static void nexthops_print(struct list *nhs)
-{
- struct listnode *node;
- struct isis_nexthop *nh;
-
- for (ALL_LIST_ELEMENTS_RO(nhs, node, nh))
- nexthop_print(nh);
-}
-#endif /* EXTREME_DEBUG */
-
static struct isis_nexthop6 *isis_nexthop6_new(struct in6_addr *ip6,
ifindex_t ifindex)
{
@@ -184,26 +164,6 @@ static int nexthop6lookup(struct list *nexthops6, struct in6_addr *ip6,
return 0;
}
-#ifdef EXTREME_DEBUG
-static void nexthop6_print(struct isis_nexthop6 *nh6)
-{
- u_char buf[BUFSIZ];
-
- inet_ntop(AF_INET6, &nh6->ip6, (char *)buf, BUFSIZ);
-
- zlog_debug(" %s %u", buf, nh6->ifindex);
-}
-
-static void nexthops6_print(struct list *nhs6)
-{
- struct listnode *node;
- struct isis_nexthop6 *nh6;
-
- for (ALL_LIST_ELEMENTS_RO(nhs6, node, nh6))
- nexthop6_print(nh6);
-}
-#endif /* EXTREME_DEBUG */
-
static void adjinfo2nexthop(struct list *nexthops, struct isis_adjacency *adj)
{
struct isis_nexthop *nh;
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 0eabcb7e47..dc86d4c105 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -85,10 +85,10 @@ struct isis_vertex {
struct prefix prefix;
} N;
- u_int32_t d_N; /* d(N) Distance from this IS */
- u_int16_t depth; /* The depth in the imaginary tree */
- struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
- struct list *parents; /* list of parents for ECMP */
+ u_int32_t d_N; /* d(N) Distance from this IS */
+ u_int16_t depth; /* The depth in the imaginary tree */
+ struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
+ struct list *parents; /* list of parents for ECMP */
uint64_t insert_counter;
};
@@ -276,12 +276,11 @@ static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
struct isis_spftree {
struct isis_vertex_queue paths; /* the SPT */
struct isis_vertex_queue tents; /* TENT */
- struct isis_area *area; /* back pointer to area */
- unsigned int runcount; /* number of runs since uptime */
- time_t last_run_timestamp; /* last run timestamp as wall time for
- display */
- time_t last_run_monotime; /* last run as monotime for scheduling */
- time_t last_run_duration; /* last run duration in msec */
+ struct isis_area *area; /* back pointer to area */
+ unsigned int runcount; /* number of runs since uptime */
+ time_t last_run_timestamp; /* last run timestamp as wall time for display */
+ time_t last_run_monotime; /* last run as monotime for scheduling */
+ time_t last_run_duration; /* last run duration in msec */
uint16_t mtid;
int family;
@@ -335,12 +334,12 @@ static void remove_excess_adjs(struct list *adjs)
if (comp < 0)
continue;
- if (candidate->circuit->circuit_id > adj->circuit->circuit_id) {
+ if (candidate->circuit->idx > adj->circuit->idx) {
excess = node;
continue;
}
- if (candidate->circuit->circuit_id < adj->circuit->circuit_id)
+ if (candidate->circuit->idx < adj->circuit->idx)
continue;
comp = memcmp(candidate->snpa, adj->snpa, ETH_ALEN);
@@ -831,10 +830,10 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree,
return ISIS_OK;
/* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
- bool no_overload =
- (pseudo_lsp || (spftree->mtid == ISIS_MT_IPV4_UNICAST
+ bool no_overload = (pseudo_lsp
+ || (spftree->mtid == ISIS_MT_IPV4_UNICAST
&& !ISIS_MASK_LSP_OL_BIT(lsp->hdr.lsp_bits))
- || (mt_router_info && !mt_router_info->overload));
+ || (mt_router_info && !mt_router_info->overload));
lspfragloop:
if (lsp->hdr.seqno == 0) {
@@ -1153,7 +1152,7 @@ static int isis_spf_preload_tent(struct isis_spftree *spftree,
root_sysid, parent);
} else if (circuit->circ_type == CIRCUIT_T_P2P) {
adj = circuit->u.p2p.neighbor;
- if (!adj)
+ if (!adj || adj->adj_state != ISIS_ADJ_UP)
continue;
if (!adj_has_mt(adj, spftree->mtid))
continue;
@@ -1430,8 +1429,7 @@ int isis_spf_schedule(struct isis_area *area, int level)
/* wait configured min_spf_interval before doing the SPF */
long timer;
if (diff >= area->min_spf_interval[level - 1]) {
- /* Last run is more than min interval ago, schedule immediate
- * run */
+ /* Last run is more than min interval ago, schedule immediate run */
timer = 0;
} else {
timer = area->min_spf_interval[level - 1] - diff;
@@ -1549,9 +1547,7 @@ DEFUN (show_isis_topology,
continue;
if (area->ip_circuits > 0 && area->spftree[level - 1]
- && isis_vertex_queue_count(
- &area->spftree[level - 1]->paths)
- > 0) {
+ && isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) {
vty_out(vty,
"IS-IS paths to level-%d routers that speak IP\n",
level);
@@ -1561,9 +1557,7 @@ DEFUN (show_isis_topology,
vty_out(vty, "\n");
}
if (area->ipv6_circuits > 0 && area->spftree6[level - 1]
- && isis_vertex_queue_count(
- &area->spftree6[level - 1]->paths)
- > 0) {
+ && isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) {
vty_out(vty,
"IS-IS paths to level-%d routers that speak IPv6\n",
level);
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index df0b8b62d6..5de936a6ea 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -549,7 +549,8 @@ void isis_link_params_update(struct isis_circuit *circuit,
if ((SUBTLV_TYPE(mtc->rmt_ipaddr) == 0)
&& (circuit->circ_type == CIRCUIT_T_P2P)) {
struct isis_adjacency *adj = circuit->u.p2p.neighbor;
- if (adj->ipv4_address_count) {
+ if (adj && adj->adj_state == ISIS_ADJ_UP
+ && adj->ipv4_address_count) {
set_circuitparams_rmt_ipaddr(
mtc, adj->ipv4_addresses[0]);
}
@@ -805,8 +806,7 @@ static u_char print_subtlv_mm_delay(struct sbuf *buf, int indent,
A = (u_int32_t)ntohl(tlv->low) & TE_EXT_ANORMAL;
high = (u_int32_t)ntohl(tlv->high) & TE_EXT_MASK;
- sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32
- " (micro-sec)\n",
+ sbuf_push(buf, indent, "%s Min/Max Link Delay: %" PRIu32 " / %" PRIu32 " (micro-sec)\n",
A ? "Anomalous" : "Normal", low, high);
return (SUBTLV_HDR_SIZE + SUBTLV_DEF_SIZE);
@@ -913,8 +913,8 @@ static u_char print_unknown_tlv(struct sbuf *buf, int indent,
}
/* Main Show function */
-void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs,
- uint8_t subtlv_len)
+void mpls_te_print_detail(struct sbuf *buf, int indent,
+ uint8_t *subtlvs, uint8_t subtlv_len)
{
struct subtlv_header *tlvh = (struct subtlv_header *)subtlvs;
uint16_t sum = 0;
@@ -922,8 +922,7 @@ void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs,
for (; sum < subtlv_len; tlvh = SUBTLV_HDR_NEXT(tlvh)) {
switch (tlvh->type) {
case TE_SUBTLV_ADMIN_GRP:
- sum += print_subtlv_admin_grp(
- buf, indent,
+ sum += print_subtlv_admin_grp(buf, indent,
(struct te_subtlv_admin_grp *)tlvh);
break;
case TE_SUBTLV_LLRI:
@@ -931,31 +930,27 @@ void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs,
(struct te_subtlv_llri *)tlvh);
break;
case TE_SUBTLV_LOCAL_IPADDR:
- sum += print_subtlv_local_ipaddr(
- buf, indent,
+ sum += print_subtlv_local_ipaddr(buf, indent,
(struct te_subtlv_local_ipaddr *)tlvh);
break;
case TE_SUBTLV_RMT_IPADDR:
- sum += print_subtlv_rmt_ipaddr(
- buf, indent,
+ sum += print_subtlv_rmt_ipaddr(buf, indent,
(struct te_subtlv_rmt_ipaddr *)tlvh);
break;
case TE_SUBTLV_MAX_BW:
- sum += print_subtlv_max_bw(
- buf, indent, (struct te_subtlv_max_bw *)tlvh);
+ sum += print_subtlv_max_bw(buf, indent,
+ (struct te_subtlv_max_bw *)tlvh);
break;
case TE_SUBTLV_MAX_RSV_BW:
- sum += print_subtlv_max_rsv_bw(
- buf, indent,
+ sum += print_subtlv_max_rsv_bw(buf, indent,
(struct te_subtlv_max_rsv_bw *)tlvh);
break;
case TE_SUBTLV_UNRSV_BW:
- sum += print_subtlv_unrsv_bw(
- buf, indent, (struct te_subtlv_unrsv_bw *)tlvh);
+ sum += print_subtlv_unrsv_bw(buf, indent,
+ (struct te_subtlv_unrsv_bw *)tlvh);
break;
case TE_SUBTLV_TE_METRIC:
- sum += print_subtlv_te_metric(
- buf, indent,
+ sum += print_subtlv_te_metric(buf, indent,
(struct te_subtlv_te_metric *)tlvh);
break;
case TE_SUBTLV_RAS:
@@ -967,33 +962,32 @@ void mpls_te_print_detail(struct sbuf *buf, int indent, uint8_t *subtlvs,
(struct te_subtlv_rip *)tlvh);
break;
case TE_SUBTLV_AV_DELAY:
- sum += print_subtlv_av_delay(
- buf, indent, (struct te_subtlv_av_delay *)tlvh);
+ sum += print_subtlv_av_delay(buf, indent,
+ (struct te_subtlv_av_delay *)tlvh);
break;
case TE_SUBTLV_MM_DELAY:
- sum += print_subtlv_mm_delay(
- buf, indent, (struct te_subtlv_mm_delay *)tlvh);
+ sum += print_subtlv_mm_delay(buf, indent,
+ (struct te_subtlv_mm_delay *)tlvh);
break;
case TE_SUBTLV_DELAY_VAR:
- sum += print_subtlv_delay_var(
- buf, indent,
+ sum += print_subtlv_delay_var(buf, indent,
(struct te_subtlv_delay_var *)tlvh);
break;
case TE_SUBTLV_PKT_LOSS:
- sum += print_subtlv_pkt_loss(
- buf, indent, (struct te_subtlv_pkt_loss *)tlvh);
+ sum += print_subtlv_pkt_loss(buf, indent,
+ (struct te_subtlv_pkt_loss *)tlvh);
break;
case TE_SUBTLV_RES_BW:
- sum += print_subtlv_res_bw(
- buf, indent, (struct te_subtlv_res_bw *)tlvh);
+ sum += print_subtlv_res_bw(buf, indent,
+ (struct te_subtlv_res_bw *)tlvh);
break;
case TE_SUBTLV_AVA_BW:
- sum += print_subtlv_ava_bw(
- buf, indent, (struct te_subtlv_ava_bw *)tlvh);
+ sum += print_subtlv_ava_bw(buf, indent,
+ (struct te_subtlv_ava_bw *)tlvh);
break;
case TE_SUBTLV_USE_BW:
- sum += print_subtlv_use_bw(
- buf, indent, (struct te_subtlv_use_bw *)tlvh);
+ sum += print_subtlv_use_bw(buf, indent,
+ (struct te_subtlv_use_bw *)tlvh);
break;
default:
sum += print_unknown_tlv(buf, indent, tlvh);
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index 8e0fd74b73..66a19e150f 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -161,11 +161,9 @@ static int unpack_subtlv_ipv6_source_prefix(enum isis_tlv_context context,
sbuf_push(log, indent, "Unpacking IPv6 Source Prefix Sub-TLV...\n");
if (tlv_len < 1) {
- sbuf_push(
- log, indent,
- "Not enough data left. (expected 1 or more bytes, got %" PRIu8
- ")\n",
- tlv_len);
+ sbuf_push(log, indent,
+ "Not enough data left. (expected 1 or more bytes, got %" PRIu8 ")\n",
+ tlv_len);
return 1;
}
@@ -625,11 +623,10 @@ static int unpack_item_extended_reach(uint16_t mtid, uint8_t len,
(mtid == ISIS_MT_IPV4_UNICAST) ? "extended" : "mt");
if (len < 11) {
- sbuf_push(
- log, indent,
- "Not enough data left. (expected 11 or more bytes, got %" PRIu8
- ")\n",
- len);
+ sbuf_push(log, indent,
+ "Not enough data left. (expected 11 or more bytes, got %"
+ PRIu8 ")\n",
+ len);
goto out;
}
@@ -977,7 +974,8 @@ static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i,
struct isis_mt_router_info *info = (struct isis_mt_router_info *)i;
sbuf_push(buf, indent, "MT Router Info: %s%s%s\n",
- isis_mtid2str(info->mtid), info->overload ? " Overload" : "",
+ isis_mtid2str(info->mtid),
+ info->overload ? " Overload" : "",
info->attached ? " Attached" : "");
}
@@ -1126,8 +1124,8 @@ static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i,
sbuf_push(buf, indent, "%s IP Reachability: %s (Metric: %u)%s",
(mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT",
- prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
- r->metric, r->down ? " Down" : "");
+ prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)), r->metric,
+ r->down ? " Down" : "");
if (mtid != ISIS_MT_IPV4_UNICAST)
sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
sbuf_push(buf, 0, "\n");
@@ -1180,11 +1178,9 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
consume = 5;
if (len < consume) {
- sbuf_push(
- log, indent,
- "Not enough data left. (expected 5 or more bytes, got %" PRIu8
- ")\n",
- len);
+ sbuf_push(log, indent,
+ "Not enough data left. (expected 5 or more bytes, got %" PRIu8 ")\n",
+ len);
goto out;
}
@@ -1203,10 +1199,9 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
consume += PSIZE(rv->prefix.prefixlen);
if (len < consume) {
- sbuf_push(
- log, indent,
- "Expected %u bytes of prefix, but only %u bytes available.\n",
- PSIZE(rv->prefix.prefixlen), len - 5);
+ sbuf_push(log, indent,
+ "Expected %u bytes of prefix, but only %u bytes available.\n",
+ PSIZE(rv->prefix.prefixlen), len - 5);
goto out;
}
stream_get(&rv->prefix.prefix.s_addr, s, PSIZE(rv->prefix.prefixlen));
@@ -1221,26 +1216,23 @@ static int unpack_item_extended_ip_reach(uint16_t mtid, uint8_t len,
if (control & ISIS_EXTENDED_IP_REACH_SUBTLV) {
consume += 1;
if (len < consume) {
- sbuf_push(
- log, indent,
- "Expected 1 byte of subtlv len, but no more data present.\n");
+ sbuf_push(log, indent,
+ "Expected 1 byte of subtlv len, but no more data present.\n");
goto out;
}
subtlv_len = stream_getc(s);
if (!subtlv_len) {
- sbuf_push(
- log, indent + 2,
- " WARNING: subtlv bit is set, but there are no subtlvs.\n");
+ sbuf_push(log, indent + 2,
+ " WARNING: subtlv bit is set, but there are no subtlvs.\n");
}
consume += subtlv_len;
if (len < consume) {
- sbuf_push(
- log, indent,
- "Expected %" PRIu8
- " bytes of subtlvs, but only %u bytes available.\n",
- subtlv_len,
- len - 6 - PSIZE(rv->prefix.prefixlen));
+ sbuf_push(log, indent,
+ "Expected %" PRIu8
+ " bytes of subtlvs, but only %u bytes available.\n",
+ subtlv_len,
+ len - 6 - PSIZE(rv->prefix.prefixlen));
goto out;
}
sbuf_push(log, indent, "Skipping %" PRIu8 " bytes of subvls",
@@ -1337,6 +1329,119 @@ static int unpack_tlv_dynamic_hostname(enum isis_tlv_context context,
return 0;
}
+/* Functions related to TLV 240 P2P Three-Way Adjacency */
+
+const char *isis_threeway_state_name(enum isis_threeway_state state)
+{
+ switch (state) {
+ case ISIS_THREEWAY_DOWN:
+ return "Down";
+ case ISIS_THREEWAY_INITIALIZING:
+ return "Initializing";
+ case ISIS_THREEWAY_UP:
+ return "Up";
+ default:
+ return "Invalid!";
+ }
+}
+
+static struct isis_threeway_adj *copy_tlv_threeway_adj(
+ const struct isis_threeway_adj *threeway_adj)
+{
+ if (!threeway_adj)
+ return NULL;
+
+ struct isis_threeway_adj *rv = XMALLOC(MTYPE_ISIS_TLV, sizeof(*rv));
+ memcpy(rv, threeway_adj, sizeof(*rv));
+
+ return rv;
+}
+
+static void format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
+ struct sbuf *buf, int indent)
+{
+ if (!threeway_adj)
+ return;
+
+ sbuf_push(buf, indent, "P2P Three-Way Adjacency:\n");
+ sbuf_push(buf, indent, " State: %s (%d)\n",
+ isis_threeway_state_name(threeway_adj->state),
+ threeway_adj->state);
+ sbuf_push(buf, indent, " Extended Local Circuit ID: %" PRIu32 "\n",
+ threeway_adj->local_circuit_id);
+ if (!threeway_adj->neighbor_set)
+ return;
+
+ sbuf_push(buf, indent, " Neighbor System ID: %s\n",
+ isis_format_id(threeway_adj->neighbor_id, 6));
+ sbuf_push(buf, indent, " Neighbor Extended Circuit ID: %" PRIu32 "\n",
+ threeway_adj->neighbor_circuit_id);
+}
+
+static void free_tlv_threeway_adj(struct isis_threeway_adj *threeway_adj)
+{
+ XFREE(MTYPE_ISIS_TLV, threeway_adj);
+}
+
+static int pack_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj,
+ struct stream *s)
+{
+ if (!threeway_adj)
+ return 0;
+
+ uint8_t tlv_len = (threeway_adj->neighbor_set) ? 15 : 5;
+
+ if (STREAM_WRITEABLE(s) < (unsigned)(2 + tlv_len))
+ return 1;
+
+ stream_putc(s, ISIS_TLV_THREE_WAY_ADJ);
+ stream_putc(s, tlv_len);
+ stream_putc(s, threeway_adj->state);
+ stream_putl(s, threeway_adj->local_circuit_id);
+
+ if (threeway_adj->neighbor_set) {
+ stream_put(s, threeway_adj->neighbor_id, 6);
+ stream_putl(s, threeway_adj->neighbor_circuit_id);
+ }
+
+ return 0;
+}
+
+static int unpack_tlv_threeway_adj(enum isis_tlv_context context,
+ uint8_t tlv_type, uint8_t tlv_len,
+ struct stream *s, struct sbuf *log,
+ void *dest, int indent)
+{
+ struct isis_tlvs *tlvs = dest;
+
+ sbuf_push(log, indent, "Unpacking P2P Three-Way Adjacency TLV...\n");
+ if (tlv_len != 5 && tlv_len != 15) {
+ sbuf_push(log, indent, "WARNING: Unexepected TLV size\n");
+ stream_forward_getp(s, tlv_len);
+ return 0;
+ }
+
+ if (tlvs->threeway_adj) {
+ sbuf_push(log, indent,
+ "WARNING: P2P Three-Way Adjacency TLV present multiple times.\n");
+ stream_forward_getp(s, tlv_len);
+ return 0;
+ }
+
+ tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
+
+ tlvs->threeway_adj->state = stream_getc(s);
+ tlvs->threeway_adj->local_circuit_id = stream_getl(s);
+
+ if (tlv_len == 15) {
+ tlvs->threeway_adj->neighbor_set = true;
+ stream_get(tlvs->threeway_adj->neighbor_id, s, 6);
+ tlvs->threeway_adj->neighbor_circuit_id = stream_getl(s);
+ }
+
+ return 0;
+}
+
/* Functions related to TLVs 236/237 IPv6/MT-IPv6 reach */
static struct isis_item *copy_item_ipv6_reach(struct isis_item *i)
@@ -1361,7 +1466,8 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i,
sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s",
(mtid == ISIS_MT_IPV4_UNICAST) ? "" : "MT ",
prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf)),
- r->metric, r->down ? " Down" : "",
+ r->metric,
+ r->down ? " Down" : "",
r->external ? " External" : "");
if (mtid != ISIS_MT_IPV4_UNICAST)
sbuf_push(buf, 0, " %s", isis_mtid2str(mtid));
@@ -1426,11 +1532,10 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
(mtid == ISIS_MT_IPV4_UNICAST) ? "" : "mt ");
consume = 6;
if (len < consume) {
- sbuf_push(
- log, indent,
- "Not enough data left. (expected 6 or more bytes, got %" PRIu8
- ")\n",
- len);
+ sbuf_push(log, indent,
+ "Not enough data left. (expected 6 or more bytes, got %"
+ PRIu8 ")\n",
+ len);
goto out;
}
@@ -1451,10 +1556,9 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
consume += PSIZE(rv->prefix.prefixlen);
if (len < consume) {
- sbuf_push(
- log, indent,
- "Expected %u bytes of prefix, but only %u bytes available.\n",
- PSIZE(rv->prefix.prefixlen), len - 6);
+ sbuf_push(log, indent,
+ "Expected %u bytes of prefix, but only %u bytes available.\n",
+ PSIZE(rv->prefix.prefixlen), len - 6);
goto out;
}
stream_get(&rv->prefix.prefix.s6_addr, s, PSIZE(rv->prefix.prefixlen));
@@ -1468,26 +1572,23 @@ static int unpack_item_ipv6_reach(uint16_t mtid, uint8_t len, struct stream *s,
if (control & ISIS_IPV6_REACH_SUBTLV) {
consume += 1;
if (len < consume) {
- sbuf_push(
- log, indent,
- "Expected 1 byte of subtlv len, but no more data persent.\n");
+ sbuf_push(log, indent,
+ "Expected 1 byte of subtlv len, but no more data persent.\n");
goto out;
}
subtlv_len = stream_getc(s);
if (!subtlv_len) {
- sbuf_push(
- log, indent + 2,
- " WARNING: subtlv bit set, but there are no subtlvs.\n");
+ sbuf_push(log, indent + 2,
+ " WARNING: subtlv bit set, but there are no subtlvs.\n");
}
consume += subtlv_len;
if (len < consume) {
- sbuf_push(
- log, indent,
- "Expected %" PRIu8
- " bytes of subtlvs, but only %u bytes available.\n",
- subtlv_len,
- len - 6 - PSIZE(rv->prefix.prefixlen));
+ sbuf_push(log, indent,
+ "Expected %" PRIu8
+ " bytes of subtlvs, but only %u bytes available.\n",
+ subtlv_len,
+ len - 6 - PSIZE(rv->prefix.prefixlen));
goto out;
}
@@ -1710,19 +1811,16 @@ static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type,
return 1;
}
-static void add_item_to_fragment(struct isis_item *i,
- struct pack_order_entry *pe,
+static void add_item_to_fragment(struct isis_item *i, struct pack_order_entry *pe,
struct isis_tlvs *fragment_tlvs, uint16_t mtid)
{
struct isis_item_list *l;
if (pe->how_to_pack == ISIS_ITEMS) {
- l = (struct isis_item_list *)(((char *)fragment_tlvs)
- + pe->what_to_pack);
+ l = (struct isis_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
} else {
struct isis_mt_item_list *m;
- m = (struct isis_mt_item_list *)(((char *)fragment_tlvs)
- + pe->what_to_pack);
+ m = (struct isis_mt_item_list *)(((char *)fragment_tlvs) + pe->what_to_pack);
l = isis_get_mt_items(m, mtid);
}
@@ -2082,6 +2180,8 @@ struct isis_tlvs *isis_copy_tlvs(struct isis_tlvs *tlvs)
copy_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
&tlvs->mt_ipv6_reach, &rv->mt_ipv6_reach);
+ rv->threeway_adj = copy_tlv_threeway_adj(tlvs->threeway_adj);
+
return rv;
}
@@ -2143,6 +2243,8 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, int indent)
format_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
&tlvs->mt_ipv6_reach, buf, indent);
+
+ format_tlv_threeway_adj(tlvs->threeway_adj, buf, indent);
}
const char *isis_format_tlvs(struct isis_tlvs *tlvs)
@@ -2193,6 +2295,7 @@ void isis_free_tlvs(struct isis_tlvs *tlvs)
free_items(ISIS_CONTEXT_LSP, ISIS_TLV_IPV6_REACH, &tlvs->ipv6_reach);
free_mt_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_IPV6_REACH,
&tlvs->mt_ipv6_reach);
+ free_tlv_threeway_adj(tlvs->threeway_adj);
XFREE(MTYPE_ISIS_TLV, tlvs);
}
@@ -2364,6 +2467,14 @@ static int pack_tlvs(struct isis_tlvs *tlvs, struct stream *stream,
copy_tlv_te_router_id(tlvs->te_router_id);
}
+ rv = pack_tlv_threeway_adj(tlvs->threeway_adj, stream);
+ if (rv)
+ return rv;
+ if (fragment_tlvs) {
+ fragment_tlvs->threeway_adj =
+ copy_tlv_threeway_adj(tlvs->threeway_adj);
+ }
+
for (size_t pack_idx = 0; pack_idx < array_size(pack_order);
pack_idx++) {
rv = handle_pack_entry(&pack_order[pack_idx], tlvs, stream,
@@ -2459,11 +2570,9 @@ static int unpack_tlv(enum isis_tlv_context context, size_t avail_len,
tlv_type, tlv_len);
if (avail_len < ((size_t)tlv_len) + 2) {
- sbuf_push(
- log, indent + 2,
- "Available data %zu too short for claimed TLV len %" PRIu8
- ".\n",
- avail_len - 2, tlv_len);
+ sbuf_push(log, indent + 2,
+ "Available data %zu too short for claimed TLV len %" PRIu8 ".\n",
+ avail_len - 2, tlv_len);
return 1;
}
@@ -2541,7 +2650,7 @@ int isis_unpack_tlvs(size_t avail_len, struct stream *stream,
static const struct tlv_ops tlv_##_name_##_ops = { \
.name = _desc_, \
.unpack = unpack_tlv_with_items, \
- \
+ \
.pack_item = pack_item_##_name_, \
.free_item = free_item_##_name_, \
.unpack_item = unpack_item_##_name_, \
@@ -2566,54 +2675,41 @@ TLV_OPS(te_router_id, "TLV 134 TE Router ID");
ITEM_TLV_OPS(extended_ip_reach, "TLV 135 Extended IP Reachability");
TLV_OPS(dynamic_hostname, "TLV 137 Dynamic Hostname");
ITEM_TLV_OPS(mt_router_info, "TLV 229 MT Router Information");
+TLV_OPS(threeway_adj, "TLV 240 P2P Three-Way Adjacency");
ITEM_TLV_OPS(ipv6_address, "TLV 232 IPv6 Interface Address");
ITEM_TLV_OPS(ipv6_reach, "TLV 236 IPv6 Reachability");
SUBTLV_OPS(ipv6_source_prefix, "Sub-TLV 22 IPv6 Source Prefix");
-static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] =
- {[ISIS_CONTEXT_LSP] =
- {
- [ISIS_TLV_AREA_ADDRESSES] =
- &tlv_area_address_ops,
- [ISIS_TLV_OLDSTYLE_REACH] =
- &tlv_oldstyle_reach_ops,
- [ISIS_TLV_LAN_NEIGHBORS] =
- &tlv_lan_neighbor_ops,
- [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
- [ISIS_TLV_AUTH] = &tlv_auth_ops,
- [ISIS_TLV_EXTENDED_REACH] =
- &tlv_extended_reach_ops,
- [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
- [ISIS_TLV_OLDSTYLE_IP_REACH] =
- &tlv_oldstyle_ip_reach_ops,
- [ISIS_TLV_PROTOCOLS_SUPPORTED] =
- &tlv_protocols_supported_ops,
- [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] =
- &tlv_oldstyle_ip_reach_ops,
- [ISIS_TLV_IPV4_ADDRESS] =
- &tlv_ipv4_address_ops,
- [ISIS_TLV_TE_ROUTER_ID] =
- &tlv_te_router_id_ops,
- [ISIS_TLV_EXTENDED_IP_REACH] =
- &tlv_extended_ip_reach_ops,
- [ISIS_TLV_MT_IP_REACH] =
- &tlv_extended_ip_reach_ops,
- [ISIS_TLV_DYNAMIC_HOSTNAME] =
- &tlv_dynamic_hostname_ops,
- [ISIS_TLV_MT_ROUTER_INFO] =
- &tlv_mt_router_info_ops,
- [ISIS_TLV_IPV6_ADDRESS] =
- &tlv_ipv6_address_ops,
- [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
- [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
- },
- [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
- [ISIS_CONTEXT_SUBTLV_IP_REACH] = {},
- [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
- [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] =
- &subtlv_ipv6_source_prefix_ops,
- }};
+static const struct tlv_ops *tlv_table[ISIS_CONTEXT_MAX][ISIS_TLV_MAX] = {
+ [ISIS_CONTEXT_LSP] = {
+ [ISIS_TLV_AREA_ADDRESSES] = &tlv_area_address_ops,
+ [ISIS_TLV_OLDSTYLE_REACH] = &tlv_oldstyle_reach_ops,
+ [ISIS_TLV_LAN_NEIGHBORS] = &tlv_lan_neighbor_ops,
+ [ISIS_TLV_LSP_ENTRY] = &tlv_lsp_entry_ops,
+ [ISIS_TLV_AUTH] = &tlv_auth_ops,
+ [ISIS_TLV_EXTENDED_REACH] = &tlv_extended_reach_ops,
+ [ISIS_TLV_MT_REACH] = &tlv_extended_reach_ops,
+ [ISIS_TLV_OLDSTYLE_IP_REACH] = &tlv_oldstyle_ip_reach_ops,
+ [ISIS_TLV_PROTOCOLS_SUPPORTED] = &tlv_protocols_supported_ops,
+ [ISIS_TLV_OLDSTYLE_IP_REACH_EXT] = &tlv_oldstyle_ip_reach_ops,
+ [ISIS_TLV_IPV4_ADDRESS] = &tlv_ipv4_address_ops,
+ [ISIS_TLV_TE_ROUTER_ID] = &tlv_te_router_id_ops,
+ [ISIS_TLV_EXTENDED_IP_REACH] = &tlv_extended_ip_reach_ops,
+ [ISIS_TLV_MT_IP_REACH] = &tlv_extended_ip_reach_ops,
+ [ISIS_TLV_DYNAMIC_HOSTNAME] = &tlv_dynamic_hostname_ops,
+ [ISIS_TLV_MT_ROUTER_INFO] = &tlv_mt_router_info_ops,
+ [ISIS_TLV_THREE_WAY_ADJ] = &tlv_threeway_adj_ops,
+ [ISIS_TLV_IPV6_ADDRESS] = &tlv_ipv6_address_ops,
+ [ISIS_TLV_IPV6_REACH] = &tlv_ipv6_reach_ops,
+ [ISIS_TLV_MT_IPV6_REACH] = &tlv_ipv6_reach_ops,
+ },
+ [ISIS_CONTEXT_SUBTLV_NE_REACH] = {},
+ [ISIS_CONTEXT_SUBTLV_IP_REACH] = {},
+ [ISIS_CONTEXT_SUBTLV_IPV6_REACH] = {
+ [ISIS_SUBTLV_IPV6_SOURCE_PREFIX] = &subtlv_ipv6_source_prefix_ops,
+ }
+};
/* Accessor functions */
@@ -3104,6 +3200,25 @@ void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
append_item(l, (struct isis_item *)r);
}
+void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
+ enum isis_threeway_state state,
+ uint32_t local_circuit_id,
+ const uint8_t *neighbor_id,
+ uint32_t neighbor_circuit_id)
+{
+ assert(!tlvs->threeway_adj);
+
+ tlvs->threeway_adj = XCALLOC(MTYPE_ISIS_TLV, sizeof(*tlvs->threeway_adj));
+ tlvs->threeway_adj->state = state;
+ tlvs->threeway_adj->local_circuit_id = local_circuit_id;
+
+ if (neighbor_id) {
+ tlvs->threeway_adj->neighbor_set = true;
+ memcpy(tlvs->threeway_adj->neighbor_id, neighbor_id, 6);
+ tlvs->threeway_adj->neighbor_circuit_id = neighbor_circuit_id;
+ }
+}
+
struct isis_mt_router_info *
isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid)
{
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index 6ade0af28c..98edbf14e7 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -103,6 +103,20 @@ struct isis_protocols_supported {
uint8_t *protocols;
};
+enum isis_threeway_state {
+ ISIS_THREEWAY_DOWN = 2,
+ ISIS_THREEWAY_INITIALIZING = 1,
+ ISIS_THREEWAY_UP = 0
+};
+
+struct isis_threeway_adj {
+ enum isis_threeway_state state;
+ uint32_t local_circuit_id;
+ bool neighbor_set;
+ uint8_t neighbor_id[6];
+ uint32_t neighbor_circuit_id;
+};
+
struct isis_item;
struct isis_item {
struct isis_item *next;
@@ -190,6 +204,7 @@ struct isis_tlvs {
char *hostname;
struct isis_item_list ipv6_reach;
struct isis_mt_item_list mt_ipv6_reach;
+ struct isis_threeway_adj *threeway_adj;
};
struct isis_subtlvs {
@@ -227,6 +242,7 @@ enum isis_tlv_type {
ISIS_TLV_MT_IP_REACH = 235,
ISIS_TLV_IPV6_REACH = 236,
ISIS_TLV_MT_IPV6_REACH = 237,
+ ISIS_TLV_THREE_WAY_ADJ = 240,
ISIS_TLV_MAX = 256,
ISIS_SUBTLV_IPV6_SOURCE_PREFIX = 22
@@ -303,6 +319,14 @@ void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,
uint8_t *id, uint32_t metric,
uint8_t *subtlvs, uint8_t subtlv_len);
+const char *isis_threeway_state_name(enum isis_threeway_state state);
+
+void isis_tlvs_add_threeway_adj(struct isis_tlvs *tlvs,
+ enum isis_threeway_state state,
+ uint32_t local_circuit_id,
+ const uint8_t *neighbor_id,
+ uint32_t neighbor_circuit_id);
+
struct isis_mt_router_info *
isis_tlvs_lookup_mt_router_info(struct isis_tlvs *tlvs, uint16_t mtid);
#endif
diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c
index 02e28a73fe..66d79b2e9f 100644
--- a/isisd/isis_vty.c
+++ b/isisd/isis_vty.c
@@ -927,6 +927,21 @@ DEFUN (no_isis_hello_padding,
return CMD_SUCCESS;
}
+DEFUN (isis_threeway_adj,
+ isis_threeway_adj_cmd,
+ "[no] isis three-way-handshake",
+ NO_STR
+ "IS-IS commands\n"
+ "Enable/Disable three-way handshake\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup(vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ circuit->disable_threeway_adj = !strcmp(argv[0]->text, "no");
+ return CMD_SUCCESS;
+}
+
DEFUN (csnp_interval,
csnp_interval_cmd,
"isis csnp-interval (1-600)",
@@ -2085,6 +2100,8 @@ void isis_vty_init(void)
install_element(INTERFACE_NODE, &isis_hello_padding_cmd);
install_element(INTERFACE_NODE, &no_isis_hello_padding_cmd);
+ install_element(INTERFACE_NODE, &isis_threeway_adj_cmd);
+
install_element(INTERFACE_NODE, &csnp_interval_cmd);
install_element(INTERFACE_NODE, &no_csnp_interval_cmd);
install_element(INTERFACE_NODE, &csnp_interval_l1_cmd);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index a8dcc8adaf..85d3974fa6 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -52,9 +52,8 @@ struct isis {
struct area_addr *man_area_addrs; /* manualAreaAddresses */
u_int32_t debugs; /* bitmap for debug */
time_t uptime; /* when did we start */
- struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */
- uint32_t circuit_ids_used
- [8]; /* 256 bits to track circuit ids 0 through 255 */
+ struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */
+ uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */
struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
diff --git a/lib/strlcat.c b/lib/strlcat.c
index 8186304437..be211f82a8 100644
--- a/lib/strlcat.c
+++ b/lib/strlcat.c
@@ -28,23 +28,25 @@
#ifndef HAVE_STRLCAT
#undef strlcat
-size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcat(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
-size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size)
+size_t strlcat(char *__restrict dest,
+ const char *__restrict src, size_t destsize)
{
size_t src_length = strlen(src);
/* Our implementation strlcat supports dest == NULL if size == 0
(for consistency with snprintf and strlcpy), but strnlen does
not, so we have to cover this case explicitly. */
- if (size == 0)
+ if (destsize == 0)
return src_length;
- size_t dest_length = strnlen(dest, size);
- if (dest_length != size) {
+ size_t dest_length = strnlen(dest, destsize);
+ if (dest_length != destsize) {
/* Copy at most the remaining number of characters in the
destination buffer. Leave for the NUL terminator. */
- size_t to_copy = size - dest_length - 1;
+ size_t to_copy = destsize - dest_length - 1;
/* But not more than what is available in the source string. */
if (to_copy > src_length)
to_copy = src_length;
diff --git a/lib/strlcpy.c b/lib/strlcpy.c
index b7681754aa..b0c33ca7f4 100644
--- a/lib/strlcpy.c
+++ b/lib/strlcpy.c
@@ -27,23 +27,26 @@
#ifndef HAVE_STRLCPY
#undef strlcpy
-size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcpy(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
-size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size)
+size_t strlcpy(char *__restrict dest,
+ const char *__restrict src, size_t destsize)
{
size_t src_length = strlen(src);
- if (__builtin_expect(src_length >= size, 0)) {
- if (size > 0) {
- /* Copy the leading portion of the string. The last
- character is subsequently overwritten with the NUL
- terminator, but the destination size is usually a
- multiple of a small power of two, so writing it twice
- should be more efficient than copying an odd number
- of
- bytes. */
- memcpy(dest, src, size);
- dest[size - 1] = '\0';
+ if (__builtin_expect(src_length >= destsize, 0)) {
+ if (destsize > 0) {
+ /*
+ * Copy the leading portion of the string. The last
+ * character is subsequently overwritten with the NUL
+ * terminator, but the destination destsize is usually
+ * a multiple of a small power of two, so writing it
+ * twice should be more efficient than copying an odd
+ * number of bytes.
+ */
+ memcpy(dest, src, destsize);
+ dest[destsize - 1] = '\0';
}
} else
/* Copy the string and its terminating NUL character. */
diff --git a/lib/zebra.h b/lib/zebra.h
index 262ad2e43d..923f6f77c6 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -232,10 +232,12 @@ typedef unsigned char u_int8_t;
#include "zassert.h"
#ifndef HAVE_STRLCAT
-size_t strlcat(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcat(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
#endif
#ifndef HAVE_STRLCPY
-size_t strlcpy(char *__restrict dest, const char *__restrict src, size_t size);
+size_t strlcpy(char *__restrict dest,
+ const char *__restrict src, size_t destsize);
#endif
#ifdef HAVE_BROKEN_CMSG_FIRSTHDR
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index b75d5b70fa..f32cd6e7e3 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1573,7 +1573,8 @@ int ospf6_receive(struct thread *thread)
oi = ospf6_interface_lookup_by_ifindex(ifindex);
if (oi == NULL || oi->area == NULL
|| CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
- zlog_debug("Message received on disabled interface");
+ if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+ zlog_debug("Message received on disabled interface");
return 0;
}
if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)) {
diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
index 3eb0205a5d..cca702b138 100644
--- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
+++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
Binary files differ
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 0b7e80962c..208fb116e6 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -413,7 +413,7 @@ end
ctx_keys = []
current_context_lines = []
- elif line == "exit-address-family" or line == "exit" or line == "exit-vni":
+ elif line in ["exit-address-family", "exit", "exit-vnc", "exit-vni"]:
# if this exit is for address-family ipv4 unicast, ignore the pop
if main_ctx_key:
self.save_contexts(ctx_keys, current_context_lines)
@@ -433,26 +433,14 @@ end
current_context_lines = []
new_ctx = False
log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys)
-
- # The 'vni' keyword under 'router bgp X/address-family l2vpn evpn' creates
- # a sub-context but the 'vni' keyword in other places (such as 'vrf BLUE')
- # does not.
- elif ("vni " in line and
- len(ctx_keys) == 2 and
- ctx_keys[0].startswith('router bgp') and
- ctx_keys[1] == 'address-family l2vpn evpn'):
-
- main_ctx_key = []
-
- # Save old context first
- self.save_contexts(ctx_keys, current_context_lines)
- current_context_lines = []
- main_ctx_key = copy.deepcopy(ctx_keys)
- log.debug('LINE %-50s: entering sub-context, append to ctx_keys', line)
-
- ctx_keys.append(line)
-
- elif "address-family " in line:
+ elif (line.startswith("address-family ") or
+ line.startswith("vnc defaults") or
+ line.startswith("vnc l2-group") or
+ line.startswith("vnc nve-group") or
+ (line.startswith("vni ") and
+ len(ctx_keys) == 2 and
+ ctx_keys[0].startswith('router bgp') and
+ ctx_keys[1] == 'address-family l2vpn evpn')):
main_ctx_key = []
# Save old context first
diff --git a/zebra/rib.h b/zebra/rib.h
index 5dd444dce0..0ee89e015a 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -447,6 +447,8 @@ DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
extern void zebra_vty_init(void);
extern int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi,
safi_t safi, const char *cmd);
+extern void static_config_install_delayed_routes(struct zebra_vrf *zvrf);
+
extern pid_t pid;
#endif /*_ZEBRA_RIB_H */
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 64585c4c1a..f7877f71b6 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -162,6 +162,12 @@ static int zebra_vrf_enable(struct vrf *vrf)
}
}
+ /*
+ * We may have static routes that are now possible to
+ * insert into the appropriate tables
+ */
+ static_config_install_delayed_routes(zvrf);
+
/* Kick off any VxLAN-EVPN processing. */
zebra_vxlan_vrf_enable(zvrf);
@@ -569,7 +575,6 @@ static int vrf_config_write(struct vty *vty)
? " prefix-routes-only"
: "");
zebra_ns_config_write(vty, (struct ns *)vrf->ns_ctxt);
- vty_out(vty, "!\n");
}
static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route");
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 9fe3c707bb..32d5286d5e 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -29,6 +29,7 @@
#include "rib.h"
#include "nexthop.h"
#include "vrf.h"
+#include "linklist.h"
#include "mpls.h"
#include "routemap.h"
#include "srcdest_table.h"
@@ -76,7 +77,186 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
/* VNI range as per RFC 7432 */
#define CMD_VNI_RANGE "(1-16777215)"
+struct static_hold_route {
+ char *vrf_name;
+ char *nhvrf_name;
+ afi_t afi;
+ safi_t safi;
+ char *dest_str;
+ char *mask_str;
+ char *src_str;
+ char *gate_str;
+ char *ifname;
+ char *flag_str;
+ char *tag_str;
+ char *distance_str;
+ char *label_str;
+};
+
+static struct list *static_list;
+
+static int static_list_compare_helper(const char *s1, const char *s2)
+{
+ /* Are Both NULL */
+ if (s1 == s2)
+ return 0;
+
+ if (!s1 && s2)
+ return -1;
+
+ if (s1 && !s2)
+ return 1;
+
+ return strcmp(s1, s2);
+}
+
+static void static_list_delete(struct static_hold_route *shr)
+{
+ if (shr->vrf_name)
+ XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
+ if (shr->nhvrf_name)
+ XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
+ if (shr->dest_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
+ if (shr->mask_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
+ if (shr->src_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
+ if (shr->gate_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
+ if (shr->ifname)
+ XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
+ if (shr->flag_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
+ if (shr->tag_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
+ if (shr->distance_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
+ if (shr->label_str)
+ XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
+
+ XFREE(MTYPE_STATIC_ROUTE, shr);
+}
+
+static int static_list_compare(void *arg1, void *arg2)
+{
+ struct static_hold_route *shr1 = arg1;
+ struct static_hold_route *shr2 = arg2;
+ int ret;
+
+ ret = strcmp(shr1->vrf_name, shr2->vrf_name);
+ if (ret)
+ return ret;
+
+ ret = strcmp(shr2->nhvrf_name, shr2->nhvrf_name);
+ if (ret)
+ return ret;
+
+ ret = shr1->afi - shr2->afi;
+ if (ret)
+ return ret;
+
+ ret = shr1->safi - shr2->afi;
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->dest_str, shr2->dest_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->mask_str, shr2->mask_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->src_str, shr2->src_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->ifname, shr2->ifname);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str);
+ if (ret)
+ return ret;
+
+ ret = static_list_compare_helper(shr1->distance_str,
+ shr2->distance_str);
+ if (ret)
+ return ret;
+
+ return static_list_compare_helper(shr1->label_str, shr2->label_str);
+}
+
+
/* General function for static route. */
+static int zebra_static_route_holdem(struct zebra_vrf *zvrf,
+ struct zebra_vrf *nh_zvrf,
+ afi_t afi, safi_t safi,
+ const char *negate, const char *dest_str,
+ const char *mask_str, const char *src_str,
+ const char *gate_str, const char *ifname,
+ const char *flag_str, const char *tag_str,
+ const char *distance_str,
+ const char *label_str)
+{
+ struct static_hold_route *shr, *lookup;
+ struct listnode *node;
+
+ shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr));
+ shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, zvrf->vrf->name);
+ shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_zvrf->vrf->name);
+ shr->afi = afi;
+ shr->safi = safi;
+ if (dest_str)
+ shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str);
+ if (mask_str)
+ shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str);
+ if (src_str)
+ shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str);
+ if (gate_str)
+ shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str);
+ if (ifname)
+ shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname);
+ if (flag_str)
+ shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str);
+ if (tag_str)
+ shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str);
+ if (distance_str)
+ shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str);
+ if (label_str)
+ shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str);
+
+ for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) {
+ if (static_list_compare(shr, lookup) == 0)
+ break;
+ }
+
+ if (lookup) {
+ if (negate) {
+ listnode_delete(static_list, lookup);
+ static_list_delete(shr);
+ static_list_delete(lookup);
+
+ return CMD_SUCCESS;
+ }
+
+ assert(!"We should not have found a duplicate and not remove it");
+ }
+
+ listnode_add_sort(static_list, shr);
+
+ return CMD_SUCCESS;
+}
+
static int zebra_static_route_leak(
struct vty *vty, struct zebra_vrf *zvrf, struct zebra_vrf *nh_zvrf,
afi_t afi, safi_t safi, const char *negate, const char *dest_str,
@@ -98,17 +278,34 @@ static int zebra_static_route_leak(
ret = str2prefix(dest_str, &p);
if (ret <= 0) {
- vty_out(vty, "%% Malformed address\n");
+ if (vty)
+ vty_out(vty, "%% Malformed address\n");
+ else
+ zlog_warn("%s: Malformed address: %s",
+ __PRETTY_FUNCTION__, dest_str);
return CMD_WARNING_CONFIG_FAILED;
}
+ if (zvrf->vrf->vrf_id == VRF_UNKNOWN
+ || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN) {
+ vrf_set_user_cfged(zvrf->vrf);
+ return zebra_static_route_holdem(
+ zvrf, nh_zvrf, afi, safi, negate, dest_str, mask_str,
+ src_str, gate_str, ifname, flag_str, tag_str,
+ distance_str, label_str);
+ }
switch (afi) {
case AFI_IP:
/* Cisco like mask notation. */
if (mask_str) {
ret = inet_aton(mask_str, &mask);
if (ret == 0) {
- vty_out(vty, "%% Malformed address\n");
+ if (vty)
+ vty_out(vty, "%% Malformed address\n");
+ else
+ zlog_warn("%s: Malformed address: %s",
+ __PRETTY_FUNCTION__,
+ mask_str);
return CMD_WARNING_CONFIG_FAILED;
}
p.prefixlen = ip_masklen(mask);
@@ -119,7 +316,13 @@ static int zebra_static_route_leak(
if (src_str) {
ret = str2prefix(src_str, &src);
if (ret <= 0 || src.family != AF_INET6) {
- vty_out(vty, "%% Malformed source address\n");
+ if (vty)
+ vty_out(vty,
+ "%% Malformed source address\n");
+ else
+ zlog_warn(
+ "%s: Malformed Source address: %s",
+ __PRETTY_FUNCTION__, src_str);
return CMD_WARNING_CONFIG_FAILED;
}
src_p = (struct prefix_ipv6 *)&src;
@@ -146,8 +349,13 @@ static int zebra_static_route_leak(
memset(&snh_label, 0, sizeof(struct static_nh_label));
if (label_str) {
if (!mpls_enabled) {
- vty_out(vty,
- "%% MPLS not turned on in kernel, ignoring command\n");
+ if (vty)
+ vty_out(vty,
+ "%% MPLS not turned on in kernel, ignoring command\n");
+ else
+ zlog_warn(
+ "%s: MPLS not turned on in kernel ignoring static route to %s",
+ __PRETTY_FUNCTION__, dest_str);
return CMD_WARNING_CONFIG_FAILED;
}
int rc = mpls_str2label(label_str, &snh_label.num_labels,
@@ -155,18 +363,37 @@ static int zebra_static_route_leak(
if (rc < 0) {
switch (rc) {
case -1:
- vty_out(vty, "%% Malformed label(s)\n");
+ if (vty)
+ vty_out(vty, "%% Malformed label(s)\n");
+ else
+ zlog_warn(
+ "%s: Malformed labels specified for route %s",
+ __PRETTY_FUNCTION__, dest_str);
break;
case -2:
- vty_out(vty,
- "%% Cannot use reserved label(s) (%d-%d)\n",
- MPLS_LABEL_RESERVED_MIN,
- MPLS_LABEL_RESERVED_MAX);
+ if (vty)
+ vty_out(vty,
+ "%% Cannot use reserved label(s) (%d-%d)\n",
+ MPLS_LABEL_RESERVED_MIN,
+ MPLS_LABEL_RESERVED_MAX);
+ else
+ zlog_warn(
+ "%s: Cannot use reserved labels (%d-%d) for %s",
+ __PRETTY_FUNCTION__,
+ MPLS_LABEL_RESERVED_MIN,
+ MPLS_LABEL_RESERVED_MAX,
+ dest_str);
break;
case -3:
- vty_out(vty,
- "%% Too many labels. Enter %d or fewer\n",
- MPLS_MAX_LABELS);
+ if (vty)
+ vty_out(vty,
+ "%% Too many labels. Enter %d or fewer\n",
+ MPLS_MAX_LABELS);
+ else
+ zlog_warn(
+ "%s: Too many labels, Enter %d or fewer for %s",
+ __PRETTY_FUNCTION__,
+ MPLS_MAX_LABELS, dest_str);
break;
}
return CMD_WARNING_CONFIG_FAILED;
@@ -178,8 +405,13 @@ static int zebra_static_route_leak(
if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0
|| strncasecmp(ifname, "reject", strlen(ifname)) == 0
|| strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) {
- vty_out(vty,
- "%% Nexthop interface cannot be Null0, reject or blackhole\n");
+ if (vty)
+ vty_out(vty,
+ "%% Nexthop interface cannot be Null0, reject or blackhole\n");
+ else
+ zlog_warn(
+ "%s: Nexthop interface cannot be Null0, reject or blackhole for %s",
+ __PRETTY_FUNCTION__, dest_str);
return CMD_WARNING_CONFIG_FAILED;
}
}
@@ -197,15 +429,28 @@ static int zebra_static_route_leak(
bh_type = STATIC_BLACKHOLE_NULL;
break;
default:
- vty_out(vty, "%% Malformed flag %s \n", flag_str);
+ if (vty)
+ vty_out(vty, "%% Malformed flag %s \n",
+ flag_str);
+ else
+ zlog_warn("%s: Malformed flag %s for %s",
+ __PRETTY_FUNCTION__, flag_str,
+ dest_str);
return CMD_WARNING_CONFIG_FAILED;
}
}
if (gate_str) {
if (inet_pton(afi2family(afi), gate_str, &gate) != 1) {
- vty_out(vty, "%% Malformed nexthop address %s\n",
- gate_str);
+ if (vty)
+ vty_out(vty,
+ "%% Malformed nexthop address %s\n",
+ gate_str);
+ else
+ zlog_warn(
+ "%s: Malformed nexthop address %s for %s",
+ __PRETTY_FUNCTION__, gate_str,
+ dest_str);
return CMD_WARNING_CONFIG_FAILED;
}
gatep = &gate;
@@ -287,7 +532,38 @@ static int zebra_static_route(struct vty *vty, afi_t afi, safi_t safi,
gate_str, ifname, flag_str, tag_str, distance_str, label_str);
}
+void static_config_install_delayed_routes(struct zebra_vrf *zvrf)
+{
+ struct listnode *node, *nnode;
+ struct static_hold_route *shr;
+ struct zebra_vrf *ozvrf, *nh_zvrf;
+ int installed;
+
+ for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) {
+ ozvrf = zebra_vrf_lookup_by_name(shr->vrf_name);
+ nh_zvrf = zebra_vrf_lookup_by_name(shr->nhvrf_name);
+
+ if (ozvrf != zvrf && nh_zvrf != zvrf)
+ continue;
+
+ if (ozvrf->vrf->vrf_id == VRF_UNKNOWN
+ || nh_zvrf->vrf->vrf_id == VRF_UNKNOWN)
+ continue;
+ installed = zebra_static_route_leak(
+ NULL, ozvrf, nh_zvrf, shr->afi, shr->safi, NULL,
+ shr->dest_str, shr->mask_str, shr->src_str,
+ shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str,
+ shr->distance_str, shr->label_str);
+
+ if (installed != CMD_SUCCESS)
+ zlog_debug(
+ "%s: Attempt to install %s as a route and it was rejected",
+ __PRETTY_FUNCTION__, shr->dest_str);
+ listnode_delete(static_list, shr);
+ static_list_delete(shr);
+ }
+}
/* Static unicast routes for multicast RPF lookup. */
DEFPY (ip_mroute_dist,
ip_mroute_dist_cmd,
@@ -1894,6 +2170,8 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi,
safi_t safi, const char *cmd)
{
+ struct static_hold_route *shr;
+ struct listnode *node;
char spacing[100];
struct route_node *rn;
struct static_route *si;
@@ -1907,6 +2185,40 @@ int static_config(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi,
sprintf(spacing, "%s%s", (zvrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ",
cmd);
+ /*
+ * Static routes for vrfs not fully inited
+ */
+ for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) {
+ if (shr->afi != afi || shr->safi != safi)
+ continue;
+
+ if (strcmp(zvrf->vrf->name, shr->vrf_name) != 0)
+ continue;
+
+ vty_out(vty, "%s ", spacing);
+ if (shr->dest_str)
+ vty_out(vty, "%s ", shr->dest_str);
+ if (shr->mask_str)
+ vty_out(vty, "%s ", shr->mask_str);
+ if (shr->src_str)
+ vty_out(vty, "from %s ", shr->src_str);
+ if (shr->gate_str)
+ vty_out(vty, "%s ", shr->gate_str);
+ if (shr->ifname)
+ vty_out(vty, "%s ", shr->ifname);
+ if (shr->flag_str)
+ vty_out(vty, "%s ", shr->flag_str);
+ if (shr->tag_str)
+ vty_out(vty, "tag %s", shr->tag_str);
+ if (shr->distance_str)
+ vty_out(vty, "%s ", shr->distance_str);
+ if (shr->label_str)
+ vty_out(vty, "label %s ", shr->label_str);
+ if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0)
+ vty_out(vty, "nexthop-vrf %s", shr->nhvrf_name);
+ vty_out(vty, "\n");
+ }
+
for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
for (si = rn->info; si; si = si->next) {
vty_out(vty, "%s %s", spacing,
@@ -3409,4 +3721,8 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &no_default_vrf_vni_mapping_cmd);
install_element(VRF_NODE, &vrf_vni_mapping_cmd);
install_element(VRF_NODE, &no_vrf_vni_mapping_cmd);
+
+ static_list = list_new();
+ static_list->cmp = (int (*)(void *, void *))static_list_compare;
+ static_list->del = (void (*)(void *))static_list_delete;
}