isisd: merge osr/google-is-is
this is essentially half of a rewrite of isisd. please note that a lot
of things are still broken and isisd is not ready for production use.
diff --git a/isisd/AUTHORS b/isisd/AUTHORS
index d9f98b2..05fc0a5 100644
--- a/isisd/AUTHORS
+++ b/isisd/AUTHORS
@@ -1,3 +1,4 @@
-Sampo Saaristo <sambo@cs.tut.fi>
-Ofer Wald <ofersf@islands.co.il>
-Hannes Gredler <hannes@gredler.at>
+Sampo Saaristo <sambo@cs.tut.fi>
+Ofer Wald <ofersf@islands.co.il>
+Hannes Gredler <hannes@gredler.at>
+Subbaiah Venkata <svenkata@google.com>
diff --git a/isisd/dict.c b/isisd/dict.c
index a78b82a..bbcb421 100644
--- a/isisd/dict.c
+++ b/isisd/dict.c
@@ -15,17 +15,11 @@
* contain a copyright notice related to this source.
*/
-#include <stdlib.h>
-#include <stddef.h>
#include "zebra.h"
#include "zassert.h"
-#define DICT_IMPLEMENTATION
+#include "memory.h"
#include "dict.h"
-#ifdef KAZLIB_RCSID
-static const char rcsid[] = "Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz";
-#endif
-
/*
* These macros provide short convenient names for structure members,
* which are embellished with dict_ prefixes so that they are
@@ -243,7 +237,7 @@
dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
{
- dict_t *new = malloc(sizeof *new);
+ dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t));
if (new) {
new->compare = comp;
@@ -284,7 +278,7 @@
void dict_destroy(dict_t *dict)
{
assert (dict_isempty(dict));
- free(dict);
+ XFREE(MTYPE_ISIS_DICT, dict);
}
/*
@@ -307,9 +301,6 @@
void dict_free(dict_t *dict)
{
-#ifdef KAZLIB_OBSOLESCENT_DEBUG
- assert ("call to obsolescent function dict_free()" && 0);
-#endif
dict_free_nodes(dict);
}
@@ -810,7 +801,7 @@
int dict_alloc_insert(dict_t *dict, const void *key, void *data)
{
- dnode_t *node = dict->allocnode(dict->context);
+ dnode_t *node = dict->allocnode (dict->context);
if (node) {
dnode_init(node, data);
@@ -946,17 +937,17 @@
static dnode_t *dnode_alloc(void *context)
{
- return malloc(sizeof *dnode_alloc(NULL));
+ return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
}
static void dnode_free(dnode_t *node, void *context)
{
- free(node);
+ XFREE(MTYPE_ISIS_DICT_NODE, node);
}
dnode_t *dnode_create(void *data)
{
- dnode_t *new = malloc(sizeof *new);
+ dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
if (new) {
new->data = data;
new->parent = NULL;
@@ -978,7 +969,7 @@
void dnode_destroy(dnode_t *dnode)
{
assert (!dnode_is_in_a_dict(dnode));
- free(dnode);
+ XFREE(MTYPE_ISIS_DICT_NODE, dnode);
}
void *dnode_get(dnode_t *dnode)
@@ -1232,7 +1223,7 @@
static char *dupstring(char *str)
{
int sz = strlen(str) + 1;
- char *new = malloc(sz);
+ char *new = XCALLOC(MTYPE_ISIS_TMP, sz);
if (new)
memcpy(new, str, sz);
return new;
@@ -1347,7 +1338,7 @@
"s switch to non-functioning allocator\n"
"q quit";
- for (i = 0; i < sizeof darray / sizeof *darray; i++)
+ for (i = 0; i < 10; i++)
dict_init(&darray[i], DICTCOUNT_T_MAX, comparef);
for (;;) {
diff --git a/isisd/dict.h b/isisd/dict.h
index 9395d1c..93edb7d 100644
--- a/isisd/dict.h
+++ b/isisd/dict.h
@@ -22,9 +22,6 @@
#define DICT_H
#include <limits.h>
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#include "sfx.h"
-#endif
/*
* Blurb for inclusion into C++ translation units
@@ -44,16 +41,12 @@
typedef enum { dnode_red, dnode_black } dnode_color_t;
typedef struct dnode_t {
- #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
struct dnode_t *dict_left;
struct dnode_t *dict_right;
struct dnode_t *dict_parent;
dnode_color_t dict_color;
const void *dict_key;
void *dict_data;
- #else
- int dict_dummy;
- #endif
} dnode_t;
typedef int (*dict_comp_t)(const void *, const void *);
@@ -61,7 +54,6 @@
typedef void (*dnode_free_t)(dnode_t *, void *);
typedef struct dict_t {
- #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
dnode_t dict_nilnode;
dictcount_t dict_nodecount;
dictcount_t dict_maxcount;
@@ -70,20 +62,13 @@
dnode_free_t dict_freenode;
void *dict_context;
int dict_dupes;
- #else
- int dict_dummmy;
- #endif
} dict_t;
typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *);
typedef struct dict_load_t {
- #if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
dict_t *dict_dictptr;
dnode_t dict_nilnode;
- #else
- int dict_dummmy;
- #endif
} dict_load_t;
extern dict_t *dict_create(dictcount_t, dict_comp_t);
@@ -124,18 +109,12 @@
extern void dict_load_end(dict_load_t *);
extern void dict_merge(dict_t *, dict_t *);
-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG)
-#ifdef KAZLIB_SIDEEFFECT_DEBUG
-#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount)
-#else
#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount)
-#endif
#define dict_count(D) ((D)->dict_nodecount)
#define dict_isempty(D) ((D)->dict_nodecount == 0)
#define dnode_get(N) ((N)->dict_data)
#define dnode_getkey(N) ((N)->dict_key)
#define dnode_put(N, X) ((N)->dict_data = (X))
-#endif
#ifdef __cplusplus
}
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index de34bea..468b0a6 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -36,6 +36,7 @@
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isisd.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_adjacency.h"
@@ -43,6 +44,10 @@
#include "isisd/isis_dr.h"
#include "isisd/isis_dynhn.h"
#include "isisd/isis_pdu.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_events.h"
extern struct isis *isis;
@@ -73,9 +78,9 @@
}
if (snpa) {
- memcpy (adj->snpa, snpa, 6);
+ memcpy (adj->snpa, snpa, ETH_ALEN);
} else {
- memset (adj->snpa, ' ', 6);
+ memset (adj->snpa, ' ', ETH_ALEN);
}
adj->circuit = circuit;
@@ -125,37 +130,60 @@
}
void
-isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
+isis_delete_adj (void *arg)
{
+ struct isis_adjacency *adj = arg;
+
if (!adj)
return;
- /* When we recieve a NULL list, we will know its p2p. */
- if (adjdb)
- listnode_delete (adjdb, adj);
- THREAD_OFF (adj->t_expire);
+ THREAD_TIMER_OFF (adj->t_expire);
+ /* remove from SPF trees */
+ spftree_area_adj_del (adj->circuit->area, adj);
+
+ if (adj->area_addrs)
+ list_delete (adj->area_addrs);
if (adj->ipv4_addrs)
list_delete (adj->ipv4_addrs);
#ifdef HAVE_IPV6
if (adj->ipv6_addrs)
list_delete (adj->ipv6_addrs);
#endif
-
+
XFREE (MTYPE_ISIS_ADJACENCY, adj);
return;
}
+static const char *
+adj_state2string (int state)
+{
+
+ switch (state)
+ {
+ case ISIS_ADJ_INITIALIZING:
+ return "Initializing";
+ case ISIS_ADJ_UP:
+ return "Up";
+ case ISIS_ADJ_DOWN:
+ return "Down";
+ default:
+ return "Unknown";
+ }
+
+ return NULL; /* not reached */
+}
+
void
-isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
+isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
const char *reason)
{
int old_state;
- int level = adj->level;
+ int level;
struct isis_circuit *circuit;
old_state = adj->adj_state;
- adj->adj_state = state;
+ adj->adj_state = new_state;
circuit = adj->circuit;
@@ -163,42 +191,107 @@
{
zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
circuit->area->area_tag,
- old_state, state, reason ? reason : "unspecified");
+ old_state, new_state, reason ? reason : "unspecified");
+ }
+
+ if (circuit->area->log_adj_changes)
+ {
+ const char *adj_name;
+ struct isis_dynhn *dyn;
+
+ dyn = dynhn_find_by_id (adj->sysid);
+ if (dyn)
+ adj_name = (const char *)dyn->name.name;
+ else
+ adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown";
+
+ zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
+ adj_name,
+ adj->circuit ? adj->circuit->interface->name : "no circuit",
+ adj_state2string (old_state),
+ adj_state2string (new_state),
+ reason ? reason : "unspecified");
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
{
- if (state == ISIS_ADJ_UP)
- circuit->upadjcount[level - 1]++;
- if (state == ISIS_ADJ_DOWN)
- {
- listnode_delete (adj->circuit->u.bc.adjdb[level - 1], adj);
- circuit->upadjcount[level - 1]--;
- }
+ for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
+ {
+ if ((adj->level & level) == 0)
+ continue;
+ if (new_state == ISIS_ADJ_UP)
+ {
+ circuit->upadjcount[level - 1]++;
+ isis_event_adjacency_state_change (adj, new_state);
+ /* update counter & timers for debugging purposes */
+ adj->last_flap = time (NULL);
+ adj->flaps++;
+ }
+ else if (new_state == ISIS_ADJ_DOWN)
+ {
+ listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
+ circuit->upadjcount[level - 1]--;
+ if (circuit->upadjcount[level - 1] == 0)
+ {
+ /* Clean lsp_queue when no adj is up. */
+ if (circuit->lsp_queue)
+ list_delete_all_node (circuit->lsp_queue);
+ }
+ isis_event_adjacency_state_change (adj, new_state);
+ isis_delete_adj (adj);
+ }
- list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
- isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
- circuit->u.bc.lan_neighs[level - 1]);
- }
- else if (state == ISIS_ADJ_UP)
- { /* p2p interface */
- if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
- send_hello (circuit, 1);
+ if (circuit->u.bc.lan_neighs[level - 1])
+ {
+ list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
+ isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
+ circuit->u.bc.lan_neighs[level - 1]);
+ }
- /* update counter & timers for debugging purposes */
- adj->last_flap = time (NULL);
- adj->flaps++;
+ /* On adjacency state change send new pseudo LSP if we are the DR */
+ if (circuit->u.bc.is_dr[level - 1])
+ lsp_regenerate_schedule_pseudo (circuit, level);
+ }
+ }
+ else if (circuit->circ_type == CIRCUIT_T_P2P)
+ {
+ for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
+ {
+ if ((adj->level & level) == 0)
+ continue;
+ if (new_state == ISIS_ADJ_UP)
+ {
+ circuit->upadjcount[level - 1]++;
+ isis_event_adjacency_state_change (adj, new_state);
- /* 7.3.17 - going up on P2P -> send CSNP */
- /* FIXME: yup, I know its wrong... but i will do it! (for now) */
- send_csnp (circuit, 1);
- send_csnp (circuit, 2);
+ if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
+ send_hello (circuit, level);
+
+ /* update counter & timers for debugging purposes */
+ adj->last_flap = time (NULL);
+ adj->flaps++;
+
+ /* 7.3.17 - going up on P2P -> send CSNP */
+ /* FIXME: yup, I know its wrong... but i will do it! (for now) */
+ send_csnp (circuit, level);
+ }
+ else if (new_state == ISIS_ADJ_DOWN)
+ {
+ if (adj->circuit->u.p2p.neighbor == adj)
+ adj->circuit->u.p2p.neighbor = NULL;
+ circuit->upadjcount[level - 1]--;
+ if (circuit->upadjcount[level - 1] == 0)
+ {
+ /* Clean lsp_queue when no adj is up. */
+ if (circuit->lsp_queue)
+ list_delete_all_node (circuit->lsp_queue);
+ }
+ isis_event_adjacency_state_change (adj, new_state);
+ isis_delete_adj (adj);
+ }
+ }
}
- else if (state == ISIS_ADJ_DOWN)
- { /* p2p interface */
- adj->circuit->u.p2p.neighbor = NULL;
- isis_delete_adj (adj, NULL);
- }
+
return;
}
@@ -225,7 +318,7 @@
snpa_print (adj->snpa), adj->level, adj->hold_time);
if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
{
- zlog_debug ("IPv4 Addresses:");
+ zlog_debug ("IPv4 Address(es):");
for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
zlog_debug ("%s", inet_ntoa (*ipv4_addr));
@@ -234,7 +327,7 @@
#ifdef HAVE_IPV6
if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
{
- zlog_debug ("IPv6 Addresses:");
+ zlog_debug ("IPv6 Address(es):");
for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
{
inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
@@ -251,14 +344,12 @@
isis_adj_expire (struct thread *thread)
{
struct isis_adjacency *adj;
- int level;
/*
* Get the adjacency
*/
adj = THREAD_ARG (thread);
assert (adj);
- level = adj->level;
adj->t_expire = NULL;
/* trigger the adj expire event */
@@ -267,32 +358,12 @@
return 0;
}
-static const char *
-adj_state2string (int state)
-{
-
- switch (state)
- {
- case ISIS_ADJ_INITIALIZING:
- return "Initializing";
- case ISIS_ADJ_UP:
- return "Up";
- case ISIS_ADJ_DOWN:
- return "Down";
- default:
- return "Unknown";
- }
-
- return NULL; /* not reached */
-}
-
/*
- * show clns/isis neighbor (detail)
+ * show isis neighbor [detail]
*/
-static void
-isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
+void
+isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
{
-
#ifdef HAVE_IPV6
struct in6_addr *ipv6_addr;
u_char ip6[INET6_ADDRSTRLEN];
@@ -335,10 +406,11 @@
if (detail == ISIS_UI_LEVEL_DETAIL)
{
level = adj->level;
+ vty_out (vty, "%s", VTY_NEWLINE);
if (adj->circuit)
- vty_out (vty, "%s Interface: %s", VTY_NEWLINE, adj->circuit->interface->name); /* interface name */
+ vty_out (vty, " Interface: %s", adj->circuit->interface->name);
else
- vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
+ vty_out (vty, " Interface: NULL circuit");
vty_out (vty, ", Level: %u", adj->level); /* level */
vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
now = time (NULL);
@@ -347,40 +419,54 @@
time2string (adj->last_upd + adj->hold_time - now));
else
vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
- vty_out (vty, "%s Adjacency flaps: %u", VTY_NEWLINE, adj->flaps);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " Adjacency flaps: %u", adj->flaps);
vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
- vty_out (vty, "%s Circuit type: %s",
- VTY_NEWLINE, circuit_t2string (adj->circuit_t));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t));
vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
- vty_out (vty, "%s SNPA: %s", VTY_NEWLINE, snpa_print (adj->snpa));
- dyn = dynhn_find_by_id (adj->lanid);
- if (dyn)
- vty_out (vty, ", LAN id: %s.%02x",
- dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
- else
- vty_out (vty, ", LAN id: %s.%02x",
- sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " SNPA: %s", snpa_print (adj->snpa));
+ if (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)
+ {
+ dyn = dynhn_find_by_id (adj->lanid);
+ if (dyn)
+ vty_out (vty, ", LAN id: %s.%02x",
+ dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
+ else
+ vty_out (vty, ", LAN id: %s.%02x",
+ sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
- vty_out (vty, "%s Priority: %u",
- VTY_NEWLINE, adj->prio[adj->level - 1]);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]);
- vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
- isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
- dis), adj->dischanges[level - 1],
- time2string (now -
- (adj->dis_record[ISIS_LEVELS + level - 1].
- last_dis_change)), VTY_NEWLINE);
+ vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
+ isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
+ dis), adj->dischanges[level - 1],
+ time2string (now -
+ (adj->dis_record[ISIS_LEVELS + level - 1].
+ last_dis_change)));
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ if (adj->area_addrs && listcount (adj->area_addrs) > 0)
+ {
+ struct area_addr *area_addr;
+ vty_out (vty, " Area Address(es):%s", VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
+ vty_out (vty, " %s%s", isonet_print (area_addr->area_addr,
+ area_addr->addr_len), VTY_NEWLINE);
+ }
if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
{
- vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE);
+ vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
}
#ifdef HAVE_IPV6
if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
{
- vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE);
+ vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
{
inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
@@ -394,53 +480,6 @@
}
void
-isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
-}
-
-void
-isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
-}
-
-void
-isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
-}
-
-void
-isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
-}
-
-void
-isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
-}
-
-void
-isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
-}
-
-void
-isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *,
- void *), void *arg)
-{
- struct listnode *node, *nnode;
- struct isis_adjacency *adj;
-
- for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj))
- (*func) (adj, arg);
-}
-
-void
isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
{
struct isis_adjacency *adj;
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 99a8bb2..caa3107 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -44,6 +44,7 @@
enum isis_adj_state
{
+ ISIS_ADJ_UNKNOWN,
ISIS_ADJ_INITIALIZING,
ISIS_ADJ_UP,
ISIS_ADJ_DOWN
@@ -83,8 +84,10 @@
struct list *area_addrs; /* areaAdressesOfNeighbour */
struct nlpids nlpids; /* protocols spoken ... */
struct list *ipv4_addrs;
+ struct in_addr router_address;
#ifdef HAVE_IPV6
struct list *ipv6_addrs;
+ struct in6_addr router_address6;
#endif /* HAVE_IPV6 */
u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */
int circuit_t; /* from hello PDU hdr */
@@ -103,25 +106,13 @@
struct list *adjdb);
struct isis_adjacency *isis_new_adj (u_char * id, u_char * snpa, int level,
struct isis_circuit *circuit);
-void isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb);
+void isis_delete_adj (void *adj);
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);
int isis_adj_expire (struct thread *thread);
-void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty);
-void isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty);
-void isis_adj_print_vty_extensive (struct isis_adjacency *adj,
- struct vty *vty);
-void isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty);
-void isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj,
- struct vty *vty);
-void isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj,
- struct vty *vty);
-
+void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail);
void isis_adj_build_neigh_list (struct list *adjdb, struct list *list);
void isis_adj_build_up_list (struct list *adjdb, struct list *list);
-void isis_adjdb_iterate (struct list *adjdb,
- void (*func) (struct isis_adjacency *,
- void *), void *arg);
#endif /* ISIS_ADJACENCY_H */
diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c
index 05f1138..4d5b165 100644
--- a/isisd/isis_bpf.c
+++ b/isisd/isis_bpf.c
@@ -301,7 +301,16 @@
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
struct ether_header *eth;
- int written;
+ int written, buflen;
+
+ buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
+ if (buflen > sizeof (sock_buff))
+ {
+ zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than "
+ "output pdu size %d on circuit %s",
+ sizeof (sock_buff), buflen, circuit->interface->name);
+ return ISIS_WARNING;
+ }
stream_set_getp (circuit->snd_stream, 0);
@@ -328,9 +337,7 @@
stream_get_endp (circuit->snd_stream));
/* now we can send this */
- written = write (circuit->fd, sock_buff,
- stream_get_endp (circuit->snd_stream)
- + LLC_LEN + ETHER_HDR_LEN);
+ written = write (circuit->fd, sock_buff, buflen);
return ISIS_OK;
}
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 99e2bf6..c09c3a2 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -44,6 +44,7 @@
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_tlv.h"
#include "isisd/isis_lsp.h"
@@ -53,18 +54,13 @@
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_dr.h"
-#include "isisd/isis_flags.h"
#include "isisd/isisd.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
-extern struct thread_master *master;
-extern struct isis *isis;
-
/*
* Prototypes.
*/
-void isis_circuit_down(struct isis_circuit *);
int isis_interface_config_write(struct vty *);
int isis_if_new_hook(struct interface *);
int isis_if_delete_hook(struct interface *);
@@ -76,55 +72,63 @@
int i;
circuit = XCALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit));
- if (circuit)
- {
- /* set default metrics for circuit */
- for (i = 0; i < 2; i++)
- {
- circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRICS;
- circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED;
- circuit->metrics[i].metric_error = METRICS_UNSUPPORTED;
- circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED;
- circuit->te_metric[i] = DEFAULT_CIRCUIT_METRICS;
- }
- }
- else
+ if (circuit == NULL)
{
zlog_err ("Can't malloc isis circuit");
return NULL;
}
+ /*
+ * Default values
+ */
+ circuit->is_type = IS_LEVEL_1_AND_2;
+ circuit->flags = 0;
+ circuit->pad_hellos = 1;
+ for (i = 0; i < 2; i++)
+ {
+ circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL;
+ circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER;
+ circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL;
+ circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL;
+ circuit->priority[i] = DEFAULT_PRIORITY;
+ circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRIC;
+ circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED;
+ circuit->metrics[i].metric_error = METRICS_UNSUPPORTED;
+ circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED;
+ circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
+ }
+
return circuit;
}
void
+isis_circuit_del (struct isis_circuit *circuit)
+{
+ if (!circuit)
+ return;
+
+ isis_circuit_if_unbind (circuit, circuit->interface);
+
+ /* and lastly the circuit itself */
+ XFREE (MTYPE_ISIS_CIRCUIT, circuit);
+
+ return;
+}
+
+void
isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)
{
- int i;
+ assert (area);
circuit->area = area;
+
/*
* The level for the circuit is same as for the area, unless configured
* otherwise.
*/
- circuit->circuit_is_type = area->is_type;
- /*
- * Default values
- */
- for (i = 0; i < 2; i++)
- {
- circuit->hello_interval[i] = HELLO_INTERVAL;
- circuit->hello_multiplier[i] = HELLO_MULTIPLIER;
- circuit->csnp_interval[i] = CSNP_INTERVAL;
- circuit->psnp_interval[i] = PSNP_INTERVAL;
- circuit->u.bc.priority[i] = DEFAULT_PRIORITY;
- }
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
- {
- circuit->u.bc.adjdb[0] = list_new ();
- circuit->u.bc.adjdb[1] = list_new ();
- circuit->u.bc.pad_hellos = 1;
- }
- circuit->lsp_interval = LSP_INTERVAL;
+ if (area->is_type != IS_LEVEL_1_AND_2 && area->is_type != circuit->is_type)
+ zlog_warn ("circut %s is_type %d mismatch with area %s is_type %d",
+ circuit->interface->name, circuit->is_type,
+ circuit->area->area_tag, area->is_type);
/*
* Add the circuit into area
@@ -132,25 +136,20 @@
listnode_add (area->circuit_list, circuit);
circuit->idx = flags_get_index (&area->flags);
- circuit->lsp_queue = list_new ();
return;
}
void
-isis_circuit_deconfigure (struct isis_circuit *circuit,
- struct isis_area *area)
+isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area)
{
-
- /* destroy adjacencies */
- if (circuit->u.bc.adjdb[0])
- isis_adjdb_iterate (circuit->u.bc.adjdb[0], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[0]);
- if (circuit->u.bc.adjdb[1])
- isis_adjdb_iterate (circuit->u.bc.adjdb[1], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[1]);
- /* Remove circuit from area */
- listnode_delete (area->circuit_list, circuit);
/* Free the index of SRM and SSN flags */
flags_free_index (&area->flags, circuit->idx);
+ circuit->idx = 0;
+ /* Remove circuit from area */
+ assert (circuit->area == area);
+ listnode_delete (area->circuit_list, circuit);
+ circuit->area = NULL;
return;
}
@@ -166,8 +165,11 @@
for (ALL_LIST_ELEMENTS_RO (list, node, circuit))
if (circuit->interface == ifp)
- return circuit;
-
+ {
+ assert (ifp->info == circuit);
+ return circuit;
+ }
+
return NULL;
}
@@ -178,83 +180,77 @@
struct listnode *node;
struct isis_circuit *circuit;
- if (!isis->area_list)
- return NULL;
+ if (ifp->info)
+ return (struct isis_circuit *)ifp->info;
- for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+ if (isis->area_list)
{
- circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
- if (circuit)
- return circuit;
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+ {
+ circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ if (circuit)
+ return circuit;
+ }
}
-
return circuit_lookup_by_ifp (ifp, isis->init_circ_list);
}
-void
-isis_circuit_del (struct isis_circuit *circuit)
+static struct isis_circuit *
+isis_circuit_lookup (struct vty *vty)
{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
- if (!circuit)
- return;
-
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ ifp = (struct interface *) vty->index;
+ if (!ifp)
{
- /* destroy adjacency databases */
- if (circuit->u.bc.adjdb[0])
- list_delete (circuit->u.bc.adjdb[0]);
- if (circuit->u.bc.adjdb[1])
- list_delete (circuit->u.bc.adjdb[1]);
- /* destroy neighbour lists */
- if (circuit->u.bc.lan_neighs[0])
- list_delete (circuit->u.bc.lan_neighs[0]);
- if (circuit->u.bc.lan_neighs[1])
- list_delete (circuit->u.bc.lan_neighs[1]);
- /* destroy addresses */
+ vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+ return NULL;
}
- if (circuit->ip_addrs)
- list_delete (circuit->ip_addrs);
-#ifdef HAVE_IPV6
- if (circuit->ipv6_link)
- list_delete (circuit->ipv6_link);
- if (circuit->ipv6_non_link)
- list_delete (circuit->ipv6_non_link);
-#endif /* HAVE_IPV6 */
- /* and lastly the circuit itself */
- XFREE (MTYPE_ISIS_CIRCUIT, circuit);
+ circuit = circuit_scan_by_ifp (ifp);
+ if (!circuit)
+ {
+ vty_out (vty, "ISIS is not enabled on circuit %s%s",
+ ifp->name, VTY_NEWLINE);
+ return NULL;
+ }
- return;
+ return circuit;
}
void
isis_circuit_add_addr (struct isis_circuit *circuit,
struct connected *connected)
{
+ struct listnode *node;
struct prefix_ipv4 *ipv4;
u_char buf[BUFSIZ];
#ifdef HAVE_IPV6
struct prefix_ipv6 *ipv6;
#endif /* HAVE_IPV6 */
- if (!circuit->ip_addrs)
- circuit->ip_addrs = list_new ();
-#ifdef HAVE_IPV6
- if (!circuit->ipv6_link)
- circuit->ipv6_link = list_new ();
- if (!circuit->ipv6_non_link)
- circuit->ipv6_non_link = list_new ();
-#endif /* HAVE_IPV6 */
-
memset (&buf, 0, BUFSIZ);
if (connected->address->family == AF_INET)
{
+ u_int32_t addr = connected->address->u.prefix4.s_addr;
+ addr = ntohl (addr);
+ if (IPV4_NET0(addr) ||
+ IPV4_NET127(addr) ||
+ IN_CLASSD(addr) ||
+ IPV4_LINKLOCAL(addr))
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ipv4))
+ if (prefix_same ((struct prefix *) ipv4, connected->address))
+ return;
+
ipv4 = prefix_ipv4_new ();
ipv4->prefixlen = connected->address->prefixlen;
ipv4->prefix = connected->address->u.prefix4;
listnode_add (circuit->ip_addrs, ipv4);
if (circuit->area)
- lsp_regenerate_schedule (circuit->area);
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
#ifdef EXTREME_DEBUG
prefix2str (connected->address, buf, BUFSIZ);
@@ -265,6 +261,16 @@
#ifdef HAVE_IPV6
if (connected->address->family == AF_INET6)
{
+ if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6))
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ipv6))
+ if (prefix_same ((struct prefix *) ipv6, connected->address))
+ return;
+ for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ipv6))
+ if (prefix_same ((struct prefix *) ipv6, connected->address))
+ return;
+
ipv6 = prefix_ipv6_new ();
ipv6->prefixlen = connected->address->prefixlen;
ipv6->prefix = connected->address->u.prefix6;
@@ -274,7 +280,7 @@
else
listnode_add (circuit->ipv6_non_link, ipv6);
if (circuit->area)
- lsp_regenerate_schedule (circuit->area);
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
#ifdef EXTREME_DEBUG
prefix2str (connected->address, buf, BUFSIZ);
@@ -306,20 +312,20 @@
ipv4->prefix = connected->address->u.prefix4;
for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip))
- if (prefix_same ((struct prefix *) ip, (struct prefix *) &ipv4))
+ if (prefix_same ((struct prefix *) ip, (struct prefix *) ipv4))
break;
if (ip)
{
listnode_delete (circuit->ip_addrs, ip);
- if (circuit->area)
- lsp_regenerate_schedule (circuit->area);
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
}
else
{
prefix2str (connected->address, (char *)buf, BUFSIZ);
- zlog_warn("Nonexitant ip address %s removal attempt from circuit \
- %d", buf, circuit->circuit_id);
+ zlog_warn ("Nonexitant ip address %s removal attempt from \
+ circuit %d", buf, circuit->circuit_id);
}
}
#ifdef HAVE_IPV6
@@ -359,72 +365,105 @@
if (!found)
{
prefix2str (connected->address, (char *)buf, BUFSIZ);
- zlog_warn("Nonexitant ip address %s removal attempt from \
- circuit %d", buf, circuit->circuit_id);
+ zlog_warn ("Nonexitant ip address %s removal attempt from \
+ circuit %d", buf, circuit->circuit_id);
}
- else
- if (circuit->area)
- lsp_regenerate_schedule (circuit->area);
+ else if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
}
#endif /* HAVE_IPV6 */
return;
}
+static u_char
+isis_circuit_id_gen (struct interface *ifp)
+{
+ u_char id = 0;
+ char ifname[16];
+ unsigned int i;
+ int start = -1, end = -1;
+
+ /*
+ * Get a stable circuit id from ifname. This makes
+ * the ifindex from flapping when netdevs are created
+ * and deleted on the fly. Note that this circuit id
+ * is used in pseudo lsps so it is better to be stable.
+ * The following code works on any reasonanle ifname
+ * like: eth1 or trk-1.1 etc.
+ */
+ for (i = 0; i < strlen (ifp->name); i++)
+ {
+ if (isdigit(ifp->name[i]))
+ {
+ if (start < 0)
+ {
+ start = i;
+ end = i + 1;
+ }
+ else
+ {
+ end = i + 1;
+ }
+ }
+ else if (start >= 0)
+ break;
+ }
+
+ if ((start >= 0) && (end >= start) && (end - start) < 16)
+ {
+ memset (ifname, 0, 16);
+ strncpy (ifname, &ifp->name[start], end - start);
+ id = (u_char)atoi(ifname);
+ }
+
+ /* Try to be unique. */
+ if (!id)
+ id = (u_char)((ifp->ifindex & 0xff) | 0x80);
+
+ return id;
+}
+
void
isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
{
struct listnode *node, *nnode;
struct connected *conn;
- circuit->interface = ifp;
- ifp->info = circuit;
+ circuit->circuit_id = isis_circuit_id_gen (ifp);
- circuit->circuit_id = ifp->ifindex % 255; /* FIXME: Why not ? */
-
+ isis_circuit_if_bind (circuit, ifp);
/* isis_circuit_update_addrs (circuit, ifp); */
if (if_is_broadcast (ifp))
{
- circuit->circ_type = CIRCUIT_T_BROADCAST;
- /*
- * Get the Hardware Address
- */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-#ifndef SUNOS_5
- if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
- zlog_warn ("unsupported link layer");
+ if (circuit->circ_type_config == CIRCUIT_T_P2P)
+ circuit->circ_type = CIRCUIT_T_P2P;
else
- memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl),
- ETH_ALEN);
-#endif
-#else
- if (circuit->interface->hw_addr_len != ETH_ALEN)
- {
- zlog_warn ("unsupported link layer");
- }
- else
- {
- memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
- }
-#ifdef EXTREME_DEGUG
- zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
- circuit->interface->ifindex, ISO_MTU (circuit),
- snpa_print (circuit->u.bc.snpa));
-
-#endif /* EXTREME_DEBUG */
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
+ circuit->circ_type = CIRCUIT_T_BROADCAST;
}
else if (if_is_pointopoint (ifp))
{
circuit->circ_type = CIRCUIT_T_P2P;
}
+ else if (if_is_loopback (ifp))
+ {
+ circuit->circ_type = CIRCUIT_T_LOOPBACK;
+ circuit->is_passive = 1;
+ }
else
{
/* It's normal in case of loopback etc. */
if (isis->debugs & DEBUG_EVENTS)
- zlog_debug ("isis_circuit_if_add: unsupported media");
+ zlog_debug ("isis_circuit_if_add: unsupported media");
+ circuit->circ_type = CIRCUIT_T_UNKNOWN;
}
+ circuit->ip_addrs = list_new ();
+#ifdef HAVE_IPV6
+ circuit->ipv6_link = list_new ();
+ circuit->ipv6_non_link = list_new ();
+#endif /* HAVE_IPV6 */
+
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
isis_circuit_add_addr (circuit, conn);
@@ -432,88 +471,158 @@
}
void
-isis_circuit_update_params (struct isis_circuit *circuit,
- struct interface *ifp)
+isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp)
{
- assert (circuit);
+ struct listnode *node, *nnode;
+ struct connected *conn;
- if (circuit->circuit_id != ifp->ifindex)
+ assert (circuit->interface == ifp);
+
+ /* destroy addresses */
+ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
+ isis_circuit_del_addr (circuit, conn);
+
+ if (circuit->ip_addrs)
{
- zlog_warn ("changing circuit_id %d->%d", circuit->circuit_id,
- ifp->ifindex);
- circuit->circuit_id = ifp->ifindex % 255;
+ assert (listcount(circuit->ip_addrs) == 0);
+ list_delete (circuit->ip_addrs);
+ circuit->ip_addrs = NULL;
}
- /* FIXME: Why is this needed? shouldn't we compare to the area's mtu */
- /* Ofer, this was here in case someone changes the mtu (e.g. with ifconfig)
- The areas MTU is the minimum of mtu's of circuits in the area
- now we can't catch the change
- if (circuit->mtu != ifp->mtu) {
- zlog_warn ("changing circuit mtu %d->%d", circuit->mtu,
- ifp->mtu);
- circuit->mtu = ifp->mtu;
- }
- */
- /*
- * Get the Hardware Address
- */
-#ifdef HAVE_STRUCT_SOCKADDR_DL
-#ifndef SUNOS_5
- if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
- zlog_warn ("unsupported link layer");
- else
- memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), ETH_ALEN);
-#endif
-#else
- if (circuit->interface->hw_addr_len != ETH_ALEN)
+#ifdef HAVE_IPV6
+ if (circuit->ipv6_link)
{
- zlog_warn ("unsupported link layer");
+ assert (listcount(circuit->ipv6_link) == 0);
+ list_delete (circuit->ipv6_link);
+ circuit->ipv6_link = NULL;
}
- else
- {
- if (memcmp (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN))
- {
- zlog_warn ("changing circuit snpa %s->%s",
- snpa_print (circuit->u.bc.snpa),
- snpa_print (circuit->interface->hw_addr));
- }
- }
-#endif
- if (if_is_broadcast (ifp))
+ if (circuit->ipv6_non_link)
{
- circuit->circ_type = CIRCUIT_T_BROADCAST;
+ assert (listcount(circuit->ipv6_non_link) == 0);
+ list_delete (circuit->ipv6_non_link);
+ circuit->ipv6_non_link = NULL;
}
- else if (if_is_pointopoint (ifp))
- {
- circuit->circ_type = CIRCUIT_T_P2P;
- }
- else
- {
- zlog_warn ("isis_circuit_update_params: unsupported media");
- }
+#endif /* HAVE_IPV6 */
+
+ circuit->circ_type = CIRCUIT_T_UNKNOWN;
+ circuit->circuit_id = 0;
return;
}
void
-isis_circuit_if_del (struct isis_circuit *circuit)
+isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp)
{
- circuit->interface->info = NULL;
+ assert (circuit != NULL);
+ assert (ifp != NULL);
+ if (circuit->interface)
+ assert (circuit->interface == ifp);
+ else
+ circuit->interface = ifp;
+ if (ifp->info)
+ assert (ifp->info == circuit);
+ else
+ ifp->info = circuit;
+}
+
+void
+isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp)
+{
+ assert (circuit != NULL);
+ assert (ifp != NULL);
+ assert (circuit->interface == ifp);
+ assert (ifp->info == circuit);
circuit->interface = NULL;
-
- return;
+ ifp->info = NULL;
}
-void
+static void
+isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set)
+{
+ struct isis_area *area;
+ struct isis_lsp *lsp;
+ dnode_t *dnode, *dnode_next;
+ int level;
+
+ assert (circuit);
+ area = circuit->area;
+ assert (area);
+ for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++)
+ {
+ if (level & circuit->is_type)
+ {
+ if (area->lspdb[level - 1] &&
+ dict_count (area->lspdb[level - 1]) > 0)
+ {
+ for (dnode = dict_first (area->lspdb[level - 1]);
+ dnode != NULL; dnode = dnode_next)
+ {
+ dnode_next = dict_next (area->lspdb[level - 1], dnode);
+ lsp = dnode_get (dnode);
+ if (is_set)
+ {
+ ISIS_SET_FLAG (lsp->SRMflags, circuit);
+ }
+ else
+ {
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+ }
+ }
+ }
+ }
+ }
+}
+
+int
isis_circuit_up (struct isis_circuit *circuit)
{
+ int retv;
+
+ /* Set the flags for all the lsps of the circuit. */
+ isis_circuit_update_all_srmflags (circuit, 1);
+
+ if (circuit->state == C_STATE_UP)
+ return ISIS_OK;
+
+ if (circuit->is_passive)
+ return ISIS_OK;
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
{
+ /*
+ * Get the Hardware Address
+ */
+#ifdef HAVE_STRUCT_SOCKADDR_DL
+#ifndef SUNOS_5
+ if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN)
+ zlog_warn ("unsupported link layer");
+ else
+ memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl),
+ ETH_ALEN);
+#endif
+#else
+ if (circuit->interface->hw_addr_len != ETH_ALEN)
+ {
+ zlog_warn ("unsupported link layer");
+ }
+ else
+ {
+ memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
+ }
+#ifdef EXTREME_DEGUG
+ zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
+ circuit->interface->ifindex, ISO_MTU (circuit),
+ snpa_print (circuit->u.bc.snpa));
+#endif /* EXTREME_DEBUG */
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
+
+ circuit->u.bc.adjdb[0] = list_new ();
+ circuit->u.bc.adjdb[1] = list_new ();
+
if (circuit->area->min_bcast_mtu == 0 ||
- ISO_MTU (circuit) < circuit->area->min_bcast_mtu)
- circuit->area->min_bcast_mtu = ISO_MTU (circuit);
+ ISO_MTU (circuit) < circuit->area->min_bcast_mtu)
+ circuit->area->min_bcast_mtu = ISO_MTU (circuit);
/*
* ISO 10589 - 8.4.1 Enabling of broadcast circuits
*/
@@ -524,98 +633,183 @@
/* 8.4.1 a) commence sending of IIH PDUs */
- if (circuit->circuit_is_type & IS_LEVEL_1)
- {
- thread_add_event (master, send_lan_l1_hello, circuit, 0);
- circuit->u.bc.lan_neighs[0] = list_new ();
- }
+ if (circuit->is_type & IS_LEVEL_1)
+ {
+ thread_add_event (master, send_lan_l1_hello, circuit, 0);
+ circuit->u.bc.lan_neighs[0] = list_new ();
+ }
- if (circuit->circuit_is_type & IS_LEVEL_2)
- {
- thread_add_event (master, send_lan_l2_hello, circuit, 0);
- circuit->u.bc.lan_neighs[1] = list_new ();
- }
+ if (circuit->is_type & IS_LEVEL_2)
+ {
+ thread_add_event (master, send_lan_l2_hello, circuit, 0);
+ circuit->u.bc.lan_neighs[1] = list_new ();
+ }
/* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
/* 8.4.1 c) FIXME: listen for ESH PDUs */
/* 8.4.1 d) */
/* dr election will commence in... */
- if (circuit->circuit_is_type & IS_LEVEL_1)
- THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
- circuit, 2 * circuit->hello_interval[0]);
- if (circuit->circuit_is_type & IS_LEVEL_2)
- THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
- circuit, 2 * circuit->hello_interval[1]);
+ if (circuit->is_type & IS_LEVEL_1)
+ THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
+ circuit, 2 * circuit->hello_interval[0]);
+ if (circuit->is_type & IS_LEVEL_2)
+ THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
+ circuit, 2 * circuit->hello_interval[1]);
}
else
{
/* initializing the hello send threads
* for a ptp IF
*/
+ circuit->u.p2p.neighbor = NULL;
thread_add_event (master, send_p2p_hello, circuit, 0);
-
}
/* initializing PSNP timers */
- if (circuit->circuit_is_type & IS_LEVEL_1)
+ if (circuit->is_type & IS_LEVEL_1)
+ THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
+ isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
+
+ if (circuit->is_type & IS_LEVEL_2)
+ THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
+ isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
+
+ /* unified init for circuits; ignore warnings below this level */
+ retv = isis_sock_init (circuit);
+ if (retv != ISIS_OK)
{
- THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
- isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
+ isis_circuit_down (circuit);
+ return retv;
}
- if (circuit->circuit_is_type & IS_LEVEL_2)
- {
- THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
- isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
- }
-
- /* initialize the circuit streams */
+ /* initialize the circuit streams after opening connection */
if (circuit->rcv_stream == NULL)
circuit->rcv_stream = stream_new (ISO_MTU (circuit));
if (circuit->snd_stream == NULL)
circuit->snd_stream = stream_new (ISO_MTU (circuit));
- /* unified init for circuits */
- isis_sock_init (circuit);
-
#ifdef GNU_LINUX
THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
- circuit->fd);
+ circuit->fd);
#else
THREAD_TIMER_ON (master, circuit->t_read, isis_receive, circuit,
- circuit->fd);
+ circuit->fd);
#endif
- return;
+
+ circuit->lsp_queue = list_new ();
+ circuit->lsp_queue_last_cleared = time (NULL);
+
+ return ISIS_OK;
}
void
isis_circuit_down (struct isis_circuit *circuit)
{
- /* Cancel all active threads -- FIXME: wrong place */
- /* HT: Read thread if GNU_LINUX, TIMER thread otherwise. */
- THREAD_OFF (circuit->t_read);
+ if (circuit->state != C_STATE_UP)
+ return;
+
+ /* Clear the flags for all the lsps of the circuit. */
+ isis_circuit_update_all_srmflags (circuit, 0);
+
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
{
+ /* destroy neighbour lists */
+ if (circuit->u.bc.lan_neighs[0])
+ {
+ list_delete (circuit->u.bc.lan_neighs[0]);
+ circuit->u.bc.lan_neighs[0] = NULL;
+ }
+ if (circuit->u.bc.lan_neighs[1])
+ {
+ list_delete (circuit->u.bc.lan_neighs[1]);
+ circuit->u.bc.lan_neighs[1] = NULL;
+ }
+ /* destroy adjacency databases */
+ if (circuit->u.bc.adjdb[0])
+ {
+ circuit->u.bc.adjdb[0]->del = isis_delete_adj;
+ list_delete (circuit->u.bc.adjdb[0]);
+ circuit->u.bc.adjdb[0] = NULL;
+ }
+ if (circuit->u.bc.adjdb[1])
+ {
+ circuit->u.bc.adjdb[1]->del = isis_delete_adj;
+ list_delete (circuit->u.bc.adjdb[1]);
+ circuit->u.bc.adjdb[1] = NULL;
+ }
+ if (circuit->u.bc.is_dr[0])
+ {
+ isis_dr_resign (circuit, 1);
+ circuit->u.bc.is_dr[0] = 0;
+ }
+ memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
+ if (circuit->u.bc.is_dr[1])
+ {
+ isis_dr_resign (circuit, 2);
+ circuit->u.bc.is_dr[1] = 0;
+ }
+ memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
+ memset (circuit->u.bc.snpa, 0, ETH_ALEN);
+
THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]);
THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]);
THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
+ THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]);
+ THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]);
}
else if (circuit->circ_type == CIRCUIT_T_P2P)
{
+ isis_delete_adj (circuit->u.p2p.neighbor);
+ circuit->u.p2p.neighbor = NULL;
THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello);
}
- if (circuit->t_send_psnp[0]) {
- THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
- }
- if (circuit->t_send_psnp[1]) {
- THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
- }
+ /* Cancel all active threads */
+ THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
+ THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
+ THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
+ THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
+ THREAD_OFF (circuit->t_read);
+
+ if (circuit->lsp_queue)
+ {
+ circuit->lsp_queue->del = NULL;
+ list_delete (circuit->lsp_queue);
+ circuit->lsp_queue = NULL;
+ }
+
+ /* send one gratuitous hello to spead up convergence */
+ if (circuit->is_type & IS_LEVEL_1)
+ send_hello (circuit, IS_LEVEL_1);
+ if (circuit->is_type & IS_LEVEL_2)
+ send_hello (circuit, IS_LEVEL_2);
+
+ circuit->upadjcount[0] = 0;
+ circuit->upadjcount[1] = 0;
+
/* close the socket */
- close (circuit->fd);
+ if (circuit->fd)
+ {
+ close (circuit->fd);
+ circuit->fd = 0;
+ }
+
+ if (circuit->rcv_stream != NULL)
+ {
+ stream_free (circuit->rcv_stream);
+ circuit->rcv_stream = NULL;
+ }
+
+ if (circuit->snd_stream != NULL)
+ {
+ stream_free (circuit->snd_stream);
+ circuit->snd_stream = NULL;
+ }
+
+ thread_cancel_event (master, circuit);
return;
}
@@ -640,216 +834,346 @@
return;
}
+void
+isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
+ char detail)
+{
+ if (detail == ISIS_UI_LEVEL_BRIEF)
+ {
+ vty_out (vty, " %-12s", circuit->interface->name);
+ vty_out (vty, "0x%-7x", circuit->circuit_id);
+ vty_out (vty, "%-9s", circuit_state2string (circuit->state));
+ vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type));
+ vty_out (vty, "%-9s", circuit_t2string (circuit->is_type));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+
+ if (detail == ISIS_UI_LEVEL_DETAIL)
+ {
+ vty_out (vty, " Interface: %s", circuit->interface->name);
+ vty_out (vty, ", State: %s", circuit_state2string (circuit->state));
+ if (circuit->is_passive)
+ vty_out (vty, ", Passive");
+ else
+ vty_out (vty, ", Active");
+ vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " Type: %s", circuit_type2string (circuit->circ_type));
+ vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type));
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ if (circuit->is_type & IS_LEVEL_1)
+ {
+ vty_out (vty, " Level-1 Information:%s", VTY_NEWLINE);
+ if (circuit->area->newmetric)
+ vty_out (vty, " Metric: %d", circuit->te_metric[0]);
+ else
+ vty_out (vty, " Metric: %d",
+ circuit->metrics[0].metric_default);
+ if (!circuit->is_passive)
+ {
+ vty_out (vty, ", Active neighbors: %u%s",
+ circuit->upadjcount[0], VTY_NEWLINE);
+ vty_out (vty, " Hello interval: %u, "
+ "Holddown count: %u %s%s",
+ circuit->hello_interval[0],
+ circuit->hello_multiplier[0],
+ (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
+ VTY_NEWLINE);
+ vty_out (vty, " CNSP interval: %u, "
+ "PSNP interval: %u%s",
+ circuit->csnp_interval[0],
+ circuit->psnp_interval[0], VTY_NEWLINE);
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ vty_out (vty, " LAN Priority: %u, %s%s",
+ circuit->priority[0],
+ (circuit->u.bc.is_dr[0] ? \
+ "is DIS" : "is not DIS"), VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ }
+ if (circuit->is_type & IS_LEVEL_2)
+ {
+ vty_out (vty, " Level-2 Information:%s", VTY_NEWLINE);
+ if (circuit->area->newmetric)
+ vty_out (vty, " Metric: %d", circuit->te_metric[1]);
+ else
+ vty_out (vty, " Metric: %d",
+ circuit->metrics[1].metric_default);
+ if (!circuit->is_passive)
+ {
+ vty_out (vty, ", Active neighbors: %u%s",
+ circuit->upadjcount[1], VTY_NEWLINE);
+ vty_out (vty, " Hello interval: %u, "
+ "Holddown count: %u %s%s",
+ circuit->hello_interval[1],
+ circuit->hello_multiplier[1],
+ (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
+ VTY_NEWLINE);
+ vty_out (vty, " CNSP interval: %u, "
+ "PSNP interval: %u%s",
+ circuit->csnp_interval[1],
+ circuit->psnp_interval[1], VTY_NEWLINE);
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ vty_out (vty, " LAN Priority: %u, %s%s",
+ circuit->priority[1],
+ (circuit->u.bc.is_dr[1] ? \
+ "is DIS" : "is not DIS"), VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ }
+ if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0)
+ {
+ struct listnode *node;
+ struct prefix *ip_addr;
+ u_char buf[BUFSIZ];
+ vty_out (vty, " IP Prefix(es):%s", VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr))
+ {
+ prefix2str (ip_addr, (char*)buf, BUFSIZ),
+ vty_out (vty, " %s%s", buf, VTY_NEWLINE);
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ return;
+}
+
int
isis_interface_config_write (struct vty *vty)
{
-
int write = 0;
struct listnode *node, *node2;
struct interface *ifp;
struct isis_area *area;
- struct isis_circuit *c;
+ struct isis_circuit *circuit;
int i;
for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
- {
- /* IF name */
- vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
- write++;
- /* IF desc */
- if (ifp->desc)
- {
- vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
- write++;
- }
- /* ISIS Circuit */
- for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area))
{
- c = circuit_lookup_by_ifp (ifp, area->circuit_list);
- if (c)
- {
- if (c->ip_router)
- {
- vty_out (vty, " ip router isis %s%s", area->area_tag,
- VTY_NEWLINE);
- write++;
- }
+ /* IF name */
+ vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
+ write++;
+ /* IF desc */
+ if (ifp->desc)
+ {
+ vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
+ write++;
+ }
+ /* ISIS Circuit */
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area))
+ {
+ circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ if (circuit == NULL)
+ continue;
+ if (circuit->ip_router)
+ {
+ vty_out (vty, " ip router isis %s%s", area->area_tag,
+ VTY_NEWLINE);
+ write++;
+ }
+ if (circuit->is_passive)
+ {
+ vty_out (vty, " isis passive%s", VTY_NEWLINE);
+ write++;
+ }
+ if (circuit->circ_type_config == CIRCUIT_T_P2P)
+ {
+ vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE);
+ write++;
+ }
#ifdef HAVE_IPV6
- if (c->ipv6_router)
- {
- vty_out (vty, " ipv6 router isis %s%s", area->area_tag,
- VTY_NEWLINE);
- write++;
- }
+ if (circuit->ipv6_router)
+ {
+ vty_out (vty, " ipv6 router isis %s%s", area->area_tag,
+ VTY_NEWLINE);
+ write++;
+ }
#endif /* HAVE_IPV6 */
- /* ISIS - circuit type */
- if (c->circuit_is_type == IS_LEVEL_1)
- {
- vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
- write++;
- }
- else
- {
- if (c->circuit_is_type == IS_LEVEL_2)
- {
- vty_out (vty, " isis circuit-type level-2-only%s",
- VTY_NEWLINE);
- write++;
- }
- }
+ /* ISIS - circuit type */
+ if (circuit->is_type == IS_LEVEL_1)
+ {
+ vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
+ write++;
+ }
+ else
+ {
+ if (circuit->is_type == IS_LEVEL_2)
+ {
+ vty_out (vty, " isis circuit-type level-2-only%s",
+ VTY_NEWLINE);
+ write++;
+ }
+ }
- /* ISIS - CSNP interval - FIXME: compare to cisco */
- if (c->csnp_interval[0] == c->csnp_interval[1])
- {
- if (c->csnp_interval[0] != CSNP_INTERVAL)
- {
- vty_out (vty, " isis csnp-interval %d%s",
- c->csnp_interval[0], VTY_NEWLINE);
- write++;
- }
- }
- else
- {
- for (i = 0; i < 2; i++)
- {
- if (c->csnp_interval[1] != CSNP_INTERVAL)
- {
- vty_out (vty, " isis csnp-interval %d level-%d%s",
- c->csnp_interval[1], i + 1, VTY_NEWLINE);
- write++;
- }
- }
- }
+ /* ISIS - CSNP interval */
+ if (circuit->csnp_interval[0] == circuit->csnp_interval[1])
+ {
+ if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL)
+ {
+ vty_out (vty, " isis csnp-interval %d%s",
+ circuit->csnp_interval[0], VTY_NEWLINE);
+ write++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL)
+ {
+ vty_out (vty, " isis csnp-interval %d level-%d%s",
+ circuit->csnp_interval[i], i + 1, VTY_NEWLINE);
+ write++;
+ }
+ }
+ }
- /* ISIS - Hello padding - Defaults to true so only display if false */
- if (c->circ_type == CIRCUIT_T_BROADCAST && !c->u.bc.pad_hellos)
- {
- vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
- write++;
- }
+ /* ISIS - PSNP interval */
+ if (circuit->psnp_interval[0] == circuit->psnp_interval[1])
+ {
+ if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL)
+ {
+ vty_out (vty, " isis psnp-interval %d%s",
+ circuit->psnp_interval[0], VTY_NEWLINE);
+ write++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL)
+ {
+ vty_out (vty, " isis psnp-interval %d level-%d%s",
+ circuit->psnp_interval[i], i + 1, VTY_NEWLINE);
+ write++;
+ }
+ }
+ }
- /* ISIS - Hello interval - FIXME: compare to cisco */
- if (c->hello_interval[0] == c->hello_interval[1])
- {
- if (c->hello_interval[0] != HELLO_INTERVAL)
- {
- vty_out (vty, " isis hello-interval %d%s",
- c->hello_interval[0], VTY_NEWLINE);
- write++;
- }
- }
- else
- {
- for (i = 0; i < 2; i++)
- {
- if (c->hello_interval[i] != HELLO_INTERVAL)
- {
- if (c->hello_interval[i] == HELLO_MINIMAL)
- {
- vty_out (vty,
- " isis hello-interval minimal level-%d%s",
- i + 1, VTY_NEWLINE);
- }
- else
- {
- vty_out (vty, " isis hello-interval %d level-%d%s",
- c->hello_interval[i], i + 1, VTY_NEWLINE);
- }
- write++;
- }
- }
- }
+ /* ISIS - Hello padding - Defaults to true so only display if false */
+ if (circuit->pad_hellos == 0)
+ {
+ vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
+ write++;
+ }
- /* ISIS - Hello Multiplier */
- if (c->hello_multiplier[0] == c->hello_multiplier[1])
- {
- if (c->hello_multiplier[0] != HELLO_MULTIPLIER)
- {
- vty_out (vty, " isis hello-multiplier %d%s",
- c->hello_multiplier[0], VTY_NEWLINE);
- write++;
- }
- }
- else
- {
- for (i = 0; i < 2; i++)
- {
- if (c->hello_multiplier[i] != HELLO_MULTIPLIER)
- {
- vty_out (vty, " isis hello-multiplier %d level-%d%s",
- c->hello_multiplier[i], i + 1, VTY_NEWLINE);
- write++;
- }
- }
- }
- /* ISIS - Priority */
- if (c->circ_type == CIRCUIT_T_BROADCAST)
- {
- if (c->u.bc.priority[0] == c->u.bc.priority[1])
- {
- if (c->u.bc.priority[0] != DEFAULT_PRIORITY)
- {
- vty_out (vty, " isis priority %d%s",
- c->u.bc.priority[0], VTY_NEWLINE);
- write++;
- }
- }
- else
- {
- for (i = 0; i < 2; i++)
- {
- if (c->u.bc.priority[i] != DEFAULT_PRIORITY)
- {
- vty_out (vty, " isis priority %d level-%d%s",
- c->u.bc.priority[i], i + 1, VTY_NEWLINE);
- write++;
- }
- }
- }
- }
- /* ISIS - Metric */
- if (c->te_metric[0] == c->te_metric[1])
- {
- if (c->te_metric[0] != DEFAULT_CIRCUIT_METRICS)
- {
- vty_out (vty, " isis metric %d%s", c->te_metric[0],
- VTY_NEWLINE);
- write++;
- }
- }
- else
- {
- for (i = 0; i < 2; i++)
- {
- if (c->te_metric[i] != DEFAULT_CIRCUIT_METRICS)
- {
- vty_out (vty, " isis metric %d level-%d%s",
- c->te_metric[i], i + 1, VTY_NEWLINE);
- write++;
- }
- }
- }
- if (c->passwd.type==ISIS_PASSWD_TYPE_HMAC_MD5)
- {
- vty_out (vty, " isis password md5 %s%s", c->passwd.passwd,
- VTY_NEWLINE);
- write++;
- }
- else
- {
- if (c->passwd.type==ISIS_PASSWD_TYPE_CLEARTXT)
- {
- vty_out (vty, " isis password clear %s%s", c->passwd.passwd,
- VTY_NEWLINE);
- write++;
- }
- }
+ /* ISIS - Hello interval */
+ if (circuit->hello_interval[0] == circuit->hello_interval[1])
+ {
+ if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL)
+ {
+ vty_out (vty, " isis hello-interval %d%s",
+ circuit->hello_interval[0], VTY_NEWLINE);
+ write++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL)
+ {
+ vty_out (vty, " isis hello-interval %d level-%d%s",
+ circuit->hello_interval[i], i + 1, VTY_NEWLINE);
+ write++;
+ }
+ }
+ }
- }
+ /* ISIS - Hello Multiplier */
+ if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1])
+ {
+ if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER)
+ {
+ vty_out (vty, " isis hello-multiplier %d%s",
+ circuit->hello_multiplier[0], VTY_NEWLINE);
+ write++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER)
+ {
+ vty_out (vty, " isis hello-multiplier %d level-%d%s",
+ circuit->hello_multiplier[i], i + 1,
+ VTY_NEWLINE);
+ write++;
+ }
+ }
+ }
+
+ /* ISIS - Priority */
+ if (circuit->priority[0] == circuit->priority[1])
+ {
+ if (circuit->priority[0] != DEFAULT_PRIORITY)
+ {
+ vty_out (vty, " isis priority %d%s",
+ circuit->priority[0], VTY_NEWLINE);
+ write++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (circuit->priority[i] != DEFAULT_PRIORITY)
+ {
+ vty_out (vty, " isis priority %d level-%d%s",
+ circuit->priority[i], i + 1, VTY_NEWLINE);
+ write++;
+ }
+ }
+ }
+
+ /* ISIS - Metric */
+ if (circuit->te_metric[0] == circuit->te_metric[1])
+ {
+ if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC)
+ {
+ vty_out (vty, " isis metric %d%s", circuit->te_metric[0],
+ VTY_NEWLINE);
+ write++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 2; i++)
+ {
+ if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC)
+ {
+ vty_out (vty, " isis metric %d level-%d%s",
+ circuit->te_metric[i], i + 1, VTY_NEWLINE);
+ write++;
+ }
+ }
+ }
+ if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
+ {
+ vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd,
+ VTY_NEWLINE);
+ write++;
+ }
+ else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
+ {
+ vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd,
+ VTY_NEWLINE);
+ write++;
+ }
+ }
+ vty_out (vty, "!%s", VTY_NEWLINE);
}
- vty_out (vty, "!%s", VTY_NEWLINE);
- }
return write;
}
@@ -862,58 +1186,45 @@
"IS-IS Routing for IP\n"
"Routing process tag\n")
{
- struct isis_circuit *c;
+ struct isis_circuit *circuit;
struct interface *ifp;
struct isis_area *area;
ifp = (struct interface *) vty->index;
assert (ifp);
- area = isis_area_lookup (argv[0]);
-
- /* Prevent more than one circuit per interface */
- if (area)
- c = circuit_lookup_by_ifp (ifp, area->circuit_list);
- else
- c = NULL;
- if (c && (ifp->info != NULL))
+ /* Prevent more than one area per circuit */
+ circuit = circuit_scan_by_ifp (ifp);
+ if (circuit)
{
-#ifdef HAVE_IPV6
- if (c->ipv6_router == 0)
- {
-#endif /* HAVE_IPV6 */
- /* FIXME: Find the way to warn only vty users. */
- /* vty_out (vty, "ISIS circuit is already defined%s", VTY_NEWLINE); */
- return CMD_WARNING;
-#ifdef HAVE_IPV6
- }
-#endif /* HAVE_IPV6 */
+ if (circuit->ip_router == 1)
+ {
+ if (strcmp (circuit->area->area_tag, argv[0]))
+ {
+ vty_out (vty, "ISIS circuit is already defined on %s%s",
+ circuit->area->area_tag, VTY_NEWLINE);
+ return CMD_ERR_NOTHING_TODO;
+ }
+ return CMD_SUCCESS;
+ }
}
- /* this is here for ciscopability */
- if (!area)
+ if (isis_area_get (vty, argv[0]) != CMD_SUCCESS)
{
- /* FIXME: Find the way to warn only vty users. */
- /* vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); */
- return CMD_WARNING;
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
+ area = vty->index;
- if (!c)
- {
- c = circuit_lookup_by_ifp (ifp, isis->init_circ_list);
- c = isis_csm_state_change (ISIS_ENABLE, c, area);
- c->interface = ifp; /* this is automatic */
- ifp->info = c; /* hardly related to the FSM */
- }
+ circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
+ isis_circuit_if_bind (circuit, ifp);
- if (!c)
- return CMD_WARNING;
-
- c->ip_router = 1;
+ circuit->ip_router = 1;
area->ip_circuits++;
- circuit_update_nlpids (c);
+ circuit_update_nlpids (circuit);
vty->node = INTERFACE_NODE;
+ vty->index = ifp;
return CMD_SUCCESS;
}
@@ -927,28 +1238,33 @@
"IS-IS Routing for IP\n"
"Routing process tag\n")
{
- struct isis_circuit *circuit = NULL;
struct interface *ifp;
struct isis_area *area;
- struct listnode *node;
+ struct isis_circuit *circuit;
ifp = (struct interface *) vty->index;
- assert (ifp);
+ if (!ifp)
+ {
+ vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
area = isis_area_lookup (argv[0]);
if (!area)
{
- vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "Can't find ISIS instance %s%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
- for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
- if (circuit->interface == ifp)
- break;
+
+ circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
if (!circuit)
{
- vty_out (vty, "Can't find ISIS interface %s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "ISIS is not enabled on circuit %s%s",
+ ifp->name, VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
+
circuit->ip_router = 0;
area->ip_circuits--;
#ifdef HAVE_IPV6
@@ -959,6 +1275,183 @@
return CMD_SUCCESS;
}
+#ifdef HAVE_IPV6
+DEFUN (ipv6_router_isis,
+ ipv6_router_isis_cmd,
+ "ipv6 router isis WORD",
+ "IPv6 interface subcommands\n"
+ "IPv6 Router interface commands\n"
+ "IS-IS Routing for IPv6\n"
+ "Routing process tag\n")
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ struct isis_area *area;
+
+ ifp = (struct interface *) vty->index;
+ assert (ifp);
+
+ /* Prevent more than one area per circuit */
+ circuit = circuit_scan_by_ifp (ifp);
+ if (circuit)
+ {
+ if (circuit->ipv6_router == 1)
+ {
+ if (strcmp (circuit->area->area_tag, argv[0]))
+ {
+ vty_out (vty, "ISIS circuit is already defined for IPv6 on %s%s",
+ circuit->area->area_tag, VTY_NEWLINE);
+ return CMD_ERR_NOTHING_TODO;
+ }
+ return CMD_SUCCESS;
+ }
+ }
+
+ if (isis_area_get (vty, argv[0]) != CMD_SUCCESS)
+ {
+ vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+ area = vty->index;
+
+ circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
+ isis_circuit_if_bind (circuit, ifp);
+
+ circuit->ipv6_router = 1;
+ area->ipv6_circuits++;
+ circuit_update_nlpids (circuit);
+
+ vty->node = INTERFACE_NODE;
+ vty->index = ifp;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_router_isis,
+ no_ipv6_router_isis_cmd,
+ "no ipv6 router isis WORD",
+ NO_STR
+ "IPv6 interface subcommands\n"
+ "IPv6 Router interface commands\n"
+ "IS-IS Routing for IPv6\n"
+ "Routing process tag\n")
+{
+ struct interface *ifp;
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *) vty->index;
+ if (!ifp)
+ {
+ vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ area = isis_area_lookup (argv[0]);
+ if (!area)
+ {
+ vty_out (vty, "Can't find ISIS instance %s%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
+ if (!circuit)
+ {
+ vty_out (vty, "ISIS is not enabled on circuit %s%s",
+ ifp->name, VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ circuit->ipv6_router = 0;
+ area->ipv6_circuits--;
+ if (circuit->ip_router == 0)
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+
+ return CMD_SUCCESS;
+}
+#endif /* HAVE_IPV6 */
+
+DEFUN (isis_passive,
+ isis_passive_cmd,
+ "isis passive",
+ "IS-IS commands\n"
+ "Configure the passive mode for interface\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ if (circuit->is_passive == 1)
+ return CMD_SUCCESS;
+
+ if (circuit->state != C_STATE_UP)
+ {
+ circuit->is_passive = 1;
+ }
+ else
+ {
+ struct isis_area *area = circuit->area;
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+ circuit->is_passive = 1;
+ isis_csm_state_change (ISIS_ENABLE, circuit, area);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_passive,
+ no_isis_passive_cmd,
+ "no isis passive",
+ NO_STR
+ "IS-IS commands\n"
+ "Configure the passive mode for interface\n")
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *) vty->index;
+ if (!ifp)
+ {
+ vty_out (vty, "Invalid interface %s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ /* FIXME: what is wrong with circuit = ifp->info ? */
+ circuit = circuit_scan_by_ifp (ifp);
+ if (!circuit)
+ {
+ vty_out (vty, "ISIS is not enabled on circuit %s%s",
+ ifp->name, VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ if (if_is_loopback(ifp))
+ {
+ vty_out (vty, "Can't set no passive for loopback interface%s",
+ VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ if (circuit->is_passive == 0)
+ return CMD_SUCCESS;
+
+ if (circuit->state != C_STATE_UP)
+ {
+ circuit->is_passive = 0;
+ }
+ else
+ {
+ struct isis_area *area = circuit->area;
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+ circuit->is_passive = 0;
+ isis_csm_state_change (ISIS_ENABLE, circuit, area);
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (isis_circuit_type,
isis_circuit_type_cmd,
"isis circuit-type (level-1|level-1-2|level-2-only)",
@@ -968,41 +1461,27 @@
"Level-1-2 adjacencies are formed\n"
"Level-2 only adjacencies are formed\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
- int circuit_t;
- int is_type;
+ int circuit_type;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- /* UGLY - will remove l8r */
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
-
- /* XXX what to do when ip_router_isis is not executed */
- if (circuit->area == NULL)
- return CMD_WARNING;
-
- assert (circuit);
-
- circuit_t = string2circuit_t (argv[0]);
-
- if (!circuit_t)
+ circuit_type = string2circuit_t (argv[0]);
+ if (!circuit_type)
{
vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE);
- return CMD_SUCCESS;
+ return CMD_ERR_AMBIGUOUS;
}
- is_type = circuit->area->is_type;
- if (is_type == IS_LEVEL_1_AND_2 || is_type == circuit_t)
- isis_event_circuit_type_change (circuit, circuit_t);
- else
+ if (circuit->state == C_STATE_UP &&
+ circuit->area->is_type != IS_LEVEL_1_AND_2 &&
+ circuit->area->is_type != circuit_type)
{
- vty_out (vty, "invalid circuit level for area %s.%s",
- circuit->area->area_tag, VTY_NEWLINE);
+ vty_out (vty, "Invalid circuit level for area %s.%s",
+ circuit->area->area_tag, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
}
+ isis_event_circuit_type_change (circuit, circuit_type);
return CMD_SUCCESS;
}
@@ -1017,22 +1496,19 @@
"Level-1-2 adjacencies are formed\n"
"Level-2 only adjacencies are formed\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
-
- assert (circuit);
+ int circuit_type;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
/*
- * Set the circuits level to its default value which is that of the area
+ * Set the circuits level to its default value
*/
- isis_event_circuit_type_change (circuit, circuit->area->is_type);
+ if (circuit->state == C_STATE_UP)
+ circuit_type = circuit->area->is_type;
+ else
+ circuit_type = IS_LEVEL_1_AND_2;
+ isis_event_circuit_type_change (circuit, circuit_type);
return CMD_SUCCESS;
}
@@ -1041,26 +1517,20 @@
isis_passwd_md5_cmd,
"isis password md5 WORD",
"IS-IS commands\n"
- "Configure the authentication password for interface\n"
- "Authentication Type\n"
- "Password\n")
+ "Configure the authentication password for a circuit\n"
+ "Authentication type\n"
+ "Circuit password\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int len;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
len = strlen (argv[0]);
if (len > 254)
{
vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_AMBIGUOUS;
}
circuit->passwd.len = len;
circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
@@ -1073,26 +1543,20 @@
isis_passwd_clear_cmd,
"isis password clear WORD",
"IS-IS commands\n"
- "Configure the authentication password for interface\n"
- "Authentication Type\n"
- "Password\n")
+ "Configure the authentication password for a circuit\n"
+ "Authentication type\n"
+ "Circuit password\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int len;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
len = strlen (argv[0]);
if (len > 254)
{
vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_AMBIGUOUS;
}
circuit->passwd.len = len;
circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
@@ -1106,17 +1570,11 @@
"no isis password",
NO_STR
"IS-IS commands\n"
- "Configure the authentication password for interface\n")
+ "Configure the authentication password for a circuit\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
memset (&circuit->passwd, 0, sizeof (struct isis_passwd));
@@ -1130,22 +1588,21 @@
"Set priority for Designated Router election\n"
"Priority value\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int prio;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
prio = atoi (argv[0]);
+ if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)
+ {
+ vty_out (vty, "Invalid priority %d - should be <0-127>%s",
+ prio, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
- circuit->u.bc.priority[0] = prio;
- circuit->u.bc.priority[1] = prio;
+ circuit->priority[0] = prio;
+ circuit->priority[1] = prio;
return CMD_SUCCESS;
}
@@ -1157,19 +1614,12 @@
"IS-IS commands\n"
"Set priority for Designated Router election\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->u.bc.priority[0] = DEFAULT_PRIORITY;
- circuit->u.bc.priority[1] = DEFAULT_PRIORITY;
+ circuit->priority[0] = DEFAULT_PRIORITY;
+ circuit->priority[1] = DEFAULT_PRIORITY;
return CMD_SUCCESS;
}
@@ -1190,21 +1640,20 @@
"Priority value\n"
"Specify priority for level-1 routing\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int prio;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
prio = atoi (argv[0]);
+ if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)
+ {
+ vty_out (vty, "Invalid priority %d - should be <0-127>%s",
+ prio, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
- circuit->u.bc.priority[0] = prio;
+ circuit->priority[0] = prio;
return CMD_SUCCESS;
}
@@ -1217,18 +1666,11 @@
"Set priority for Designated Router election\n"
"Specify priority for level-1 routing\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->u.bc.priority[0] = DEFAULT_PRIORITY;
+ circuit->priority[0] = DEFAULT_PRIORITY;
return CMD_SUCCESS;
}
@@ -1250,21 +1692,20 @@
"Priority value\n"
"Specify priority for level-2 routing\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int prio;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
prio = atoi (argv[0]);
+ if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)
+ {
+ vty_out (vty, "Invalid priority %d - should be <0-127>%s",
+ prio, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
- circuit->u.bc.priority[1] = prio;
+ circuit->priority[1] = prio;
return CMD_SUCCESS;
}
@@ -1277,18 +1718,11 @@
"Set priority for Designated Router election\n"
"Specify priority for level-2 routing\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->u.bc.priority[1] = DEFAULT_PRIORITY;
+ circuit->priority[1] = DEFAULT_PRIORITY;
return CMD_SUCCESS;
}
@@ -1303,36 +1737,49 @@
"Specify priority for level-2 routing\n")
/* Metric command */
- DEFUN (isis_metric,
+DEFUN (isis_metric,
isis_metric_cmd,
"isis metric <0-16777215>",
"IS-IS commands\n"
"Set default metric for circuit\n"
"Default metric value\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int met;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
met = atoi (argv[0]);
+ /* RFC3787 section 5.1 */
+ if (circuit->area && circuit->area->oldmetric == 1 &&
+ met > MAX_NARROW_LINK_METRIC)
+ {
+ vty_out (vty, "Invalid metric %d - should be <0-63> "
+ "when narrow metric type enabled%s",
+ met, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ /* RFC4444 */
+ if (circuit->area && circuit->area->newmetric == 1 &&
+ met > MAX_WIDE_LINK_METRIC)
+ {
+ vty_out (vty, "Invalid metric %d - should be <0-16777215> "
+ "when wide metric type enabled%s",
+ met, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
circuit->te_metric[0] = met;
circuit->te_metric[1] = met;
- if (met > 63)
- met = 63;
-
circuit->metrics[0].metric_default = met;
circuit->metrics[1].metric_default = met;
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
+
return CMD_SUCCESS;
}
@@ -1343,21 +1790,17 @@
"IS-IS commands\n"
"Set default metric for circuit\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC;
+ circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC;
+ circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC;
+ circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC;
- circuit->te_metric[0] = DEFAULT_CIRCUIT_METRICS;
- circuit->te_metric[1] = DEFAULT_CIRCUIT_METRICS;
- circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRICS;
- circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRICS;
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
return CMD_SUCCESS;
}
@@ -1370,34 +1813,175 @@
"Set default metric for circuit\n"
"Default metric value\n")
+DEFUN (isis_metric_l1,
+ isis_metric_l1_cmd,
+ "isis metric <0-16777215> level-1",
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Default metric value\n"
+ "Specify metric for level-1 routing\n")
+{
+ int met;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ met = atoi (argv[0]);
+
+ /* RFC3787 section 5.1 */
+ if (circuit->area && circuit->area->oldmetric == 1 &&
+ met > MAX_NARROW_LINK_METRIC)
+ {
+ vty_out (vty, "Invalid metric %d - should be <0-63> "
+ "when narrow metric type enabled%s",
+ met, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ /* RFC4444 */
+ if (circuit->area && circuit->area->newmetric == 1 &&
+ met > MAX_WIDE_LINK_METRIC)
+ {
+ vty_out (vty, "Invalid metric %d - should be <0-16777215> "
+ "when wide metric type enabled%s",
+ met, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ circuit->te_metric[0] = met;
+ circuit->metrics[0].metric_default = met;
+
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_metric_l1,
+ no_isis_metric_l1_cmd,
+ "no isis metric level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Specify metric for level-1 routing\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC;
+ circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC;
+
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_metric_l1,
+ no_isis_metric_l1_arg_cmd,
+ "no isis metric <0-16777215> level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Default metric value\n"
+ "Specify metric for level-1 routing\n")
+
+DEFUN (isis_metric_l2,
+ isis_metric_l2_cmd,
+ "isis metric <0-16777215> level-2",
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Default metric value\n"
+ "Specify metric for level-2 routing\n")
+{
+ int met;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ met = atoi (argv[0]);
+
+ /* RFC3787 section 5.1 */
+ if (circuit->area && circuit->area->oldmetric == 1 &&
+ met > MAX_NARROW_LINK_METRIC)
+ {
+ vty_out (vty, "Invalid metric %d - should be <0-63> "
+ "when narrow metric type enabled%s",
+ met, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ /* RFC4444 */
+ if (circuit->area && circuit->area->newmetric == 1 &&
+ met > MAX_WIDE_LINK_METRIC)
+ {
+ vty_out (vty, "Invalid metric %d - should be <0-16777215> "
+ "when wide metric type enabled%s",
+ met, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ circuit->te_metric[1] = met;
+ circuit->metrics[1].metric_default = met;
+
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_metric_l2,
+ no_isis_metric_l2_cmd,
+ "no isis metric level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Specify metric for level-2 routing\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC;
+ circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC;
+
+ if (circuit->area)
+ lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_isis_metric_l2,
+ no_isis_metric_l2_arg_cmd,
+ "no isis metric <0-16777215> level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set default metric for circuit\n"
+ "Default metric value\n"
+ "Specify metric for level-2 routing\n")
/* end of metrics */
+
DEFUN (isis_hello_interval,
isis_hello_interval_cmd,
- "isis hello-interval (<1-65535>|minimal)",
+ "isis hello-interval <1-600>",
"IS-IS commands\n"
"Set Hello interval\n"
"Hello interval value\n"
"Holdtime 1 seconds, interval depends on multiplier\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int interval;
- char c;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
+ interval = atoi (argv[0]);
+ if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)
{
- return CMD_WARNING;
+ vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
}
- assert (circuit);
- c = *argv[0];
- if (isdigit ((int) c))
- {
- interval = atoi (argv[0]);
- }
- else
- interval = HELLO_MINIMAL; /* FIXME: should be calculated */
circuit->hello_interval[0] = (u_int16_t) interval;
circuit->hello_interval[1] = (u_int16_t) interval;
@@ -1412,27 +1996,19 @@
"IS-IS commands\n"
"Set Hello interval\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
-
- circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */
- circuit->hello_interval[1] = HELLO_INTERVAL;
+ circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL;
+ circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL;
return CMD_SUCCESS;
}
ALIAS (no_isis_hello_interval,
no_isis_hello_interval_arg_cmd,
- "no isis hello-interval (<1-65535>|minimal)",
+ "no isis hello-interval <1-600>",
NO_STR
"IS-IS commands\n"
"Set Hello interval\n"
@@ -1441,33 +2017,25 @@
DEFUN (isis_hello_interval_l1,
isis_hello_interval_l1_cmd,
- "isis hello-interval (<1-65535>|minimal) level-1",
+ "isis hello-interval <1-600> level-1",
"IS-IS commands\n"
"Set Hello interval\n"
"Hello interval value\n"
"Holdtime 1 second, interval depends on multiplier\n"
"Specify hello-interval for level-1 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
long interval;
- char c;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
+ interval = atoi (argv[0]);
+ if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)
{
- return CMD_WARNING;
+ vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
}
- assert (circuit);
-
- c = *argv[0];
- if (isdigit ((int) c))
- {
- interval = atoi (argv[0]);
- }
- else
- interval = HELLO_MINIMAL;
circuit->hello_interval[0] = (u_int16_t) interval;
@@ -1482,26 +2050,18 @@
"Set Hello interval\n"
"Specify hello-interval for level-1 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
-
- circuit->hello_interval[0] = HELLO_INTERVAL; /* Default is 1 sec. */
+ circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL;
return CMD_SUCCESS;
}
ALIAS (no_isis_hello_interval_l1,
no_isis_hello_interval_l1_arg_cmd,
- "no isis hello-interval (<1-65535>|minimal) level-1",
+ "no isis hello-interval <1-600> level-1",
NO_STR
"IS-IS commands\n"
"Set Hello interval\n"
@@ -1511,33 +2071,25 @@
DEFUN (isis_hello_interval_l2,
isis_hello_interval_l2_cmd,
- "isis hello-interval (<1-65535>|minimal) level-2",
+ "isis hello-interval <1-600> level-2",
"IS-IS commands\n"
"Set Hello interval\n"
"Hello interval value\n"
"Holdtime 1 second, interval depends on multiplier\n"
"Specify hello-interval for level-2 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
long interval;
- char c;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
+ interval = atoi (argv[0]);
+ if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)
{
- return CMD_WARNING;
+ vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
}
- assert (circuit);
-
- c = *argv[0];
- if (isdigit ((int) c))
- {
- interval = atoi (argv[0]);
- }
- else
- interval = HELLO_MINIMAL;
circuit->hello_interval[1] = (u_int16_t) interval;
@@ -1552,26 +2104,18 @@
"Set Hello interval\n"
"Specify hello-interval for level-2 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
-
- circuit->hello_interval[1] = HELLO_INTERVAL; /* Default is 1 sec. */
+ circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL;
return CMD_SUCCESS;
}
ALIAS (no_isis_hello_interval_l2,
no_isis_hello_interval_l2_arg_cmd,
- "no isis hello-interval (<1-65535>|minimal) level-2",
+ "no isis hello-interval <1-600> level-2",
NO_STR
"IS-IS commands\n"
"Set Hello interval\n"
@@ -1581,24 +2125,23 @@
DEFUN (isis_hello_multiplier,
isis_hello_multiplier_cmd,
- "isis hello-multiplier <3-1000>",
+ "isis hello-multiplier <2-100>",
"IS-IS commands\n"
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int mult;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
mult = atoi (argv[0]);
+ if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)
+ {
+ vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s",
+ mult, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
circuit->hello_multiplier[0] = (u_int16_t) mult;
circuit->hello_multiplier[1] = (u_int16_t) mult;
@@ -1613,26 +2156,19 @@
"IS-IS commands\n"
"Set multiplier for Hello holding time\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->hello_multiplier[0] = HELLO_MULTIPLIER;
- circuit->hello_multiplier[1] = HELLO_MULTIPLIER;
+ circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER;
+ circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER;
return CMD_SUCCESS;
}
ALIAS (no_isis_hello_multiplier,
no_isis_hello_multiplier_arg_cmd,
- "no isis hello-multiplier <3-1000>",
+ "no isis hello-multiplier <2-100>",
NO_STR
"IS-IS commands\n"
"Set multiplier for Hello holding time\n"
@@ -1640,25 +2176,24 @@
DEFUN (isis_hello_multiplier_l1,
isis_hello_multiplier_l1_cmd,
- "isis hello-multiplier <3-1000> level-1",
+ "isis hello-multiplier <2-100> level-1",
"IS-IS commands\n"
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n"
"Specify hello multiplier for level-1 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int mult;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
mult = atoi (argv[0]);
+ if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)
+ {
+ vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s",
+ mult, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
circuit->hello_multiplier[0] = (u_int16_t) mult;
@@ -1673,25 +2208,18 @@
"Set multiplier for Hello holding time\n"
"Specify hello multiplier for level-1 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->hello_multiplier[0] = HELLO_MULTIPLIER;
+ circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER;
return CMD_SUCCESS;
}
ALIAS (no_isis_hello_multiplier_l1,
no_isis_hello_multiplier_l1_arg_cmd,
- "no isis hello-multiplier <3-1000> level-1",
+ "no isis hello-multiplier <2-100> level-1",
NO_STR
"IS-IS commands\n"
"Set multiplier for Hello holding time\n"
@@ -1700,25 +2228,24 @@
DEFUN (isis_hello_multiplier_l2,
isis_hello_multiplier_l2_cmd,
- "isis hello-multiplier <3-1000> level-2",
+ "isis hello-multiplier <2-100> level-2",
"IS-IS commands\n"
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n"
"Specify hello multiplier for level-2 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
int mult;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
mult = atoi (argv[0]);
+ if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)
+ {
+ vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s",
+ mult, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
circuit->hello_multiplier[1] = (u_int16_t) mult;
@@ -1733,57 +2260,43 @@
"Set multiplier for Hello holding time\n"
"Specify hello multiplier for level-2 IIHs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->hello_multiplier[1] = HELLO_MULTIPLIER;
+ circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER;
return CMD_SUCCESS;
}
ALIAS (no_isis_hello_multiplier_l2,
no_isis_hello_multiplier_l2_arg_cmd,
- "no isis hello-multiplier <3-1000> level-2",
+ "no isis hello-multiplier <2-100> level-2",
NO_STR
"IS-IS commands\n"
"Set multiplier for Hello holding time\n"
"Hello multiplier value\n"
"Specify hello multiplier for level-2 IIHs\n")
-DEFUN (isis_hello,
- isis_hello_cmd,
+DEFUN (isis_hello_padding,
+ isis_hello_padding_cmd,
"isis hello padding",
"IS-IS commands\n"
"Add padding to IS-IS hello packets\n"
"Pad hello packets\n"
"<cr>\n")
{
- struct interface *ifp;
- struct isis_circuit *circuit;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->u.bc.pad_hellos = 1;
+ circuit->pad_hellos = 1;
return CMD_SUCCESS;
}
-DEFUN (no_isis_hello,
- no_isis_hello_cmd,
+DEFUN (no_isis_hello_padding,
+ no_isis_hello_padding_cmd,
"no isis hello padding",
NO_STR
"IS-IS commands\n"
@@ -1791,42 +2304,34 @@
"Pad hello packets\n"
"<cr>\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->u.bc.pad_hellos = 0;
+ circuit->pad_hellos = 0;
return CMD_SUCCESS;
}
DEFUN (csnp_interval,
csnp_interval_cmd,
- "isis csnp-interval <0-65535>",
+ "isis csnp-interval <1-600>",
"IS-IS commands\n"
"Set CSNP interval in seconds\n"
"CSNP interval value\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
unsigned long interval;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
interval = atol (argv[0]);
+ if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)
+ {
+ vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
circuit->csnp_interval[0] = (u_int16_t) interval;
circuit->csnp_interval[1] = (u_int16_t) interval;
@@ -1841,26 +2346,19 @@
"IS-IS commands\n"
"Set CSNP interval in seconds\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->csnp_interval[0] = CSNP_INTERVAL;
- circuit->csnp_interval[1] = CSNP_INTERVAL;
+ circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL;
+ circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL;
return CMD_SUCCESS;
}
ALIAS (no_csnp_interval,
no_csnp_interval_arg_cmd,
- "no isis csnp-interval <0-65535>",
+ "no isis csnp-interval <1-600>",
NO_STR
"IS-IS commands\n"
"Set CSNP interval in seconds\n"
@@ -1868,25 +2366,24 @@
DEFUN (csnp_interval_l1,
csnp_interval_l1_cmd,
- "isis csnp-interval <0-65535> level-1",
+ "isis csnp-interval <1-600> level-1",
"IS-IS commands\n"
"Set CSNP interval in seconds\n"
"CSNP interval value\n"
"Specify interval for level-1 CSNPs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
unsigned long interval;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
interval = atol (argv[0]);
+ if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)
+ {
+ vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
circuit->csnp_interval[0] = (u_int16_t) interval;
@@ -1901,25 +2398,18 @@
"Set CSNP interval in seconds\n"
"Specify interval for level-1 CSNPs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->csnp_interval[0] = CSNP_INTERVAL;
+ circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL;
return CMD_SUCCESS;
}
ALIAS (no_csnp_interval_l1,
no_csnp_interval_l1_arg_cmd,
- "no isis csnp-interval <0-65535> level-1",
+ "no isis csnp-interval <1-600> level-1",
NO_STR
"IS-IS commands\n"
"Set CSNP interval in seconds\n"
@@ -1928,25 +2418,24 @@
DEFUN (csnp_interval_l2,
csnp_interval_l2_cmd,
- "isis csnp-interval <0-65535> level-2",
+ "isis csnp-interval <1-600> level-2",
"IS-IS commands\n"
"Set CSNP interval in seconds\n"
"CSNP interval value\n"
"Specify interval for level-2 CSNPs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
unsigned long interval;
-
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
interval = atol (argv[0]);
+ if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)
+ {
+ vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
circuit->csnp_interval[1] = (u_int16_t) interval;
@@ -1961,153 +2450,285 @@
"Set CSNP interval in seconds\n"
"Specify interval for level-2 CSNPs\n")
{
- struct isis_circuit *circuit;
- struct interface *ifp;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = vty->index;
- circuit = ifp->info;
- if (circuit == NULL)
- {
- return CMD_WARNING;
- }
- assert (circuit);
-
- circuit->csnp_interval[1] = CSNP_INTERVAL;
+ circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL;
return CMD_SUCCESS;
}
ALIAS (no_csnp_interval_l2,
no_csnp_interval_l2_arg_cmd,
- "no isis csnp-interval <0-65535> level-2",
+ "no isis csnp-interval <1-600> level-2",
NO_STR
"IS-IS commands\n"
"Set CSNP interval in seconds\n"
"CSNP interval value\n"
"Specify interval for level-2 CSNPs\n")
-#ifdef HAVE_IPV6
-DEFUN (ipv6_router_isis,
- ipv6_router_isis_cmd,
- "ipv6 router isis WORD",
- "IPv6 interface subcommands\n"
- "IPv6 Router interface commands\n"
- "IS-IS Routing for IPv6\n"
- "Routing process tag\n")
+DEFUN (psnp_interval,
+ psnp_interval_cmd,
+ "isis psnp-interval <1-120>",
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "PSNP interval value\n")
{
- struct isis_circuit *c;
- struct interface *ifp;
- struct isis_area *area;
+ unsigned long interval;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = (struct interface *) vty->index;
- assert (ifp);
-
- area = isis_area_lookup (argv[0]);
-
- /* Prevent more than one circuit per interface */
- if (area)
- c = circuit_lookup_by_ifp (ifp, area->circuit_list);
- else
- c = NULL;
-
- if (c && (ifp->info != NULL))
+ interval = atol (argv[0]);
+ if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL)
{
- if (c->ipv6_router == 1)
- {
- vty_out (vty, "ISIS circuit is already defined for IPv6%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
+ vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
}
- /* this is here for ciscopability */
- if (!area)
- {
- vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!c)
- {
- c = circuit_lookup_by_ifp (ifp, isis->init_circ_list);
- c = isis_csm_state_change (ISIS_ENABLE, c, area);
- c->interface = ifp;
- ifp->info = c;
- }
-
- if (!c)
- return CMD_WARNING;
-
- c->ipv6_router = 1;
- area->ipv6_circuits++;
- circuit_update_nlpids (c);
-
- vty->node = INTERFACE_NODE;
+ circuit->psnp_interval[0] = (u_int16_t) interval;
+ circuit->psnp_interval[1] = (u_int16_t) interval;
return CMD_SUCCESS;
}
-DEFUN (no_ipv6_router_isis,
- no_ipv6_router_isis_cmd,
- "no ipv6 router isis WORD",
+DEFUN (no_psnp_interval,
+ no_psnp_interval_cmd,
+ "no isis psnp-interval",
NO_STR
- "IPv6 interface subcommands\n"
- "IPv6 Router interface commands\n"
- "IS-IS Routing for IPv6\n"
- "Routing process tag\n")
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n")
{
- struct isis_circuit *c;
- struct interface *ifp;
- struct isis_area *area;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
- ifp = (struct interface *) vty->index;
- /* UGLY - will remove l8r
- if (circuit == NULL) {
- return CMD_WARNING;
- } */
- assert (ifp);
-
- area = isis_area_lookup (argv[0]);
- if (!area)
- {
- vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- c = circuit_lookup_by_ifp (ifp, area->circuit_list);
- if (!c)
- return CMD_WARNING;
-
- c->ipv6_router = 0;
- area->ipv6_circuits--;
- if (c->ip_router == 0)
- isis_csm_state_change (ISIS_DISABLE, c, area);
+ circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL;
+ circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL;
return CMD_SUCCESS;
}
-#endif /* HAVE_IPV6 */
-static struct cmd_node interface_node = {
+ALIAS (no_psnp_interval,
+ no_psnp_interval_arg_cmd,
+ "no isis psnp-interval <1-120>",
+ NO_STR
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "PSNP interval value\n")
+
+DEFUN (psnp_interval_l1,
+ psnp_interval_l1_cmd,
+ "isis psnp-interval <1-120> level-1",
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "PSNP interval value\n"
+ "Specify interval for level-1 PSNPs\n")
+{
+ unsigned long interval;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ interval = atol (argv[0]);
+ if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL)
+ {
+ vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ circuit->psnp_interval[0] = (u_int16_t) interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_psnp_interval_l1,
+ no_psnp_interval_l1_cmd,
+ "no isis psnp-interval level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "Specify interval for level-1 PSNPs\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_psnp_interval_l1,
+ no_psnp_interval_l1_arg_cmd,
+ "no isis psnp-interval <1-120> level-1",
+ NO_STR
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "PSNP interval value\n"
+ "Specify interval for level-1 PSNPs\n")
+
+DEFUN (psnp_interval_l2,
+ psnp_interval_l2_cmd,
+ "isis psnp-interval <1-120> level-2",
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "PSNP interval value\n"
+ "Specify interval for level-2 PSNPs\n")
+{
+ unsigned long interval;
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ interval = atol (argv[0]);
+ if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL)
+ {
+ vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s",
+ interval, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ circuit->psnp_interval[1] = (u_int16_t) interval;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_psnp_interval_l2,
+ no_psnp_interval_l2_cmd,
+ "no isis psnp-interval level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "Specify interval for level-2 PSNPs\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL;
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_psnp_interval_l2,
+ no_psnp_interval_l2_arg_cmd,
+ "no isis psnp-interval <1-120> level-2",
+ NO_STR
+ "IS-IS commands\n"
+ "Set PSNP interval in seconds\n"
+ "PSNP interval value\n"
+ "Specify interval for level-2 PSNPs\n")
+
+struct cmd_node interface_node = {
INTERFACE_NODE,
"%s(config-if)# ",
1,
};
+DEFUN (isis_network,
+ isis_network_cmd,
+ "isis network point-to-point",
+ "IS-IS commands\n"
+ "Set network type\n"
+ "point-to-point network type\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ /* RFC5309 section 4 */
+ if (circuit->circ_type == CIRCUIT_T_P2P)
+ return CMD_SUCCESS;
+
+ if (circuit->state != C_STATE_UP)
+ {
+ circuit->circ_type = CIRCUIT_T_P2P;
+ circuit->circ_type_config = CIRCUIT_T_P2P;
+ }
+ else
+ {
+ struct isis_area *area = circuit->area;
+ if (!if_is_broadcast (circuit->interface))
+ {
+ vty_out (vty, "isis network point-to-point "
+ "is valid only on broadcast interfaces%s",
+ VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+ circuit->circ_type = CIRCUIT_T_P2P;
+ circuit->circ_type_config = CIRCUIT_T_P2P;
+ isis_csm_state_change (ISIS_ENABLE, circuit, area);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_isis_network,
+ no_isis_network_cmd,
+ "no isis network point-to-point",
+ NO_STR
+ "IS-IS commands\n"
+ "Set network type for circuit\n"
+ "point-to-point network type\n")
+{
+ struct isis_circuit *circuit = isis_circuit_lookup (vty);
+ if (!circuit)
+ return CMD_ERR_NO_MATCH;
+
+ /* RFC5309 section 4 */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ return CMD_SUCCESS;
+
+ if (circuit->state != C_STATE_UP)
+ {
+ circuit->circ_type = CIRCUIT_T_BROADCAST;
+ circuit->circ_type_config = CIRCUIT_T_BROADCAST;
+ }
+ else
+ {
+ struct isis_area *area = circuit->area;
+ if (circuit->interface &&
+ !if_is_broadcast (circuit->interface))
+ {
+ vty_out (vty, "no isis network point-to-point "
+ "is valid only on broadcast interfaces%s",
+ VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+ circuit->circ_type = CIRCUIT_T_BROADCAST;
+ circuit->circ_type_config = CIRCUIT_T_BROADCAST;
+ isis_csm_state_change (ISIS_ENABLE, circuit, area);
+ }
+
+ return CMD_SUCCESS;
+}
+
int
isis_if_new_hook (struct interface *ifp)
{
-/* FIXME: Discuss if the circuit should be created here
- ifp->info = XMALLOC (MTYPE_ISIS_IF_INFO, sizeof (struct isis_if_info)); */
- ifp->info = NULL;
return 0;
}
int
isis_if_delete_hook (struct interface *ifp)
{
-/* FIXME: Discuss if the circuit should be created here
- XFREE (MTYPE_ISIS_IF_INFO, ifp->info);*/
- ifp->info = NULL;
+ struct isis_circuit *circuit;
+ /* Clean up the circuit data */
+ if (ifp && ifp->info)
+ {
+ circuit = ifp->info;
+ isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area);
+ isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area);
+ }
+
return 0;
}
@@ -2122,6 +2743,7 @@
/* Install interface node */
install_node (&interface_node, isis_interface_config_write);
install_element (CONFIG_NODE, &interface_cmd);
+ install_element (CONFIG_NODE, &no_interface_cmd);
install_default (INTERFACE_NODE);
install_element (INTERFACE_NODE, &interface_desc_cmd);
@@ -2130,6 +2752,9 @@
install_element (INTERFACE_NODE, &ip_router_isis_cmd);
install_element (INTERFACE_NODE, &no_ip_router_isis_cmd);
+ install_element (INTERFACE_NODE, &isis_passive_cmd);
+ install_element (INTERFACE_NODE, &no_isis_passive_cmd);
+
install_element (INTERFACE_NODE, &isis_circuit_type_cmd);
install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd);
@@ -2150,6 +2775,12 @@
install_element (INTERFACE_NODE, &isis_metric_cmd);
install_element (INTERFACE_NODE, &no_isis_metric_cmd);
install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_metric_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd);
+ install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd);
+ install_element (INTERFACE_NODE, &isis_metric_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd);
+ install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd);
install_element (INTERFACE_NODE, &isis_hello_interval_cmd);
install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd);
@@ -2171,8 +2802,9 @@
install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd);
install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd);
- install_element (INTERFACE_NODE, &isis_hello_cmd);
- install_element (INTERFACE_NODE, &no_isis_hello_cmd);
+ install_element (INTERFACE_NODE, &isis_hello_padding_cmd);
+ install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd);
+
install_element (INTERFACE_NODE, &csnp_interval_cmd);
install_element (INTERFACE_NODE, &no_csnp_interval_cmd);
install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd);
@@ -2183,6 +2815,19 @@
install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd);
install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd);
+ install_element (INTERFACE_NODE, &psnp_interval_cmd);
+ install_element (INTERFACE_NODE, &no_psnp_interval_cmd);
+ install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd);
+ install_element (INTERFACE_NODE, &psnp_interval_l1_cmd);
+ install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd);
+ install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd);
+ install_element (INTERFACE_NODE, &psnp_interval_l2_cmd);
+ install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd);
+ install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd);
+
+ install_element (INTERFACE_NODE, &isis_network_cmd);
+ install_element (INTERFACE_NODE, &no_isis_network_cmd);
+
#ifdef HAVE_IPV6
install_element (INTERFACE_NODE, &ipv6_router_isis_cmd);
install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd);
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index f32d1dd..7ed481d 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -52,8 +52,6 @@
u_char l1_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-1 DR */
u_char l2_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-2 DR */
struct thread *t_refresh_pseudo_lsp[2]; /* refresh pseudo-node LSPs */
- int pad_hellos; /* add padding to Hello PDUs ? */
- u_char priority[2]; /* l1/2 IS Priority */
};
struct isis_p2p_info
@@ -65,7 +63,6 @@
struct isis_circuit
{
int state;
- int connected;
u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */
struct isis_area *area; /* back pointer to the area */
struct interface *interface; /* interface info from z */
@@ -79,31 +76,36 @@
struct thread *t_send_csnp[2];
struct thread *t_send_psnp[2];
struct list *lsp_queue; /* LSPs to be txed (both levels) */
+ time_t lsp_queue_last_cleared;/* timestamp used to enforce transmit interval;
+ * for scalability, use one timestamp per
+ * circuit, instead of one per lsp per circuit
+ */
/* there is no real point in two streams, just for programming kicker */
int (*rx) (struct isis_circuit * circuit, u_char * ssnpa);
struct stream *rcv_stream; /* Stream for receiving */
int (*tx) (struct isis_circuit * circuit, int level);
struct stream *snd_stream; /* Stream for sending */
int idx; /* idx in S[RM|SN] flags */
-#define CIRCUIT_T_BROADCAST 0
-#define CIRCUIT_T_P2P 1
-#define CIRCUIT_T_STATIC_IN 2
-#define CIRCUIT_T_STATIC_OUT 3
-#define CIRCUIT_T_DA 4
+#define CIRCUIT_T_UNKNOWN 0
+#define CIRCUIT_T_BROADCAST 1
+#define CIRCUIT_T_P2P 2
+#define CIRCUIT_T_LOOPBACK 3
int circ_type; /* type of the physical interface */
+ int circ_type_config; /* config type of the physical interface */
union
{
struct isis_bcast_info bc;
struct isis_p2p_info p2p;
} u;
+ u_char priority[2]; /* l1/2 IS configured priority */
+ int pad_hellos; /* add padding to Hello PDUs ? */
char ext_domain; /* externalDomain (boolean) */
+ int lsp_regenerate_pending[ISIS_LEVELS];
/*
* Configurables
*/
struct isis_passwd passwd; /* Circuit rx/tx password */
- long lsp_interval;
- int manual_l2_only; /* manualL2OnlyMode (boolean) */
- int circuit_is_type; /* circuit is type == level of circuit
+ int is_type; /* circuit is type == level of circuit
* diffrenciated from circuit type (media) */
u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */
u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */
@@ -111,24 +113,17 @@
u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */
struct metric metrics[2]; /* l1XxxMetric */
u_int32_t te_metric[2];
- struct password *c_rx_passwds; /* circuitReceivePasswords */
- struct password *c_tc_passwd; /* circuitTransmitPassword */
int ip_router; /* Route IP ? */
+ int is_passive; /* Is Passive ? */
struct list *ip_addrs; /* our IP addresses */
#ifdef HAVE_IPV6
int ipv6_router; /* Route IPv6 ? */
struct list *ipv6_link; /* our link local IPv6 addresses */
struct list *ipv6_non_link; /* our non-link local IPv6 addresses */
#endif /* HAVE_IPV6 */
- /*
- * RFC 2973 IS-IS Mesh Groups
- */
-#define MESH_INACTIVE 0
-#define MESH_BLOCKED 1
-#define MESH_SET 2
- int mesh_enabled; /* meshGroupEnabled */
- u_int16_t mesh_group; /* meshGroup */
u_int16_t upadjcount[2];
+#define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01
+ u_char flags;
/*
* Counters as in 10589--11.2.5.9
*/
@@ -142,25 +137,30 @@
void isis_circuit_init (void);
struct isis_circuit *isis_circuit_new (void);
+void isis_circuit_del (struct isis_circuit *circuit);
struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp,
struct list *list);
struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp);
-void isis_circuit_del (struct isis_circuit *circuit);
void isis_circuit_configure (struct isis_circuit *circuit,
struct isis_area *area);
-void isis_circuit_up (struct isis_circuit *circuit);
void isis_circuit_deconfigure (struct isis_circuit *circuit,
struct isis_area *area);
-
-int isis_circuit_destroy (struct isis_circuit *circuit);
void isis_circuit_if_add (struct isis_circuit *circuit,
struct interface *ifp);
-void isis_circuit_if_del (struct isis_circuit *circuit);
-void circuit_update_nlpids (struct isis_circuit *circuit);
-void isis_circuit_update_params (struct isis_circuit *circuit,
- struct interface *ifp);
+void isis_circuit_if_del (struct isis_circuit *circuit,
+ struct interface *ifp);
+void isis_circuit_if_bind (struct isis_circuit *circuit,
+ struct interface *ifp);
+void isis_circuit_if_unbind (struct isis_circuit *circuit,
+ struct interface *ifp);
void isis_circuit_add_addr (struct isis_circuit *circuit,
struct connected *conn);
void isis_circuit_del_addr (struct isis_circuit *circuit,
struct connected *conn);
+int isis_circuit_up (struct isis_circuit *circuit);
+void isis_circuit_down (struct isis_circuit *);
+void circuit_update_nlpids (struct isis_circuit *circuit);
+void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
+ char detail);
+
#endif /* _ZEBRA_ISIS_CIRCUIT_H */
diff --git a/isisd/isis_common.h b/isisd/isis_common.h
index 334d339..d158961 100644
--- a/isisd/isis_common.h
+++ b/isisd/isis_common.h
@@ -21,6 +21,9 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#ifndef ISIS_COMMON_H
+#define ISIS_COMMON_H
+
/*
* Area Address
*/
@@ -65,11 +68,4 @@
u_char nlpids[4]; /* FIXME: enough ? */
};
-/*
- * Flags structure for SSN and SRM flags
- */
-struct flags
-{
- int maxindex;
- struct list *free_idcs;
-};
+#endif
diff --git a/isisd/isis_constants.h b/isisd/isis_constants.h
index 1b75ba6..bb2c4b4 100644
--- a/isisd/isis_constants.h
+++ b/isisd/isis_constants.h
@@ -27,8 +27,10 @@
* Architectural constant values from p. 35 of ISO/IEC 10589
*/
-#define MAX_LINK_METRIC 63
-#define MAX_PATH_METRIC 1023
+#define MAX_NARROW_LINK_METRIC 63
+#define MAX_NARROW_PATH_METRIC 1023
+#define MAX_WIDE_LINK_METRIC 0x00FFFFFF /* RFC4444 */
+#define MAX_WIDE_PATH_METRIC 0xFE000000 /* RFC3787 */
#define ISO_SAP 0xFE
#define INTRADOMAIN_ROUTEING_SELECTOR 0
#define SEQUENCE_MODULUS 4294967296
@@ -38,7 +40,7 @@
* implementation specific jitter values
*/
-#define IIH_JITTER 25 /* % */
+#define IIH_JITTER 10 /* % */
#define MAX_AGE_JITTER 5 /* % */
#define MAX_LSP_GEN_JITTER 5 /* % */
#define CSNP_JITTER 10 /* % */
@@ -46,36 +48,59 @@
#define RANDOM_SPREAD 100000.0
-/*
- * Default values
- * ISO - 10589
- * Section 7.3.21 - Parameters
- */
-#define MAX_AGE 1200
-#define ZERO_AGE_LIFETIME 60
-#define MAX_LSP_GEN_INTERVAL 900
-#define MIN_LSP_GEN_INTERVAL 30
-#define MIN_LSP_TRANS_INTERVAL 5
-#define ISIS_MIN_LSP_LIFETIME 380
-#define CSNP_INTERVAL 10
-#define PSNP_INTERVAL 2
-#define ISIS_MAX_PATH_SPLITS 3
-
#define ISIS_LEVELS 2
#define ISIS_LEVEL1 1
#define ISIS_LEVEL2 2
-#define HELLO_INTERVAL 10
-#define HELLO_MINIMAL HELLO_INTERVAL
-#define HELLO_MULTIPLIER 3
+/*
+ * Default values
+ * ISO - 10589 Section 7.3.21 - Parameters
+ * RFC 4444
+ */
+#define MAX_AGE 1200
+#define ZERO_AGE_LIFETIME 60
+#define MIN_LSP_LIFETIME 350
+#define MAX_LSP_LIFETIME 65535
+#define DEFAULT_LSP_LIFETIME 1200
+
+#define MIN_MAX_LSP_GEN_INTERVAL 1
+#define MAX_MAX_LSP_GEN_INTERVAL 65235
+#define DEFAULT_MAX_LSP_GEN_INTERVAL 900
+
+#define MIN_MIN_LSP_GEN_INTERVAL 1
+#define MAX_MIN_LSP_GEN_INTERVAL 120 /* RFC 4444 says 65535 */
+#define DEFAULT_MIN_LSP_GEN_INTERVAL 30
+
+#define MIN_LSP_TRANS_INTERVAL 5
+
+#define MIN_CSNP_INTERVAL 1
+#define MAX_CSNP_INTERVAL 600
+#define DEFAULT_CSNP_INTERVAL 10
+
+#define MIN_PSNP_INTERVAL 1
+#define MAX_PSNP_INTERVAL 120
+#define DEFAULT_PSNP_INTERVAL 2
+
+#define MIN_HELLO_INTERVAL 1
+#define MAX_HELLO_INTERVAL 600
+#define DEFAULT_HELLO_INTERVAL 3
+
+#define MIN_HELLO_MULTIPLIER 2
+#define MAX_HELLO_MULTIPLIER 100
+#define DEFAULT_HELLO_MULTIPLIER 10
+
+#define MIN_PRIORITY 0
+#define MAX_PRIORITY 127
#define DEFAULT_PRIORITY 64
-/* different vendors implement different values 5-10 on average */
-#define LSP_GEN_INTERVAL_DEFAULT 10
-#define LSP_INTERVAL 33 /* msecs */
-#define DEFAULT_CIRCUIT_METRICS 10
-#define METRICS_UNSUPPORTED 0x80
-#define PERIODIC_SPF_INTERVAL 60 /* at the top of my head */
-#define MINIMUM_SPF_INTERVAL 5 /* .. same here */
+
+/* min and max metric varies by new vs old metric types */
+#define DEFAULT_CIRCUIT_METRIC 10
+
+#define METRICS_UNSUPPORTED 0x80
+
+#define MINIMUM_SPF_INTERVAL 1
+
+#define ISIS_MAX_PATH_SPLITS 64
/*
* NLPID values
@@ -104,6 +129,7 @@
#define SNPA_ADDRSTRLEN 18
#define ISIS_SYS_ID_LEN 6
+#define ISIS_NSEL_LEN 1
#define SYSID_STRLEN 24
/*
@@ -136,8 +162,8 @@
* packets, using isomtu = mtu - LLC_LEN
*/
#define ISO_MTU(C) \
- (C->circ_type==CIRCUIT_T_BROADCAST) ? \
- (C->interface->mtu - LLC_LEN) : (C->interface->mtu)
+ ((if_is_broadcast ((C)->interface)) ? \
+ (C->interface->mtu - LLC_LEN) : (C->interface->mtu))
#ifndef ETH_ALEN
#define ETH_ALEN 6
diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c
index 6cdde46..5d74a71 100644
--- a/isisd/isis_csm.c
+++ b/isisd/isis_csm.c
@@ -36,6 +36,7 @@
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_tlv.h"
#include "isisd/isis_lsp.h"
@@ -45,7 +46,6 @@
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_dr.h"
-#include "isisd/isis_flags.h"
#include "isisd/isisd.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
@@ -85,6 +85,7 @@
case C_STATE_NA:
if (circuit)
zlog_warn ("Non-null circuit while state C_STATE_NA");
+ assert (circuit == NULL);
switch (event)
{
case ISIS_ENABLE:
@@ -106,24 +107,29 @@
}
break;
case C_STATE_INIT:
+ assert (circuit);
switch (event)
{
case ISIS_ENABLE:
isis_circuit_configure (circuit, (struct isis_area *) arg);
- isis_circuit_up (circuit);
+ if (isis_circuit_up (circuit) != ISIS_OK)
+ {
+ isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
+ break;
+ }
circuit->state = C_STATE_UP;
- circuit->connected = 1;
- isis_event_circuit_state_change (circuit, 1);
+ isis_event_circuit_state_change (circuit, circuit->area, 1);
listnode_delete (isis->init_circ_list, circuit);
break;
case IF_UP_FROM_Z:
+ assert (circuit);
zlog_warn ("circuit already connected");
break;
case ISIS_DISABLE:
zlog_warn ("circuit already disabled");
break;
case IF_DOWN_FROM_Z:
- isis_circuit_if_del (circuit);
+ isis_circuit_if_del (circuit, (struct interface *) arg);
listnode_delete (isis->init_circ_list, circuit);
isis_circuit_del (circuit);
circuit = NULL;
@@ -131,19 +137,21 @@
}
break;
case C_STATE_CONF:
+ assert (circuit);
switch (event)
{
case ISIS_ENABLE:
zlog_warn ("circuit already enabled");
break;
case IF_UP_FROM_Z:
- if (!circuit->connected) {
- isis_circuit_if_add (circuit, (struct interface *) arg);
- isis_circuit_up (circuit);
- }
+ isis_circuit_if_add (circuit, (struct interface *) arg);
+ if (isis_circuit_up (circuit) != ISIS_OK)
+ {
+ isis_circuit_if_del (circuit, (struct interface *) arg);
+ break;
+ }
circuit->state = C_STATE_UP;
- circuit->connected = 1;
- isis_event_circuit_state_change (circuit, 1);
+ isis_event_circuit_state_change (circuit, circuit->area, 1);
break;
case ISIS_DISABLE:
isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
@@ -156,6 +164,7 @@
}
break;
case C_STATE_UP:
+ assert (circuit);
switch (event)
{
case ISIS_ENABLE:
@@ -165,14 +174,18 @@
zlog_warn ("circuit already connected");
break;
case ISIS_DISABLE:
+ isis_circuit_down (circuit);
isis_circuit_deconfigure (circuit, (struct isis_area *) arg);
- listnode_add (isis->init_circ_list, circuit);
circuit->state = C_STATE_INIT;
- isis_event_circuit_state_change (circuit, 0);
+ isis_event_circuit_state_change (circuit,
+ (struct isis_area *)arg, 0);
+ listnode_add (isis->init_circ_list, circuit);
break;
case IF_DOWN_FROM_Z:
+ isis_circuit_down (circuit);
+ isis_circuit_if_del (circuit, (struct interface *) arg);
circuit->state = C_STATE_CONF;
- isis_event_circuit_state_change (circuit, 0);
+ isis_event_circuit_state_change (circuit, circuit->area, 0);
break;
}
break;
diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c
index fe872a9..73b6d3e 100644
--- a/isisd/isis_dlpi.c
+++ b/isisd/isis_dlpi.c
@@ -442,12 +442,12 @@
* 8.4.2 - Broadcast subnetwork IIH PDUs
*/
retval = 0;
- if (circuit->circuit_is_type & IS_LEVEL_1)
+ if (circuit->is_type & IS_LEVEL_1)
{
retval |= dlpimcast (fd, ALL_L1_ISS);
retval |= dlpimcast (fd, ALL_ISS);
}
- if (circuit->circuit_is_type & IS_LEVEL_2)
+ if (circuit->is_type & IS_LEVEL_2)
retval |= dlpimcast (fd, ALL_L2_ISS);
if (retval != 0)
@@ -589,6 +589,16 @@
dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl;
char *dstaddr;
u_short *dstsap;
+ int buflen;
+
+ buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN;
+ if (buflen > sizeof (sock_buff))
+ {
+ zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than "
+ "output pdu size %d on circuit %s",
+ sizeof (sock_buff), buflen, circuit->interface->name);
+ return ISIS_WARNING;
+ }
stream_set_getp (circuit->snd_stream, 0);
@@ -612,7 +622,7 @@
else
memcpy (dstaddr, ALL_L2_ISS, ETHERADDRL);
/* Note: DLPI SAP values are in host byte order */
- *dstsap = stream_get_endp (circuit->snd_stream) + LLC_LEN;
+ *dstsap = buflen;
sock_buff[0] = ISO_SAP;
sock_buff[1] = ISO_SAP;
@@ -620,7 +630,7 @@
memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
stream_get_endp (circuit->snd_stream));
dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length,
- sock_buff, stream_get_endp (circuit->snd_stream) + LLC_LEN, 0);
+ sock_buff, buflen, 0);
return ISIS_OK;
}
diff --git a/isisd/isis_dr.c b/isisd/isis_dr.c
index 8d306c8..bc6ec11 100644
--- a/isisd/isis_dr.c
+++ b/isisd/isis_dr.c
@@ -47,9 +47,6 @@
#include "isisd/isis_dr.h"
#include "isisd/isis_events.h"
-extern struct isis *isis;
-extern struct thread_master *master;
-
const char *
isis_disflag2string (int disflag)
{
@@ -137,15 +134,14 @@
int biggest_prio = -1;
int cmp_res, retval = ISIS_OK;
- own_prio = circuit->u.bc.priority[level - 1];
+ own_prio = circuit->priority[level - 1];
adjdb = circuit->u.bc.adjdb[level - 1];
if (!adjdb)
{
zlog_warn ("isis_dr_elect() adjdb == NULL");
- retval = ISIS_WARNING;
list_delete (list);
- goto out;
+ return ISIS_WARNING;
}
isis_adj_build_up_list (adjdb, list);
@@ -189,42 +185,34 @@
if (!adj_dr)
{
/*
- * Could not find the DR - means we are alone and thus the DR
+ * Could not find the DR - means we are alone. Resign if we were DR.
*/
- if (!circuit->u.bc.is_dr[level - 1])
- {
- list_delete (list);
- list = NULL;
- return isis_dr_commence (circuit, level);
- }
- goto out;
+ if (circuit->u.bc.is_dr[level - 1])
+ retval = isis_dr_resign (circuit, level);
+ list_delete (list);
+ return retval;
}
/*
* Now we have the DR adjacency, compare it to self
*/
- if (adj_dr->prio[level - 1] < own_prio
- || (adj_dr->prio[level - 1] == own_prio
- && memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
+ if (adj_dr->prio[level - 1] < own_prio ||
+ (adj_dr->prio[level - 1] == own_prio &&
+ memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0))
{
- if (!circuit->u.bc.is_dr[level - 1])
- {
- /*
- * We are the DR
- */
+ adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS;
+ adj_dr->dis_record[level - 1].last_dis_change = time (NULL);
- /* rotate the history log */
- for (ALL_LIST_ELEMENTS_RO (list, node, adj))
- isis_check_dr_change (adj, level);
+ /* rotate the history log */
+ for (ALL_LIST_ELEMENTS_RO (list, node, adj))
+ isis_check_dr_change (adj, level);
- /* commence */
- list_delete (list);
- return isis_dr_commence (circuit, level);
- }
+ /* We are the DR, commence DR */
+ if (circuit->u.bc.is_dr[level - 1] == 0 && listcount (list) > 0)
+ retval = isis_dr_commence (circuit, level);
}
else
{
-
/* ok we have found the DIS - lets mark the adjacency */
/* set flag for show output */
adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS;
@@ -240,16 +228,10 @@
/*
* We are not DR - if we were -> resign
*/
-
if (circuit->u.bc.is_dr[level - 1])
- {
- list_delete (list);
- return isis_dr_resign (circuit, level);
- }
+ retval = isis_dr_resign (circuit, level);
}
-out:
- if (list)
- list_delete (list);
+ list_delete (list);
return retval;
}
@@ -264,11 +246,12 @@
circuit->u.bc.run_dr_elect[level - 1] = 0;
THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]);
THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
+ circuit->lsp_regenerate_pending[level - 1] = 0;
memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID (id) = circuit->circuit_id;
LSP_FRAGMENT (id) = 0;
- lsp_purge_dr (id, circuit, level);
+ lsp_purge_pseudo (id, circuit, level);
if (level == 1)
{
@@ -327,7 +310,7 @@
if (LSP_PSEUDO_ID (old_dr))
{
/* there was a dr elected, purge its LSPs from the db */
- lsp_purge_dr (old_dr, circuit, level);
+ lsp_purge_pseudo (old_dr, circuit, level);
}
memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
*(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
@@ -335,7 +318,7 @@
assert (circuit->circuit_id); /* must be non-zero */
/* if (circuit->t_send_l1_psnp)
thread_cancel (circuit->t_send_l1_psnp); */
- lsp_l1_pseudo_generate (circuit);
+ lsp_generate_pseudo (circuit, 1);
THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
@@ -353,7 +336,7 @@
if (LSP_PSEUDO_ID (old_dr))
{
/* there was a dr elected, purge its LSPs from the db */
- lsp_purge_dr (old_dr, circuit, level);
+ lsp_purge_pseudo (old_dr, circuit, level);
}
memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN);
*(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id;
@@ -361,7 +344,7 @@
assert (circuit->circuit_id); /* must be non-zero */
/* if (circuit->t_send_l1_psnp)
thread_cancel (circuit->t_send_l1_psnp); */
- lsp_l2_pseudo_generate (circuit);
+ lsp_generate_pseudo (circuit, 2);
THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c
index 0b758c8..ffb0d50 100644
--- a/isisd/isis_dynhn.c
+++ b/isisd/isis_dynhn.c
@@ -41,8 +41,6 @@
#include "isisd/isis_misc.h"
#include "isisd/isis_constants.h"
-extern struct isis *isis;
-extern struct thread_master *master;
extern struct host host;
struct list *dyn_cache = NULL;
@@ -51,7 +49,8 @@
void
dyn_cache_init (void)
{
- dyn_cache = list_new ();
+ if (dyn_cache == NULL)
+ dyn_cache = list_new ();
THREAD_TIMER_ON (master, isis->t_dync_clean, dyn_cache_cleanup, NULL, 120);
return;
}
@@ -67,8 +66,8 @@
for (ALL_LIST_ELEMENTS (dyn_cache, node, nnode, dyn))
{
- if ((now - dyn->refresh) < (MAX_AGE + 120))
- continue;
+ if ((now - dyn->refresh) < MAX_LSP_LIFETIME)
+ continue;
list_delete_node (dyn_cache, node);
XFREE (MTYPE_ISIS_DYNHN, dyn);
@@ -91,6 +90,19 @@
return NULL;
}
+struct isis_dynhn *
+dynhn_find_by_name (const char *hostname)
+{
+ struct listnode *node = NULL;
+ struct isis_dynhn *dyn = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn))
+ if (strncmp ((char *)dyn->name.name, hostname, 255) == 0)
+ return dyn;
+
+ return NULL;
+}
+
void
isis_dynhn_insert (u_char * id, struct hostname *hostname, int level)
{
@@ -122,6 +134,19 @@
return;
}
+void
+isis_dynhn_remove (u_char * id)
+{
+ struct isis_dynhn *dyn;
+
+ dyn = dynhn_find_by_id (id);
+ if (!dyn)
+ return;
+ listnode_delete (dyn_cache, dyn);
+ XFREE (MTYPE_ISIS_DYNHN, dyn);
+ return;
+}
+
/*
* Level System ID Dynamic Hostname (notag)
* 2 0000.0000.0001 foo-gw
diff --git a/isisd/isis_dynhn.h b/isisd/isis_dynhn.h
index 37a7b03..379c454 100644
--- a/isisd/isis_dynhn.h
+++ b/isisd/isis_dynhn.h
@@ -33,7 +33,9 @@
void dyn_cache_init (void);
void isis_dynhn_insert (u_char * id, struct hostname *hostname, int level);
+void isis_dynhn_remove (u_char * id);
struct isis_dynhn *dynhn_find_by_id (u_char * id);
+struct isis_dynhn *dynhn_find_by_name (const char *hostname);
void dynhn_print_all (struct vty *vty);
#endif /* _ZEBRA_ISIS_DYNHN_H */
diff --git a/isisd/isis_events.c b/isisd/isis_events.c
index 4380092..3887b7c 100644
--- a/isisd/isis_events.c
+++ b/isisd/isis_events.c
@@ -30,11 +30,13 @@
#include "hash.h"
#include "prefix.h"
#include "stream.h"
+#include "table.h"
#include "isisd/dict.h"
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_tlv.h"
#include "isisd/isis_lsp.h"
@@ -44,15 +46,11 @@
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_dr.h"
-#include "isisd/isis_flags.h"
#include "isisd/isisd.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_spf.h"
-extern struct thread_master *master;
-extern struct isis *isis;
-
/* debug isis-spf spf-events
4w4d: ISIS-Spf (tlt): L2 SPF needed, new adjacency, from 0x609229F4
4w4d: ISIS-Spf (tlt): L2, 0000.0000.0042.01-00 TLV contents changed, code 0x2
@@ -62,26 +60,59 @@
*/
void
-isis_event_circuit_state_change (struct isis_circuit *circuit, int up)
+isis_event_circuit_state_change (struct isis_circuit *circuit,
+ struct isis_area *area, int up)
{
- struct isis_area *area;
-
- area = circuit->area;
- assert (area);
area->circuit_state_changes++;
if (isis->debugs & DEBUG_EVENTS)
- zlog_debug ("ISIS-Evt (%s) circuit %s", circuit->area->area_tag,
- up ? "up" : "down");
+ zlog_debug ("ISIS-Evt (%s) circuit %s", area->area_tag,
+ up ? "up" : "down");
/*
* Regenerate LSPs this affects
*/
- lsp_regenerate_schedule (area);
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
return;
}
+static void
+area_resign_level (struct isis_area *area, int level)
+{
+ if (area->lspdb[level - 1])
+ {
+ lsp_db_destroy (area->lspdb[level - 1]);
+ area->lspdb[level - 1] = NULL;
+ }
+ if (area->spftree[level - 1])
+ {
+ isis_spftree_del (area->spftree[level - 1]);
+ area->spftree[level - 1] = NULL;
+ }
+#ifdef HAVE_IPV6
+ if (area->spftree6[level - 1])
+ {
+ isis_spftree_del (area->spftree6[level - 1]);
+ area->spftree6[level - 1] = NULL;
+ }
+#endif
+ if (area->route_table[level - 1])
+ {
+ route_table_finish (area->route_table[level - 1]);
+ area->route_table[level - 1] = NULL;
+ }
+#ifdef HAVE_IPV6
+ if (area->route_table6[level - 1])
+ {
+ route_table_finish (area->route_table6[level - 1]);
+ area->route_table6[level - 1] = NULL;
+ }
+#endif /* HAVE_IPV6 */
+
+ THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
+}
+
void
isis_event_system_type_change (struct isis_area *area, int newtype)
{
@@ -96,59 +127,79 @@
return; /* No change */
switch (area->is_type)
- {
+ {
case IS_LEVEL_1:
+ if (newtype == IS_LEVEL_2)
+ area_resign_level (area, IS_LEVEL_1);
+
if (area->lspdb[1] == NULL)
- area->lspdb[1] = lsp_db_init ();
- lsp_l2_generate (area);
+ area->lspdb[1] = lsp_db_init ();
+ if (area->route_table[1] == NULL)
+ area->route_table[1] = route_table_init ();
+#ifdef HAVE_IPV6
+ if (area->route_table6[1] == NULL)
+ area->route_table6[1] = route_table_init ();
+#endif /* HAVE_IPV6 */
break;
+
case IS_LEVEL_1_AND_2:
if (newtype == IS_LEVEL_1)
- {
- lsp_db_destroy (area->lspdb[1]);
- }
+ area_resign_level (area, IS_LEVEL_2);
else
- {
- lsp_db_destroy (area->lspdb[0]);
- }
+ area_resign_level (area, IS_LEVEL_1);
break;
+
case IS_LEVEL_2:
+ if (newtype == IS_LEVEL_1)
+ area_resign_level (area, IS_LEVEL_2);
+
if (area->lspdb[0] == NULL)
- area->lspdb[0] = lsp_db_init ();
- lsp_l1_generate (area);
+ area->lspdb[0] = lsp_db_init ();
+ if (area->route_table[0] == NULL)
+ area->route_table[0] = route_table_init ();
+#ifdef HAVE_IPV6
+ if (area->route_table6[0] == NULL)
+ area->route_table6[0] = route_table_init ();
+#endif /* HAVE_IPV6 */
break;
+
default:
break;
- }
+ }
area->is_type = newtype;
- for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
- isis_event_circuit_type_change (circuit, newtype);
+
+ /* override circuit's is_type */
+ if (area->is_type != IS_LEVEL_1_AND_2)
+ {
+ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
+ isis_event_circuit_type_change (circuit, newtype);
+ }
spftree_area_init (area);
- lsp_regenerate_schedule (area);
+
+ if (newtype & IS_LEVEL_1)
+ lsp_generate (area, IS_LEVEL_1);
+ if (newtype & IS_LEVEL_2)
+ lsp_generate (area, IS_LEVEL_2);
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
return;
}
-void
-isis_event_area_addr_change (struct isis_area *area)
-{
-
-}
-
static void
circuit_commence_level (struct isis_circuit *circuit, int level)
{
if (level == 1)
{
- THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
- isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
+ if (! circuit->is_passive)
+ THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
+ isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
{
THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
- circuit, 2 * circuit->hello_interval[1]);
+ circuit, 2 * circuit->hello_interval[0]);
THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
send_lan_l1_hello, circuit,
@@ -160,8 +211,9 @@
}
else
{
- THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
- isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
+ if (! circuit->is_passive)
+ THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
+ isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
{
@@ -194,6 +246,8 @@
THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[idx]);
THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]);
circuit->u.bc.run_dr_elect[idx] = 0;
+ list_delete (circuit->u.bc.lan_neighs[idx]);
+ circuit->u.bc.lan_neighs[idx] = NULL;
}
return;
@@ -202,14 +256,19 @@
void
isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype)
{
+ if (circuit->state != C_STATE_UP)
+ {
+ circuit->is_type = newtype;
+ return;
+ }
if (isis->debugs & DEBUG_EVENTS)
zlog_debug ("ISIS-Evt (%s) circuit type change %s -> %s",
circuit->area->area_tag,
- circuit_t2string (circuit->circuit_is_type),
+ circuit_t2string (circuit->is_type),
circuit_t2string (newtype));
- if (circuit->circuit_is_type == newtype)
+ if (circuit->is_type == newtype)
return; /* No change */
if (!(newtype & circuit->area->is_type))
@@ -221,7 +280,7 @@
return;
}
- switch (circuit->circuit_is_type)
+ switch (circuit->is_type)
{
case IS_LEVEL_1:
if (newtype == IS_LEVEL_2)
@@ -243,8 +302,8 @@
break;
}
- circuit->circuit_is_type = newtype;
- lsp_regenerate_schedule (circuit->area);
+ circuit->is_type = newtype;
+ lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
return;
}
@@ -286,7 +345,7 @@
adj->circuit->area->area_tag);
/* LSP generation again */
- lsp_regenerate_schedule (adj->circuit->area);
+ lsp_regenerate_schedule (adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
return;
}
@@ -307,7 +366,7 @@
zlog_debug ("ISIS-Evt (%s) DIS status change", circuit->area->area_tag);
/* LSP generation again */
- lsp_regenerate_schedule (circuit->area);
+ lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
return 0;
}
diff --git a/isisd/isis_events.h b/isisd/isis_events.h
index 86bf051..c252f3d 100644
--- a/isisd/isis_events.h
+++ b/isisd/isis_events.h
@@ -26,13 +26,12 @@
* Events related to area
*/
void isis_event_system_type_change (struct isis_area *area, int newtype);
-void isis_event_area_addr_change (struct isis_area *area);
/*
* Events related to circuit
*/
void isis_event_circuit_state_change (struct isis_circuit *circuit,
- int state);
+ struct isis_area *area, int state);
void isis_event_circuit_type_change (struct isis_circuit *circuit,
int newtype);
/*
diff --git a/isisd/isis_flags.c b/isisd/isis_flags.c
index 03c9110..ec0eaa4 100644
--- a/isisd/isis_flags.c
+++ b/isisd/isis_flags.c
@@ -36,11 +36,11 @@
flags->free_idcs = NULL;
}
-int
+long int
flags_get_index (struct flags *flags)
{
struct listnode *node;
- int index;
+ long int index;
if (flags->free_idcs == NULL || flags->free_idcs->count == 0)
{
@@ -49,7 +49,7 @@
else
{
node = listhead (flags->free_idcs);
- index = (int) listgetdata (node);
+ index = (long int) listgetdata (node);
listnode_delete (flags->free_idcs, (void *) index);
index--;
}
@@ -58,7 +58,7 @@
}
void
-flags_free_index (struct flags *flags, int index)
+flags_free_index (struct flags *flags, long int index)
{
if (index + 1 == flags->maxindex)
{
diff --git a/isisd/isis_flags.h b/isisd/isis_flags.h
index 13dd9e1..e2e42ad 100644
--- a/isisd/isis_flags.h
+++ b/isisd/isis_flags.h
@@ -26,28 +26,43 @@
/* The grand plan is to support 1024 circuits so we have 32*32 bit flags
* the support will be achived using the newest drafts */
-#define ISIS_MAX_CIRCUITS 32 /* = 1024 */ /*FIXME:defined in lsp.h as well */
+#define ISIS_MAX_CIRCUITS 32 /* = 1024 */
+
+/*
+ * Flags structure for SSN and SRM flags
+ */
+struct flags
+{
+ int maxindex;
+ struct list *free_idcs;
+};
void flags_initialize (struct flags *flags);
-struct flags *new_flags (int size);
-int flags_get_index (struct flags *flags);
-void flags_free_index (struct flags *flags, int index);
-
+long int flags_get_index (struct flags *flags);
+void flags_free_index (struct flags *flags, long int index);
int flags_any_set (u_int32_t * flags);
#define ISIS_SET_FLAG(F,C) \
- F[C->idx>>5] |= (1<<(C->idx & 0x1F));
+ { \
+ F[C->idx>>5] |= (1<<(C->idx & 0x1F)); \
+ }
#define ISIS_CLEAR_FLAG(F,C) \
- F[C->idx>>5] &= ~(1<<(C->idx & 0x1F));
+ { \
+ F[C->idx>>5] &= ~(1<<(C->idx & 0x1F)); \
+ }
-#define ISIS_CHECK_FLAG(F, C) F[(C)->idx>>5] & (1<<(C->idx & 0x1F))
+#define ISIS_CHECK_FLAG(F, C) (F[(C)->idx>>5] & (1<<(C->idx & 0x1F)))
/* sets all u_32int_t flags to 1 */
#define ISIS_FLAGS_SET_ALL(FLAGS) \
- memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4);
+ { \
+ memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4); \
+ }
#define ISIS_FLAGS_CLEAR_ALL(FLAGS) \
- memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4);
+ { \
+ memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4); \
+ }
#endif /* _ZEBRA_ISIS_FLAGS_H */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index fd40bb3..5c1e993 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -34,10 +34,12 @@
#include "hash.h"
#include "if.h"
#include "checksum.h"
+#include "md5.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isisd.h"
#include "isisd/isis_tlv.h"
@@ -45,7 +47,6 @@
#include "isisd/isis_pdu.h"
#include "isisd/isis_dynhn.h"
#include "isisd/isis_misc.h"
-#include "isisd/isis_flags.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_spf.h"
@@ -54,15 +55,14 @@
#include "spgrid.h"
#endif
-#define LSP_MEMORY_PREASSIGN
-
-extern struct isis *isis;
-extern struct thread_master *master;
-extern struct in_addr router_id_zebra;
-
/* staticly assigned vars for printing purposes */
char lsp_bits_string[200]; /* FIXME: enough ? */
+static int lsp_l1_refresh (struct thread *thread);
+static int lsp_l2_refresh (struct thread *thread);
+static int lsp_l1_refresh_pseudo (struct thread *thread);
+static int lsp_l2_refresh_pseudo (struct thread *thread);
+
int
lsp_id_cmp (u_char * id1, u_char * id2)
{
@@ -90,7 +90,7 @@
zlog_debug ("searching db");
for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn))
{
- zlog_debug ("%s\t%pX", rawlspid_print ((char *) dnode_getkey (dn)),
+ zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)),
dnode_get (dn));
}
#endif /* EXTREME DEBUG */
@@ -109,54 +109,56 @@
if (!lsp)
return;
+ if (lsp->tlv_data.hostname)
+ isis_dynhn_remove (lsp->lsp_header->lsp_id);
+
if (lsp->own_lsp)
{
if (lsp->tlv_data.nlpids)
- XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
+ XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids);
if (lsp->tlv_data.hostname)
- XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
+ XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname);
+ if (lsp->tlv_data.router_id)
+ XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id);
}
- if (lsp->tlv_data.is_neighs)
- list_delete (lsp->tlv_data.is_neighs);
- if (lsp->tlv_data.te_is_neighs)
- list_delete (lsp->tlv_data.te_is_neighs);
- if (lsp->tlv_data.area_addrs)
- list_delete (lsp->tlv_data.area_addrs);
- if (lsp->tlv_data.es_neighs)
- list_delete (lsp->tlv_data.es_neighs);
- if (lsp->tlv_data.ipv4_addrs)
- list_delete (lsp->tlv_data.ipv4_addrs);
- if (lsp->tlv_data.ipv4_int_reachs)
- list_delete (lsp->tlv_data.ipv4_int_reachs);
- if (lsp->tlv_data.ipv4_ext_reachs)
- list_delete (lsp->tlv_data.ipv4_ext_reachs);
- if (lsp->tlv_data.te_ipv4_reachs)
- list_delete (lsp->tlv_data.te_ipv4_reachs);
-#ifdef HAVE_IPV6
- if (lsp->tlv_data.ipv6_addrs)
- list_delete (lsp->tlv_data.ipv6_addrs);
- if (lsp->tlv_data.ipv6_reachs)
- list_delete (lsp->tlv_data.ipv6_reachs);
-#endif /* HAVE_IPV6 */
- memset (&lsp->tlv_data, 0, sizeof (struct tlvs));
-
- return;
+ free_tlvs (&lsp->tlv_data);
}
static void
lsp_destroy (struct isis_lsp *lsp)
{
+ struct listnode *cnode, *lnode, *lnnode;
+ struct isis_lsp *lsp_in_list;
+ struct isis_circuit *circuit;
+
if (!lsp)
return;
+ for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit))
+ {
+ if (circuit->lsp_queue == NULL)
+ continue;
+ for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list))
+ if (lsp_in_list == lsp)
+ list_delete_node(circuit->lsp_queue, lnode);
+ }
+ ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags);
+ ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
+
lsp_clear_data (lsp);
if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags)
{
list_delete (lsp->lspu.frags);
+ lsp->lspu.frags = NULL;
}
+ isis_spf_schedule (lsp->area, lsp->level);
+#ifdef HAVE_IPV6
+ isis_spf_schedule6 (lsp->area, lsp->level);
+#endif
+
if (lsp->pdu)
stream_free (lsp->pdu);
XFREE (MTYPE_ISIS_LSP, lsp);
@@ -254,7 +256,7 @@
{
if (isis->debugs & DEBUG_SNP_PACKETS)
{
- zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
+ zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
" lifetime %us",
areatag,
rawlspid_print (lsp->lsp_header->lsp_id),
@@ -273,7 +275,7 @@
{
if (isis->debugs & DEBUG_SNP_PACKETS)
{
- zlog_debug ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x,"
+ zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x,"
" lifetime %us",
areatag,
rawlspid_print (lsp->lsp_header->lsp_id),
@@ -290,7 +292,7 @@
if (isis->debugs & DEBUG_SNP_PACKETS)
{
zlog_debug
- ("ISIS-Snp (%s): LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
+ ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us",
areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num),
ntohs (checksum), ntohs (rem_lifetime));
zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x,"
@@ -303,6 +305,91 @@
return LSP_OLDER;
}
+static void
+lsp_auth_add (struct isis_lsp *lsp)
+{
+ struct isis_passwd *passwd;
+ unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+
+ /*
+ * Add the authentication info if its present
+ */
+ (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
+ (passwd = &lsp->area->domain_passwd);
+ switch (passwd->type)
+ {
+ /* Cleartext */
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
+ tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
+ break;
+
+ /* HMAC MD5 */
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
+ /* Remember where TLV is written so we can later
+ * overwrite the MD5 hash */
+ lsp->auth_tlv_offset = stream_get_endp (lsp->pdu);
+ memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
+ lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5;
+ lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE;
+ memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
+ ISIS_AUTH_MD5_SIZE);
+ tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash,
+ lsp->pdu);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+lsp_auth_update (struct isis_lsp *lsp)
+{
+ struct isis_passwd *passwd;
+ unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+ uint16_t checksum, rem_lifetime;
+
+ /* For HMAC MD5 we need to recompute the md5 hash and store it */
+ (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) :
+ (passwd = &lsp->area->domain_passwd);
+ if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5)
+ return;
+
+ /*
+ * In transient conditions (when net is configured where authentication
+ * config and lsp regenerate schedule is not yet run), there could be
+ * an own_lsp with auth_tlv_offset set to 0. In such a case, simply
+ * return, when lsp_regenerate is run, lsp will have auth tlv.
+ */
+ if (lsp->auth_tlv_offset == 0)
+ return;
+
+ /*
+ * RFC 5304 set auth value, checksum and remaining lifetime to zero
+ * before computation and reset to old values after computation.
+ */
+ checksum = lsp->lsp_header->checksum;
+ rem_lifetime = lsp->lsp_header->rem_lifetime;
+ lsp->lsp_header->checksum = 0;
+ lsp->lsp_header->rem_lifetime = 0;
+ /* Set the authentication value as well to zero */
+ memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
+ 0, ISIS_AUTH_MD5_SIZE);
+ /* Compute autentication value */
+ hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu),
+ (unsigned char *) &passwd->passwd, passwd->len,
+ (caddr_t) &hmac_md5_hash);
+ /* Copy the hash into the stream */
+ memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3,
+ hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
+ memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash,
+ ISIS_AUTH_MD5_SIZE);
+ /* Copy back the checksum and remaining lifetime */
+ lsp->lsp_header->checksum = checksum;
+ lsp->lsp_header->rem_lifetime = rem_lifetime;
+}
+
void
lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)
{
@@ -311,11 +398,25 @@
if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num)
newseq = ntohl (lsp->lsp_header->seq_num) + 1;
else
- newseq = seq_num++;
+ newseq = seq_num + 1;
lsp->lsp_header->seq_num = htonl (newseq);
- fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
- ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+
+ /* Recompute authentication and checksum information */
+ lsp_auth_update (lsp);
+ /* ISO 10589 - 7.3.11 Generation of the checksum
+ * The checksum shall be computed over all fields in the LSP which appear
+ * after the Remaining Lifetime field. This field (and those appearing
+ * before it) are excluded so that the LSP may be aged by systems without
+ * requiring recomputation.
+ */
+ fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+ ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+
+ isis_spf_schedule (lsp->area, lsp->level);
+#ifdef HAVE_IPV6
+ isis_spf_schedule6 (lsp->area, lsp->level);
+#endif
return;
}
@@ -340,54 +441,40 @@
return;
}
-int
-isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
- int pdulen, struct isis_passwd *passwd)
+static u_int8_t
+lsp_bits_generate (int level, int overload_bit)
{
- uint32_t expected = 0, found;
- struct tlvs tlvs;
- int retval = 0;
-
- expected |= TLVFLAG_AUTH_INFO;
- retval = parse_tlvs (area->area_tag, stream->data +
- ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
- pdulen - ISIS_FIXED_HDR_LEN
- - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);
-
- if (retval || !(found & TLVFLAG_AUTH_INFO))
- return 1; /* Auth fail (parsing failed or no auth-tlv) */
-
- switch (tlvs.auth_info.type)
- {
- case ISIS_PASSWD_TYPE_HMAC_MD5:
- zlog_debug("Got LSP with ISIS_PASSWD_TYPE_HMAC_MD5");
- break;
- case ISIS_PASSWD_TYPE_CLEARTXT:
- zlog_debug("Got LSP with ISIS_PASSWD_TYPE_CLEARTXT");
- break;
- default:
- zlog_debug("Unknown authentication type in LSP");
- break;
- }
-
- return 0;
- /* return authentication_check (passwd, &tlvs.auth_info);*/
+ u_int8_t lsp_bits = 0;
+ if (level == IS_LEVEL_1)
+ lsp_bits = IS_LEVEL_1;
+ else
+ lsp_bits = IS_LEVEL_1_AND_2;
+ if (overload_bit)
+ lsp_bits |= overload_bit;
+ return lsp_bits;
}
static void
lsp_update_data (struct isis_lsp *lsp, struct stream *stream,
- struct isis_area *area)
+ struct isis_area *area, int level)
{
uint32_t expected = 0, found;
int retval;
+ /* free the old lsp data */
+ lsp_clear_data (lsp);
+
/* copying only the relevant part of our stream */
+ if (lsp->pdu != NULL)
+ stream_free (lsp->pdu);
lsp->pdu = stream_dup (stream);
-
+
/* setting pointers to the correct place */
lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
ISIS_FIXED_HDR_LEN);
+ lsp->area = area;
+ lsp->level = level;
lsp->age_out = ZERO_AGE_LIFETIME;
lsp->installed = time (NULL);
/*
@@ -396,8 +483,6 @@
expected |= TLVFLAG_AUTH_INFO;
expected |= TLVFLAG_AREA_ADDRS;
expected |= TLVFLAG_IS_NEIGHS;
- if ((lsp->lsp_header->lsp_bits & 3) == 3) /* a level 2 LSP */
- expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS;
expected |= TLVFLAG_NLPID;
if (area->dynhostname)
expected |= TLVFLAG_DYN_HOSTNAME;
@@ -415,57 +500,58 @@
expected |= TLVFLAG_IPV6_REACHABILITY;
#endif /* HAVE_IPV6 */
- retval = parse_tlvs (area->area_tag, lsp->pdu->data +
- ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
- ntohs (lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN
- - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data);
-
- if (found & TLVFLAG_DYN_HOSTNAME)
+ retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
+ ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
+ ntohs (lsp->lsp_header->pdu_len) -
+ ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
+ &expected, &found, &lsp->tlv_data,
+ NULL);
+ if (retval != ISIS_OK)
{
- if (area->dynhostname)
- isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
- (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
- IS_LEVEL_1_AND_2 ? IS_LEVEL_2 :
- (lsp->lsp_header->lsp_bits & LSPBIT_IST));
+ zlog_warn ("Could not parse LSP");
+ return;
}
+ if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))
+ {
+ isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
+ (lsp->lsp_header->lsp_bits & LSPBIT_IST) ==
+ IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1);
+ }
+
+ return;
}
void
-lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
- struct stream *stream, struct isis_area *area, int level)
+lsp_update (struct isis_lsp *lsp, struct stream *stream,
+ struct isis_area *area, int level)
{
dnode_t *dnode = NULL;
- /* Remove old LSP from LSP database. */
+ /* Remove old LSP from database. This is required since the
+ * lsp_update_data will free the lsp->pdu (which has the key, lsp_id)
+ * and will update it with the new data in the stream. */
dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id);
if (dnode)
dnode_destroy (dict_delete (area->lspdb[level - 1], dnode));
- /* free the old lsp data */
- XFREE (MTYPE_STREAM_DATA, lsp->pdu);
- lsp_clear_data (lsp);
-
/* rebuild the lsp data */
- lsp_update_data (lsp, stream, area);
+ lsp_update_data (lsp, stream, area, level);
- /* set the new values for lsp header */
- memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
-
- if (dnode)
- lsp_insert (lsp, area->lspdb[level - 1]);
+ /* insert the lsp back into the database */
+ lsp_insert (lsp, area->lspdb[level - 1]);
}
/* creation of LSP directly from what we received */
struct isis_lsp *
lsp_new_from_stream_ptr (struct stream *stream,
u_int16_t pdu_len, struct isis_lsp *lsp0,
- struct isis_area *area)
+ struct isis_area *area, int level)
{
struct isis_lsp *lsp;
lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
- lsp_update_data (lsp, stream, area);
+ lsp_update_data (lsp, stream, area, level);
if (lsp0 == NULL)
{
@@ -499,12 +585,8 @@
zlog_warn ("lsp_new(): out of memory");
return NULL;
}
-#ifdef LSP_MEMORY_PREASSIGN
- lsp->pdu = stream_new (1514); /*Should be minimal mtu? yup... */
-#else
- /* We need to do realloc on TLVs additions */
- lsp->pdu = malloc (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-#endif /* LSP_MEMORY_PREASSIGN */
+ /* FIXME: Should be minimal mtu? */
+ lsp->pdu = stream_new (1500);
if (LSP_FRAGMENT (lsp_id) == 0)
lsp->lspu.frags = list_new ();
lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu));
@@ -512,7 +594,7 @@
(STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN);
/* at first we fill the FIXED HEADER */
- (level == 1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
+ (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) :
fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE);
/* now for the LSP HEADER */
@@ -529,9 +611,10 @@
stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
if (isis->debugs & DEBUG_EVENTS)
- zlog_debug ("New LSP with ID %s-%02x-%02x seqnum %08x",
+ zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x",
sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id),
LSP_FRAGMENT (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->pdu_len),
ntohl (lsp->lsp_header->seq_num));
return lsp;
@@ -541,6 +624,13 @@
lsp_insert (struct isis_lsp *lsp, dict_t * lspdb)
{
dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp);
+ if (lsp->lsp_header->seq_num != 0)
+ {
+ isis_spf_schedule (lsp->area, lsp->level);
+#ifdef HAVE_IPV6
+ isis_spf_schedule6 (lsp->area, lsp->level);
+#endif
+ }
}
/*
@@ -577,12 +667,13 @@
}
/*
- * Build a list of all LSPs bounded by start and stop ids
+ * Build a list of num_lsps LSPs bounded by start_id and stop_id.
*/
void
-lsp_build_list (u_char * start_id, u_char * stop_id,
+lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
struct list *list, dict_t * lspdb)
{
+ u_char count;
dnode_t *first, *last, *curr;
first = dict_lower_bound (lspdb, start_id);
@@ -594,14 +685,18 @@
curr = first;
listnode_add (list, first->dict_data);
+ count = 1;
while (curr)
{
curr = dict_next (lspdb, curr);
if (curr)
- listnode_add (list, curr->dict_data);
- if (curr == last)
- break;
+ {
+ listnode_add (list, curr->dict_data);
+ count++;
+ }
+ if (count == num_lsps || curr == last)
+ break;
}
return;
@@ -611,11 +706,12 @@
* Build a list of LSPs with SSN flag set for the given circuit
*/
void
-lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
- dict_t * lspdb)
+lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
+ struct list *list, dict_t * lspdb)
{
dnode_t *dnode, *next;
struct isis_lsp *lsp;
+ u_char count = 0;
dnode = dict_first (lspdb);
while (dnode != NULL)
@@ -623,7 +719,12 @@
next = dict_next (lspdb, dnode);
lsp = dnode_get (dnode);
if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit))
- listnode_add (list, lsp);
+ {
+ listnode_add (list, lsp);
+ ++count;
+ }
+ if (count == num_lsps)
+ break;
dnode = next;
}
@@ -637,22 +738,11 @@
if (lsp->lsp_header->rem_lifetime == 0)
{
- if (lsp->age_out != 0)
- lsp->age_out--;
+ if (lsp->age_out > 0)
+ lsp->age_out--;
return;
}
- /* If we are turning 0 */
- /* ISO 10589 - 7.3.16.4 first paragraph */
-
- if (ntohs (lsp->lsp_header->rem_lifetime) == 1)
- {
- /* 7.3.16.4 a) set SRM flags on all */
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
- /* 7.3.16.4 b) retain only the header FIXME */
- /* 7.3.16.4 c) record the time to purge FIXME (other way to do it) */
- }
-
lsp->lsp_header->rem_lifetime =
htons (ntohs (lsp->lsp_header->rem_lifetime) - 1);
}
@@ -669,13 +759,11 @@
dyn = NULL;
if (dyn)
- sprintf ((char *)id, "%.14s", dyn->name.name);
- else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) & dynhost)
- sprintf ((char *)id, "%.14s", unix_hostname ());
+ sprintf ((char *)id, "%.14s", dyn->name.name);
+ else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost)
+ sprintf ((char *)id, "%.14s", unix_hostname ());
else
- {
memcpy (id, sysid_print (lsp_id), 15);
- }
if (frag)
sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id),
LSP_FRAGMENT (lsp_id));
@@ -707,30 +795,32 @@
}
/* this function prints the lsp on show isis database */
-static void
-lsp_print (dnode_t * node, struct vty *vty, char dynhost)
+void
+lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost)
{
- struct isis_lsp *lsp = dnode_get (node);
u_char LSPid[255];
+ char age_out[8];
lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
- vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
- vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num));
- vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum));
-
+ vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' ');
+ vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len));
+ vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num));
+ vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum));
if (ntohs (lsp->lsp_header->rem_lifetime) == 0)
- vty_out (vty, " (%2u)", lsp->age_out);
+ {
+ snprintf (age_out, 8, "(%u)", lsp->age_out);
+ age_out[7] = '\0';
+ vty_out (vty, "%7s ", age_out);
+ }
else
- vty_out (vty, "%5u", ntohs (lsp->lsp_header->rem_lifetime));
-
- vty_out (vty, " %s%s",
- lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
+ vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime));
+ vty_out (vty, "%s%s",
+ lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE);
}
-static void
-lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)
+void
+lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost)
{
- struct isis_lsp *lsp = dnode_get (node);
struct area_addr *area_addr;
int i;
struct listnode *lnode;
@@ -751,7 +841,7 @@
u_char ipv4_address[20];
lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1);
- lsp_print (node, vty, dynhost);
+ lsp_print (lsp, vty, dynhost);
/* for all area address */
if (lsp->tlv_data.area_addrs)
@@ -771,11 +861,11 @@
{
case NLPID_IP:
case NLPID_IPV6:
- vty_out (vty, " NLPID: 0x%X%s",
+ vty_out (vty, " NLPID : 0x%X%s",
lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE);
break;
default:
- vty_out (vty, " NLPID: %s%s", "unknown", VTY_NEWLINE);
+ vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE);
break;
}
}
@@ -784,33 +874,42 @@
/* for the hostname tlv */
if (lsp->tlv_data.hostname)
{
- memset (hostname, 0, sizeof (hostname));
+ bzero (hostname, sizeof (hostname));
memcpy (hostname, lsp->tlv_data.hostname->name,
lsp->tlv_data.hostname->namelen);
- vty_out (vty, " Hostname: %s%s", hostname, VTY_NEWLINE);
+ vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE);
}
- if (lsp->tlv_data.ipv4_addrs)
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
- {
- memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
- vty_out (vty, " IP: %s%s", ipv4_address, VTY_NEWLINE);
- }
+ /* authentication tlv */
+ if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED)
+ {
+ if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5)
+ vty_out (vty, " Auth type : md5%s", VTY_NEWLINE);
+ else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT)
+ vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE);
+ }
/* TE router id */
if (lsp->tlv_data.router_id)
{
memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id),
sizeof (ipv4_address));
- vty_out (vty, " Router ID: %s%s", ipv4_address, VTY_NEWLINE);
+ vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE);
}
+ if (lsp->tlv_data.ipv4_addrs)
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr))
+ {
+ memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address));
+ vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE);
+ }
+
/* for the IS neighbor tlv */
if (lsp->tlv_data.is_neighs)
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh))
{
lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0);
- vty_out (vty, " Metric: %-10d IS %s%s",
+ vty_out (vty, " Metric : %-8d IS : %s%s",
is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE);
}
@@ -823,7 +922,7 @@
sizeof (ipv4_reach_prefix));
memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
sizeof (ipv4_reach_mask));
- vty_out (vty, " Metric: %-10d IP-Internal %s %s%s",
+ vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s",
ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
ipv4_reach_mask, VTY_NEWLINE);
}
@@ -837,7 +936,7 @@
sizeof (ipv4_reach_prefix));
memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask),
sizeof (ipv4_reach_mask));
- vty_out (vty, " Metric: %-10d IP-External %s %s%s",
+ vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s",
ipv4_reach->metrics.metric_default, ipv4_reach_prefix,
ipv4_reach_mask, VTY_NEWLINE);
}
@@ -853,11 +952,11 @@
inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ);
if ((ipv6_reach->control_info &&
CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL)
- vty_out (vty, " Metric: %-10d IPv6-Internal %s/%d%s",
+ vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
else
- vty_out (vty, " Metric: %-10d IPv6-External %s/%d%s",
+ vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s",
ntohl (ipv6_reach->metric),
buff, ipv6_reach->prefix_len, VTY_NEWLINE);
}
@@ -867,11 +966,9 @@
if (lsp->tlv_data.te_is_neighs)
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh))
{
- uint32_t metric;
- memcpy (&metric, te_is_neigh->te_metric, 3);
lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0);
- vty_out (vty, " Metric: %-10d IS-Extended %s%s",
- ntohl (metric << 8), LSPid, VTY_NEWLINE);
+ vty_out (vty, " Metric : %-8d IS-Extended : %s%s",
+ GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE);
}
/* TE IPv4 tlv */
@@ -880,12 +977,13 @@
te_ipv4_reach))
{
/* FIXME: There should be better way to output this stuff. */
- vty_out (vty, " Metric: %-10d IP-Extended %s/%d%s",
+ vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s",
ntohl (te_ipv4_reach->te_metric),
inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start,
te_ipv4_reach->control)),
te_ipv4_reach->control & 0x3F, VTY_NEWLINE);
}
+ vty_out (vty, "%s", VTY_NEWLINE);
return;
}
@@ -898,10 +996,6 @@
dnode_t *node = dict_first (lspdb), *next;
int lsp_count = 0;
- /* print the title, for both modes */
- vty_out (vty, "LSP ID LSP Seq Num LSP Checksum "
- "LSP Holdtime ATT/P/OL%s", VTY_NEWLINE);
-
if (detail == ISIS_UI_LEVEL_BRIEF)
{
while (node != NULL)
@@ -909,7 +1003,7 @@
/* I think it is unnecessary, so I comment it out */
/* dict_contains (lspdb, node); */
next = dict_next (lspdb, node);
- lsp_print (node, vty, dynhost);
+ lsp_print (dnode_get (node), vty, dynhost);
node = next;
lsp_count++;
}
@@ -919,7 +1013,7 @@
while (node != NULL)
{
next = dict_next (lspdb, node);
- lsp_print_detail (node, vty, dynhost);
+ lsp_print_detail (dnode_get (node), vty, dynhost);
node = next;
lsp_count++;
}
@@ -929,7 +1023,7 @@
}
#define FRAG_THOLD(S,T) \
-((STREAM_SIZE(S)*T)/100)
+ ((STREAM_SIZE(S)*T)/100)
/* stream*, area->lsp_frag_threshold, increment */
#define FRAG_NEEDED(S,T,I) \
@@ -948,16 +1042,32 @@
if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2))
{
tlv_build_func (*from, lsp->pdu);
- *to = *from;
- *from = NULL;
+ if (listcount (*to) != 0)
+ {
+ struct listnode *node, *nextnode;
+ void *elem;
+
+ for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem))
+ {
+ listnode_add (*to, elem);
+ list_delete_node (*from, node);
+ }
+ }
+ else
+ {
+ list_free (*to);
+ *to = *from;
+ *from = NULL;
+ }
}
else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2))
{
/* fit all we can */
count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 -
(STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu));
- if (count)
- count = count / tlvsize;
+ count = count / tlvsize;
+ if (count > (int)listcount (*from))
+ count = listcount (*from);
for (i = 0; i < count; i++)
{
listnode_add (*to, listgetdata (listhead (*from)));
@@ -969,6 +1079,44 @@
return;
}
+static u_int16_t
+lsp_rem_lifetime (struct isis_area *area, int level)
+{
+ u_int16_t rem_lifetime;
+
+ /* Add jitter to configured LSP lifetime */
+ rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1],
+ MAX_AGE_JITTER);
+
+ /* No jitter if the max refresh will be less than configure gen interval */
+ if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300))
+ rem_lifetime = area->max_lsp_lifetime[level - 1];
+
+ return rem_lifetime;
+}
+
+static u_int16_t
+lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime)
+{
+ struct isis_area *area = lsp->area;
+ int level = lsp->level;
+ u_int16_t refresh_time;
+
+ /* Add jitter to LSP refresh time */
+ refresh_time = isis_jitter (area->lsp_refresh[level - 1],
+ MAX_LSP_GEN_JITTER);
+
+ /* RFC 4444 : make sure the refresh time is at least less than 300
+ * of the remaining lifetime and more than gen interval */
+ if (refresh_time <= area->lsp_gen_interval[level - 1] ||
+ refresh_time > (rem_lifetime - 300))
+ refresh_time = rem_lifetime - 300;
+
+ assert (area->lsp_gen_interval[level - 1] < refresh_time);
+
+ return refresh_time;
+}
+
static struct isis_lsp *
lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,
int level)
@@ -978,40 +1126,21 @@
memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1);
LSP_FRAGMENT (frag_id) = frag_num;
+ /* FIXME add authentication TLV for fragment LSPs */
lsp = lsp_search (frag_id, area->lspdb[level - 1]);
if (lsp)
{
- /*
- * Clear the TLVs, but inherit the authinfo
- */
+ /* Clear the TLVs */
lsp_clear_data (lsp);
- if (lsp0->tlv_data.auth_info.type)
- {
- memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
- sizeof (struct isis_passwd));
- tlv_add_authinfo (lsp->tlv_data.auth_info.type,
- lsp->tlv_data.auth_info.len,
- lsp->tlv_data.auth_info.passwd, lsp->pdu);
- }
return lsp;
}
- lsp = lsp_new (frag_id, area->max_lsp_lifetime[level - 1], 0, area->is_type,
- 0, level);
+ lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0,
+ lsp_bits_generate (level, area->overload_bit), 0, level);
+ lsp->area = area;
lsp->own_lsp = 1;
lsp_insert (lsp, area->lspdb[level - 1]);
listnode_add (lsp0->lspu.frags, lsp);
lsp->lspu.zero_lsp = lsp0;
- /*
- * Copy the authinfo from zero LSP
- */
- if (lsp0->tlv_data.auth_info.type)
- {
- memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info,
- sizeof (struct isis_passwd));
- tlv_add_authinfo (lsp->tlv_data.auth_info.type,
- lsp->tlv_data.auth_info.len,
- lsp->tlv_data.auth_info.passwd, lsp->pdu);
- }
return lsp;
}
@@ -1020,7 +1149,7 @@
* area->lsp_frag_threshold is exceeded.
*/
static void
-lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)
+lsp_build (struct isis_lsp *lsp, struct isis_area *area)
{
struct is_neigh *is_neigh;
struct te_is_neigh *te_is_neigh;
@@ -1037,8 +1166,27 @@
#endif /* HAVE_IPV6 */
struct tlvs tlv_data;
struct isis_lsp *lsp0 = lsp;
- struct isis_passwd *passwd;
struct in_addr *routerid;
+ uint32_t expected = 0, found = 0;
+ uint32_t metric;
+ u_char zero_id[ISIS_SYS_ID_LEN + 1];
+ int retval = ISIS_OK;
+
+ /*
+ * Building the zero lsp
+ */
+ memset (zero_id, 0, ISIS_SYS_ID_LEN + 1);
+
+ /* Reset stream endp. Stream is always there and on every LSP refresh only
+ * TLV part of it is overwritten. So we must seek past header we will not
+ * touch. */
+ stream_reset (lsp->pdu);
+ stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+
+ /*
+ * Add the authentication info if its present
+ */
+ lsp_auth_add (lsp);
/*
* First add the tlvs related to area
@@ -1048,6 +1196,9 @@
if (lsp->tlv_data.area_addrs == NULL)
lsp->tlv_data.area_addrs = list_new ();
list_add_list (lsp->tlv_data.area_addrs, area->area_addrs);
+ if (listcount (lsp->tlv_data.area_addrs) > 0)
+ tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
+
/* Protocols Supported */
if (area->ip_circuits > 0
#ifdef HAVE_IPV6
@@ -1070,7 +1221,9 @@
NLPID_IPV6;
}
#endif /* HAVE_IPV6 */
+ tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
}
+
/* Dynamic Hostname */
if (area->dynhostname)
{
@@ -1080,39 +1233,13 @@
memcpy (lsp->tlv_data.hostname->name, unix_hostname (),
strlen (unix_hostname ()));
lsp->tlv_data.hostname->namelen = strlen (unix_hostname ());
+ tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
}
- /*
- * Building the zero lsp
- */
-
- /* Reset stream endp. Stream is always there and on every LSP refresh only
- * TLV part of it is overwritten. So we must seek past header we will not
- * touch. */
- stream_reset (lsp->pdu);
- stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
-
- /*
- * Add the authentication info if its present
- */
- (level == 1) ? (passwd = &area->area_passwd) :
- (passwd = &area->domain_passwd);
- if (passwd->type)
- {
- memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
- tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
- }
- if (lsp->tlv_data.nlpids)
- tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);
- if (lsp->tlv_data.hostname)
- tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu);
- if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0)
- tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu);
-
/* IPv4 address and TE router ID TLVs. In case of the first one we don't
* follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into
* LSP and this address is same as router id. */
- if (router_id_zebra.s_addr != 0)
+ if (isis->router_id != 0)
{
if (lsp->tlv_data.ipv4_addrs == NULL)
{
@@ -1121,7 +1248,7 @@
}
routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr));
- routerid->s_addr = router_id_zebra.s_addr;
+ routerid->s_addr = isis->router_id;
listnode_add (lsp->tlv_data.ipv4_addrs, routerid);
tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR);
@@ -1131,8 +1258,9 @@
{
lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
sizeof (struct in_addr));
- lsp->tlv_data.router_id->id.s_addr = router_id_zebra.s_addr;
- tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, TE_ROUTER_ID);
+ lsp->tlv_data.router_id->id.s_addr = isis->router_id;
+ tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu,
+ TE_ROUTER_ID);
}
}
@@ -1141,7 +1269,7 @@
#ifdef TOPOLOGY_GENERATE
/* If topology exists (and we create topology for level 1 only), create
* (hardcoded) link to topology. */
- if (area->topology && level == 1)
+ if (area->topology && level == IS_LEVEL_1)
{
if (tlv_data.is_neighs == NULL)
{
@@ -1192,7 +1320,6 @@
(ipv4->prefix.s_addr));
listnode_add (tlv_data.ipv4_int_reachs, ipreach);
}
- tlv_data.ipv4_int_reachs->del = free_tlv;
}
if (area->newmetric)
{
@@ -1220,6 +1347,7 @@
}
}
}
+
#ifdef HAVE_IPV6
/*
* Add IPv6 reachability of this circuit
@@ -1258,7 +1386,7 @@
switch (circuit->circ_type)
{
case CIRCUIT_T_BROADCAST:
- if (level & circuit->circuit_is_type)
+ if (level & circuit->is_type)
{
if (area->oldmetric)
{
@@ -1268,20 +1396,21 @@
tlv_data.is_neighs->del = free_tlv;
}
is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh));
- if (level == 1)
+ if (level == IS_LEVEL_1)
memcpy (is_neigh->neigh_id,
circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
else
memcpy (is_neigh->neigh_id,
circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
is_neigh->metrics = circuit->metrics[level - 1];
- listnode_add (tlv_data.is_neighs, is_neigh);
- tlv_data.is_neighs->del = free_tlv;
+ if (!memcmp (is_neigh->neigh_id, zero_id,
+ ISIS_SYS_ID_LEN + 1))
+ XFREE (MTYPE_ISIS_TLV, is_neigh);
+ else
+ listnode_add (tlv_data.is_neighs, is_neigh);
}
if (area->newmetric)
{
- uint32_t metric;
-
if (tlv_data.te_is_neighs == NULL)
{
tlv_data.te_is_neighs = list_new ();
@@ -1289,21 +1418,22 @@
}
te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
sizeof (struct te_is_neigh));
- if (level == 1)
+ if (level == IS_LEVEL_1)
memcpy (te_is_neigh->neigh_id,
circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
else
memcpy (te_is_neigh->neigh_id,
circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
if (area->oldmetric)
- metric =
- ((htonl(circuit->metrics[level - 1].metric_default) >> 8)
- & 0xffffff);
+ metric = circuit->metrics[level - 1].metric_default;
else
- metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
-
- memcpy (te_is_neigh->te_metric, &metric, 3);
- listnode_add (tlv_data.te_is_neighs, te_is_neigh);
+ metric = circuit->te_metric[level - 1];
+ SET_TE_METRIC(te_is_neigh, metric);
+ if (!memcmp (te_is_neigh->neigh_id, zero_id,
+ ISIS_SYS_ID_LEN + 1))
+ XFREE (MTYPE_ISIS_TLV, te_is_neigh);
+ else
+ listnode_add (tlv_data.te_is_neighs, te_is_neigh);
}
}
break;
@@ -1335,21 +1465,14 @@
te_is_neigh = XCALLOC (MTYPE_ISIS_TLV,
sizeof (struct te_is_neigh));
memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN);
- metric = ((htonl(*circuit->te_metric) >> 8) & 0xffffff);
- memcpy (te_is_neigh->te_metric, &metric, 3);
+ metric = circuit->te_metric[level - 1];
+ SET_TE_METRIC(te_is_neigh, metric);
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
}
}
break;
- case CIRCUIT_T_STATIC_IN:
- zlog_warn ("lsp_area_create: unsupported circuit type");
- break;
- case CIRCUIT_T_STATIC_OUT:
- zlog_warn ("lsp_area_create: unsupported circuit type");
- break;
- case CIRCUIT_T_DA:
- zlog_warn ("lsp_area_create: unsupported circuit type");
- break;
+ case CIRCUIT_T_LOOPBACK:
+ break;
default:
zlog_warn ("lsp_area_create: unknown circuit type");
}
@@ -1367,6 +1490,7 @@
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
+
/* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit()
* for now. lsp_tlv_fit() needs to be fixed to deal with variable length
* TLVs (sub TLVs!). */
@@ -1376,7 +1500,8 @@
lsp->tlv_data.te_ipv4_reachs = list_new ();
lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs,
&lsp->tlv_data.te_ipv4_reachs,
- 9, area->lsp_frag_threshold, tlv_add_te_ipv4_reachs);
+ TE_IPV4_REACH_LEN, area->lsp_frag_threshold,
+ tlv_add_te_ipv4_reachs);
if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs))
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
@@ -1421,87 +1546,99 @@
lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1,
lsp0, area, level);
}
+ lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
free_tlvs (&tlv_data);
+
+ /* Validate the LSP */
+ retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) +
+ ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
+ stream_get_endp (lsp->pdu) -
+ ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
+ &expected, &found, &tlv_data, NULL);
+ assert (retval == ISIS_OK);
+
return;
}
/*
- * 7.3.7 Generation on non-pseudonode LSPs
+ * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs
*/
-static int
-lsp_generate_non_pseudo (struct isis_area *area, int level)
+int
+lsp_generate (struct isis_area *area, int level)
{
struct isis_lsp *oldlsp, *newlsp;
u_int32_t seq_num = 0;
u_char lspid[ISIS_SYS_ID_LEN + 2];
+ u_int16_t rem_lifetime, refresh_time;
+
+ if ((area == NULL) || (area->is_type & level) != level)
+ return ISIS_ERROR;
memset (&lspid, 0, ISIS_SYS_ID_LEN + 2);
memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN);
/* only builds the lsp if the area shares the level */
- if ((area->is_type & level) == level)
+ oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
+ if (oldlsp)
{
- oldlsp = lsp_search (lspid, area->lspdb[level - 1]);
- if (oldlsp)
- {
- seq_num = ntohl (oldlsp->lsp_header->seq_num);
- lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
- area->lspdb[level - 1]);
- /* FIXME: we should actually initiate a purge */
- }
- newlsp = lsp_new (lspid, area->max_lsp_lifetime[level - 1], seq_num,
- area->is_type, 0, level);
- newlsp->own_lsp = 1;
-
- lsp_insert (newlsp, area->lspdb[level - 1]);
- /* build_lsp_data (newlsp, area); */
- lsp_build_nonpseudo (newlsp, area);
- /* time to calculate our checksum */
- lsp_seqnum_update (newlsp);
+ /* FIXME: we should actually initiate a purge */
+ seq_num = ntohl (oldlsp->lsp_header->seq_num);
+ lsp_search_and_destroy (oldlsp->lsp_header->lsp_id,
+ area->lspdb[level - 1]);
}
+ rem_lifetime = lsp_rem_lifetime (area, level);
+ newlsp = lsp_new (lspid, rem_lifetime, seq_num,
+ area->is_type | area->overload_bit, 0, level);
+ newlsp->area = area;
+ newlsp->own_lsp = 1;
- /* DEBUG_ADJ_PACKETS */
- if (isis->debugs & DEBUG_ADJ_PACKETS)
+ lsp_insert (newlsp, area->lspdb[level - 1]);
+ /* build_lsp_data (newlsp, area); */
+ lsp_build (newlsp, area);
+ /* time to calculate our checksum */
+ lsp_seqnum_update (newlsp);
+ lsp_set_all_srmflags (newlsp);
+
+ refresh_time = lsp_refresh_time (newlsp, rem_lifetime);
+ THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]);
+ if (level == IS_LEVEL_1)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+ lsp_l1_refresh, area, refresh_time);
+ else if (level == IS_LEVEL_2)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+ lsp_l2_refresh, area, refresh_time);
+
+ if (isis->debugs & DEBUG_UPDATE_PACKETS)
{
- /* FIXME: is this place right? fix missing info */
- zlog_debug ("ISIS-Upd (%s): Building L%d LSP", area->area_tag, level);
+ zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, "
+ "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
+ area->area_tag, level,
+ rawlspid_print (newlsp->lsp_header->lsp_id),
+ ntohl (newlsp->lsp_header->pdu_len),
+ ntohl (newlsp->lsp_header->seq_num),
+ ntohs (newlsp->lsp_header->checksum),
+ ntohs (newlsp->lsp_header->rem_lifetime),
+ refresh_time);
}
return ISIS_OK;
}
/*
- * 7.3.9 Generation of level 1 LSPs (non-pseudonode)
+ * Search own LSPs, update holding time and set SRM
*/
-int
-lsp_l1_generate (struct isis_area *area)
-{
- THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,
- MAX_LSP_GEN_INTERVAL);
-
- return lsp_generate_non_pseudo (area, 1);
-}
-
-/*
- * 7.3.9 Generation of level 2 LSPs (non-pseudonode)
- */
-int
-lsp_l2_generate (struct isis_area *area)
-{
- THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,
- MAX_LSP_GEN_INTERVAL);
-
- return lsp_generate_non_pseudo (area, 2);
-}
-
static int
-lsp_non_pseudo_regenerate (struct isis_area *area, int level)
+lsp_regenerate (struct isis_area *area, int level)
{
dict_t *lspdb = area->lspdb[level - 1];
struct isis_lsp *lsp, *frag;
struct listnode *node;
u_char lspid[ISIS_SYS_ID_LEN + 2];
+ u_int16_t rem_lifetime, refresh_time;
+
+ if ((area == NULL) || (area->is_type & level) != level)
+ return ISIS_ERROR;
memset (lspid, 0, ISIS_SYS_ID_LEN + 2);
memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
@@ -1510,180 +1647,148 @@
if (!lsp)
{
- zlog_err
- ("ISIS-Upd (%s): lsp_non_pseudo_regenerate(): no L%d LSP found!",
- area->area_tag, level);
-
+ zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
+ area->area_tag, level);
return ISIS_ERROR;
}
lsp_clear_data (lsp);
- lsp_build_nonpseudo (lsp, area);
- lsp->lsp_header->rem_lifetime = htons (isis_jitter
- (area->max_lsp_lifetime[level - 1],
- MAX_AGE_JITTER));
+ lsp_build (lsp, area);
+ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit);
+ rem_lifetime = lsp_rem_lifetime (area, level);
+ lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
lsp_seqnum_update (lsp);
+ lsp->last_generated = time (NULL);
+ lsp_set_all_srmflags (lsp);
+ for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
+ {
+ frag->lsp_header->lsp_bits = lsp_bits_generate (level,
+ area->overload_bit);
+ /* Set the lifetime values of all the fragments to the same value,
+ * so that no fragment expires before the lsp is refreshed.
+ */
+ frag->lsp_header->rem_lifetime = htons (rem_lifetime);
+ lsp_set_all_srmflags (frag);
+ }
+
+ refresh_time = lsp_refresh_time (lsp, rem_lifetime);
+ if (level == IS_LEVEL_1)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+ lsp_l1_refresh, area, refresh_time);
+ else if (level == IS_LEVEL_2)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1],
+ lsp_l2_refresh, area, refresh_time);
+
if (isis->debugs & DEBUG_UPDATE_PACKETS)
{
- zlog_debug ("ISIS-Upd (%s): refreshing our L%d LSP %s, "
- "seq 0x%08x, cksum 0x%04x lifetime %us",
- area->area_tag,
- level,
- rawlspid_print (lsp->lsp_header->lsp_id),
- ntohl (lsp->lsp_header->seq_num),
- ntohs (lsp->lsp_header->checksum),
- ntohs (lsp->lsp_header->rem_lifetime));
+ zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, "
+ "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us",
+ area->area_tag, level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->pdu_len),
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum),
+ ntohs (lsp->lsp_header->rem_lifetime),
+ refresh_time);
}
- lsp->last_generated = time (NULL);
- area->lsp_regenerate_pending[level - 1] = 0;
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
- for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))
- {
- frag->lsp_header->rem_lifetime = htons (isis_jitter
- (area->
- max_lsp_lifetime[level - 1],
- MAX_AGE_JITTER));
- ISIS_FLAGS_SET_ALL (frag->SRMflags);
- }
-
- if (area->ip_circuits)
- isis_spf_schedule (area, level);
-#ifdef HAVE_IPV6
- if (area->ipv6_circuits)
- isis_spf_schedule6 (area, level);
-#endif
return ISIS_OK;
}
/*
- * Done at least every MAX_LSP_GEN_INTERVAL. Search own LSPs, update holding
- * time and set SRM
+ * Something has changed or periodic refresh -> regenerate LSP
*/
-int
-lsp_refresh_l1 (struct thread *thread)
+static int
+lsp_l1_refresh (struct thread *thread)
{
struct isis_area *area;
- unsigned long ref_time;
area = THREAD_ARG (thread);
assert (area);
area->t_lsp_refresh[0] = NULL;
- if (area->is_type & IS_LEVEL_1)
- lsp_non_pseudo_regenerate (area, 1);
+ area->lsp_regenerate_pending[0] = 0;
- ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];
+ if ((area->is_type & IS_LEVEL_1) == 0)
+ return ISIS_ERROR;
- THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area,
- isis_jitter (ref_time, MAX_AGE_JITTER));
-
- return ISIS_OK;
+ return lsp_regenerate (area, IS_LEVEL_1);
}
-int
-lsp_refresh_l2 (struct thread *thread)
+static int
+lsp_l2_refresh (struct thread *thread)
{
struct isis_area *area;
- unsigned long ref_time;
area = THREAD_ARG (thread);
assert (area);
area->t_lsp_refresh[1] = NULL;
- if (area->is_type & IS_LEVEL_2)
- lsp_non_pseudo_regenerate (area, 2);
-
- ref_time = area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : area->lsp_refresh[1];
-
- THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area,
- isis_jitter (ref_time, MAX_AGE_JITTER));
-
- return ISIS_OK;
-}
-
-/*
- * Something has changed -> regenerate LSP
- */
-
-static int
-lsp_l1_regenerate (struct thread *thread)
-{
- struct isis_area *area;
-
- area = THREAD_ARG (thread);
- area->lsp_regenerate_pending[0] = 0;
-
- return lsp_non_pseudo_regenerate (area, 1);
-}
-
-static int
-lsp_l2_regenerate (struct thread *thread)
-{
- struct isis_area *area;
-
- area = THREAD_ARG (thread);
area->lsp_regenerate_pending[1] = 0;
- return lsp_non_pseudo_regenerate (area, 2);
+ if ((area->is_type & IS_LEVEL_2) == 0)
+ return ISIS_ERROR;
+
+ return lsp_regenerate (area, IS_LEVEL_2);
}
int
-lsp_regenerate_schedule (struct isis_area *area)
+lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo)
{
struct isis_lsp *lsp;
u_char id[ISIS_SYS_ID_LEN + 2];
time_t now, diff;
+ struct listnode *cnode;
+ struct isis_circuit *circuit;
+ int lvl;
+
+ if (area == NULL)
+ return ISIS_ERROR;
+
memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0;
now = time (NULL);
- /*
- * First level 1
- */
- if (area->is_type & IS_LEVEL_1)
+
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
{
- lsp = lsp_search (id, area->lspdb[0]);
- if (!lsp || area->lsp_regenerate_pending[0])
- goto L2;
+ if (!((level & lvl) && (area->is_type & lvl)))
+ continue;
+
+ if (area->lsp_regenerate_pending[lvl - 1])
+ continue;
+
+ lsp = lsp_search (id, area->lspdb[lvl - 1]);
+ if (!lsp)
+ continue;
+
/*
* Throttle avoidance
*/
+ THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]);
diff = now - lsp->last_generated;
- if (diff < MIN_LSP_GEN_INTERVAL)
- {
- area->lsp_regenerate_pending[0] = 1;
- area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area,
- MIN_LSP_GEN_INTERVAL - diff);
- goto L2;
- }
+ if (diff < area->lsp_gen_interval[lvl - 1])
+ {
+ area->lsp_regenerate_pending[lvl - 1] = 1;
+ if (lvl == IS_LEVEL_1)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
+ lsp_l1_refresh, area,
+ area->lsp_gen_interval[lvl - 1] - diff);
+ else if (lvl == IS_LEVEL_2)
+ THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1],
+ lsp_l2_refresh, area,
+ area->lsp_gen_interval[lvl - 1] - diff);
+ }
else
- lsp_non_pseudo_regenerate (area, 1);
+ {
+ lsp_regenerate (area, lvl);
+ }
}
- /*
- * then 2
- */
-L2:
- if (area->is_type & IS_LEVEL_2)
+
+ if (all_pseudo)
{
- lsp = lsp_search (id, area->lspdb[1]);
- if (!lsp || area->lsp_regenerate_pending[1])
- return ISIS_OK;
- /*
- * Throttle avoidance
- */
- diff = now - lsp->last_generated;
- if (diff < MIN_LSP_GEN_INTERVAL)
- {
- area->lsp_regenerate_pending[1] = 1;
- area->t_lsp_l2_regenerate=thread_add_timer (master, lsp_l2_regenerate, area,
- MIN_LSP_GEN_INTERVAL - diff);
- return ISIS_OK;
- }
- else
- lsp_non_pseudo_regenerate (area, 2);
+ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
+ lsp_regenerate_schedule_pseudo (circuit, level);
}
return ISIS_OK;
@@ -1706,19 +1811,10 @@
struct es_neigh *es_neigh;
struct list *adj_list;
struct listnode *node;
- struct isis_passwd *passwd;
-
- assert (circuit);
- assert (circuit->circ_type == CIRCUIT_T_BROADCAST);
-
- if (!circuit->u.bc.is_dr[level - 1])
- return; /* we are not DIS on this circuit */
lsp->level = level;
- if (level == 1)
- lsp->lsp_header->lsp_bits |= IS_LEVEL_1;
- else
- lsp->lsp_header->lsp_bits |= IS_LEVEL_2;
+ /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
+ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0);
/*
* add self to IS neighbours
@@ -1753,12 +1849,12 @@
for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj))
{
- if (adj->circuit_t & level)
+ if (adj->level & level)
{
- if ((level == 1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
- (level == 1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
+ if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) ||
+ (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS &&
adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
- (level == 2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
+ (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS))
{
/* an IS neighbour -> add it */
if (circuit->area->oldmetric)
@@ -1776,7 +1872,7 @@
listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh);
}
}
- else if (level == 1 && adj->sys_type == ISIS_SYSTYPE_ES)
+ else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES)
{
/* an ES neigbour add it, if we are building level 1 LSP */
/* FIXME: the tlv-format is hard to use here */
@@ -1792,6 +1888,7 @@
}
}
}
+ list_delete (adj_list);
/* Reset endp of stream to overwrite only TLV part of it. */
stream_reset (lsp->pdu);
@@ -1800,13 +1897,7 @@
/*
* Add the authentication info if it's present
*/
- (level == 1) ? (passwd = &circuit->area->area_passwd) :
- (passwd = &circuit->area->domain_passwd);
- if (passwd->type)
- {
- memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd));
- tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu);
- }
+ lsp_auth_add (lsp);
if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0)
tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu);
@@ -1818,20 +1909,89 @@
tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
- fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
- ntohs (lsp->lsp_header->pdu_len) - 12, 12);
- list_delete (adj_list);
+ /* Recompute authentication and checksum information */
+ lsp_auth_update (lsp);
+ fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+ ntohs (lsp->lsp_header->pdu_len) - 12, 12);
return;
}
-static int
-lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)
+int
+lsp_generate_pseudo (struct isis_circuit *circuit, int level)
{
dict_t *lspdb = circuit->area->lspdb[level - 1];
struct isis_lsp *lsp;
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+ u_int16_t rem_lifetime, refresh_time;
+
+ if ((circuit->is_type & level) != level ||
+ (circuit->state != C_STATE_UP) ||
+ (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
+ (circuit->u.bc.is_dr[level - 1] == 0))
+ return ISIS_ERROR;
+
+ memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_FRAGMENT (lsp_id) = 0;
+ LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
+
+ /*
+ * If for some reason have a pseudo LSP in the db already -> regenerate
+ */
+ if (lsp_search (lsp_id, lspdb))
+ return lsp_regenerate_schedule_pseudo (circuit, level);
+
+ rem_lifetime = lsp_rem_lifetime (circuit->area, level);
+ /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
+ lsp = lsp_new (lsp_id, rem_lifetime, 1, circuit->area->is_type, 0, level);
+ lsp->area = circuit->area;
+
+ lsp_build_pseudo (lsp, circuit, level);
+
+ lsp->own_lsp = 1;
+ lsp_insert (lsp, lspdb);
+ lsp_set_all_srmflags (lsp);
+
+ refresh_time = lsp_refresh_time (lsp, rem_lifetime);
+ THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]);
+ circuit->lsp_regenerate_pending[level - 1] = 0;
+ if (level == IS_LEVEL_1)
+ THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+ lsp_l1_refresh_pseudo, circuit, refresh_time);
+ else if (level == IS_LEVEL_2)
+ THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+ lsp_l2_refresh_pseudo, circuit, refresh_time);
+
+ if (isis->debugs & DEBUG_UPDATE_PACKETS)
+ {
+ zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, "
+ "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+ circuit->area->area_tag, level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->pdu_len),
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum),
+ ntohs (lsp->lsp_header->rem_lifetime),
+ refresh_time);
+ }
+
+ return ISIS_OK;
+}
+
+static int
+lsp_regenerate_pseudo (struct isis_circuit *circuit, int level)
+{
+ dict_t *lspdb = circuit->area->lspdb[level - 1];
+ struct isis_lsp *lsp;
+ u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+ u_int16_t rem_lifetime, refresh_time;
+
+ if ((circuit->is_type & level) != level ||
+ (circuit->state != C_STATE_UP) ||
+ (circuit->circ_type != CIRCUIT_T_BROADCAST) ||
+ (circuit->u.bc.is_dr[level - 1] == 0))
+ return ISIS_ERROR;
memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
@@ -1841,151 +2001,154 @@
if (!lsp)
{
- zlog_err ("lsp_pseudo_regenerate(): no l%d LSP %s found!", level,
- rawlspid_print (lsp_id));
+ zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!",
+ level, rawlspid_print (lsp_id));
return ISIS_ERROR;
}
lsp_clear_data (lsp);
lsp_build_pseudo (lsp, circuit, level);
- lsp->lsp_header->rem_lifetime =
- htons (isis_jitter (circuit->area->max_lsp_lifetime[level - 1],
- MAX_AGE_JITTER));
-
+ /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */
+ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0);
+ rem_lifetime = lsp_rem_lifetime (circuit->area, level);
+ lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
lsp_inc_seqnum (lsp, 0);
+ lsp->last_generated = time (NULL);
+ lsp_set_all_srmflags (lsp);
+
+ refresh_time = lsp_refresh_time (lsp, rem_lifetime);
+ if (level == IS_LEVEL_1)
+ THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+ lsp_l1_refresh_pseudo, circuit, refresh_time);
+ else if (level == IS_LEVEL_2)
+ THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1],
+ lsp_l2_refresh_pseudo, circuit, refresh_time);
if (isis->debugs & DEBUG_UPDATE_PACKETS)
{
- zlog_debug ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s",
- circuit->area->area_tag, level,
- rawlspid_print (lsp->lsp_header->lsp_id));
+ zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, "
+ "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us",
+ circuit->area->area_tag, level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->pdu_len),
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum),
+ ntohs (lsp->lsp_header->rem_lifetime),
+ refresh_time);
}
- lsp->last_generated = time (NULL);
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-
return ISIS_OK;
}
-int
+/*
+ * Something has changed or periodic refresh -> regenerate pseudo LSP
+ */
+static int
lsp_l1_refresh_pseudo (struct thread *thread)
{
struct isis_circuit *circuit;
- int retval;
- unsigned long ref_time;
+ u_char id[ISIS_SYS_ID_LEN + 2];
circuit = THREAD_ARG (thread);
- if (!circuit->u.bc.is_dr[0])
- return ISIS_ERROR; /* FIXME: purge and such */
-
circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL;
+ circuit->lsp_regenerate_pending[0] = 0;
- retval = lsp_pseudo_regenerate (circuit, 1);
+ if ((circuit->u.bc.is_dr[0] == 0) ||
+ (circuit->is_type & IS_LEVEL_1) == 0)
+ {
+ memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (id) = circuit->circuit_id;
+ LSP_FRAGMENT (id) = 0;
+ lsp_purge_pseudo (id, circuit, IS_LEVEL_1);
+ return ISIS_ERROR;
+ }
- ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
-
- THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0],
- lsp_l1_refresh_pseudo, circuit,
- isis_jitter (ref_time, MAX_AGE_JITTER));
-
- return retval;
+ return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);
}
-int
-lsp_l1_pseudo_generate (struct isis_circuit *circuit)
-{
- struct isis_lsp *lsp;
- u_char id[ISIS_SYS_ID_LEN + 2];
- unsigned long ref_time;
-
- memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
- LSP_FRAGMENT (id) = 0;
- LSP_PSEUDO_ID (id) = circuit->circuit_id;
-
- /*
- * If for some reason have a pseudo LSP in the db already -> regenerate
- */
- if (lsp_search (id, circuit->area->lspdb[0]))
- return lsp_pseudo_regenerate (circuit, 1);
- lsp = lsp_new (id, circuit->area->max_lsp_lifetime[0],
- 1, circuit->area->is_type, 0, 1);
-
- lsp_build_pseudo (lsp, circuit, 1);
-
- lsp->own_lsp = 1;
- lsp_insert (lsp, circuit->area->lspdb[0]);
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-
- ref_time = circuit->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[0];
-
- THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[0],
- lsp_l1_refresh_pseudo, circuit,
- isis_jitter (ref_time, MAX_AGE_JITTER));
-
- return lsp_regenerate_schedule (circuit->area);
-}
-
-int
+static int
lsp_l2_refresh_pseudo (struct thread *thread)
{
struct isis_circuit *circuit;
- int retval;
- unsigned long ref_time;
+ u_char id[ISIS_SYS_ID_LEN + 2];
+
circuit = THREAD_ARG (thread);
- if (!circuit->u.bc.is_dr[1])
- return ISIS_ERROR; /* FIXME: purge and such */
-
circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL;
+ circuit->lsp_regenerate_pending[1] = 0;
- retval = lsp_pseudo_regenerate (circuit, 2);
+ if ((circuit->u.bc.is_dr[1] == 0) ||
+ (circuit->is_type & IS_LEVEL_2) == 0)
+ {
+ memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (id) = circuit->circuit_id;
+ LSP_FRAGMENT (id) = 0;
+ lsp_purge_pseudo (id, circuit, IS_LEVEL_2);
+ return ISIS_ERROR;
+ }
- ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
-
- THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1],
- lsp_l2_refresh_pseudo, circuit,
- isis_jitter (ref_time, MAX_AGE_JITTER));
-
- return retval;
+ return lsp_regenerate_pseudo (circuit, IS_LEVEL_2);
}
int
-lsp_l2_pseudo_generate (struct isis_circuit *circuit)
+lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level)
{
struct isis_lsp *lsp;
- u_char id[ISIS_SYS_ID_LEN + 2];
- unsigned long ref_time;
+ u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+ time_t now, diff;
+ int lvl;
- memcpy (id, isis->sysid, ISIS_SYS_ID_LEN);
- LSP_FRAGMENT (id) = 0;
- LSP_PSEUDO_ID (id) = circuit->circuit_id;
+ if (circuit == NULL ||
+ circuit->circ_type != CIRCUIT_T_BROADCAST ||
+ circuit->state != C_STATE_UP)
+ return ISIS_OK;
- if (lsp_search (id, circuit->area->lspdb[1]))
- return lsp_pseudo_regenerate (circuit, 2);
+ memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id;
+ LSP_FRAGMENT (lsp_id) = 0;
+ now = time (NULL);
- lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1],
- 1, circuit->area->is_type, 0, 2);
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
+ {
+ if (!((level & lvl) && (circuit->is_type & lvl)))
+ continue;
- lsp_build_pseudo (lsp, circuit, 2);
+ if (circuit->u.bc.is_dr[lvl - 1] == 0 ||
+ circuit->lsp_regenerate_pending[lvl - 1])
+ continue;
- ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1];
+ lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]);
+ if (!lsp)
+ continue;
+ /*
+ * Throttle avoidance
+ */
+ THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]);
+ diff = now - lsp->last_generated;
+ if (diff < circuit->area->lsp_gen_interval[lvl - 1])
+ {
+ circuit->lsp_regenerate_pending[lvl - 1] = 1;
+ if (lvl == IS_LEVEL_1)
+ THREAD_TIMER_ON (master,
+ circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
+ lsp_l1_refresh_pseudo, circuit,
+ circuit->area->lsp_gen_interval[lvl - 1] - diff);
+ else if (lvl == IS_LEVEL_2)
+ THREAD_TIMER_ON (master,
+ circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1],
+ lsp_l2_refresh_pseudo, circuit,
+ circuit->area->lsp_gen_interval[lvl - 1] - diff);
+ }
+ else
+ {
+ lsp_regenerate_pseudo (circuit, lvl);
+ }
+ }
- lsp->own_lsp = 1;
- lsp_insert (lsp, circuit->area->lspdb[1]);
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
-
- THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1],
- lsp_l2_refresh_pseudo, circuit,
- isis_jitter (ref_time, MAX_AGE_JITTER));
-
- return lsp_regenerate_schedule (circuit->area);
+ return ISIS_OK;
}
/*
@@ -2003,6 +2166,7 @@
struct listnode *lspnode, *cnode;
dnode_t *dnode, *dnode_next;
int level;
+ u_int16_t rem_lifetime;
lsp_list = list_new ();
@@ -2018,56 +2182,87 @@
for (level = 0; level < ISIS_LEVELS; level++)
{
if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
- {
- dnode = dict_first (area->lspdb[level]);
- while (dnode != NULL)
- {
- dnode_next = dict_next (area->lspdb[level], dnode);
- lsp = dnode_get (dnode);
- lsp_set_time (lsp);
- if (lsp->age_out == 0)
- {
+ {
+ for (dnode = dict_first (area->lspdb[level]);
+ dnode != NULL; dnode = dnode_next)
+ {
+ dnode_next = dict_next (area->lspdb[level], dnode);
+ lsp = dnode_get (dnode);
- zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
- area->area_tag,
- lsp->level,
- rawlspid_print (lsp->lsp_header->lsp_id),
- ntohl (lsp->lsp_header->seq_num));
+ /*
+ * The lsp rem_lifetime is kept at 0 for MaxAge or
+ * ZeroAgeLifetime depending on explicit purge or
+ * natural age out. So schedule spf only once when
+ * the first time rem_lifetime becomes 0.
+ */
+ rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime);
+ lsp_set_time (lsp);
+
+ /*
+ * Schedule may run spf which should be done only after
+ * the lsp rem_lifetime becomes 0 for the first time.
+ * ISO 10589 - 7.3.16.4 first paragraph.
+ */
+ if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0)
+ {
+ /* 7.3.16.4 a) set SRM flags on all */
+ lsp_set_all_srmflags (lsp);
+ /* 7.3.16.4 b) retain only the header FIXME */
+ /* 7.3.16.4 c) record the time to purge FIXME */
+ /* run/schedule spf */
+ /* isis_spf_schedule is called inside lsp_destroy() below;
+ * so it is not needed here. */
+ /* isis_spf_schedule (lsp->area, lsp->level); */
+ }
+
+ if (lsp->age_out == 0)
+ {
+ zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out",
+ area->area_tag,
+ lsp->level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->seq_num));
#ifdef TOPOLOGY_GENERATE
- if (lsp->from_topology)
- THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
+ if (lsp->from_topology)
+ THREAD_TIMER_OFF (lsp->t_lsp_top_ref);
#endif /* TOPOLOGY_GENERATE */
- lsp_destroy (lsp);
- dict_delete (area->lspdb[level], dnode);
- }
- else if (flags_any_set (lsp->SRMflags))
- listnode_add (lsp_list, lsp);
- dnode = dnode_next;
- }
+ lsp_destroy (lsp);
+ lsp = NULL;
+ dict_delete_free (area->lspdb[level], dnode);
+ }
+ else if (flags_any_set (lsp->SRMflags))
+ listnode_add (lsp_list, lsp);
+ }
- /*
- * Send LSPs on circuits indicated by the SRMflags
- */
- if (listcount (lsp_list) > 0)
- {
+ /*
+ * Send LSPs on circuits indicated by the SRMflags
+ */
+ if (listcount (lsp_list) > 0)
+ {
for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
- {
- if (circuit->state != C_STATE_UP)
- continue;
+ {
+ int diff = time (NULL) - circuit->lsp_queue_last_cleared;
+ if (circuit->lsp_queue == NULL ||
+ diff < MIN_LSP_TRANS_INTERVAL)
+ continue;
for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp))
- {
- if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
- {
- /* FIXME: if same or elder lsp is already in lsp
- * queue */
- listnode_add (circuit->lsp_queue, lsp);
- thread_add_event (master, send_lsp, circuit, 0);
- }
- }
- }
- }
- list_delete_all_node (lsp_list);
- }
+ {
+ if (circuit->upadjcount[lsp->level - 1] &&
+ ISIS_CHECK_FLAG (lsp->SRMflags, circuit))
+ {
+ /* Add the lsp only if it is not already in lsp
+ * queue */
+ if (! listnode_lookup (circuit->lsp_queue, lsp))
+ {
+ listnode_add (circuit->lsp_queue, lsp);
+ thread_add_event (master, send_lsp, circuit, 0);
+ }
+ }
+ }
+ }
+ list_delete_all_node (lsp_list);
+ }
+ }
}
list_delete (lsp_list);
@@ -2076,22 +2271,45 @@
}
void
-lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level)
+lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level)
{
struct isis_lsp *lsp;
+ u_int16_t seq_num;
+ u_int8_t lsp_bits;
lsp = lsp_search (id, circuit->area->lspdb[level - 1]);
+ if (!lsp)
+ return;
- if (lsp && lsp->purged == 0)
- {
- lsp->lsp_header->rem_lifetime = htons (0);
- lsp->lsp_header->pdu_len =
- htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
- lsp->purged = 0;
- fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
- ntohs (lsp->lsp_header->pdu_len) - 12, 12);
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
- }
+ /* store old values */
+ seq_num = lsp->lsp_header->seq_num;
+ lsp_bits = lsp->lsp_header->lsp_bits;
+
+ /* reset stream */
+ lsp_clear_data (lsp);
+ stream_reset (lsp->pdu);
+
+ /* update header */
+ lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+ memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2);
+ lsp->lsp_header->checksum = 0;
+ lsp->lsp_header->seq_num = seq_num;
+ lsp->lsp_header->rem_lifetime = 0;
+ lsp->lsp_header->lsp_bits = lsp_bits;
+ lsp->level = level;
+ lsp->age_out = lsp->area->max_lsp_lifetime[level-1];
+ stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+
+ /*
+ * Add and update the authentication info if its present
+ */
+ lsp_auth_add (lsp);
+ lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
+ lsp_auth_update (lsp);
+ fletcher_checksum(STREAM_DATA (lsp->pdu) + 12,
+ ntohs (lsp->lsp_header->pdu_len) - 12, 12);
+
+ lsp_set_all_srmflags (lsp);
return;
}
@@ -2109,27 +2327,36 @@
/*
* We need to create the LSP to be purged
*/
- zlog_debug ("LSP PURGE NON EXIST");
lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp));
- /*FIXME: BUG BUG BUG! the lsp doesn't exist here! */
- /*did smt here, maybe good probably not */
- lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2;
- lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
+ lsp->area = area;
+ lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ?
+ IS_LEVEL_1 : IS_LEVEL_2;
+ /* FIXME: Should be minimal mtu? */
+ lsp->pdu = stream_new (1500);
lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu);
- fill_fixed_hdr (lsp->isis_header, (lsp->level == 1) ? L1_LINK_STATE
+ fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE
: L2_LINK_STATE);
lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) +
ISIS_FIXED_HDR_LEN);
memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN);
+ stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
/*
- * Retain only LSP header
- */
- lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
- /*
* Set the remaining lifetime to 0
*/
lsp->lsp_header->rem_lifetime = 0;
+
+ /*
+ * Add and update the authentication info if its present
+ */
+ lsp_auth_add (lsp);
+ lsp_auth_update (lsp);
+
+ /*
+ * Update the PDU length to header plus any authentication TLV.
+ */
+ lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
+
/*
* Put the lsp into LSPdb
*/
@@ -2138,17 +2365,36 @@
/*
* Send in to whole area
*/
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ lsp_set_all_srmflags (lsp);
return;
}
+void lsp_set_all_srmflags (struct isis_lsp *lsp)
+{
+ struct listnode *node;
+ struct isis_circuit *circuit;
+
+ assert (lsp);
+
+ ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags);
+
+ if (lsp->area)
+ {
+ struct list *circuit_list = lsp->area->circuit_list;
+ for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit))
+ {
+ ISIS_SET_FLAG(lsp->SRMflags, circuit);
+ }
+ }
+}
+
#ifdef TOPOLOGY_GENERATE
static int
top_lsp_refresh (struct thread *thread)
{
struct isis_lsp *lsp;
- unsigned long ref_time;
+ u_int16_t rem_lifetime, refresh_time;
lsp = THREAD_ARG (thread);
assert (lsp);
@@ -2157,7 +2403,7 @@
lsp_seqnum_update (lsp);
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ lsp_set_all_srmflags (lsp);
if (isis->debugs & DEBUG_UPDATE_PACKETS)
{
zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s",
@@ -2167,14 +2413,14 @@
isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname,
IS_LEVEL_1);
- lsp->lsp_header->rem_lifetime =
- htons (isis_jitter (lsp->area->max_lsp_lifetime[0], MAX_AGE_JITTER));
+ lsp->lsp_header->lsp_bits = lsp_bits_generate (level,
+ lsp->area->overload_bit);
+ rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1);
+ lsp->lsp_header->rem_lifetime = htons (rem_lifetime);
- ref_time = lsp->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : lsp->area->lsp_refresh[0];
-
+ refresh_time = lsp_refresh_time (lsp, rem_lifetime);
THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
- isis_jitter (ref_time, MAX_LSP_GEN_JITTER));
+ lsp->area->lsp_refresh[0]);
return ISIS_OK;
}
@@ -2187,16 +2433,16 @@
struct arc *arc;
u_char lspid[ISIS_SYS_ID_LEN + 2];
struct isis_lsp *lsp;
- unsigned long ref_time;
+ u_int16_t rem_lifetime, refresh_time;
/* first we find the maximal node */
for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc))
- {
- if (arc->from_node > max)
- max = arc->from_node;
- if (arc->to_node > max)
- max = arc->to_node;
- }
+ {
+ if (arc->from_node > max)
+ max = arc->from_node;
+ if (arc->to_node > max)
+ max = arc->to_node;
+ }
for (i = 1; i < (max + 1); i++)
{
@@ -2206,12 +2452,13 @@
lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF);
lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF);
- lsp = lsp_new (lspid, isis_jitter (area->max_lsp_lifetime[0],
- MAX_AGE_JITTER), 1, IS_LEVEL_1, 0, 1);
+ rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1);
+ lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit,
+ 0, 1);
if (!lsp)
return;
- lsp->from_topology = 1;
lsp->area = area;
+ lsp->from_topology = 1;
/* Creating LSP data based on topology info. */
build_topology_lsp_data (lsp, area, i);
@@ -2220,12 +2467,10 @@
/* Take care of inserting dynamic hostname into cache. */
isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1);
- ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ?
- MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0];
-
+ refresh_time = lsp_refresh_time (lsp, rem_lifetime);
THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp,
- isis_jitter (ref_time, MAX_LSP_GEN_JITTER));
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ refresh_time);
+ lsp_set_all_srmflags (lsp);
lsp_insert (lsp, area->lspdb[0]);
}
}
@@ -2342,8 +2587,6 @@
if (area->newmetric)
{
- uint32_t metric;
-
if (tlv_data.te_is_neighs == NULL)
{
tlv_data.te_is_neighs = list_new ();
@@ -2354,8 +2597,7 @@
ISIS_SYS_ID_LEN);
te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF);
te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF);
- metric = ((htonl(arc->distance) >> 8) & 0xffffff);
- memcpy (te_is_neigh->te_metric, &metric, 3);
+ SET_TE_METRIC(te_is_neigh, arc->distance);
listnode_add (tlv_data.te_is_neighs, te_is_neigh);
}
}
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index 8d648d0..6e7f745 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -24,10 +24,6 @@
#ifndef _ZEBRA_ISIS_LSP_H
#define _ZEBRA_ISIS_LSP_H
-/* The grand plan is to support 1024 circuits so we have 32*32 bit flags
- * the support will be achived using the newest drafts */
-#define ISIS_MAX_CIRCUITS 32 /* = 1024 - FIXME:defined in flags.h as well */
-
/* Structure for isis_lsp, this structure will only support the fixed
* System ID (Currently 6) (atleast for now). In order to support more
* We will have to split the header into two parts, and for readability
@@ -42,15 +38,13 @@
struct list *frags;
struct isis_lsp *zero_lsp;
} lspu;
+ u_int32_t auth_tlv_offset; /* authentication TLV position in the pdu */
u_int32_t SRMflags[ISIS_MAX_CIRCUITS];
u_int32_t SSNflags[ISIS_MAX_CIRCUITS];
- u_int32_t rexmit_queue[ISIS_MAX_CIRCUITS];
int level; /* L1 or L2? */
- int purged; /* have purged this one */
int scheduled; /* scheduled for sending */
time_t installed;
time_t last_generated;
- time_t last_sent;
int own_lsp;
#ifdef TOPOLOGY_GENERATE
int from_topology;
@@ -58,7 +52,6 @@
#endif
/* used for 60 second counting when rem_lifetime is zero */
int age_out;
- /* FIXME: For now only topology LSP's use this. Is it helpful for others? */
struct isis_area *area;
struct tlvs tlv_data; /* Simplifies TLV access */
};
@@ -67,37 +60,32 @@
void lsp_db_destroy (dict_t * lspdb);
int lsp_tick (struct thread *thread);
-int lsp_l1_generate (struct isis_area *area);
-int lsp_l2_generate (struct isis_area *area);
-int lsp_refresh_l1 (struct thread *thread);
-int lsp_refresh_l2 (struct thread *thread);
-int lsp_regenerate_schedule (struct isis_area *area);
+int lsp_generate (struct isis_area *area, int level);
+int lsp_regenerate_schedule (struct isis_area *area, int level,
+ int all_pseudo);
+int lsp_generate_pseudo (struct isis_circuit *circuit, int level);
+int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level);
-int lsp_l1_pseudo_generate (struct isis_circuit *circuit);
-int lsp_l2_pseudo_generate (struct isis_circuit *circuit);
-int lsp_l1_refresh_pseudo (struct thread *thread);
-int lsp_l2_refresh_pseudo (struct thread *thread);
-int isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
- int pdulen, struct isis_passwd *passwd);
struct isis_lsp *lsp_new (u_char * lsp_id, u_int16_t rem_lifetime,
u_int32_t seq_num, u_int8_t lsp_bits,
u_int16_t checksum, int level);
struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream,
u_int16_t pdu_len,
struct isis_lsp *lsp0,
- struct isis_area *area);
+ struct isis_area *area,
+ int level);
void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb);
struct isis_lsp *lsp_search (u_char * id, dict_t * lspdb);
-void lsp_build_list (u_char * start_id, u_char * stop_id,
+void lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps,
struct list *list, dict_t * lspdb);
void lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,
struct list *list, dict_t * lspdb);
-void lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,
- dict_t * lspdb);
+void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps,
+ struct list *list, dict_t * lspdb);
void lsp_search_and_destroy (u_char * id, dict_t * lspdb);
-void lsp_purge_dr (u_char * id, struct isis_circuit *circuit, int level);
+void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level);
void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,
struct isis_area *area);
@@ -114,13 +102,18 @@
int lsp_id_cmp (u_char * id1, u_char * id2);
int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,
u_int16_t checksum, u_int16_t rem_lifetime);
-void lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr,
- struct stream *stream, struct isis_area *area, int level);
+void lsp_update (struct isis_lsp *lsp, struct stream *stream,
+ struct isis_area *area, int level);
void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num);
+void lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost);
+void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost);
int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail,
char dynhost);
const char *lsp_bits2string (u_char *);
+/* sets SRMflags for all active circuits of an lsp */
+void lsp_set_all_srmflags (struct isis_lsp *lsp);
+
#ifdef TOPOLOGY_GENERATE
void generate_topology_lsps (struct isis_area *area);
void remove_topology_lsps (struct isis_area *area);
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 15d85d6..f5266aa 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -44,6 +44,9 @@
#include "isisd/isis_circuit.h"
#include "isisd/isisd.h"
#include "isisd/isis_dynhn.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_route.h"
+#include "isisd/isis_zebra.h"
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
@@ -67,7 +70,7 @@
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
- .cap_num_p = 2,
+ .cap_num_p = sizeof (_caps_p) / sizeof (*_caps_p),
.cap_num_i = 0
};
@@ -154,7 +157,10 @@
zlog_debug ("Reload");
/* FIXME: Clean up func call here */
vty_reset ();
+ (void) isisd_privs.change (ZPRIVS_RAISE);
execve (_progpath, _argv, _envp);
+ zlog_err ("Reload failed: cannot exec %s: %s", _progpath,
+ safe_strerror (errno));
}
static void
@@ -325,28 +331,31 @@
memory_init ();
access_list_init();
isis_init ();
- dyn_cache_init ();
+ isis_circuit_init ();
+ isis_spf_cmds_init ();
+
+ /* create the global 'isis' instance */
+ isis_new (1);
+
+ isis_zebra_init ();
+
sort_node ();
/* parse config file */
/* this is needed three times! because we have interfaces before the areas */
vty_read_config (config_file, config_default);
- vty_read_config (config_file, config_default);
- vty_read_config (config_file, config_default);
/* Start execution only if not in dry-run mode */
if (dryrun)
return(0);
/* demonize */
- if (daemon_mode && daemon (0, 0) < 0)
- {
- zlog_err("ISISd daemon failed: %s", strerror(errno));
- exit (1);
- }
+ if (daemon_mode)
+ daemon (0, 0);
/* Process ID file creation. */
- pid_output (pid_file);
+ if (pid_file[0] != '\0')
+ pid_output (pid_file);
/* Make isis vty socket. */
vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH);
diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c
index 6b565bc..968fa05 100644
--- a/isisd/isis_misc.c
+++ b/isisd/isis_misc.c
@@ -32,7 +32,9 @@
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
+#include "isisd/isis_csm.h"
#include "isisd/isisd.h"
#include "isisd/isis_misc.h"
@@ -40,6 +42,7 @@
#include "isisd/isis_lsp.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dynhn.h"
/* staticly assigned vars for printing purposes */
struct in_addr new_prefix;
@@ -99,10 +102,10 @@
* extract dot from the dotted str, and insert all the number in a buff
*/
int
-dotformat2buff (u_char * buff, const u_char * dotted)
+dotformat2buff (u_char * buff, const char * dotted)
{
int dotlen, len = 0;
- const u_char *pos = dotted;
+ const char *pos = dotted;
u_char number[3];
int nextdotpos = 2;
@@ -157,10 +160,10 @@
* conversion of XXXX.XXXX.XXXX to memory
*/
int
-sysid2buff (u_char * buff, const u_char * dotted)
+sysid2buff (u_char * buff, const char * dotted)
{
int len = 0;
- const u_char *pos = dotted;
+ const char *pos = dotted;
u_char number[3];
number[2] = '\0';
@@ -271,7 +274,7 @@
* Returns 0 on error, IS-IS Circuit Type on ok
*/
int
-string2circuit_t (const u_char * str)
+string2circuit_t (const char * str)
{
if (!str)
@@ -290,6 +293,42 @@
}
const char *
+circuit_state2string (int state)
+{
+
+ switch (state)
+ {
+ case C_STATE_INIT:
+ return "Init";
+ case C_STATE_CONF:
+ return "Config";
+ case C_STATE_UP:
+ return "Up";
+ default:
+ return "Unknown";
+ }
+ return NULL;
+}
+
+const char *
+circuit_type2string (int type)
+{
+
+ switch (type)
+ {
+ case CIRCUIT_T_P2P:
+ return "p2p";
+ case CIRCUIT_T_BROADCAST:
+ return "lan";
+ case CIRCUIT_T_LOOPBACK:
+ return "loopback";
+ default:
+ return "Unknown";
+ }
+ return NULL;
+}
+
+const char *
circuit_t2string (int circuit_t)
{
switch (circuit_t)
@@ -498,7 +537,6 @@
{
static struct utsname names;
const char *hostname;
- extern struct host host;
hostname = host.name;
if (!hostname)
@@ -509,3 +547,87 @@
return hostname;
}
+
+/*
+ * Returns the dynamic hostname associated with the passed system ID.
+ * If no dynamic hostname found then returns formatted system ID.
+ */
+const char *
+print_sys_hostname (u_char *sysid)
+{
+ struct isis_dynhn *dyn;
+
+ if (!sysid)
+ return "nullsysid";
+
+ /* For our system ID return our host name */
+ if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
+ return unix_hostname();
+
+ dyn = dynhn_find_by_id (sysid);
+ if (dyn)
+ return (const char *)dyn->name.name;
+
+ return sysid_print (sysid);
+}
+
+/*
+ * This function is a generic utility that logs data of given length.
+ * Move this to a shared lib so that any protocol can use it.
+ */
+void
+zlog_dump_data (void *data, int len)
+{
+ int i;
+ unsigned char *p;
+ unsigned char c;
+ char bytestr[4];
+ char addrstr[10];
+ char hexstr[ 16*3 + 5];
+ char charstr[16*1 + 5];
+
+ p = data;
+ memset (bytestr, 0, sizeof(bytestr));
+ memset (addrstr, 0, sizeof(addrstr));
+ memset (hexstr, 0, sizeof(hexstr));
+ memset (charstr, 0, sizeof(charstr));
+
+ for (i = 1; i <= len; i++)
+ {
+ c = *p;
+ if (isalnum (c) == 0)
+ c = '.';
+
+ /* store address for this line */
+ if ((i % 16) == 1)
+ snprintf (addrstr, sizeof(addrstr), "%p", p);
+
+ /* store hex str (for left side) */
+ snprintf (bytestr, sizeof (bytestr), "%02X ", *p);
+ strncat (hexstr, bytestr, sizeof (hexstr) - strlen (hexstr) - 1);
+
+ /* store char str (for right side) */
+ snprintf (bytestr, sizeof (bytestr), "%c", c);
+ strncat (charstr, bytestr, sizeof (charstr) - strlen (charstr) - 1);
+
+ if ((i % 16) == 0)
+ {
+ /* line completed */
+ zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr);
+ hexstr[0] = 0;
+ charstr[0] = 0;
+ }
+ else if ((i % 8) == 0)
+ {
+ /* half line: add whitespaces */
+ strncat (hexstr, " ", sizeof (hexstr) - strlen (hexstr) - 1);
+ strncat (charstr, " ", sizeof (charstr) - strlen (charstr) - 1);
+ }
+ p++; /* next byte */
+ }
+
+ /* print rest of buffer if not empty */
+ if (strlen (hexstr) > 0)
+ zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr);
+ return;
+}
diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h
index d5003a8..0cd65a6 100644
--- a/isisd/isis_misc.h
+++ b/isisd/isis_misc.h
@@ -24,8 +24,10 @@
#ifndef _ZEBRA_ISIS_MISC_H
#define _ZEBRA_ISIS_MISC_H
-int string2circuit_t (const u_char *);
+int string2circuit_t (const char *);
const char *circuit_t2string (int);
+const char *circuit_state2string (int state);
+const char *circuit_type2string (int type);
const char *syst2string (int);
struct in_addr newprefix2inaddr (u_char * prefix_start,
u_char prefix_masklen);
@@ -33,8 +35,8 @@
* Converting input to memory stored format
* return value of 0 indicates wrong input
*/
-int dotformat2buff (u_char *, const u_char *);
-int sysid2buff (u_char *, const u_char *);
+int dotformat2buff (u_char *, const char *);
+int sysid2buff (u_char *, const char *);
/*
* Printing functions
@@ -46,6 +48,8 @@
const char *time2string (u_int32_t);
/* typedef struct nlpids nlpids; */
char *nlpid2string (struct nlpids *);
+const char *print_sys_hostname (u_char *sysid);
+void zlog_dump_data (void *data, int len);
/*
* misc functions
@@ -57,7 +61,8 @@
/*
* macros
*/
-#define GETSYSID(A,L) (A->area_addr + (A->addr_len - (L + 1)))
+#define GETSYSID(A) (A->area_addr + (A->addr_len - \
+ (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN)))
/* used for calculating nice string representation instead of plain seconds */
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index d67df31..497fad2 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -39,12 +39,12 @@
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_network.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_dr.h"
-#include "isisd/isis_flags.h"
#include "isisd/isis_tlv.h"
#include "isisd/isisd.h"
#include "isisd/isis_dynhn.h"
@@ -54,9 +54,6 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
-extern struct thread_master *master;
-extern struct isis *isis;
-
#define ISIS_MINIMUM_FIXED_HDR_LEN 15
#define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */
@@ -65,7 +62,7 @@
#endif /* PNBBY */
/* Utility mask array. */
-static const u_char maskbit[] = {
+static u_char maskbit[] = {
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
};
@@ -169,44 +166,152 @@
return retval;
}
-
/*
* Verify authentication information
* Support cleartext and HMAC MD5 authentication
*/
-int
-authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit* c)
+static int
+authentication_check (struct isis_passwd *remote, struct isis_passwd *local,
+ struct stream *stream, uint32_t auth_tlv_offset)
{
unsigned char digest[ISIS_AUTH_MD5_SIZE];
- if (c->passwd.type)
- {
- switch (c->passwd.type)
- {
- case ISIS_PASSWD_TYPE_HMAC_MD5:
- /* HMAC MD5 (RFC 3567) */
- /* MD5 computation according to RFC 2104 */
- hmac_md5(c->rcv_stream->data, stream_get_endp(c->rcv_stream), (unsigned char *) &(local->passwd), c->passwd.len, (unsigned char *) &digest);
- return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
- break;
+ /* Auth fail () - passwd type mismatch */
+ if (local->type != remote->type)
+ return ISIS_ERROR;
+
+ switch (local->type)
+ {
+ /* No authentication required */
+ case ISIS_PASSWD_TYPE_UNUSED:
+ break;
+
+ /* Cleartext (ISO 10589) */
case ISIS_PASSWD_TYPE_CLEARTXT:
- /* Cleartext (ISO 10589) */
- if (local->len != remote->len)
- return 1; /* Auth fail () - passwd len mismatch */
- return memcmp (local->passwd, remote->passwd, local->len);
- break;
+ /* Auth fail () - passwd len mismatch */
+ if (remote->len != local->len)
+ return ISIS_ERROR;
+ return memcmp (local->passwd, remote->passwd, local->len);
+
+ /* HMAC MD5 (RFC 3567) */
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
+ /* Auth fail () - passwd len mismatch */
+ if (remote->len != ISIS_AUTH_MD5_SIZE)
+ return ISIS_ERROR;
+ /* Set the authentication value to 0 before the check */
+ memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0,
+ ISIS_AUTH_MD5_SIZE);
+ /* Compute the digest */
+ hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream),
+ (unsigned char *) &(local->passwd), local->len,
+ (caddr_t) &digest);
+ /* Copy back the authentication value after the check */
+ memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3,
+ remote->passwd, ISIS_AUTH_MD5_SIZE);
+ return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
+
default:
- zlog_warn ("Unsupported authentication type");
- break;
+ zlog_err ("Unsupported authentication type");
+ return ISIS_ERROR;
+ }
+
+ /* Authentication pass when no authentication is configured */
+ return ISIS_OK;
+}
+
+static int
+lsp_authentication_check (struct stream *stream, struct isis_area *area,
+ int level, struct isis_passwd *passwd)
+{
+ struct isis_link_state_hdr *hdr;
+ uint32_t expected = 0, found = 0, auth_tlv_offset = 0;
+ uint16_t checksum, rem_lifetime, pdu_len;
+ struct tlvs tlvs;
+ int retval = ISIS_OK;
+
+ hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream));
+ pdu_len = ntohs (hdr->pdu_len);
+ expected |= TLVFLAG_AUTH_INFO;
+ auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN;
+ retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN,
+ pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN,
+ &expected, &found, &tlvs, &auth_tlv_offset);
+
+ if (retval != ISIS_OK)
+ {
+ zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, "
+ "cksum 0x%04x, lifetime %us, len %u",
+ area->area_tag, level, rawlspid_print (hdr->lsp_id),
+ ntohl (hdr->seq_num), ntohs (hdr->checksum),
+ ntohs (hdr->rem_lifetime), pdu_len);
+ if ((isis->debugs & DEBUG_UPDATE_PACKETS) &&
+ (isis->debugs & DEBUG_PACKET_DUMP))
+ zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream));
+ return retval;
}
+
+ if (!(found & TLVFLAG_AUTH_INFO))
+ {
+ zlog_err ("No authentication tlv in LSP");
+ return ISIS_ERROR;
}
- return 0; /* Authentication pass when no authentication is configured */
+
+ if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT &&
+ tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5)
+ {
+ zlog_err ("Unknown authentication type in LSP");
+ return ISIS_ERROR;
+ }
+
+ /*
+ * RFC 5304 set checksum and remaining lifetime to zero before
+ * verification and reset to old values after verification.
+ */
+ checksum = hdr->checksum;
+ rem_lifetime = hdr->rem_lifetime;
+ hdr->checksum = 0;
+ hdr->rem_lifetime = 0;
+ retval = authentication_check (&tlvs.auth_info, passwd, stream,
+ auth_tlv_offset);
+ hdr->checksum = checksum;
+ hdr->rem_lifetime = rem_lifetime;
+
+ return retval;
}
/*
* Processing helper functions
*/
static void
+del_addr (void *val)
+{
+ XFREE (MTYPE_ISIS_TMP, val);
+}
+
+static void
+tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
+{
+ struct listnode *node;
+ struct area_addr *area_addr, *malloced;
+
+ if (adj->area_addrs)
+ {
+ adj->area_addrs->del = del_addr;
+ list_delete (adj->area_addrs);
+ }
+ adj->area_addrs = list_new ();
+ if (tlvs->area_addrs)
+ {
+ for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr))
+ {
+ malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr));
+ memcpy (malloced, area_addr, sizeof (struct area_addr));
+ listnode_add (adj->area_addrs, malloced);
+ }
+ }
+}
+
+static void
tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)
{
int i;
@@ -227,12 +332,6 @@
}
static void
-del_ip_addr (void *val)
-{
- XFREE (MTYPE_ISIS_TMP, val);
-}
-
-static void
tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)
{
struct listnode *node;
@@ -240,7 +339,7 @@
if (adj->ipv4_addrs)
{
- adj->ipv4_addrs->del = del_ip_addr;
+ adj->ipv4_addrs->del = del_addr;
list_delete (adj->ipv4_addrs);
}
adj->ipv4_addrs = list_new ();
@@ -264,7 +363,7 @@
if (adj->ipv6_addrs)
{
- adj->ipv6_addrs->del = del_ip_addr;
+ adj->ipv6_addrs->del = del_addr;
list_delete (adj->ipv6_addrs);
}
adj->ipv6_addrs = list_new ();
@@ -297,9 +396,26 @@
int retval = ISIS_OK;
struct isis_p2p_hello_hdr *hdr;
struct isis_adjacency *adj;
- u_int32_t expected = 0, found;
+ u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
+ uint16_t pdu_len;
struct tlvs tlvs;
+ if (isis->debugs & DEBUG_ADJ_PACKETS)
+ {
+ zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u",
+ circuit->area->area_tag, circuit->interface->name,
+ circuit_t2string (circuit->is_type), circuit->circuit_id);
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+ stream_get_endp (circuit->rcv_stream));
+ }
+
+ if (circuit->circ_type != CIRCUIT_T_P2P)
+ {
+ zlog_warn ("p2p hello on non p2p circuit");
+ return ISIS_WARNING;
+ }
+
if ((stream_get_endp (circuit->rcv_stream) -
stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN)
{
@@ -324,42 +440,25 @@
* Get the header
*/
hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream);
- circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN;
+ pdu_len = ntohs (hdr->pdu_len);
- /* hdr.circuit_t = stream_getc (stream);
- stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN);
- hdr.hold_time = stream_getw (stream);
- hdr.pdu_len = stream_getw (stream);
- hdr.local_id = stream_getc (stream); */
+ if (pdu_len > ISO_MTU(circuit) ||
+ pdu_len > stream_get_endp (circuit->rcv_stream))
+ {
+ zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with "
+ "invalid pdu length %d",
+ circuit->area->area_tag, circuit->interface->name, pdu_len);
+ return ISIS_WARNING;
+ }
/*
- * My interpertation of the ISO, if no adj exists we will create one for
- * the circuit
+ * Set the stream endp to PDU length, ignoring additional padding
+ * introduced by transport chips.
*/
+ if (pdu_len < stream_get_endp (circuit->rcv_stream))
+ stream_set_endp (circuit->rcv_stream, pdu_len);
- if (isis->debugs & DEBUG_ADJ_PACKETS)
- {
- zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
- " cir id %02d, length %d",
- circuit->area->area_tag, circuit->interface->name,
- circuit_t2string (circuit->circuit_is_type),
- circuit->circuit_id, ntohs (hdr->pdu_len));
- }
-
- adj = circuit->u.p2p.neighbor;
- if (!adj)
- {
- adj = isis_new_adj (hdr->source_id, NULL, 0, circuit);
- if (adj == NULL)
- return ISIS_ERROR;
- circuit->u.p2p.neighbor = adj;
- isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
- adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
- }
-
- /* 8.2.6 Monitoring point-to-point adjacencies */
- adj->hold_time = ntohs (hdr->hold_time);
- adj->last_upd = time (NULL);
+ stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);
/*
* Lets get the TLVS now
@@ -370,37 +469,93 @@
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
+ auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
STREAM_PNT (circuit->rcv_stream),
- ntohs (hdr->pdu_len) - ISIS_P2PHELLO_HDRLEN
- - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);
+ pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
+ &expected, &found, &tlvs, &auth_tlv_offset);
if (retval > ISIS_WARNING)
{
+ zlog_warn ("parse_tlvs() failed");
free_tlvs (&tlvs);
return retval;
};
+ if (!(found & TLVFLAG_AREA_ADDRS))
+ {
+ zlog_warn ("No Area addresses TLV in P2P IS to IS hello");
+ free_tlvs (&tlvs);
+ return ISIS_WARNING;
+ }
+
/* 8.2.5.1 c) Authentication */
if (circuit->passwd.type)
{
if (!(found & TLVFLAG_AUTH_INFO) ||
- authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
- {
- isis_event_auth_failure (circuit->area->area_tag,
- "P2P hello authentication failure",
- hdr->source_id);
- return ISIS_OK;
- }
+ authentication_check (&tlvs.auth_info, &circuit->passwd,
+ circuit->rcv_stream, auth_tlv_offset))
+ {
+ isis_event_auth_failure (circuit->area->area_tag,
+ "P2P hello authentication failure",
+ hdr->source_id);
+ free_tlvs (&tlvs);
+ return ISIS_OK;
+ }
}
+ /*
+ * check if it's own interface ip match iih ip addrs
+ */
+ if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
+ ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
+ {
+ zlog_warn ("ISIS-Adj: No usable IP interface addresses "
+ "in LAN IIH from %s\n", circuit->interface->name);
+ free_tlvs (&tlvs);
+ return ISIS_WARNING;
+ }
+
+ /*
+ * My interpertation of the ISO, if no adj exists we will create one for
+ * the circuit
+ */
+ adj = circuit->u.p2p.neighbor;
+ if (!adj || adj->level != hdr->circuit_t)
+ {
+ if (!adj)
+ {
+ adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit);
+ if (adj == NULL)
+ return ISIS_ERROR;
+ }
+ else
+ {
+ adj->level = hdr->circuit_t;
+ }
+ circuit->u.p2p.neighbor = adj;
+ isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
+ adj->sys_type = ISIS_SYSTYPE_UNKNOWN;
+ }
+
+ /* 8.2.6 Monitoring point-to-point adjacencies */
+ adj->hold_time = ntohs (hdr->hold_time);
+ adj->last_upd = time (NULL);
+
/* we do this now because the adj may not survive till the end... */
+ tlvs_to_adj_area_addrs (&tlvs, adj);
+
+ /* which protocol are spoken ??? */
+ if (found & TLVFLAG_NLPID)
+ tlvs_to_adj_nlpids (&tlvs, adj);
/* we need to copy addresses to the adj */
- tlvs_to_adj_ipv4_addrs (&tlvs, adj);
+ if (found & TLVFLAG_IPV4_ADDR)
+ tlvs_to_adj_ipv4_addrs (&tlvs, adj);
#ifdef HAVE_IPV6
- tlvs_to_adj_ipv6_addrs (&tlvs, adj);
+ if (found & TLVFLAG_IPV6_ADDR)
+ tlvs_to_adj_ipv6_addrs (&tlvs, adj);
#endif /* HAVE_IPV6 */
/* lets take care of the expiry */
@@ -435,6 +590,7 @@
{
/* (7) reject - wrong system type event */
zlog_warn ("wrongSystemType");
+ free_tlvs (&tlvs);
return ISIS_WARNING; /* Reject */
}
else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
@@ -521,6 +677,7 @@
{
/* (5) reject - wrong system type event */
zlog_warn ("wrongSystemType");
+ free_tlvs (&tlvs);
return ISIS_WARNING; /* Reject */
}
else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) ||
@@ -553,7 +710,7 @@
}
}
/* 8.2.5.2 b) if no match was detected */
- else
+ else if (listcount (circuit->area->area_addrs) > 0)
{
if (circuit->area->is_type == IS_LEVEL_1)
{
@@ -579,6 +736,7 @@
{
/* (6) reject - Area Mismatch event */
zlog_warn ("AreaMismatch");
+ free_tlvs (&tlvs);
return ISIS_WARNING; /* Reject */
}
else if (adj->adj_usage == ISIS_ADJ_LEVEL1)
@@ -631,6 +789,11 @@
}
}
}
+ else
+ {
+ /* down - area mismatch */
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch");
+ }
/* 8.2.5.2 c) if the action was up - comparing circuit IDs */
/* FIXME - Missing parts */
@@ -654,7 +817,15 @@
}
adj->circuit_t = hdr->circuit_t;
- adj->level = hdr->circuit_t;
+
+ if (isis->debugs & DEBUG_ADJ_PACKETS)
+ {
+ zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s,"
+ " cir id %02d, length %d",
+ circuit->area->area_tag, circuit->interface->name,
+ circuit_t2string (circuit->is_type),
+ circuit->circuit_id, pdu_len);
+ }
free_tlvs (&tlvs);
@@ -670,11 +841,28 @@
int retval = ISIS_OK;
struct isis_lan_hello_hdr hdr;
struct isis_adjacency *adj;
- u_int32_t expected = 0, found;
+ u_int32_t expected = 0, found = 0, auth_tlv_offset = 0;
struct tlvs tlvs;
u_char *snpa;
struct listnode *node;
+ if (isis->debugs & DEBUG_ADJ_PACKETS)
+ {
+ zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, "
+ "cirID %u",
+ circuit->area->area_tag, level, circuit->interface->name,
+ circuit_t2string (circuit->is_type), circuit->circuit_id);
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+ stream_get_endp (circuit->rcv_stream));
+ }
+
+ if (circuit->circ_type != CIRCUIT_T_BROADCAST)
+ {
+ zlog_warn ("lan hello on non broadcast circuit");
+ return ISIS_WARNING;
+ }
+
if ((stream_get_endp (circuit->rcv_stream) -
stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN)
{
@@ -689,7 +877,7 @@
return ISIS_WARNING;
}
- if (!accept_level (level, circuit->circuit_is_type))
+ if (!accept_level (level, circuit->is_type))
{
if (isis->debugs & DEBUG_ADJ_PACKETS)
{
@@ -721,13 +909,33 @@
hdr.prio = stream_getc (circuit->rcv_stream);
stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1);
- if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 &&
- hdr.circuit_t != IS_LEVEL_1_AND_2)
+ if (hdr.pdu_len > ISO_MTU(circuit) ||
+ hdr.pdu_len > stream_get_endp (circuit->rcv_stream))
{
- zlog_warn ("Level %d LAN Hello with Circuit Type %d", level,
- hdr.circuit_t);
+ zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with "
+ "invalid pdu length %d",
+ circuit->area->area_tag, circuit->interface->name,
+ hdr.pdu_len);
+ return ISIS_WARNING;
+ }
+
+ /*
+ * Set the stream endp to PDU length, ignoring additional padding
+ * introduced by transport chips.
+ */
+ if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream))
+ stream_set_endp (circuit->rcv_stream, hdr.pdu_len);
+
+ if (hdr.circuit_t != IS_LEVEL_1 &&
+ hdr.circuit_t != IS_LEVEL_2 &&
+ hdr.circuit_t != IS_LEVEL_1_AND_2 &&
+ (level & hdr.circuit_t) == 0)
+ {
+ zlog_err ("Level %d LAN Hello with Circuit Type %d", level,
+ hdr.circuit_t);
return ISIS_ERROR;
}
+
/*
* Then get the tlvs
*/
@@ -738,10 +946,12 @@
expected |= TLVFLAG_IPV4_ADDR;
expected |= TLVFLAG_IPV6_ADDR;
+ auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
- STREAM_PNT (circuit->rcv_stream),
- hdr.pdu_len - ISIS_LANHELLO_HDRLEN -
- ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs);
+ STREAM_PNT (circuit->rcv_stream),
+ hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN,
+ &expected, &found, &tlvs,
+ &auth_tlv_offset);
if (retval > ISIS_WARNING)
{
@@ -761,21 +971,24 @@
if (circuit->passwd.type)
{
if (!(found & TLVFLAG_AUTH_INFO) ||
- authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
- {
- isis_event_auth_failure (circuit->area->area_tag,
- "LAN hello authentication failure",
- hdr.source_id);
- retval = ISIS_WARNING;
- goto out;
- }
+ authentication_check (&tlvs.auth_info, &circuit->passwd,
+ circuit->rcv_stream, auth_tlv_offset))
+ {
+ isis_event_auth_failure (circuit->area->area_tag,
+ "LAN hello authentication failure",
+ hdr.source_id);
+ retval = ISIS_WARNING;
+ goto out;
+ }
}
/*
* Accept the level 1 adjacency only if a match between local and
* remote area addresses is found
*/
- if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs))
+ if (listcount (circuit->area->area_addrs) == 0 ||
+ (level == IS_LEVEL_1 &&
+ area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0))
{
if (isis->debugs & DEBUG_ADJ_PACKETS)
{
@@ -802,43 +1015,49 @@
/*
* check if it's own interface ip match iih ip addrs
*/
- if (!(found & TLVFLAG_IPV4_ADDR)
- || !ip_match (circuit->ip_addrs, tlvs.ipv4_addrs))
+ if ((found & TLVFLAG_IPV4_ADDR) == 0 ||
+ ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0)
{
- zlog_debug
- ("ISIS-Adj: No usable IP interface addresses in LAN IIH from %s\n",
- circuit->interface->name);
+ zlog_debug ("ISIS-Adj: No usable IP interface addresses "
+ "in LAN IIH from %s\n", circuit->interface->name);
retval = ISIS_WARNING;
goto out;
}
adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]);
- if (!adj)
+ if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) ||
+ (adj->level != level))
{
- /*
- * Do as in 8.4.2.5
- */
- adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
- if (adj == NULL)
- {
- retval = ISIS_ERROR;
- goto out;
- }
-
- adj->level = level;
+ if (!adj)
+ {
+ /*
+ * Do as in 8.4.2.5
+ */
+ adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit);
+ if (adj == NULL)
+ {
+ retval = ISIS_ERROR;
+ goto out;
+ }
+ }
+ else
+ {
+ if (ssnpa) {
+ memcpy (adj->snpa, ssnpa, 6);
+ } else {
+ memset (adj->snpa, ' ', 6);
+ }
+ adj->level = level;
+ }
isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL);
- if (level == 1)
- {
- adj->sys_type = ISIS_SYSTYPE_L1_IS;
- }
+ if (level == IS_LEVEL_1)
+ adj->sys_type = ISIS_SYSTYPE_L1_IS;
else
- {
- adj->sys_type = ISIS_SYSTYPE_L2_IS;
- }
+ adj->sys_type = ISIS_SYSTYPE_L2_IS;
list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
- circuit->u.bc.lan_neighs[level - 1]);
+ circuit->u.bc.lan_neighs[level - 1]);
}
if(adj->dis_record[level-1].dis==ISIS_IS_DIS)
@@ -847,7 +1066,7 @@
case 1:
if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
{
- thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+ thread_add_event (master, isis_event_dis_status_change, circuit, 0);
memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id,
ISIS_SYS_ID_LEN + 1);
}
@@ -855,7 +1074,7 @@
case 2:
if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1))
{
- thread_add_event (master, isis_event_dis_status_change, circuit, 0);
+ thread_add_event (master, isis_event_dis_status_change, circuit, 0);
memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id,
ISIS_SYS_ID_LEN + 1);
}
@@ -868,6 +1087,8 @@
memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1);
+ tlvs_to_adj_area_addrs (&tlvs, adj);
+
/* which protocol are spoken ??? */
if (found & TLVFLAG_NLPID)
tlvs_to_adj_nlpids (&tlvs, adj);
@@ -886,7 +1107,7 @@
/* lets take care of the expiry */
THREAD_TIMER_OFF (adj->t_expire);
THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj,
- (long) adj->hold_time);
+ (long) adj->hold_time);
/*
* If the snpa for this circuit is found from LAN Neighbours TLV
@@ -894,31 +1115,48 @@
*/
if (found & TLVFLAG_LAN_NEIGHS)
+ {
+ if (adj->adj_state != ISIS_ADJ_UP)
{
- if (adj->adj_state != ISIS_ADJ_UP)
- {
- for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
- if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
- {
- isis_adj_state_change (adj, ISIS_ADJ_UP,
- "own SNPA found in LAN Neighbours TLV");
- }
- }
+ for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
+ {
+ if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
+ {
+ isis_adj_state_change (adj, ISIS_ADJ_UP,
+ "own SNPA found in LAN Neighbours TLV");
+ }
+ }
}
+ else
+ {
+ int found = 0;
+ for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa))
+ if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN))
+ {
+ found = 1;
+ break;
+ }
+ if (found == 0)
+ isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
+ "own SNPA not found in LAN Neighbours TLV");
+ }
+ }
+ else if (adj->adj_state == ISIS_ADJ_UP)
+ {
+ isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING,
+ "no LAN Neighbours TLV found");
+ }
out:
- /* DEBUG_ADJ_PACKETS */
if (isis->debugs & DEBUG_ADJ_PACKETS)
{
- /* FIXME: is this place right? fix missing info */
zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, "
"cirID %u, length %ld",
circuit->area->area_tag,
level, snpa_print (ssnpa), circuit->interface->name,
- circuit_t2string (circuit->circuit_is_type),
+ circuit_t2string (circuit->is_type),
circuit->circuit_id,
- /* FIXME: use %z when we stop supporting old compilers. */
- (unsigned long) stream_get_endp (circuit->rcv_stream));
+ stream_get_endp (circuit->rcv_stream));
}
free_tlvs (&tlvs);
@@ -940,8 +1178,18 @@
int retval = ISIS_OK, comp = 0;
u_char lspid[ISIS_SYS_ID_LEN + 2];
struct isis_passwd *passwd;
+ uint16_t pdu_len;
- /* Sanity check - FIXME: move to correct place */
+ if (isis->debugs & DEBUG_UPDATE_PACKETS)
+ {
+ zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u",
+ circuit->area->area_tag, level, circuit->interface->name,
+ circuit_t2string (circuit->is_type), circuit->circuit_id);
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+ stream_get_endp (circuit->rcv_stream));
+ }
+
if ((stream_get_endp (circuit->rcv_stream) -
stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN)
{
@@ -951,28 +1199,56 @@
/* Reference the header */
hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream);
+ pdu_len = ntohs (hdr->pdu_len);
+
+ /* lsp length check */
+ if (pdu_len < ISIS_LSP_HDR_LEN ||
+ pdu_len > ISO_MTU(circuit) ||
+ pdu_len > stream_get_endp (circuit->rcv_stream))
+ {
+ zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d",
+ circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id), pdu_len);
+
+ return ISIS_WARNING;
+ }
+
+ /*
+ * Set the stream endp to PDU length, ignoring additional padding
+ * introduced by transport chips.
+ */
+ if (pdu_len < stream_get_endp (circuit->rcv_stream))
+ stream_set_endp (circuit->rcv_stream, pdu_len);
if (isis->debugs & DEBUG_UPDATE_PACKETS)
{
zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, "
- "lifetime %us, len %lu, on %s",
+ "lifetime %us, len %u, on %s",
circuit->area->area_tag,
level,
rawlspid_print (hdr->lsp_id),
ntohl (hdr->seq_num),
ntohs (hdr->checksum),
ntohs (hdr->rem_lifetime),
- /* FIXME: use %z when we stop supporting old compilers. */
- (unsigned long) stream_get_endp (circuit->rcv_stream),
+ pdu_len,
circuit->interface->name);
}
- assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN);
+ /* lsp is_type check */
+ if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 &&
+ (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2)
+ {
+ zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x",
+ circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id), hdr->lsp_bits);
+ /* continue as per RFC1122 Be liberal in what you accept, and
+ * conservative in what you send */
+ }
/* Checksum sanity check - FIXME: move to correct place */
/* 12 = sysid+pdu+remtime */
if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4,
- ntohs (hdr->pdu_len) - 12, &hdr->checksum))
+ pdu_len - 12, &hdr->checksum))
{
zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x",
circuit->area->area_tag,
@@ -993,13 +1269,13 @@
}
/* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */
- if (!accept_level (level, circuit->circuit_is_type))
+ if (!accept_level (level, circuit->is_type))
{
zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of"
" type %s",
circuit->area->area_tag,
rawlspid_print (hdr->lsp_id),
- level, circuit_t2string (circuit->circuit_is_type));
+ level, circuit_t2string (circuit->is_type));
return ISIS_WARNING;
}
@@ -1009,12 +1285,12 @@
/* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */
/* 7.3.15.1 a) 7 - password check */
- (level == ISIS_LEVEL1) ? (passwd = &circuit->area->area_passwd) :
- (passwd = &circuit->area->domain_passwd);
+ (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) :
+ (passwd = &circuit->area->domain_passwd);
if (passwd->type)
{
- if (isis_lsp_authinfo_check (circuit->rcv_stream, circuit->area,
- ntohs (hdr->pdu_len), passwd))
+ if (lsp_authentication_check (circuit->rcv_stream, circuit->area,
+ level, passwd))
{
isis_event_auth_failure (circuit->area->area_tag,
"LSP authentication failure", hdr->lsp_id);
@@ -1035,7 +1311,6 @@
/* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */
/* for broadcast circuits, snpa should be compared */
- /* FIXME : Point To Point */
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
{
@@ -1052,7 +1327,6 @@
return ISIS_WARNING; /* Silently discard */
}
}
-
/* for non broadcast, we just need to find same level adj */
else
{
@@ -1063,13 +1337,15 @@
}
else
{
- if (((level == 1) &&
+ if (((level == IS_LEVEL_1) &&
(circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) ||
- ((level == 2) &&
+ ((level == IS_LEVEL_2) &&
(circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1)))
return ISIS_WARNING; /* Silently discard */
+ adj = circuit->u.p2p.neighbor;
}
}
+
dontcheckadj:
/* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */
@@ -1096,10 +1372,9 @@
/* 7.3.16.4 b) 1) */
if (comp == LSP_NEWER)
{
- lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area,
- level);
+ lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
/* ii */
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ lsp_set_all_srmflags (lsp);
/* iii */
ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
/* v */
@@ -1123,38 +1398,25 @@
ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
}
}
- else
- {
- /* our own LSP -> 7.3.16.4 c) */
- if (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) !=
- circuit->circuit_id
- || (LSP_PSEUDO_ID (lsp->lsp_header->lsp_id) ==
- circuit->circuit_id
- && circuit->u.bc.is_dr[level - 1] == 1))
- {
- lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
- if (isis->debugs & DEBUG_UPDATE_PACKETS)
- zlog_debug ("LSP LEN: %d",
- ntohs (lsp->lsp_header->pdu_len));
- fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
- ntohs (lsp->lsp_header->pdu_len) - 12, 12);
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
- if (isis->debugs & DEBUG_UPDATE_PACKETS)
- zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
- "seq 0x%08x", circuit->area->area_tag,
- rawlspid_print (hdr->lsp_id),
- ntohl (lsp->lsp_header->seq_num));
- lsp->lsp_header->rem_lifetime =
- htons (isis_jitter
- (circuit->area->max_lsp_lifetime[level - 1],
- MAX_AGE_JITTER));
- }
- else
- {
- /* Got purge for own pseudo-lsp, and we are not DR */
- lsp_purge_dr (lsp->lsp_header->lsp_id, circuit, level);
- }
- }
+ else if (lsp->lsp_header->rem_lifetime != 0)
+ {
+ /* our own LSP -> 7.3.16.4 c) */
+ if (comp == LSP_NEWER)
+ {
+ lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
+ lsp_set_all_srmflags (lsp);
+ }
+ else
+ {
+ ISIS_SET_FLAG (lsp->SRMflags, circuit);
+ ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
+ }
+ if (isis->debugs & DEBUG_UPDATE_PACKETS)
+ zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new "
+ "seq 0x%08x", circuit->area->area_tag,
+ rawlspid_print (hdr->lsp_id),
+ ntohl (lsp->lsp_header->seq_num));
+ }
}
return retval;
}
@@ -1174,25 +1436,19 @@
* has information that the current sequence number for source S is
* "greater" than that held by S, ... */
- else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
+ if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num))
{
/* 7.3.16.1 */
- lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
-
- fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
- ntohs (lsp->lsp_header->pdu_len) - 12, 12);
-
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ lsp_inc_seqnum (lsp, ntohl (hdr->seq_num));
if (isis->debugs & DEBUG_UPDATE_PACKETS)
zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq "
"0x%08x", circuit->area->area_tag,
rawlspid_print (hdr->lsp_id),
ntohl (lsp->lsp_header->seq_num));
- lsp->lsp_header->rem_lifetime =
- htons (isis_jitter
- (circuit->area->max_lsp_lifetime[level - 1],
- MAX_AGE_JITTER));
}
+ /* If the received LSP is older or equal,
+ * resend the LSP which will act as ACK */
+ lsp_set_all_srmflags (lsp);
}
else
{
@@ -1201,22 +1457,6 @@
/* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */
if ((!lsp || comp == LSP_NEWER))
{
- int regenerate = (lsp == NULL);
- /* i */
- if (lsp)
- {
-#ifdef EXTREME_DEBUG
- zlog_debug ("level %d number is - %ld", level,
- circuit->area->lspdb[level - 1]->dict_nodecount);
-#endif /* EXTREME DEBUG */
- lsp_search_and_destroy (hdr->lsp_id,
- circuit->area->lspdb[level - 1]);
- /* exists, so we overwrite */
-#ifdef EXTREME_DEBUG
- zlog_debug ("level %d number is - %ld", level,
- circuit->area->lspdb[level - 1]->dict_nodecount);
-#endif /* EXTREME DEBUG */
- }
/*
* If this lsp is a frag, need to see if we have zero lsp present
*/
@@ -1227,18 +1467,24 @@
lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]);
if (!lsp0)
{
- zlog_debug ("Got lsp frag, while zero lsp not database");
+ zlog_debug ("Got lsp frag, while zero lsp not in database");
return ISIS_OK;
}
}
- lsp =
- lsp_new_from_stream_ptr (circuit->rcv_stream,
- ntohs (hdr->pdu_len), lsp0,
- circuit->area);
- lsp->level = level;
- lsp_insert (lsp, circuit->area->lspdb[level - 1]);
+ /* i */
+ if (!lsp)
+ {
+ lsp = lsp_new_from_stream_ptr (circuit->rcv_stream,
+ pdu_len, lsp0,
+ circuit->area, level);
+ lsp_insert (lsp, circuit->area->lspdb[level - 1]);
+ }
+ else /* exists, so we overwrite */
+ {
+ lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
+ }
/* ii */
- ISIS_FLAGS_SET_ALL (lsp->SRMflags);
+ lsp_set_all_srmflags (lsp);
/* iii */
ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
@@ -1246,19 +1492,14 @@
if (circuit->circ_type != CIRCUIT_T_BROADCAST)
ISIS_SET_FLAG (lsp->SSNflags, circuit);
/* FIXME: v) */
- if (regenerate && circuit->u.bc.is_dr[level - 1]) {
- lsp_l1_pseudo_generate (circuit);
- }
}
/* 7.3.15.1 e) 2) LSP equal to the one in db */
else if (comp == LSP_EQUAL)
{
ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
- lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area, level);
+ lsp_update (lsp, circuit->rcv_stream, circuit->area, level);
if (circuit->circ_type != CIRCUIT_T_BROADCAST)
- {
- ISIS_SET_FLAG (lsp->SSNflags, circuit);
- }
+ ISIS_SET_FLAG (lsp->SSNflags, circuit);
}
/* 7.3.15.1 e) 3) LSP older than the one in db */
else
@@ -1267,7 +1508,6 @@
ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
}
}
-
return retval;
}
@@ -1284,11 +1524,11 @@
int retval = ISIS_OK;
int cmp, own_lsp;
char typechar = ' ';
- int len;
+ uint16_t pdu_len;
struct isis_adjacency *adj;
struct isis_complete_seqnum_hdr *chdr = NULL;
struct isis_partial_seqnum_hdr *phdr = NULL;
- uint32_t found = 0, expected = 0;
+ uint32_t found = 0, expected = 0, auth_tlv_offset = 0;
struct isis_lsp *lsp;
struct lsp_entry *entry;
struct listnode *node, *nnode;
@@ -1303,12 +1543,14 @@
typechar = 'C';
chdr =
(struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
- circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN;
- len = ntohs (chdr->pdu_len);
- if (len < ISIS_CSNP_HDRLEN)
+ stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN);
+ pdu_len = ntohs (chdr->pdu_len);
+ if (pdu_len < ISIS_CSNP_HDRLEN ||
+ pdu_len > ISO_MTU(circuit) ||
+ pdu_len > stream_get_endp (circuit->rcv_stream))
{
- zlog_warn ("Received a CSNP with bogus length!");
- return ISIS_OK;
+ zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
+ return ISIS_WARNING;
}
}
else
@@ -1316,15 +1558,24 @@
typechar = 'P';
phdr =
(struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream);
- circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN;
- len = ntohs (phdr->pdu_len);
- if (len < ISIS_PSNP_HDRLEN)
+ stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN);
+ pdu_len = ntohs (phdr->pdu_len);
+ if (pdu_len < ISIS_PSNP_HDRLEN ||
+ pdu_len > ISO_MTU(circuit) ||
+ pdu_len > stream_get_endp (circuit->rcv_stream))
{
- zlog_warn ("Received a CSNP with bogus length!");
- return ISIS_OK;
+ zlog_warn ("Received a CSNP with bogus length %d", pdu_len);
+ return ISIS_WARNING;
}
}
+ /*
+ * Set the stream endp to PDU length, ignoring additional padding
+ * introduced by transport chips.
+ */
+ if (pdu_len < stream_get_endp (circuit->rcv_stream))
+ stream_set_endp (circuit->rcv_stream, pdu_len);
+
/* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */
if (circuit->ext_domain)
{
@@ -1338,7 +1589,7 @@
}
/* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */
- if (!accept_level (level, circuit->circuit_is_type))
+ if (!accept_level (level, circuit->is_type))
{
zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, "
@@ -1347,26 +1598,23 @@
level,
typechar,
circuit->interface->name,
- circuit_t2string (circuit->circuit_is_type), level);
+ circuit_t2string (circuit->is_type), level);
return ISIS_OK;
}
/* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */
if ((snp_type == ISIS_SNP_PSNP_FLAG) &&
- (circuit->circ_type == CIRCUIT_T_BROADCAST))
+ (circuit->circ_type == CIRCUIT_T_BROADCAST) &&
+ (!circuit->u.bc.is_dr[level - 1]))
{
- if (!circuit->u.bc.is_dr[level - 1])
- {
+ zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
+ "skipping: we are not the DIS",
+ circuit->area->area_tag,
+ level,
+ typechar, snpa_print (ssnpa), circuit->interface->name);
- zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, "
- "skipping: we are not the DIS",
- circuit->area->area_tag,
- level,
- typechar, snpa_print (ssnpa), circuit->interface->name);
-
- return ISIS_OK;
- }
+ return ISIS_OK;
}
/* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */
@@ -1396,7 +1644,10 @@
else
{
if (!circuit->u.p2p.neighbor)
- return ISIS_OK; /* Silently discard */
+ {
+ zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name);
+ return ISIS_OK; /* Silently discard */
+ }
}
/* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */
@@ -1408,10 +1659,12 @@
/* parse the SNP */
expected |= TLVFLAG_LSP_ENTRIES;
expected |= TLVFLAG_AUTH_INFO;
+
+ auth_tlv_offset = stream_get_getp (circuit->rcv_stream);
retval = parse_tlvs (circuit->area->area_tag,
STREAM_PNT (circuit->rcv_stream),
- len - circuit->rcv_stream->getp,
- &expected, &found, &tlvs);
+ pdu_len - stream_get_getp (circuit->rcv_stream),
+ &expected, &found, &tlvs, &auth_tlv_offset);
if (retval > ISIS_WARNING)
{
@@ -1420,7 +1673,7 @@
return retval;
}
- if (level == 1)
+ if (level == IS_LEVEL_1)
passwd = &circuit->area->area_passwd;
else
passwd = &circuit->area->domain_passwd;
@@ -1428,16 +1681,19 @@
if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))
{
if (passwd->type)
- {
- if (!(found & TLVFLAG_AUTH_INFO) ||
- authentication_check (&tlvs.auth_info, passwd, circuit))
- {
- isis_event_auth_failure (circuit->area->area_tag,
- "SNP authentication" " failure",
- phdr ? phdr->source_id : chdr->source_id);
- return ISIS_OK;
- }
- }
+ {
+ if (!(found & TLVFLAG_AUTH_INFO) ||
+ authentication_check (&tlvs.auth_info, passwd,
+ circuit->rcv_stream, auth_tlv_offset))
+ {
+ isis_event_auth_failure (circuit->area->area_tag,
+ "SNP authentication" " failure",
+ phdr ? phdr->source_id :
+ chdr->source_id);
+ free_tlvs (&tlvs);
+ return ISIS_OK;
+ }
+ }
}
/* debug isis snp-packets */
@@ -1477,19 +1733,18 @@
/* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */
if (cmp == LSP_EQUAL)
{
- if (circuit->circ_type != CIRCUIT_T_BROADCAST)
- ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
- /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
+ /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
}
+ /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */
else if (cmp == LSP_OLDER)
{
ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
ISIS_SET_FLAG (lsp->SRMflags, circuit);
}
+ /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */
else
{
- /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM
- * on p2p */
if (own_lsp)
{
lsp_inc_seqnum (lsp, ntohl (entry->seq_num));
@@ -1498,8 +1753,8 @@
else
{
ISIS_SET_FLAG (lsp->SSNflags, circuit);
- if (circuit->circ_type != CIRCUIT_T_BROADCAST)
- ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
+ /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
}
}
}
@@ -1512,7 +1767,9 @@
{
lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime),
0, 0, entry->checksum, level);
+ lsp->area = circuit->area;
lsp_insert (lsp, circuit->area->lspdb[level - 1]);
+ ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags);
ISIS_SET_FLAG (lsp->SSNflags, circuit);
}
}
@@ -1523,7 +1780,8 @@
if (snp_type == ISIS_SNP_CSNP_FLAG)
{
/*
- * Build a list from our own LSP db bounded with start_ and stop_lsp_id
+ * Build a list from our own LSP db bounded with
+ * start_lsp_id and stop_lsp_id
*/
lsp_list = list_new ();
lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id,
@@ -1546,11 +1804,10 @@
}
/* on remaining LSPs we set SRM (neighbor knew not of) */
for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp))
- {
ISIS_SET_FLAG (lsp->SRMflags, circuit);
- }
/* lets free it */
- list_free (lsp_list);
+ list_delete (lsp_list);
+
}
free_tlvs (&tlvs);
@@ -1560,6 +1817,16 @@
static int
process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
{
+ if (isis->debugs & DEBUG_SNP_PACKETS)
+ {
+ zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u",
+ circuit->area->area_tag, level, circuit->interface->name,
+ circuit_t2string (circuit->is_type), circuit->circuit_id);
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+ stream_get_endp (circuit->rcv_stream));
+ }
+
/* Sanity check - FIXME: move to correct place */
if ((stream_get_endp (circuit->rcv_stream) -
stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN)
@@ -1574,10 +1841,20 @@
static int
process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa)
{
+ if (isis->debugs & DEBUG_SNP_PACKETS)
+ {
+ zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u",
+ circuit->area->area_tag, level, circuit->interface->name,
+ circuit_t2string (circuit->is_type), circuit->circuit_id);
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+ stream_get_endp (circuit->rcv_stream));
+ }
+
if ((stream_get_endp (circuit->rcv_stream) -
stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN)
{
- zlog_warn ("Packet too short");
+ zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN);
return ISIS_WARNING;
}
@@ -1601,6 +1878,16 @@
u_char neigh_len;
u_char *sysid;
+ if (isis->debugs & DEBUG_ADJ_PACKETS)
+ {
+ zlog_debug ("ISIS-Adj (%s): Rcvd ISH on %s, cirType %s, cirID %u",
+ circuit->area->area_tag, circuit->interface->name,
+ circuit_t2string (circuit->is_type), circuit->circuit_id);
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->rcv_stream),
+ stream_get_endp (circuit->rcv_stream));
+ }
+
/* In this point in time we are not yet able to handle is_hellos
* on lan - Sorry juniper...
*/
@@ -1665,7 +1952,6 @@
isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)
{
struct isis_fixed_hdr *hdr;
- struct esis_fixed_hdr *esis_hdr;
int retval = ISIS_OK;
@@ -1676,7 +1962,7 @@
if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS))
{
- zlog_warn ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
+ zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp);
return ISIS_ERROR;
}
@@ -1685,28 +1971,11 @@
*/
if (hdr->idrp == ISO9542_ESIS)
{
- esis_hdr = (struct esis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream);
- stream_set_getp (circuit->rcv_stream, ESIS_FIXED_HDR_LEN);
- /* FIXME: Need to do some acceptence tests */
- /* example length... */
- switch (esis_hdr->pdu_type)
- {
- case ESH_PDU:
- /* FIXME */
- break;
- case ISH_PDU:
- zlog_debug ("AN ISH PDU!!");
- retval = process_is_hello (circuit);
- break;
- default:
- return ISIS_ERROR;
- }
- return retval;
+ zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp);
+ return ISIS_ERROR;
}
- else
- {
- stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
- }
+ stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN);
+
/*
* and then process it
*/
@@ -1737,6 +2006,14 @@
zlog_warn ("Unsupported ISIS version %u", hdr->version2);
return ISIS_WARNING;
}
+
+ if (circuit->is_passive)
+ {
+ zlog_warn ("Received ISIS PDU on passive circuit %s",
+ circuit->interface->name);
+ return ISIS_WARNING;
+ }
+
/* either 3 or 0 */
if ((hdr->max_area_addrs != 0)
&& (hdr->max_area_addrs != isis->max_area_addrs))
@@ -1797,9 +2074,6 @@
circuit = THREAD_ARG (thread);
assert (circuit);
- if (!circuit->area)
- return ISIS_OK;
-
if (circuit->rcv_stream == NULL)
circuit->rcv_stream = stream_new (ISO_MTU (circuit));
else
@@ -1814,8 +2088,11 @@
/*
* prepare for next packet.
*/
- THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
- circuit->fd);
+ if (!circuit->is_passive)
+ {
+ THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
+ circuit->fd);
+ }
return retval;
}
@@ -1849,10 +2126,13 @@
/*
* prepare for next packet.
*/
- circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
- listcount
- (circuit->area->circuit_list) *
- 100);
+ if (!circuit->is_passive)
+ {
+ circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit,
+ listcount
+ (circuit->area->circuit_list) *
+ 100);
+ }
return retval;
}
@@ -1927,14 +2207,13 @@
struct isis_fixed_hdr fixed_hdr;
struct isis_lan_hello_hdr hello_hdr;
struct isis_p2p_hello_hdr p2p_hello_hdr;
- char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
-
+ unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+ unsigned long len_pointer, length, auth_tlv_offset = 0;
u_int32_t interval;
- unsigned long len_pointer, length, auth_tlv;
int retval;
- if (circuit->state != C_STATE_UP || circuit->interface == NULL)
- return ISIS_WARNING;
+ if (circuit->is_passive)
+ return ISIS_OK;
if (circuit->interface->mtu == 0)
{
@@ -1948,7 +2227,7 @@
stream_reset (circuit->snd_stream);
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
- if (level == 1)
+ if (level == IS_LEVEL_1)
fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO,
circuit->snd_stream);
else
@@ -1963,12 +2242,9 @@
memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr));
interval = circuit->hello_multiplier[level - 1] *
circuit->hello_interval[level - 1];
- /* If we are the DIS then hello interval is divided by three, as is the hold-timer */
- if (circuit->u.bc.is_dr[level - 1])
- interval=interval/3;
if (interval > USHRT_MAX)
interval = USHRT_MAX;
- hello_hdr.circuit_t = circuit->circuit_is_type;
+ hello_hdr.circuit_t = circuit->is_type;
memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN);
hello_hdr.hold_time = htons ((u_int16_t) interval);
@@ -1985,13 +2261,13 @@
}
else
{
- hello_hdr.prio = circuit->u.bc.priority[level - 1];
- if (level == 1 && circuit->u.bc.l1_desig_is)
+ hello_hdr.prio = circuit->priority[level - 1];
+ if (level == IS_LEVEL_1)
{
memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is,
ISIS_SYS_ID_LEN + 1);
}
- else if (level == 2 && circuit->u.bc.l2_desig_is)
+ else if (level == IS_LEVEL_2)
{
memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is,
ISIS_SYS_ID_LEN + 1);
@@ -2000,68 +2276,73 @@
}
/*
- * Then the variable length part
+ * Then the variable length part.
*/
/* add circuit password */
- /* Cleartext */
- if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
- if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, circuit->passwd.len,
- circuit->passwd.passwd, circuit->snd_stream))
- return ISIS_WARNING;
+ switch (circuit->passwd.type)
+ {
+ /* Cleartext */
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
+ circuit->passwd.passwd, circuit->snd_stream))
+ return ISIS_WARNING;
+ break;
- /* or HMAC MD5 */
- if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
- {
+ /* HMAC MD5 */
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
/* Remember where TLV is written so we can later overwrite the MD5 hash */
- auth_tlv = stream_get_endp (circuit->snd_stream);
+ auth_tlv_offset = stream_get_endp (circuit->snd_stream);
memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
- if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
- hmac_md5_hash, circuit->snd_stream))
- return ISIS_WARNING;
+ if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE,
+ hmac_md5_hash, circuit->snd_stream))
+ return ISIS_WARNING;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Area Addresses TLV */
+ if (listcount (circuit->area->area_addrs) == 0)
+ return ISIS_WARNING;
+ if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
+ return ISIS_WARNING;
+
+ /* LAN Neighbors TLV */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ {
+ if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] &&
+ listcount (circuit->u.bc.lan_neighs[0]) > 0)
+ if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
+ circuit->snd_stream))
+ return ISIS_WARNING;
+ if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] &&
+ listcount (circuit->u.bc.lan_neighs[1]) > 0)
+ if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
+ circuit->snd_stream))
+ return ISIS_WARNING;
}
/* Protocols Supported TLV */
if (circuit->nlpids.count > 0)
if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
return ISIS_WARNING;
-
- /* Area Addresses TLV */
- assert (circuit->area);
- if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0)
- if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream))
- return ISIS_WARNING;
-
/* IP interface Address TLV */
- if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0)
+ if (circuit->ip_router && circuit->ip_addrs &&
+ listcount (circuit->ip_addrs) > 0)
if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream))
return ISIS_WARNING;
#ifdef HAVE_IPV6
/* IPv6 Interface Address TLV */
if (circuit->ipv6_router && circuit->ipv6_link &&
- circuit->ipv6_link->count > 0)
+ listcount (circuit->ipv6_link) > 0)
if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream))
return ISIS_WARNING;
#endif /* HAVE_IPV6 */
- /* Restart signaling, vendor C sends it too */
- retval = add_tlv (211, 3, 0, circuit->snd_stream);
-
- /* LAN Neighbors TLV */
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
- {
- if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0)
- if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0],
- circuit->snd_stream))
- return ISIS_WARNING;
- if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0)
- if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1],
- circuit->snd_stream))
- return ISIS_WARNING;
- }
-
- if (circuit->u.bc.pad_hellos)
+ if (circuit->pad_hellos)
if (tlv_add_padding (circuit->snd_stream))
return ISIS_WARNING;
@@ -2072,16 +2353,15 @@
/* For HMAC MD5 we need to compute the md5 hash and store it */
if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
{
- hmac_md5(circuit->snd_stream->data, stream_get_endp(circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash);
+ hmac_md5 (STREAM_DATA (circuit->snd_stream),
+ stream_get_endp (circuit->snd_stream),
+ (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len,
+ (caddr_t) &hmac_md5_hash);
/* Copy the hash into the stream */
- memcpy(circuit->snd_stream->data+auth_tlv+3,hmac_md5_hash,ISIS_AUTH_MD5_SIZE);
+ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
+ hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
}
- retval = circuit->tx (circuit, level);
- if (retval)
- zlog_warn ("sending of LAN Level %d Hello failed", level);
-
- /* DEBUG_ADJ_PACKETS */
if (isis->debugs & DEBUG_ADJ_PACKETS)
{
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
@@ -2089,24 +2369,26 @@
zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld",
circuit->area->area_tag, level, circuit->interface->name,
/* FIXME: use %z when we stop supporting old compilers. */
- (unsigned long) STREAM_SIZE (circuit->snd_stream));
+ length);
}
else
{
zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld",
circuit->area->area_tag, circuit->interface->name,
/* FIXME: use %z when we stop supporting old compilers. */
- (unsigned long) STREAM_SIZE (circuit->snd_stream));
+ length);
}
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+ stream_get_endp (circuit->snd_stream));
}
- return retval;
-}
+ retval = circuit->tx (circuit, level);
+ if (retval != ISIS_OK)
+ zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed",
+ circuit->area->area_tag, level, circuit->interface->name);
-static int
-send_lan_hello (struct isis_circuit *circuit, int level)
-{
- return send_hello (circuit, level);
+ return retval;
}
int
@@ -2114,32 +2396,20 @@
{
struct isis_circuit *circuit;
int retval;
- unsigned long next_hello;
circuit = THREAD_ARG (thread);
assert (circuit);
-
- if (!circuit->area) {
- return ISIS_OK;
- }
-
- /* Pseudonode sends hellos three times more than the other nodes */
- if (circuit->u.bc.is_dr[0])
- next_hello=circuit->hello_interval[0]/3+1;
- else
- next_hello=circuit->hello_interval[0];
-
circuit->u.bc.t_send_lan_hello[0] = NULL;
if (circuit->u.bc.run_dr_elect[0])
retval = isis_dr_elect (circuit, 1);
- retval = send_lan_hello (circuit, 1);
+ retval = send_hello (circuit, 1);
/* set next timer thread */
THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0],
send_lan_l1_hello, circuit,
- isis_jitter (next_hello, IIH_JITTER));
+ isis_jitter (circuit->hello_interval[0], IIH_JITTER));
return retval;
}
@@ -2149,32 +2419,20 @@
{
struct isis_circuit *circuit;
int retval;
- unsigned long next_hello;
circuit = THREAD_ARG (thread);
assert (circuit);
-
- if (!circuit->area) {
- return ISIS_OK;
- }
-
- /* Pseudonode sends hellos three times more than the other nodes */
- if (circuit->u.bc.is_dr[1])
- next_hello=circuit->hello_interval[1]/3+1;
- else
- next_hello=circuit->hello_interval[1];
-
circuit->u.bc.t_send_lan_hello[1] = NULL;
if (circuit->u.bc.run_dr_elect[1])
retval = isis_dr_elect (circuit, 2);
- retval = send_lan_hello (circuit, 2);
+ retval = send_hello (circuit, 2);
/* set next timer thread */
THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1],
send_lan_l2_hello, circuit,
- isis_jitter (next_hello, IIH_JITTER));
+ isis_jitter (circuit->hello_interval[1], IIH_JITTER));
return retval;
}
@@ -2204,11 +2462,18 @@
{
struct isis_fixed_hdr fixed_hdr;
struct isis_passwd *passwd;
- int retval = ISIS_OK;
unsigned long lenp;
u_int16_t length;
+ unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+ unsigned long auth_tlv_offset = 0;
+ int retval = ISIS_OK;
- if (level == 1)
+ if (circuit->snd_stream == NULL)
+ circuit->snd_stream = stream_new (ISO_MTU (circuit));
+ else
+ stream_reset (circuit->snd_stream);
+
+ if (level == IS_LEVEL_1)
fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,
circuit->snd_stream);
else
@@ -2232,84 +2497,244 @@
/*
* And TLVs
*/
- if (level == 1)
+ if (level == IS_LEVEL_1)
passwd = &circuit->area->area_passwd;
else
passwd = &circuit->area->domain_passwd;
if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
- if (passwd->type)
- retval = tlv_add_authinfo (passwd->type, passwd->len,
- passwd->passwd, circuit->snd_stream);
-
- if (!retval && lsps)
+ {
+ switch (passwd->type)
{
- retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+ /* Cleartext */
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
+ passwd->passwd, circuit->snd_stream))
+ return ISIS_WARNING;
+ break;
+
+ /* HMAC MD5 */
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
+ /* Remember where TLV is written so we can later overwrite the MD5 hash */
+ auth_tlv_offset = stream_get_endp (circuit->snd_stream);
+ memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
+ if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
+ hmac_md5_hash, circuit->snd_stream))
+ return ISIS_WARNING;
+ break;
+
+ default:
+ break;
}
+ }
+
+ retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+ if (retval != ISIS_OK)
+ return retval;
+
length = (u_int16_t) stream_get_endp (circuit->snd_stream);
- assert (length >= ISIS_CSNP_HDRLEN);
/* Update PU length */
stream_putw_at (circuit->snd_stream, lenp, length);
+ /* For HMAC MD5 we need to compute the md5 hash and store it */
+ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
+ passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
+ {
+ hmac_md5 (STREAM_DATA (circuit->snd_stream),
+ stream_get_endp(circuit->snd_stream),
+ (unsigned char *) &passwd->passwd, passwd->len,
+ (caddr_t) &hmac_md5_hash);
+ /* Copy the hash into the stream */
+ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
+ hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
+ }
+
return retval;
}
/*
+ * Count the maximum number of lsps that can be accomodated by a given size.
+ */
+static uint16_t
+get_max_lsp_count (uint16_t size)
+{
+ uint16_t tlv_count;
+ uint16_t lsp_count;
+ uint16_t remaining_size;
+
+ /* First count the full size TLVs */
+ tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE;
+ lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN);
+
+ /* The last TLV, if any */
+ remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE;
+ if (remaining_size - 2 >= LSP_ENTRIES_LEN)
+ lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN;
+
+ return lsp_count;
+}
+
+/*
+ * Calculate the length of Authentication Info. TLV.
+ */
+static uint16_t
+auth_tlv_length (int level, struct isis_circuit *circuit)
+{
+ struct isis_passwd *passwd;
+ uint16_t length;
+
+ if (level == IS_LEVEL_1)
+ passwd = &circuit->area->area_passwd;
+ else
+ passwd = &circuit->area->domain_passwd;
+
+ /* Also include the length of TLV header */
+ length = AUTH_INFO_HDRLEN;
+ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
+ {
+ switch (passwd->type)
+ {
+ /* Cleartext */
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ length += passwd->len;
+ break;
+
+ /* HMAC MD5 */
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
+ length += ISIS_AUTH_MD5_SIZE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return length;
+}
+
+/*
+ * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP.
+ */
+static uint16_t
+max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit)
+{
+ int snp_hdr_len;
+ int auth_tlv_len;
+ uint16_t lsp_count;
+
+ snp_hdr_len = ISIS_FIXED_HDR_LEN;
+ if (snp_type == ISIS_SNP_CSNP_FLAG)
+ snp_hdr_len += ISIS_CSNP_HDRLEN;
+ else
+ snp_hdr_len += ISIS_PSNP_HDRLEN;
+
+ auth_tlv_len = auth_tlv_length (level, circuit);
+ lsp_count = get_max_lsp_count (
+ stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len);
+ return lsp_count;
+}
+
+/*
* FIXME: support multiple CSNPs
*/
int
send_csnp (struct isis_circuit *circuit, int level)
{
- int retval = ISIS_OK;
u_char start[ISIS_SYS_ID_LEN + 2];
u_char stop[ISIS_SYS_ID_LEN + 2];
struct list *list = NULL;
struct listnode *node;
struct isis_lsp *lsp;
+ u_char num_lsps, loop = 1;
+ int i, retval = ISIS_OK;
- if (circuit->state != C_STATE_UP || circuit->interface == NULL)
- return ISIS_WARNING;
+ if (circuit->area->lspdb[level - 1] == NULL ||
+ dict_count (circuit->area->lspdb[level - 1]) == 0)
+ return retval;
memset (start, 0x00, ISIS_SYS_ID_LEN + 2);
memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
- if (circuit->area->lspdb[level - 1] &&
- dict_count (circuit->area->lspdb[level - 1]) > 0)
+ num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit);
+
+ while (loop)
{
list = list_new ();
- lsp_build_list (start, stop, list, circuit->area->lspdb[level - 1]);
-
- if (circuit->snd_stream == NULL)
- circuit->snd_stream = stream_new (ISO_MTU (circuit));
+ lsp_build_list (start, stop, num_lsps, list,
+ circuit->area->lspdb[level - 1]);
+ /*
+ * Update the stop lsp_id before encoding this CSNP.
+ */
+ if (listcount (list) < num_lsps)
+ {
+ memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
+ }
else
- stream_reset (circuit->snd_stream);
+ {
+ node = listtail (list);
+ lsp = listgetdata (node);
+ memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2);
+ }
retval = build_csnp (level, start, stop, list, circuit);
+ if (retval != ISIS_OK)
+ {
+ zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed",
+ circuit->area->area_tag, level, circuit->interface->name);
+ list_delete (list);
+ return retval;
+ }
if (isis->debugs & DEBUG_SNP_PACKETS)
- {
- zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
- circuit->area->area_tag, level, circuit->interface->name,
- /* FIXME: use %z when we stop supporting old compilers. */
- (unsigned long) STREAM_SIZE (circuit->snd_stream));
- for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
- {
- zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
- " cksum 0x%04x, lifetime %us",
- circuit->area->area_tag,
- rawlspid_print (lsp->lsp_header->lsp_id),
- ntohl (lsp->lsp_header->seq_num),
- ntohs (lsp->lsp_header->checksum),
- ntohs (lsp->lsp_header->rem_lifetime));
- }
- }
+ {
+ zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld",
+ circuit->area->area_tag, level, circuit->interface->name,
+ stream_get_endp (circuit->snd_stream));
+ for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
+ {
+ zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x,"
+ " cksum 0x%04x, lifetime %us",
+ circuit->area->area_tag,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum),
+ ntohs (lsp->lsp_header->rem_lifetime));
+ }
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+ stream_get_endp (circuit->snd_stream));
+ }
+ retval = circuit->tx (circuit, level);
+ if (retval != ISIS_OK)
+ {
+ zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
+ list_delete (list);
+ return retval;
+ }
+
+ /*
+ * Start lsp_id of the next CSNP should be one plus the
+ * stop lsp_id in this current CSNP.
+ */
+ memcpy (start, stop, ISIS_SYS_ID_LEN + 2);
+ loop = 0;
+ for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i)
+ {
+ if (start[i] < (u_char)0xff)
+ {
+ start[i] += 1;
+ loop = 1;
+ break;
+ }
+ }
+ memset (stop, 0xff, ISIS_SYS_ID_LEN + 2);
list_delete (list);
-
- if (retval == ISIS_OK)
- retval = circuit->tx (circuit, level);
}
+
return retval;
}
@@ -2325,7 +2750,9 @@
circuit->t_send_csnp[0] = NULL;
if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0])
+ {
send_csnp (circuit, 1);
+ }
/* set next timer thread */
THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));
@@ -2345,7 +2772,9 @@
circuit->t_send_csnp[1] = NULL;
if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1])
+ {
send_csnp (circuit, 2);
+ }
/* set next timer thread */
THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));
@@ -2359,12 +2788,19 @@
struct isis_fixed_hdr fixed_hdr;
unsigned long lenp;
u_int16_t length;
- int retval = 0;
struct isis_lsp *lsp;
struct isis_passwd *passwd;
struct listnode *node;
+ unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];
+ unsigned long auth_tlv_offset = 0;
+ int retval = ISIS_OK;
- if (level == 1)
+ if (circuit->snd_stream == NULL)
+ circuit->snd_stream = stream_new (ISO_MTU (circuit));
+ else
+ stream_reset (circuit->snd_stream);
+
+ if (level == IS_LEVEL_1)
fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
circuit->snd_stream);
else
@@ -2383,20 +2819,40 @@
* And TLVs
*/
- if (level == 1)
+ if (level == IS_LEVEL_1)
passwd = &circuit->area->area_passwd;
else
passwd = &circuit->area->domain_passwd;
if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND))
- if (passwd->type)
- retval = tlv_add_authinfo (passwd->type, passwd->len,
- passwd->passwd, circuit->snd_stream);
-
- if (!retval && lsps)
+ {
+ switch (passwd->type)
{
- retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+ /* Cleartext */
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len,
+ passwd->passwd, circuit->snd_stream))
+ return ISIS_WARNING;
+ break;
+
+ /* HMAC MD5 */
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
+ /* Remember where TLV is written so we can later overwrite the MD5 hash */
+ auth_tlv_offset = stream_get_endp (circuit->snd_stream);
+ memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
+ if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
+ hmac_md5_hash, circuit->snd_stream))
+ return ISIS_WARNING;
+ break;
+
+ default:
+ break;
}
+ }
+
+ retval = tlv_add_lsp_entries (lsps, circuit->snd_stream);
+ if (retval != ISIS_OK)
+ return retval;
if (isis->debugs & DEBUG_SNP_PACKETS)
{
@@ -2413,10 +2869,22 @@
}
length = (u_int16_t) stream_get_endp (circuit->snd_stream);
- assert (length >= ISIS_PSNP_HDRLEN);
/* Update PDU length */
stream_putw_at (circuit->snd_stream, lenp, length);
+ /* For HMAC MD5 we need to compute the md5 hash and store it */
+ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) &&
+ passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5)
+ {
+ hmac_md5 (STREAM_DATA (circuit->snd_stream),
+ stream_get_endp(circuit->snd_stream),
+ (unsigned char *) &passwd->passwd, passwd->len,
+ (caddr_t) &hmac_md5_hash);
+ /* Copy the hash into the stream */
+ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3,
+ hmac_md5_hash, ISIS_AUTH_MD5_SIZE);
+ }
+
return ISIS_OK;
}
@@ -2427,57 +2895,74 @@
static int
send_psnp (int level, struct isis_circuit *circuit)
{
- int retval = ISIS_OK;
struct isis_lsp *lsp;
struct list *list = NULL;
struct listnode *node;
+ u_char num_lsps;
+ int retval = ISIS_OK;
- if (circuit->state != C_STATE_UP || circuit->interface == NULL)
- return ISIS_WARNING;
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST &&
+ circuit->u.bc.is_dr[level - 1])
+ return ISIS_OK;
- if ((circuit->circ_type == CIRCUIT_T_BROADCAST &&
- !circuit->u.bc.is_dr[level - 1]) ||
- circuit->circ_type != CIRCUIT_T_BROADCAST)
+ if (circuit->area->lspdb[level - 1] == NULL ||
+ dict_count (circuit->area->lspdb[level - 1]) == 0)
+ return ISIS_OK;
+
+ if (! circuit->snd_stream)
+ return ISIS_ERROR;
+
+ num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit);
+
+ while (1)
{
+ list = list_new ();
+ lsp_build_list_ssn (circuit, num_lsps, list,
+ circuit->area->lspdb[level - 1]);
- if (circuit->area->lspdb[level - 1] &&
- dict_count (circuit->area->lspdb[level - 1]) > 0)
- {
- list = list_new ();
- lsp_build_list_ssn (circuit, list, circuit->area->lspdb[level - 1]);
+ if (listcount (list) == 0)
+ {
+ list_delete (list);
+ return ISIS_OK;
+ }
- if (listcount (list) > 0)
- {
- if (circuit->snd_stream == NULL)
- circuit->snd_stream = stream_new (ISO_MTU (circuit));
- else
- stream_reset (circuit->snd_stream);
+ retval = build_psnp (level, circuit, list);
+ if (retval != ISIS_OK)
+ {
+ zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed",
+ circuit->area->area_tag, level, circuit->interface->name);
+ list_delete (list);
+ return retval;
+ }
+ if (isis->debugs & DEBUG_SNP_PACKETS)
+ {
+ zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
+ circuit->area->area_tag, level,
+ circuit->interface->name,
+ stream_get_endp (circuit->snd_stream));
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+ stream_get_endp (circuit->snd_stream));
+ }
- if (isis->debugs & DEBUG_SNP_PACKETS)
- zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld",
- circuit->area->area_tag, level,
- circuit->interface->name,
- /* FIXME: use %z when we stop supporting old
- * compilers. */
- (unsigned long) STREAM_SIZE (circuit->snd_stream));
+ retval = circuit->tx (circuit, level);
+ if (retval != ISIS_OK)
+ {
+ zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
+ list_delete (list);
+ return retval;
+ }
- retval = build_psnp (level, circuit, list);
- if (retval == ISIS_OK)
- retval = circuit->tx (circuit, level);
-
- if (retval == ISIS_OK)
- {
- /*
- * sending succeeded, we can clear SSN flags of this circuit
- * for the LSPs in list
- */
- for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
- ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
- }
- }
- list_delete (list);
- }
+ /*
+ * sending succeeded, we can clear SSN flags of this circuit
+ * for the LSPs in list
+ */
+ for (ALL_LIST_ELEMENTS_RO (list, node, lsp))
+ ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);
+ list_delete (list);
}
return retval;
@@ -2536,90 +3021,80 @@
struct isis_circuit *circuit;
struct isis_lsp *lsp;
struct listnode *node;
- int retval = 0;
+ int retval = ISIS_OK;
circuit = THREAD_ARG (thread);
assert (circuit);
- if (circuit->state != C_STATE_UP || circuit->interface == NULL)
- return ISIS_WARNING;
+ if (circuit->state != C_STATE_UP || circuit->is_passive == 1)
+ {
+ return retval;
+ }
lsp = listgetdata ((node = listhead (circuit->lsp_queue)));
/*
* Do not send if levels do not match
*/
- if (!(lsp->level & circuit->circuit_is_type))
- goto dontsend;
+ if (!(lsp->level & circuit->is_type))
+ {
+ list_delete_node (circuit->lsp_queue, node);
+ return retval;
+ }
/*
* Do not send if we do not have adjacencies in state up on the circuit
*/
if (circuit->upadjcount[lsp->level - 1] == 0)
- goto dontsend;
- /* only send if it needs sending */
- if ((time (NULL) - lsp->last_sent) >=
- circuit->area->lsp_gen_interval[lsp->level - 1])
{
-
- if (isis->debugs & DEBUG_UPDATE_PACKETS)
- {
- zlog_debug
- ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
- " lifetime %us on %s", circuit->area->area_tag, lsp->level,
- rawlspid_print (lsp->lsp_header->lsp_id),
- ntohl (lsp->lsp_header->seq_num),
- ntohs (lsp->lsp_header->checksum),
- ntohs (lsp->lsp_header->rem_lifetime),
- circuit->interface->name);
- }
- /* copy our lsp to the send buffer */
- stream_copy (circuit->snd_stream, lsp->pdu);
-
- retval = circuit->tx (circuit, lsp->level);
-
- /*
- * If the sending succeeded, we can del the lsp from circuits
- * lsp_queue
- */
- if (retval == ISIS_OK)
- {
- list_delete_node (circuit->lsp_queue, node);
-
- /*
- * On broadcast circuits also the SRMflag can be cleared
- */
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
- ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
-
- if (flags_any_set (lsp->SRMflags) == 0)
- {
- /*
- * need to remember when we were last sent
- */
- lsp->last_sent = time (NULL);
- }
- }
- else
- {
- zlog_debug ("sending of level %d link state failed", lsp->level);
- }
- }
- else
- {
- /* my belief is that if it wasn't his time, the lsp can be removed
- * from the queue
- */
- dontsend:
list_delete_node (circuit->lsp_queue, node);
+ return retval;
}
-#if 0
+
+ /* copy our lsp to the send buffer */
+ stream_copy (circuit->snd_stream, lsp->pdu);
+
+ if (isis->debugs & DEBUG_UPDATE_PACKETS)
+ {
+ zlog_debug
+ ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x,"
+ " lifetime %us on %s", circuit->area->area_tag, lsp->level,
+ rawlspid_print (lsp->lsp_header->lsp_id),
+ ntohl (lsp->lsp_header->seq_num),
+ ntohs (lsp->lsp_header->checksum),
+ ntohs (lsp->lsp_header->rem_lifetime),
+ circuit->interface->name);
+ if (isis->debugs & DEBUG_PACKET_DUMP)
+ zlog_dump_data (STREAM_DATA (circuit->snd_stream),
+ stream_get_endp (circuit->snd_stream));
+ }
+
+ retval = circuit->tx (circuit, lsp->level);
+ if (retval != ISIS_OK)
+ {
+ zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed",
+ circuit->area->area_tag, lsp->level,
+ circuit->interface->name);
+ return retval;
+ }
+
/*
- * If there are still LSPs send next one after lsp-interval (33 msecs)
+ * If the sending succeeded, we can del the lsp from circuits
+ * lsp_queue
*/
- if (listcount (circuit->lsp_queue) > 0)
- thread_add_timer (master, send_lsp, circuit, 1);
-#endif
+ list_delete_node (circuit->lsp_queue, node);
+
+ /* Set the last-cleared time if the queue is empty. */
+ /* TODO: Is is possible that new lsps keep being added to the queue
+ * that the queue is never empty? */
+ if (list_isempty (circuit->lsp_queue))
+ circuit->lsp_queue_last_cleared = time (NULL);
+
+ /*
+ * On broadcast circuits also the SRMflag can be cleared
+ */
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
return retval;
}
@@ -2638,8 +3113,8 @@
else
stream_reset (circuit->snd_stream);
-// fill_llc_hdr (stream);
- if (level == 1)
+ // fill_llc_hdr (stream);
+ if (level == IS_LEVEL_1)
fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM,
circuit->snd_stream);
else
@@ -2664,7 +3139,10 @@
stream_putw_at (circuit->snd_stream, lenp, length);
retval = circuit->tx (circuit, level);
+ if (retval != ISIS_OK)
+ zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
return retval;
}
-
diff --git a/isisd/isis_pdu.h b/isisd/isis_pdu.h
index c4c38e2..3eca731 100644
--- a/isisd/isis_pdu.h
+++ b/isisd/isis_pdu.h
@@ -95,7 +95,7 @@
u_char version2;
u_char reserved;
u_char max_area_addrs;
-};
+} __attribute__ ((packed));
#define ISIS_FIXED_HDR_LEN 8
@@ -114,7 +114,7 @@
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Holding Time | 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
- * | PDU Lenght | 2
+ * | PDU Length | 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | R | Priority | 1
* +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -142,7 +142,7 @@
* +-------+-------+-------+-------+-------+-------+-------+-------+
* + Holding Time + 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
- * + PDU Lenght + 2
+ * + PDU Length + 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
* | Local Circuit ID | 1
* +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -186,12 +186,23 @@
} __attribute__ ((packed));
#define ISIS_LSP_HDR_LEN 19
+/*
+ * Since the length field of LSP Entries TLV is one byte long, and each LSP
+ * entry is LSP_ENTRIES_LEN (16) bytes long, the maximum number of LSP entries
+ * can be accomodated in a TLV is
+ * 255 / 16 = 15.
+ *
+ * Therefore, the maximum length of the LSP Entries TLV is
+ * 16 * 15 + 2 (header) = 242 bytes.
+ */
+#define MAX_LSP_ENTRIES_TLV_SIZE 242
+
#define L1_COMPLETE_SEQ_NUM 24
#define L2_COMPLETE_SEQ_NUM 25
/*
* L1 and L2 IS to IS complete sequence numbers PDU header
* +-------+-------+-------+-------+-------+-------+-------+-------+
- * + PDU Lenght + 2
+ * + PDU Length + 2
* +-------+-------+-------+-------+-------+-------+-------+-------+
* + Source ID + id_len + 1
* +-------+-------+-------+-------+-------+-------+-------+-------+
@@ -241,6 +252,8 @@
#define ISIS_SNP_PSNP_FLAG 0
#define ISIS_SNP_CSNP_FLAG 1
+#define ISIS_AUTH_MD5_SIZE 16U
+
/*
* Sending functions
*/
@@ -258,7 +271,4 @@
void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type);
int send_hello (struct isis_circuit *circuit, int level);
-#define ISIS_AUTH_MD5_SIZE 16U
-int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit *c);
-
#endif /* _ZEBRA_ISIS_PDU_H */
diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c
index 8a5c3ed..42947b2 100644
--- a/isisd/isis_pfpacket.c
+++ b/isisd/isis_pfpacket.c
@@ -134,7 +134,7 @@
circuit->fd = fd;
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ if (if_is_broadcast (circuit->interface))
{
/*
* Join to multicast groups
@@ -142,24 +142,22 @@
* 8.4.2 - Broadcast subnetwork IIH PDUs
* FIXME: is there a case only one will fail??
*/
- if (circuit->circuit_is_type & IS_LEVEL_1)
- {
- /* joining ALL_L1_ISS */
- retval = isis_multicast_join (circuit->fd, 1,
- circuit->interface->ifindex);
- /* joining ALL_ISS */
- retval = isis_multicast_join (circuit->fd, 3,
- circuit->interface->ifindex);
- }
- if (circuit->circuit_is_type & IS_LEVEL_2)
- /* joining ALL_L2_ISS */
- retval = isis_multicast_join (circuit->fd, 2,
- circuit->interface->ifindex);
+ if (circuit->is_type & IS_LEVEL_1)
+ /* joining ALL_L1_ISS */
+ retval = isis_multicast_join (circuit->fd, 1,
+ circuit->interface->ifindex);
+ if (circuit->is_type & IS_LEVEL_2)
+ /* joining ALL_L2_ISS */
+ retval = isis_multicast_join (circuit->fd, 2,
+ circuit->interface->ifindex);
+ /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */
+ retval = isis_multicast_join (circuit->fd, 3,
+ circuit->interface->ifindex);
}
else
{
retval =
- isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
+ isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex);
}
return retval;
@@ -184,12 +182,13 @@
goto end;
}
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ /* Assign Rx and Tx callbacks are based on real if type */
+ if (if_is_broadcast (circuit->interface))
{
circuit->tx = isis_send_pdu_bcast;
circuit->rx = isis_recv_pdu_bcast;
}
- else if (circuit->circ_type == CIRCUIT_T_P2P)
+ else if (if_is_pointopoint (circuit->interface))
{
circuit->tx = isis_send_pdu_p2p;
circuit->rx = isis_recv_pdu_p2p;
@@ -232,19 +231,16 @@
LLC_LEN, MSG_PEEK,
(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
- if (!circuit->area) {
- return ISIS_OK;
- }
-
if (bytesread < 0)
{
- zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s",
- circuit->fd, safe_strerror (errno));
- zlog_warn ("circuit is %s", circuit->interface->name);
- zlog_warn ("circuit fd %d", circuit->fd);
- zlog_warn ("bytesread %d", bytesread);
+ zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, "
+ "recvfrom(): %s",
+ circuit->interface->name, circuit->fd, bytesread,
+ safe_strerror (errno));
/* get rid of the packet */
- bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
+ MSG_DONTWAIT, (struct sockaddr *) &s_addr,
+ (socklen_t *) &addr_len);
return ISIS_WARNING;
}
/*
@@ -253,15 +249,22 @@
if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING)
{
/* Read the packet into discard buff */
- bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
+ MSG_DONTWAIT, (struct sockaddr *) &s_addr,
+ (socklen_t *) &addr_len);
if (bytesread < 0)
- zlog_warn ("isis_recv_pdu_bcast(): read() failed");
+ zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
return ISIS_WARNING;
}
/* on lan we have to read to the static buff first */
- bytesread = recvfrom (circuit->fd, sock_buff, circuit->interface->mtu, 0,
+ bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT,
(struct sockaddr *) &s_addr, (socklen_t *) &addr_len);
+ if (bytesread < 0)
+ {
+ zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed");
+ return ISIS_WARNING;
+ }
/* then we lose the LLC */
stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN);
@@ -289,9 +292,11 @@
if (s_addr.sll_pkttype == PACKET_OUTGOING)
{
/* Read the packet into discard buff */
- bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff));
+ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff),
+ MSG_DONTWAIT, (struct sockaddr *) &s_addr,
+ (socklen_t *) &addr_len);
if (bytesread < 0)
- zlog_warn ("isis_recv_pdu_p2p(): read() failed");
+ zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed");
return ISIS_WARNING;
}
@@ -313,6 +318,9 @@
int
isis_send_pdu_bcast (struct isis_circuit *circuit, int level)
{
+ struct msghdr msg;
+ struct iovec iov[2];
+
/* we need to do the LLC in here because of P2P circuits, which will
* not need it
*/
@@ -325,7 +333,10 @@
sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN);
sa.sll_ifindex = circuit->interface->ifindex;
sa.sll_halen = ETH_ALEN;
- if (level == 1)
+ /* RFC5309 section 4.1 recommends ALL_ISS */
+ if (circuit->circ_type == CIRCUIT_T_P2P)
+ memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN);
+ else if (level == 1)
memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN);
else
memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN);
@@ -336,14 +347,17 @@
sock_buff[1] = 0xFE;
sock_buff[2] = 0x03;
- /* then we copy the data */
- memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data,
- stream_get_endp (circuit->snd_stream));
+ memset (&msg, 0, sizeof (msg));
+ msg.msg_name = &sa;
+ msg.msg_namelen = sizeof (struct sockaddr_ll);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+ iov[0].iov_base = sock_buff;
+ iov[0].iov_len = LLC_LEN;
+ iov[1].iov_base = circuit->snd_stream->data;
+ iov[1].iov_len = stream_get_endp (circuit->snd_stream);
- /* now we can send this */
- written = sendto (circuit->fd, sock_buff,
- stream_get_endp(circuit->snd_stream) + LLC_LEN, 0,
- (struct sockaddr *) &sa, sizeof (struct sockaddr_ll));
+ written = sendmsg (circuit->fd, &msg, 0);
return ISIS_OK;
}
@@ -351,7 +365,6 @@
int
isis_send_pdu_p2p (struct isis_circuit *circuit, int level)
{
-
int written = 1;
struct sockaddr_ll sa;
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index 1286486..c99d958 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -36,6 +36,7 @@
#include "isis_constants.h"
#include "isis_common.h"
+#include "isis_flags.h"
#include "dict.h"
#include "isisd.h"
#include "isis_misc.h"
@@ -48,9 +49,6 @@
#include "isis_route.h"
#include "isis_zebra.h"
-extern struct isis *isis;
-extern struct thread_master *master;
-
static struct isis_nexthop *
isis_nexthop_create (struct in_addr *ip, unsigned int ifindex)
{
@@ -246,6 +244,7 @@
{
nh = isis_nexthop_create (ipv4_addr,
adj->circuit->interface->ifindex);
+ nh->router_address = adj->router_address;
listnode_add (nexthops, nh);
}
}
@@ -269,6 +268,7 @@
{
nh6 = isis_nexthop6_create (ipv6_addr,
adj->circuit->interface->ifindex);
+ nh6->router_address6 = adj->router_address6;
listnode_add (nexthops6, nh6);
}
}
@@ -276,8 +276,8 @@
#endif /* HAVE_IPV6 */
static struct isis_route_info *
-isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,
- struct list *adjacencies)
+isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth,
+ struct list *adjacencies)
{
struct isis_route_info *rinfo;
struct isis_adjacency *adj;
@@ -290,18 +290,34 @@
return NULL;
}
- if (family == AF_INET)
+ if (prefix->family == AF_INET)
{
rinfo->nexthops = list_new ();
for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
- adjinfo2nexthop (rinfo->nexthops, adj);
+ {
+ /* check for force resync this route */
+ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
+ SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
+ /* update neighbor router address */
+ if (depth == 2 && prefix->prefixlen == 32)
+ adj->router_address = prefix->u.prefix4;
+ adjinfo2nexthop (rinfo->nexthops, adj);
+ }
}
#ifdef HAVE_IPV6
- if (family == AF_INET6)
+ if (prefix->family == AF_INET6)
{
rinfo->nexthops6 = list_new ();
for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj))
- adjinfo2nexthop6 (rinfo->nexthops6, adj);
+ {
+ /* check for force resync this route */
+ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF))
+ SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
+ /* update neighbor router address */
+ if (depth == 2 && prefix->prefixlen == 128)
+ adj->router_address6 = prefix->u.prefix6;
+ adjinfo2nexthop6 (rinfo->nexthops6, adj);
+ }
}
#endif /* HAVE_IPV6 */
@@ -353,18 +369,25 @@
#ifdef HAVE_IPV6
struct isis_nexthop6 *nexthop6;
#endif /* HAVE_IPV6 */
+
+ if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+ return 0;
+
+ if (CHECK_FLAG (new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC))
+ return 0;
+
if (!isis_route_info_same_attrib (new, old))
return 0;
if (family == AF_INET)
{
for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop))
- if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
+ if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex)
== 0)
return 0;
for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop))
- if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
+ if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex)
== 0)
return 0;
}
@@ -386,65 +409,6 @@
return 1;
}
-static void
-isis_nexthops_merge (struct list *new, struct list *old)
-{
- struct listnode *node;
- struct isis_nexthop *nexthop;
-
- for (ALL_LIST_ELEMENTS_RO (new, node, nexthop))
- {
- if (nexthoplookup (old, &nexthop->ip, nexthop->ifindex))
- continue;
- listnode_add (old, nexthop);
- nexthop->lock++;
- }
-}
-
-#ifdef HAVE_IPV6
-static void
-isis_nexthops6_merge (struct list *new, struct list *old)
-{
- struct listnode *node;
- struct isis_nexthop6 *nexthop6;
-
- for (ALL_LIST_ELEMENTS_RO (new, node, nexthop6))
- {
- if (nexthop6lookup (old, &nexthop6->ip6, nexthop6->ifindex))
- continue;
- listnode_add (old, nexthop6);
- nexthop6->lock++;
- }
-}
-#endif /* HAVE_IPV6 */
-
-static void
-isis_route_info_merge (struct isis_route_info *new,
- struct isis_route_info *old, u_char family)
-{
- if (family == AF_INET)
- isis_nexthops_merge (new->nexthops, old->nexthops);
-#ifdef HAVE_IPV6
- else if (family == AF_INET6)
- isis_nexthops6_merge (new->nexthops6, old->nexthops6);
-#endif /* HAVE_IPV6 */
-
- return;
-}
-
-static int
-isis_route_info_prefer_new (struct isis_route_info *new,
- struct isis_route_info *old)
-{
- if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ACTIVE))
- return 1;
-
- if (new->cost < old->cost)
- return 1;
-
- return 0;
-}
-
struct isis_route_info *
isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,
struct list *adjacencies, struct isis_area *area,
@@ -459,7 +423,7 @@
/* for debugs */
prefix2str (prefix, (char *) buff, BUFSIZ);
- rinfo_new = isis_route_info_new (cost, depth, family, adjacencies);
+ rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies);
if (!rinfo_new)
{
zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!",
@@ -479,68 +443,32 @@
if (!rinfo_old)
{
if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
- SET_FLAG (rinfo_new->flag, ISIS_ROUTE_FLAG_ACTIVE);
- route_node->info = rinfo_new;
- return rinfo_new;
- }
-
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
- buff);
-
- if (isis_route_info_same (rinfo_new, rinfo_old, family))
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff);
- isis_route_info_delete (rinfo_new);
- route_info = rinfo_old;
- }
- else if (isis_route_info_same_attrib (rinfo_new, rinfo_old))
- {
- /* merge the nexthop lists */
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route changed (same attribs): %s",
- area->area_tag, buff);
-#ifdef EXTREME_DEBUG
- if (family == AF_INET)
- {
- zlog_debug ("Old nexthops");
- nexthops_print (rinfo_old->nexthops);
- zlog_debug ("New nexthops");
- nexthops_print (rinfo_new->nexthops);
- }
- else if (family == AF_INET6)
- {
- zlog_debug ("Old nexthops");
- nexthops6_print (rinfo_old->nexthops6);
- zlog_debug ("New nexthops");
- nexthops6_print (rinfo_new->nexthops6);
- }
-#endif /* EXTREME_DEBUG */
- isis_route_info_merge (rinfo_new, rinfo_old, family);
- isis_route_info_delete (rinfo_new);
- route_info = rinfo_old;
- UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+ zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff);
+ route_info = rinfo_new;
+ UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
else
{
- if (isis_route_info_prefer_new (rinfo_new, rinfo_old))
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
- buff);
- isis_route_info_delete (rinfo_old);
- route_info = rinfo_new;
- }
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag,
+ buff);
+ if (isis_route_info_same (rinfo_new, rinfo_old, family))
+ {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag,
+ buff);
+ isis_route_info_delete (rinfo_new);
+ route_info = rinfo_old;
+ }
else
- {
- if (isis->debugs & DEBUG_RTE_EVENTS)
- zlog_debug ("ISIS-Rte (%s) route rejected: %s", area->area_tag,
- buff);
- isis_route_info_delete (rinfo_new);
- route_info = rinfo_old;
- }
+ {
+ if (isis->debugs & DEBUG_RTE_EVENTS)
+ zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag,
+ buff);
+ isis_route_info_delete (rinfo_old);
+ route_info = rinfo_new;
+ UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+ }
}
SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE);
@@ -570,7 +498,7 @@
return;
}
- if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+ if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
{
UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
if (isis->debugs & DEBUG_RTE_EVENTS)
@@ -600,10 +528,12 @@
if (isis->debugs & DEBUG_RTE_EVENTS)
{
prefix2str (&rnode->p, (char *) buff, BUFSIZ);
- zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s",
+ zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s",
area->area_tag,
- (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC) ?
- "sync'ed" : "nosync"),
+ (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED) ?
+ "synced" : "not-synced"),
+ (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC) ?
+ "resync" : "not-resync"),
(CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ?
"active" : "inactive"), buff);
}
@@ -706,41 +636,55 @@
/* Walk through route tables and propagate necessary changes into RIB. In case
* of L1L2 area, level tables have to be merged at first. */
-int
-isis_route_validate (struct thread *thread)
+void
+isis_route_validate (struct isis_area *area)
{
- struct isis_area *area;
-
- area = THREAD_ARG (thread);
+ struct listnode *node;
+ struct isis_circuit *circuit;
if (area->is_type == IS_LEVEL_1)
- {
- isis_route_validate_table (area, area->route_table[0]);
- goto validate_ipv6;
- }
- if (area->is_type == IS_LEVEL_2)
- {
- isis_route_validate_table (area, area->route_table[1]);
- goto validate_ipv6;
- }
+ isis_route_validate_table (area, area->route_table[0]);
+ else if (area->is_type == IS_LEVEL_2)
+ isis_route_validate_table (area, area->route_table[1]);
+ else
+ isis_route_validate_merge (area, AF_INET);
- isis_route_validate_merge (area, AF_INET);
-
-validate_ipv6:
#ifdef HAVE_IPV6
if (area->is_type == IS_LEVEL_1)
- {
- isis_route_validate_table (area, area->route_table6[0]);
- return ISIS_OK;
- }
- if (area->is_type == IS_LEVEL_2)
- {
- isis_route_validate_table (area, area->route_table6[1]);
- return ISIS_OK;
- }
-
- isis_route_validate_merge (area, AF_INET6);
+ isis_route_validate_table (area, area->route_table6[0]);
+ else if (area->is_type == IS_LEVEL_2)
+ isis_route_validate_table (area, area->route_table6[1]);
+ else
+ isis_route_validate_merge (area, AF_INET6);
#endif
- return ISIS_OK;
+ /* walk all circuits and reset any spf specific flags */
+ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
+ UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
+
+ return;
+}
+
+void
+isis_route_invalidate_table (struct isis_area *area, struct route_table *table)
+{
+ struct route_node *rode;
+ struct isis_route_info *rinfo;
+ for (rode = route_top (table); rode; rode = route_next (rode))
+ {
+ if (rode->info == NULL)
+ continue;
+ rinfo = rode->info;
+
+ UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
+ }
+}
+
+void
+isis_route_invalidate (struct isis_area *area)
+{
+ if (area->is_type & IS_LEVEL_1)
+ isis_route_invalidate_table (area, area->route_table[0]);
+ if (area->is_type & IS_LEVEL_2)
+ isis_route_invalidate_table (area, area->route_table[1]);
}
diff --git a/isisd/isis_route.h b/isisd/isis_route.h
index 4eac79b..5adea22 100644
--- a/isisd/isis_route.h
+++ b/isisd/isis_route.h
@@ -30,6 +30,7 @@
{
unsigned int ifindex;
struct in6_addr ip6;
+ struct in6_addr router_address6;
unsigned int lock;
};
#endif /* HAVE_IPV6 */
@@ -38,13 +39,15 @@
{
unsigned int ifindex;
struct in_addr ip;
+ struct in_addr router_address;
unsigned int lock;
};
struct isis_route_info
{
-#define ISIS_ROUTE_FLAG_ZEBRA_SYNC 0x01
-#define ISIS_ROUTE_FLAG_ACTIVE 0x02
+#define ISIS_ROUTE_FLAG_ACTIVE 0x01 /* active route for the prefix */
+#define ISIS_ROUTE_FLAG_ZEBRA_SYNCED 0x02 /* set when route synced to zebra */
+#define ISIS_ROUTE_FLAG_ZEBRA_RESYNC 0x04 /* set when route needs to sync */
u_char flag;
u_int32_t cost;
u_int32_t depth;
@@ -59,6 +62,9 @@
struct list *adjacencies,
struct isis_area *area, int level);
-int isis_route_validate (struct thread *thread);
+void isis_route_validate (struct isis_area *area);
+void isis_route_invalidate_table (struct isis_area *area,
+ struct route_table *table);
+void isis_route_invalidate (struct isis_area *area);
#endif /* _ZEBRA_ISIS_ROUTE_H */
diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c
index cff0fa3..558d391 100644
--- a/isisd/isis_routemap.c
+++ b/isisd/isis_routemap.c
@@ -35,6 +35,7 @@
#include "isis_constants.h"
#include "isis_common.h"
+#include "isis_flags.h"
#include "dict.h"
#include "isisd.h"
#include "isis_misc.h"
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 5d0b161..198104a 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -36,6 +36,7 @@
#include "isis_constants.h"
#include "isis_common.h"
+#include "isis_flags.h"
#include "dict.h"
#include "isisd.h"
#include "isis_misc.h"
@@ -49,10 +50,6 @@
#include "isis_route.h"
#include "isis_csm.h"
-extern struct isis *isis;
-extern struct thread_master *master;
-extern struct host host;
-
int isis_run_spf_l1 (struct thread *thread);
int isis_run_spf_l2 (struct thread *thread);
@@ -113,7 +110,6 @@
return;
}
-#ifdef EXTREME_DEBUG
static const char *
vtype2string (enum vertextype vtype)
{
@@ -164,12 +160,12 @@
{
case VTYPE_PSEUDO_IS:
case VTYPE_PSEUDO_TE_IS:
- return rawlspid_print (vertex->N.id);
+ return print_sys_hostname (vertex->N.id);
break;
case VTYPE_NONPSEUDO_IS:
case VTYPE_NONPSEUDO_TE_IS:
case VTYPE_ES:
- return sysid_print (vertex->N.id);
+ return print_sys_hostname (vertex->N.id);
break;
case VTYPE_IPREACH_INTERNAL:
case VTYPE_IPREACH_EXTERNAL:
@@ -186,77 +182,6 @@
return (char *) buff;
}
-#endif /* EXTREME_DEBUG */
-
-static struct isis_spftree *
-isis_spftree_new ()
-{
- struct isis_spftree *tree;
-
- tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
- if (tree == NULL)
- {
- zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
- return NULL;
- }
-
- tree->tents = list_new ();
- tree->paths = list_new ();
- return tree;
-}
-
-static void
-isis_vertex_del (struct isis_vertex *vertex)
-{
- list_delete (vertex->Adj_N);
-
- XFREE (MTYPE_ISIS_VERTEX, vertex);
-
- return;
-}
-
-#if 0 /* HT: Not used yet. */
-static void
-isis_spftree_del (struct isis_spftree *spftree)
-{
- spftree->tents->del = (void (*)(void *)) isis_vertex_del;
- list_delete (spftree->tents);
-
- spftree->paths->del = (void (*)(void *)) isis_vertex_del;
- list_delete (spftree->paths);
-
- XFREE (MTYPE_ISIS_SPFTREE, spftree);
-
- return;
-}
-#endif
-
-void
-spftree_area_init (struct isis_area *area)
-{
- if ((area->is_type & IS_LEVEL_1) && area->spftree[0] == NULL)
- {
- area->spftree[0] = isis_spftree_new ();
-#ifdef HAVE_IPV6
- area->spftree6[0] = isis_spftree_new ();
-#endif
-
- /* thread_add_timer (master, isis_run_spf_l1, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
- }
-
- if ((area->is_type & IS_LEVEL_2) && area->spftree[1] == NULL)
- {
- area->spftree[1] = isis_spftree_new ();
-#ifdef HAVE_IPV6
- area->spftree6[1] = isis_spftree_new ();
-#endif
- /* thread_add_timer (master, isis_run_spf_l2, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10)); */
- }
-
- return;
-}
static struct isis_vertex *
isis_vertex_new (void *id, enum vertextype vtype)
@@ -297,38 +222,225 @@
}
vertex->Adj_N = list_new ();
+ vertex->parents = list_new ();
+ vertex->children = list_new ();
return vertex;
}
+static void
+isis_vertex_del (struct isis_vertex *vertex)
+{
+ list_delete (vertex->Adj_N);
+ vertex->Adj_N = NULL;
+ list_delete (vertex->parents);
+ vertex->parents = NULL;
+ list_delete (vertex->children);
+ vertex->children = NULL;
+
+ memset(vertex, 0, sizeof(struct isis_vertex));
+ XFREE (MTYPE_ISIS_VERTEX, vertex);
+
+ return;
+}
+
+static void
+isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj)
+{
+ struct listnode *node, *nextnode;
+ if (!vertex)
+ return;
+ for (node = listhead (vertex->Adj_N); node; node = nextnode)
+ {
+ nextnode = listnextnode(node);
+ if (listgetdata(node) == adj)
+ list_delete_node(vertex->Adj_N, node);
+ }
+ return;
+}
+
+struct isis_spftree *
+isis_spftree_new (struct isis_area *area)
+{
+ struct isis_spftree *tree;
+
+ tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree));
+ if (tree == NULL)
+ {
+ zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!");
+ return NULL;
+ }
+
+ tree->tents = list_new ();
+ tree->paths = list_new ();
+ tree->area = area;
+ tree->last_run_timestamp = 0;
+ tree->last_run_duration = 0;
+ tree->runcount = 0;
+ tree->pending = 0;
+ return tree;
+}
+
+void
+isis_spftree_del (struct isis_spftree *spftree)
+{
+ THREAD_TIMER_OFF (spftree->t_spf);
+
+ spftree->tents->del = (void (*)(void *)) isis_vertex_del;
+ list_delete (spftree->tents);
+ spftree->tents = NULL;
+
+ spftree->paths->del = (void (*)(void *)) isis_vertex_del;
+ list_delete (spftree->paths);
+ spftree->paths = NULL;
+
+ XFREE (MTYPE_ISIS_SPFTREE, spftree);
+
+ return;
+}
+
+void
+isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj)
+{
+ struct listnode *node;
+ if (!adj)
+ return;
+ for (node = listhead (spftree->tents); node; node = listnextnode (node))
+ isis_vertex_adj_del (listgetdata (node), adj);
+ for (node = listhead (spftree->paths); node; node = listnextnode (node))
+ isis_vertex_adj_del (listgetdata (node), adj);
+ return;
+}
+
+void
+spftree_area_init (struct isis_area *area)
+{
+ if (area->is_type & IS_LEVEL_1)
+ {
+ if (area->spftree[0] == NULL)
+ area->spftree[0] = isis_spftree_new (area);
+#ifdef HAVE_IPV6
+ if (area->spftree6[0] == NULL)
+ area->spftree6[0] = isis_spftree_new (area);
+#endif
+ }
+
+ if (area->is_type & IS_LEVEL_2)
+ {
+ if (area->spftree[1] == NULL)
+ area->spftree[1] = isis_spftree_new (area);
+#ifdef HAVE_IPV6
+ if (area->spftree6[1] == NULL)
+ area->spftree6[1] = isis_spftree_new (area);
+#endif
+ }
+
+ return;
+}
+
+void
+spftree_area_del (struct isis_area *area)
+{
+ if (area->is_type & IS_LEVEL_1)
+ {
+ if (area->spftree[0] != NULL)
+ {
+ isis_spftree_del (area->spftree[0]);
+ area->spftree[0] = NULL;
+ }
+#ifdef HAVE_IPV6
+ if (area->spftree6[0])
+ {
+ isis_spftree_del (area->spftree6[0]);
+ area->spftree6[0] = NULL;
+ }
+#endif
+ }
+
+ if (area->is_type & IS_LEVEL_2)
+ {
+ if (area->spftree[1] != NULL)
+ {
+ isis_spftree_del (area->spftree[1]);
+ area->spftree[1] = NULL;
+ }
+#ifdef HAVE_IPV6
+ if (area->spftree[1] != NULL)
+ {
+ isis_spftree_del (area->spftree6[1]);
+ area->spftree6[1] = NULL;
+ }
+#endif
+ }
+
+ return;
+}
+
+void
+spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj)
+{
+ if (area->is_type & IS_LEVEL_1)
+ {
+ if (area->spftree[0] != NULL)
+ isis_spftree_adj_del (area->spftree[0], adj);
+#ifdef HAVE_IPV6
+ if (area->spftree6[0] != NULL)
+ isis_spftree_adj_del (area->spftree6[0], adj);
+#endif
+ }
+
+ if (area->is_type & IS_LEVEL_2)
+ {
+ if (area->spftree[1] != NULL)
+ isis_spftree_adj_del (area->spftree[1], adj);
+#ifdef HAVE_IPV6
+ if (area->spftree6[1] != NULL)
+ isis_spftree_adj_del (area->spftree6[1], adj);
+#endif
+ }
+
+ return;
+}
+
+/*
+ * Find the system LSP: returns the LSP in our LSP database
+ * associated with the given system ID.
+ */
+static struct isis_lsp *
+isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid)
+{
+ struct isis_lsp *lsp;
+ u_char lspid[ISIS_SYS_ID_LEN + 2];
+
+ memcpy (lspid, sysid, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID (lspid) = 0;
+ LSP_FRAGMENT (lspid) = 0;
+ lsp = lsp_search (lspid, area->lspdb[level - 1]);
+ if (lsp && lsp->lsp_header->rem_lifetime != 0)
+ return lsp;
+ return NULL;
+}
+
/*
* Add this IS to the root of SPT
*/
-static void
-isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,
- int level)
+static struct isis_vertex *
+isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid)
{
struct isis_vertex *vertex;
struct isis_lsp *lsp;
- u_char lspid[ISIS_SYS_ID_LEN + 2];
#ifdef EXTREME_DEBUG
u_char buff[BUFSIZ];
#endif /* EXTREME_DEBUG */
- memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
- LSP_PSEUDO_ID (lspid) = 0;
- LSP_FRAGMENT (lspid) = 0;
- lsp = lsp_search (lspid, area->lspdb[level - 1]);
-
+ lsp = isis_root_system_lsp (spftree->area, level, sysid);
if (lsp == NULL)
zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level);
- if (!area->oldmetric)
- vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_TE_IS);
+ if (!spftree->area->oldmetric)
+ vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS);
else
- vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS);
-
- vertex->lsp = lsp;
+ vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS);
listnode_add (spftree->paths, vertex);
@@ -338,7 +450,7 @@
vertex->depth, vertex->d_N);
#endif /* EXTREME_DEBUG */
- return;
+ return vertex;
}
static struct isis_vertex *
@@ -390,26 +502,40 @@
*/
static struct isis_vertex *
isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,
- void *id, struct isis_adjacency *adj, u_int32_t cost,
- int depth, int family)
+ void *id, uint32_t cost, int depth, int family,
+ struct isis_adjacency *adj, struct isis_vertex *parent)
{
struct isis_vertex *vertex, *v;
struct listnode *node;
+ struct isis_adjacency *parent_adj;
#ifdef EXTREME_DEBUG
u_char buff[BUFSIZ];
#endif
+ assert (isis_find_vertex (spftree->paths, id, vtype) == NULL);
+ assert (isis_find_vertex (spftree->tents, id, vtype) == NULL);
vertex = isis_vertex_new (id, vtype);
vertex->d_N = cost;
vertex->depth = depth;
- if (adj)
+ if (parent) {
+ listnode_add (vertex->parents, parent);
+ if (listnode_lookup (parent->children, vertex) == NULL)
+ listnode_add (parent->children, vertex);
+ }
+
+ if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
+ for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
+ listnode_add (vertex->Adj_N, parent_adj);
+ } else if (adj) {
listnode_add (vertex->Adj_N, adj);
+ }
#ifdef EXTREME_DEBUG
- zlog_debug ("ISIS-Spf: add to TENT %s %s depth %d dist %d",
+ zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d",
+ print_sys_hostname (vertex->N.id),
vtype2string (vertex->type), vid2string (vertex, buff),
- vertex->depth, vertex->d_N);
+ vertex->depth, vertex->d_N, listcount(vertex->Adj_N));
#endif /* EXTREME_DEBUG */
if (list_isempty (spftree->tents))
@@ -417,8 +543,8 @@
listnode_add (spftree->tents, vertex);
return vertex;
}
-
- /* XXX: This cant use the standard ALL_LIST_ELEMENT macro */
+
+ /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
for (node = listhead (spftree->tents); node; node = listnextnode (node))
{
v = listgetdata (node);
@@ -427,35 +553,24 @@
list_add_node_prev (spftree->tents, node, vertex);
break;
}
- else if (v->d_N == vertex->d_N)
+ else if (v->d_N == vertex->d_N && v->type > vertex->type)
{
/* Tie break, add according to type */
- while (v && v->d_N == vertex->d_N && v->type > vertex->type)
- {
- if (v->type > vertex->type)
- {
- break;
- }
- /* XXX: this seems dubious, node is the loop iterator */
- node = listnextnode (node);
- (node) ? (v = listgetdata (node)) : (v = NULL);
- }
- list_add_node_prev (spftree->tents, node, vertex);
- break;
- }
- else if (node->next == NULL)
- {
- list_add_node_next (spftree->tents, node, vertex);
+ list_add_node_prev (spftree->tents, node, vertex);
break;
}
}
+
+ if (node == NULL)
+ listnode_add (spftree->tents, vertex);
+
return vertex;
}
-static struct isis_vertex *
+static void
isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,
- void *id, struct isis_adjacency *adj, u_int32_t cost,
- int family)
+ void *id, struct isis_adjacency *adj, uint32_t cost,
+ int family, struct isis_vertex *parent)
{
struct isis_vertex *vertex;
@@ -471,40 +586,65 @@
/* d) */
if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
remove_excess_adjs (vertex->Adj_N);
+ if (parent && (listnode_lookup (vertex->parents, parent) == NULL))
+ listnode_add (vertex->parents, parent);
+ if (parent && (listnode_lookup (parent->children, vertex) == NULL))
+ listnode_add (parent->children, vertex);
+ return;
}
- /* f) */
- else if (vertex->d_N > cost)
+ else if (vertex->d_N < cost)
{
- listnode_delete (spftree->tents, vertex);
- goto add2tent;
+ /* e) do nothing */
+ return;
}
- /* e) do nothing */
- return vertex;
+ else { /* vertex->d_N > cost */
+ /* f) */
+ struct listnode *pnode, *pnextnode;
+ struct isis_vertex *pvertex;
+ listnode_delete (spftree->tents, vertex);
+ assert (listcount (vertex->children) == 0);
+ for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
+ listnode_delete(pvertex->children, vertex);
+ isis_vertex_del (vertex);
+ }
}
-add2tent:
- return isis_spf_add2tent (spftree, vtype, id, adj, cost, 1, family);
+ isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent);
+ return;
}
static void
process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,
- u_int16_t dist, u_int16_t depth, struct isis_adjacency *adj,
- int family)
+ uint32_t dist, uint16_t depth, int family,
+ struct isis_vertex *parent)
{
struct isis_vertex *vertex;
#ifdef EXTREME_DEBUG
u_char buff[255];
#endif
+ assert (spftree && parent);
+
+ /* RFC3787 section 5.1 */
+ if (spftree->area->newmetric == 1)
+ {
+ if (dist > MAX_WIDE_PATH_METRIC)
+ return;
+ }
/* C.2.6 b) */
- if (dist > MAX_PATH_METRIC)
- return;
+ else if (spftree->area->oldmetric == 1)
+ {
+ if (dist > MAX_NARROW_PATH_METRIC)
+ return;
+ }
+
/* c) */
vertex = isis_find_vertex (spftree->paths, id, vtype);
if (vertex)
{
#ifdef EXTREME_DEBUG
- zlog_debug ("ISIS-Spf: process_N %s %s dist %d already found from PATH",
+ zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH",
+ print_sys_hostname (vertex->N.id),
vtype2string (vtype), vid2string (vertex, buff), dist);
#endif /* EXTREME_DEBUG */
assert (dist >= vertex->d_N);
@@ -517,16 +657,26 @@
{
/* 1) */
#ifdef EXTREME_DEBUG
- zlog_debug ("ISIS-Spf: process_N %s %s dist %d",
- vtype2string (vtype), vid2string (vertex, buff), dist);
+ zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d",
+ print_sys_hostname (vertex->N.id),
+ vtype2string (vtype), vid2string (vertex, buff), dist,
+ (parent ? print_sys_hostname (parent->N.id) : "null"),
+ (parent ? listcount (parent->Adj_N) : 0));
#endif /* EXTREME_DEBUG */
if (vertex->d_N == dist)
{
- if (adj)
- listnode_add (vertex->Adj_N, adj);
+ struct listnode *node;
+ struct isis_adjacency *parent_adj;
+ for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj))
+ if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL)
+ listnode_add (vertex->Adj_N, parent_adj);
/* 2) */
if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
remove_excess_adjs (vertex->Adj_N);
+ if (listnode_lookup (vertex->parents, parent) == NULL)
+ listnode_add (vertex->parents, parent);
+ if (listnode_lookup (parent->children, vertex) == NULL)
+ listnode_add (parent->children, vertex);
/* 3) */
return;
}
@@ -537,11 +687,23 @@
}
else
{
+ struct listnode *pnode, *pnextnode;
+ struct isis_vertex *pvertex;
listnode_delete (spftree->tents, vertex);
+ assert (listcount (vertex->children) == 0);
+ for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex))
+ listnode_delete(pvertex->children, vertex);
+ isis_vertex_del (vertex);
}
}
- isis_spf_add2tent (spftree, vtype, id, adj, dist, depth, family);
+#ifdef EXTREME_DEBUG
+ zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s",
+ print_sys_hostname(id), vtype2string (vtype), dist,
+ (parent ? print_sys_hostname (parent->N.id) : "null"));
+#endif /* EXTREME_DEBUG */
+
+ isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent);
return;
}
@@ -551,10 +713,10 @@
static int
isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,
uint32_t cost, uint16_t depth, int family,
- struct isis_adjacency *adj)
+ u_char *root_sysid, struct isis_vertex *parent)
{
struct listnode *node, *fragnode = NULL;
- u_int16_t dist;
+ uint32_t dist;
struct is_neigh *is_neigh;
struct te_is_neigh *te_is_neigh;
struct ipv4_reachability *ipreach;
@@ -564,114 +726,121 @@
#ifdef HAVE_IPV6
struct ipv6_reachability *ip6reach;
#endif /* HAVE_IPV6 */
+ static const u_char null_sysid[ISIS_SYS_ID_LEN];
- if (lsp->tlv_data.nlpids == NULL || !speaks (lsp->tlv_data.nlpids, family))
+ if (!speaks (lsp->tlv_data.nlpids, family))
return ISIS_OK;
lspfragloop:
if (lsp->lsp_header->seq_num == 0)
{
- zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num"
- " - do not process");
+ zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore");
return ISIS_WARNING;
}
- if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
- {
- if (lsp->tlv_data.is_neighs)
- {
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
- {
- /* C.2.6 a) */
- /* Two way connectivity */
- if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
- continue;
- dist = cost + is_neigh->metrics.metric_default;
- vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
- : VTYPE_NONPSEUDO_IS;
- process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
- depth + 1, adj, family);
- }
- }
- if (lsp->tlv_data.te_is_neighs)
- {
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
- te_is_neigh))
- {
- uint32_t metric;
- if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
- continue;
- memcpy (&metric, te_is_neigh->te_metric, 3);
- dist = cost + ntohl (metric << 8);
- vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
- : VTYPE_NONPSEUDO_TE_IS;
- process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
- depth + 1, adj, family);
- }
- }
- if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
- {
- prefix.family = AF_INET;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs,
- node, ipreach))
- {
- dist = cost + ipreach->metrics.metric_default;
- vtype = VTYPE_IPREACH_INTERNAL;
- prefix.u.prefix4 = ipreach->prefix;
- prefix.prefixlen = ip_masklen (ipreach->mask);
- process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- adj, family);
- }
- }
+#ifdef EXTREME_DEBUG
+ zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id));
+#endif /* EXTREME_DEBUG */
- if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
- {
- prefix.family = AF_INET;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs,
- node, ipreach))
- {
- dist = cost + ipreach->metrics.metric_default;
- vtype = VTYPE_IPREACH_EXTERNAL;
- prefix.u.prefix4 = ipreach->prefix;
- prefix.prefixlen = ip_masklen (ipreach->mask);
- process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- adj, family);
- }
- }
- if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
- {
- prefix.family = AF_INET;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
- node, te_ipv4_reach))
- {
- dist = cost + ntohl (te_ipv4_reach->te_metric);
- vtype = VTYPE_IPREACH_TE;
- prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
- te_ipv4_reach->control);
- prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
- process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- adj, family);
- }
- }
-#ifdef HAVE_IPV6
- if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
- {
- prefix.family = AF_INET6;
- for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs,
- node, ip6reach))
- {
- dist = cost + ip6reach->metric;
- vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
- VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
- prefix.prefixlen = ip6reach->prefix_len;
- memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
- PSIZE (ip6reach->prefix_len));
- process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
- adj, family);
- }
- }
-#endif /* HAVE_IPV6 */
+ if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits))
+ {
+ if (lsp->tlv_data.is_neighs)
+ {
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
+ {
+ /* C.2.6 a) */
+ /* Two way connectivity */
+ if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
+ continue;
+ if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+ continue;
+ dist = cost + is_neigh->metrics.metric_default;
+ vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+ : VTYPE_NONPSEUDO_IS;
+ process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
+ depth + 1, family, parent);
+ }
}
+ if (lsp->tlv_data.te_is_neighs)
+ {
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node,
+ te_is_neigh))
+ {
+ if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
+ continue;
+ if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN))
+ continue;
+ dist = cost + GET_TE_METRIC(te_is_neigh);
+ vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+ : VTYPE_NONPSEUDO_TE_IS;
+ process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
+ depth + 1, family, parent);
+ }
+ }
+ }
+
+ if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs)
+ {
+ prefix.family = AF_INET;
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach))
+ {
+ dist = cost + ipreach->metrics.metric_default;
+ vtype = VTYPE_IPREACH_INTERNAL;
+ prefix.u.prefix4 = ipreach->prefix;
+ prefix.prefixlen = ip_masklen (ipreach->mask);
+ apply_mask (&prefix);
+ process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+ family, parent);
+ }
+ }
+ if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs)
+ {
+ prefix.family = AF_INET;
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach))
+ {
+ dist = cost + ipreach->metrics.metric_default;
+ vtype = VTYPE_IPREACH_EXTERNAL;
+ prefix.u.prefix4 = ipreach->prefix;
+ prefix.prefixlen = ip_masklen (ipreach->mask);
+ apply_mask (&prefix);
+ process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+ family, parent);
+ }
+ }
+ if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs)
+ {
+ prefix.family = AF_INET;
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs,
+ node, te_ipv4_reach))
+ {
+ dist = cost + ntohl (te_ipv4_reach->te_metric);
+ vtype = VTYPE_IPREACH_TE;
+ prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start,
+ te_ipv4_reach->control);
+ prefix.prefixlen = (te_ipv4_reach->control & 0x3F);
+ apply_mask (&prefix);
+ process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+ family, parent);
+ }
+ }
+#ifdef HAVE_IPV6
+ if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs)
+ {
+ prefix.family = AF_INET6;
+ for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach))
+ {
+ dist = cost + ip6reach->metric;
+ vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ?
+ VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL;
+ prefix.prefixlen = ip6reach->prefix_len;
+ memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix,
+ PSIZE (ip6reach->prefix_len));
+ apply_mask (&prefix);
+ process_N (spftree, vtype, (void *) &prefix, dist, depth + 1,
+ family, parent);
+ }
+ }
+#endif /* HAVE_IPV6 */
if (fragnode == NULL)
fragnode = listhead (lsp->lspu.frags);
@@ -689,14 +858,16 @@
static int
isis_spf_process_pseudo_lsp (struct isis_spftree *spftree,
- struct isis_lsp *lsp, uint16_t cost,
+ struct isis_lsp *lsp, uint32_t cost,
uint16_t depth, int family,
- struct isis_adjacency *adj)
+ u_char *root_sysid,
+ struct isis_vertex *parent)
{
struct listnode *node, *fragnode = NULL;
struct is_neigh *is_neigh;
struct te_is_neigh *te_is_neigh;
enum vertextype vtype;
+ uint32_t dist;
pseudofragloop:
@@ -707,41 +878,36 @@
return ISIS_WARNING;
}
+#ifdef EXTREME_DEBUG
+ zlog_debug ("ISIS-Spf: process_pseudo_lsp %s",
+ print_sys_hostname(lsp->lsp_header->lsp_id));
+#endif /* EXTREME_DEBUG */
+
+ /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */
+
if (lsp->tlv_data.is_neighs)
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh))
{
- vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
- : VTYPE_NONPSEUDO_IS;
/* Two way connectivity */
- if (!memcmp (is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
+ if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
continue;
- if ((depth > 0 || isis_find_vertex
- (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL)
- && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id,
- vtype) == NULL)
- {
- /* C.2.5 i) */
- isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, adj,
- cost, depth, family);
- }
+ dist = cost + is_neigh->metrics.metric_default;
+ vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS
+ : VTYPE_NONPSEUDO_IS;
+ process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist,
+ depth + 1, family, parent);
}
if (lsp->tlv_data.te_is_neighs)
for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh))
{
- vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
- : VTYPE_NONPSEUDO_TE_IS;
/* Two way connectivity */
- if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN))
+ if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN))
continue;
- if ((depth > 0 || isis_find_vertex
- (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL)
- && isis_find_vertex (spftree->paths, (void *) te_is_neigh->neigh_id,
- vtype) == NULL)
- {
- /* C.2.5 i) */
- isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, adj,
- cost, depth, family);
- }
+ dist = cost + GET_TE_METRIC(te_is_neigh);
+ vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS
+ : VTYPE_NONPSEUDO_TE_IS;
+ process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist,
+ depth + 1, family, parent);
}
if (fragnode == NULL)
@@ -759,10 +925,10 @@
}
static int
-isis_spf_preload_tent (struct isis_spftree *spftree,
- struct isis_area *area, int level, int family)
+isis_spf_preload_tent (struct isis_spftree *spftree, int level,
+ int family, u_char *root_sysid,
+ struct isis_vertex *parent)
{
- struct isis_vertex *vertex;
struct isis_circuit *circuit;
struct listnode *cnode, *anode, *ipnode;
struct isis_adjacency *adj;
@@ -773,15 +939,16 @@
struct prefix prefix;
int retval = ISIS_OK;
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
+ static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2];
#ifdef HAVE_IPV6
struct prefix_ipv6 *ipv6;
#endif /* HAVE_IPV6 */
- for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
+ for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit))
{
if (circuit->state != C_STATE_UP)
continue;
- if (!(circuit->circuit_is_type & level))
+ if (!(circuit->is_type & level))
continue;
if (family == AF_INET && !circuit->ip_router)
continue;
@@ -799,8 +966,9 @@
{
prefix.u.prefix4 = ipv4->prefix;
prefix.prefixlen = ipv4->prefixlen;
+ apply_mask (&prefix);
isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix,
- NULL, 0, family);
+ NULL, 0, family, parent);
}
}
#ifdef HAVE_IPV6
@@ -811,8 +979,9 @@
{
prefix.prefixlen = ipv6->prefixlen;
prefix.u.prefix6 = ipv6->prefix;
+ apply_mask (&prefix);
isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL,
- &prefix, NULL, 0, family);
+ &prefix, NULL, 0, family, parent);
}
}
#endif /* HAVE_IPV6 */
@@ -832,40 +1001,41 @@
level, circuit->interface->name);
continue;
}
- anode = listhead (adj_list);
- while (anode)
+ for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj))
{
- adj = listgetdata (anode);
if (!speaks (&adj->nlpids, family))
- {
- anode = listnextnode (anode);
continue;
- }
switch (adj->sys_type)
{
case ISIS_SYSTYPE_ES:
isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
- circuit->te_metric[level - 1], family);
+ circuit->te_metric[level - 1],
+ family, parent);
break;
case ISIS_SYSTYPE_IS:
case ISIS_SYSTYPE_L1_IS:
case ISIS_SYSTYPE_L2_IS:
- vertex =
- isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS,
- adj->sysid, adj,
- circuit->te_metric[level - 1], family);
+ isis_spf_add_local (spftree,
+ spftree->area->oldmetric ?
+ VTYPE_NONPSEUDO_IS :
+ VTYPE_NONPSEUDO_TE_IS,
+ adj->sysid, adj,
+ circuit->te_metric[level - 1],
+ family, parent);
memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID (lsp_id) = 0;
LSP_FRAGMENT (lsp_id) = 0;
- lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
- if (!lsp)
- zlog_warn ("No lsp found for IS adjacency");
+ lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+ if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
+ zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency "
+ "L%d on %s (ID %u)",
+ rawlspid_print (lsp_id), level,
+ circuit->interface->name, circuit->circuit_id);
break;
case ISIS_SYSTYPE_UNKNOWN:
default:
zlog_warn ("isis_spf_preload_tent unknow adj type");
}
- anode = listnextnode (anode);
}
list_delete (adj_list);
/*
@@ -875,23 +1045,36 @@
memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1);
else
memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1);
- lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
+ /* can happen during DR reboot */
+ if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0)
+ {
+ if (isis->debugs & DEBUG_SPF_EVENTS)
+ zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)",
+ level, circuit->interface->name, circuit->circuit_id);
+ continue;
+ }
adj = isis_adj_lookup (lsp_id, adjdb);
/* if no adj, we are the dis or error */
if (!adj && !circuit->u.bc.is_dr[level - 1])
{
- zlog_warn ("ISIS-Spf: No adjacency found for DR");
+ zlog_warn ("ISIS-Spf: No adjacency found from root "
+ "to L%d DR %s on %s (ID %d)",
+ level, rawlspid_print (lsp_id),
+ circuit->interface->name, circuit->circuit_id);
+ continue;
}
- else if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
+ lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);
+ if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0)
{
- zlog_warn ("ISIS-Spf: No lsp found for DR");
+ zlog_warn ("ISIS-Spf: No lsp (%p) found from root "
+ "to L%d DR %s on %s (ID %d)",
+ lsp, level, rawlspid_print (lsp_id),
+ circuit->interface->name, circuit->circuit_id);
+ continue;
}
- else
- {
- isis_spf_process_pseudo_lsp (spftree, lsp,
- circuit->te_metric[level - 1], 0, family, adj);
-
- }
+ isis_spf_process_pseudo_lsp (spftree, lsp,
+ circuit->te_metric[level - 1], 0,
+ family, root_sysid, parent);
}
else if (circuit->circ_type == CIRCUIT_T_P2P)
{
@@ -902,28 +1085,36 @@
{
case ISIS_SYSTYPE_ES:
isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj,
- circuit->te_metric[level - 1], family);
+ circuit->te_metric[level - 1], family,
+ parent);
break;
case ISIS_SYSTYPE_IS:
case ISIS_SYSTYPE_L1_IS:
case ISIS_SYSTYPE_L2_IS:
if (speaks (&adj->nlpids, family))
- isis_spf_add_local (spftree, VTYPE_NONPSEUDO_IS, adj->sysid,
+ isis_spf_add_local (spftree,
+ spftree->area->oldmetric ?
+ VTYPE_NONPSEUDO_IS :
+ VTYPE_NONPSEUDO_TE_IS,
+ adj->sysid,
adj, circuit->te_metric[level - 1],
- family);
+ family, parent);
break;
case ISIS_SYSTYPE_UNKNOWN:
default:
- zlog_warn ("isis_spf_preload_tent unknow adj type");
+ zlog_warn ("isis_spf_preload_tent unknown adj type");
break;
}
}
+ else if (circuit->circ_type == CIRCUIT_T_LOOPBACK)
+ {
+ continue;
+ }
else
{
zlog_warn ("isis_spf_preload_tent unsupported media");
retval = ISIS_WARNING;
}
-
}
return retval;
@@ -935,25 +1126,30 @@
*/
static void
add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex,
- struct isis_area *area, int level)
+ int level)
{
-#ifdef EXTREME_DEBUG
u_char buff[BUFSIZ];
-#endif /* EXTREME_DEBUG */
+
+ if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
+ return;
listnode_add (spftree->paths, vertex);
#ifdef EXTREME_DEBUG
- zlog_debug ("ISIS-Spf: added %s %s depth %d dist %d to PATHS",
+ zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
+ print_sys_hostname (vertex->N.id),
vtype2string (vertex->type), vid2string (vertex, buff),
vertex->depth, vertex->d_N);
#endif /* EXTREME_DEBUG */
+
if (vertex->type > VTYPE_ES)
{
if (listcount (vertex->Adj_N) > 0)
isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N,
- vertex->depth, vertex->Adj_N, area, level);
+ vertex->depth, vertex->Adj_N, spftree->area, level);
else if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf: no adjacencies do not install route");
+ zlog_debug ("ISIS-Spf: no adjacencies do not install route for "
+ "%s depth %d dist %d", vid2string (vertex, buff),
+ vertex->depth, vertex->d_N);
}
return;
@@ -966,23 +1162,27 @@
list_delete_all_node (spftree->tents);
list_delete_all_node (spftree->paths);
spftree->tents->del = spftree->paths->del = NULL;
-
return;
}
static int
-isis_run_spf (struct isis_area *area, int level, int family)
+isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
{
int retval = ISIS_OK;
struct listnode *node;
struct isis_vertex *vertex;
+ struct isis_vertex *root_vertex;
struct isis_spftree *spftree = NULL;
u_char lsp_id[ISIS_SYS_ID_LEN + 2];
struct isis_lsp *lsp;
- struct isis_adjacency *adj = NULL;
struct route_table *table = NULL;
- struct route_node *rode;
- struct isis_route_info *rinfo;
+ struct timespec time_now;
+ unsigned long long start_time, end_time;
+
+ /* Get time that can't roll backwards. */
+ clock_gettime(CLOCK_MONOTONIC, &time_now);
+ start_time = time_now.tv_sec;
+ start_time = (start_time * 1000000) + (time_now.tv_nsec / 1000);
if (family == AF_INET)
spftree = area->spftree[level - 1];
@@ -990,8 +1190,8 @@
else if (family == AF_INET6)
spftree = area->spftree6[level - 1];
#endif
-
assert (spftree);
+ assert (sysid);
/* Make all routes in current route table inactive. */
if (family == AF_INET)
@@ -1001,71 +1201,66 @@
table = area->route_table6[level - 1];
#endif
- for (rode = route_top (table); rode; rode = route_next (rode))
- {
- if (rode->info == NULL)
- continue;
- rinfo = rode->info;
-
- UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
- }
+ isis_route_invalidate_table (area, table);
/*
* C.2.5 Step 0
*/
init_spt (spftree);
/* a) */
- isis_spf_add_self (spftree, area, level);
+ root_vertex = isis_spf_add_root (spftree, level, sysid);
/* b) */
- retval = isis_spf_preload_tent (spftree, area, level, family);
+ retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex);
+ if (retval != ISIS_OK)
+ {
+ zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid));
+ goto out;
+ }
/*
* C.2.7 Step 2
*/
if (listcount (spftree->tents) == 0)
{
- zlog_warn ("ISIS-Spf: TENT is empty");
+ zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid));
goto out;
}
while (listcount (spftree->tents) > 0)
{
- /* C.2.7 a) 1) */
node = listhead (spftree->tents);
vertex = listgetdata (node);
- /* C.2.7 a) 2) */
+#ifdef EXTREME_DEBUG
+ zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS",
+ print_sys_hostname (vertex->N.id),
+ vtype2string (vertex->type), vertex->depth, vertex->d_N);
+#endif /* EXTREME_DEBUG */
+
+ /* Remove from tent list and add to paths list */
list_delete_node (spftree->tents, node);
-
- /* C.2.7 a) 3) */
- if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type))
- continue;
- add_to_paths (spftree, vertex, area, level);
-
- if (vertex->type == VTYPE_PSEUDO_IS ||
- vertex->type == VTYPE_NONPSEUDO_IS ||
- vertex->type == VTYPE_PSEUDO_TE_IS ||
- vertex->type == VTYPE_NONPSEUDO_TE_IS )
- {
- if (listcount(vertex->Adj_N) == 0) {
- continue;
- }
- adj = listgetdata(vertex->Adj_N->head);
-
+ add_to_paths (spftree, vertex, level);
+ switch (vertex->type)
+ {
+ case VTYPE_PSEUDO_IS:
+ case VTYPE_NONPSEUDO_IS:
+ case VTYPE_PSEUDO_TE_IS:
+ case VTYPE_NONPSEUDO_TE_IS:
memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
LSP_FRAGMENT (lsp_id) = 0;
lsp = lsp_search (lsp_id, area->lspdb[level - 1]);
- if (lsp)
+ if (lsp && lsp->lsp_header->rem_lifetime != 0)
{
if (LSP_PSEUDO_ID (lsp_id))
{
isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N,
- vertex->depth, family, adj);
+ vertex->depth, family, sysid,
+ vertex);
}
else
{
isis_spf_process_lsp (spftree, lsp, vertex->d_N,
- vertex->depth, family, adj);
+ vertex->depth, family, sysid, vertex);
}
}
else
@@ -1073,13 +1268,21 @@
zlog_warn ("ISIS-Spf: No LSP found for %s",
rawlspid_print (lsp_id));
}
+ break;
+ default:;
}
}
out:
- thread_add_event (master, isis_route_validate, area, 0);
- spftree->lastrun = time (NULL);
+ isis_route_validate (area);
spftree->pending = 0;
+ spftree->runcount++;
+ spftree->last_run_timestamp = time (NULL);
+ clock_gettime(CLOCK_MONOTONIC, &time_now);
+ end_time = time_now.tv_sec;
+ end_time = (end_time * 1000000) + (time_now.tv_nsec / 1000);
+ spftree->last_run_duration = end_time - start_time;
+
return retval;
}
@@ -1094,6 +1297,7 @@
assert (area);
area->spftree[0]->t_spf = NULL;
+ area->spftree[0]->pending = 0;
if (!(area->is_type & IS_LEVEL_1))
{
@@ -1107,10 +1311,7 @@
zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
if (area->ip_circuits)
- retval = isis_run_spf (area, 1, AF_INET);
-
- THREAD_TIMER_ON (master, area->spftree[0]->t_spf, isis_run_spf_l1, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+ retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
return retval;
}
@@ -1125,6 +1326,7 @@
assert (area);
area->spftree[1]->t_spf = NULL;
+ area->spftree[1]->pending = 0;
if (!(area->is_type & IS_LEVEL_2))
{
@@ -1137,10 +1339,7 @@
zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag);
if (area->ip_circuits)
- retval = isis_run_spf (area, 2, AF_INET);
-
- THREAD_TIMER_ON (master, area->spftree[1]->t_spf, isis_run_spf_l2, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+ retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
return retval;
}
@@ -1148,53 +1347,40 @@
int
isis_spf_schedule (struct isis_area *area, int level)
{
- int retval = ISIS_OK;
struct isis_spftree *spftree = area->spftree[level - 1];
- time_t diff, now = time (NULL);
+ time_t now = time (NULL);
+ int diff = now - spftree->last_run_timestamp;
+
+ assert (diff >= 0);
+ assert (area->is_type & level);
+
+ if (isis->debugs & DEBUG_SPF_EVENTS)
+ zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
+ area->area_tag, level, diff);
if (spftree->pending)
- return retval;
-
- diff = now - spftree->lastrun;
-
- /* FIXME: let's wait a minute before doing the SPF */
- if (now - isis->uptime < 60 || isis->uptime == 0)
- {
- if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60);
- else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60);
-
- spftree->pending = 1;
- return retval;
- }
+ return ISIS_OK;
THREAD_TIMER_OFF (spftree->t_spf);
- if (diff < MINIMUM_SPF_INTERVAL)
- {
- if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
- MINIMUM_SPF_INTERVAL - diff);
- else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
- MINIMUM_SPF_INTERVAL - diff);
+ /* wait configured min_spf_interval before doing the SPF */
+ if (diff >= area->min_spf_interval[level-1])
+ return isis_run_spf (area, level, AF_INET, isis->sysid);
- spftree->pending = 1;
- }
+ if (level == 1)
+ THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
+ area->min_spf_interval[0] - diff);
else
- {
- spftree->pending = 0;
- retval = isis_run_spf (area, level, AF_INET);
- if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
- else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
- }
+ THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
+ area->min_spf_interval[1] - diff);
- return retval;
+ if (isis->debugs & DEBUG_SPF_EVENTS)
+ zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
+ area->area_tag, level, area->min_spf_interval[level-1] - diff);
+
+ spftree->pending = 1;
+
+ return ISIS_OK;
}
#ifdef HAVE_IPV6
@@ -1208,11 +1394,12 @@
assert (area);
area->spftree6[0]->t_spf = NULL;
+ area->spftree6[0]->pending = 0;
if (!(area->is_type & IS_LEVEL_1))
{
if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
+ zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
return ISIS_WARNING;
}
@@ -1220,10 +1407,7 @@
zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
if (area->ipv6_circuits)
- retval = isis_run_spf (area, 1, AF_INET6);
-
- THREAD_TIMER_ON (master, area->spftree6[0]->t_spf, isis_run_spf6_l1, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+ retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
return retval;
}
@@ -1238,6 +1422,7 @@
assert (area);
area->spftree6[1]->t_spf = NULL;
+ area->spftree6[1]->pending = 0;
if (!(area->is_type & IS_LEVEL_2))
{
@@ -1250,10 +1435,7 @@
zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
if (area->ipv6_circuits)
- retval = isis_run_spf (area, 2, AF_INET6);
-
- THREAD_TIMER_ON (master, area->spftree6[1]->t_spf, isis_run_spf6_l2, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
+ retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
return retval;
}
@@ -1263,104 +1445,110 @@
{
int retval = ISIS_OK;
struct isis_spftree *spftree = area->spftree6[level - 1];
- time_t diff, now = time (NULL);
+ time_t now = time (NULL);
+ time_t diff = now - spftree->last_run_timestamp;
+
+ assert (diff >= 0);
+ assert (area->is_type & level);
+
+ if (isis->debugs & DEBUG_SPF_EVENTS)
+ zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
+ area->area_tag, level, diff);
if (spftree->pending)
- return retval;
+ return ISIS_OK;
- diff = now - spftree->lastrun;
-
- /* FIXME: let's wait a minute before doing the SPF */
- if (now - isis->uptime < 60 || isis->uptime == 0)
- {
- if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, 60);
- else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, 60);
-
- spftree->pending = 1;
- return retval;
- }
-
THREAD_TIMER_OFF (spftree->t_spf);
- if (diff < MINIMUM_SPF_INTERVAL)
- {
- if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
- MINIMUM_SPF_INTERVAL - diff);
- else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
- MINIMUM_SPF_INTERVAL - diff);
+ /* wait configured min_spf_interval before doing the SPF */
+ if (diff >= area->min_spf_interval[level-1])
+ return isis_run_spf (area, level, AF_INET6, isis->sysid);
- spftree->pending = 1;
- }
+ if (level == 1)
+ THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+ area->min_spf_interval[0] - diff);
else
- {
- spftree->pending = 0;
- retval = isis_run_spf (area, level, AF_INET6);
+ THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+ area->min_spf_interval[1] - diff);
- if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
- else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
- isis_jitter (PERIODIC_SPF_INTERVAL, 10));
- }
+ if (isis->debugs & DEBUG_SPF_EVENTS)
+ zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
+ area->area_tag, level, area->min_spf_interval[level-1] - diff);
+
+ spftree->pending = 1;
return retval;
}
#endif
static void
-isis_print_paths (struct vty *vty, struct list *paths)
+isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid)
{
struct listnode *node;
+ struct listnode *anode;
struct isis_vertex *vertex;
- struct isis_dynhn *dyn, *nh_dyn = NULL;
struct isis_adjacency *adj;
-#if 0
u_char buff[255];
-#endif /* 0 */
- vty_out (vty, "System Id Metric Next-Hop"
- " Interface SNPA%s", VTY_NEWLINE);
+ vty_out (vty, "Vertex Type Metric "
+ "Next-Hop Interface Parent%s", VTY_NEWLINE);
- for (ALL_LIST_ELEMENTS_RO (paths, node, vertex))
- {
- if (vertex->type != VTYPE_NONPSEUDO_IS)
- continue;
- if (memcmp (vertex->N.id, isis->sysid, ISIS_SYS_ID_LEN) == 0)
- {
- vty_out (vty, "%s --%s", host.name?host.name:"",
- VTY_NEWLINE);
- }
- else
- {
- dyn = dynhn_find_by_id ((u_char *) vertex->N.id);
- adj = listgetdata (listhead (vertex->Adj_N));
- if (adj)
- {
- nh_dyn = dynhn_find_by_id (adj->sysid);
- vty_out (vty, "%-20s %-10u %-20s %-11s %-5s%s",
- (dyn != NULL) ? dyn->name.name :
- (const u_char *)rawlspid_print ((u_char *) vertex->N.id),
- vertex->d_N, (nh_dyn != NULL) ? nh_dyn->name.name :
- (const u_char *)rawlspid_print (adj->sysid),
- adj->circuit->interface->name,
- snpa_print (adj->snpa), VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) {
+ if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
+ vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid),
+ "", "");
+ vty_out (vty, "%-30s", "");
+ } else {
+ int rows = 0;
+ vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff),
+ vtype2string (vertex->type), vertex->d_N);
+ for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) {
+ if (adj) {
+ if (rows) {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%-20s %-12s %-6s ", "", "", "");
}
- else
- {
- vty_out (vty, "%s %u %s", dyn ? dyn->name.name :
- (const u_char *) rawlspid_print (vertex->N.id),
- vertex->d_N, VTY_NEWLINE);
- }
+ vty_out (vty, "%-20s %-9s ",
+ print_sys_hostname (adj->sysid),
+ adj->circuit->interface->name);
+ ++rows;
+ }
}
+ if (rows == 0)
+ vty_out (vty, "%-30s ", "");
+ }
+
+ /* Print list of parents for the ECMP DAG */
+ if (listcount (vertex->parents) > 0) {
+ struct listnode *pnode;
+ struct isis_vertex *pvertex;
+ int rows = 0;
+ for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) {
+ if (rows) {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%-72s", "");
+ }
+ vty_out (vty, "%s(%d)",
+ vid2string (pvertex, buff), pvertex->type);
+ ++rows;
+ }
+ } else {
+ vty_out (vty, " NULL ");
+ }
+
#if 0
- vty_out (vty, "%s %s %u %s", vtype2string (vertex->type),
- vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE);
+ if (listcount (vertex->children) > 0) {
+ struct listnode *cnode;
+ struct isis_vertex *cvertex;
+ for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) {
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, "%-72s", "");
+ vty_out (vty, "%s(%d) ",
+ vid2string (cvertex, buff), cvertex->type);
+ }
+ }
#endif
+ vty_out (vty, "%s", VTY_NEWLINE);
}
}
@@ -1390,7 +1578,8 @@
{
vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s",
level + 1, VTY_NEWLINE);
- isis_print_paths (vty, area->spftree[level]->paths);
+ isis_print_paths (vty, area->spftree[level]->paths, isis->sysid);
+ vty_out (vty, "%s", VTY_NEWLINE);
}
#ifdef HAVE_IPV6
if (area->ipv6_circuits > 0 && area->spftree6[level]
@@ -1399,10 +1588,13 @@
vty_out (vty,
"IS-IS paths to level-%d routers that speak IPv6%s",
level + 1, VTY_NEWLINE);
- isis_print_paths (vty, area->spftree6[level]->paths);
+ isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid);
+ vty_out (vty, "%s", VTY_NEWLINE);
}
#endif /* HAVE_IPV6 */
}
+
+ vty_out (vty, "%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
@@ -1432,7 +1624,8 @@
{
vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s",
VTY_NEWLINE);
- isis_print_paths (vty, area->spftree[0]->paths);
+ isis_print_paths (vty, area->spftree[0]->paths, isis->sysid);
+ vty_out (vty, "%s", VTY_NEWLINE);
}
#ifdef HAVE_IPV6
if (area->ipv6_circuits > 0 && area->spftree6[0]
@@ -1440,9 +1633,11 @@
{
vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s",
VTY_NEWLINE);
- isis_print_paths (vty, area->spftree6[0]->paths);
+ isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid);
+ vty_out (vty, "%s", VTY_NEWLINE);
}
#endif /* HAVE_IPV6 */
+ vty_out (vty, "%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
@@ -1472,7 +1667,8 @@
{
vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s",
VTY_NEWLINE);
- isis_print_paths (vty, area->spftree[1]->paths);
+ isis_print_paths (vty, area->spftree[1]->paths, isis->sysid);
+ vty_out (vty, "%s", VTY_NEWLINE);
}
#ifdef HAVE_IPV6
if (area->ipv6_circuits > 0 && area->spftree6[1]
@@ -1480,9 +1676,11 @@
{
vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s",
VTY_NEWLINE);
- isis_print_paths (vty, area->spftree6[1]->paths);
+ isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid);
+ vty_out (vty, "%s", VTY_NEWLINE);
}
#endif /* HAVE_IPV6 */
+ vty_out (vty, "%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
index 6bdab2d..aa543b7 100644
--- a/isisd/isis_spf.h
+++ b/isisd/isis_spf.h
@@ -54,25 +54,33 @@
struct prefix prefix;
} N;
- struct isis_lsp *lsp;
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)} */
+ struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
+ struct list *parents; /* list of parents for ECMP */
+ struct list *children; /* list of children used for tree dump */
};
struct isis_spftree
{
struct thread *t_spf; /* spf threads */
- time_t lastrun; /* for scheduling */
- int pending; /* already scheduled */
struct list *paths; /* the SPT */
struct list *tents; /* TENT */
-
- u_int32_t timerun; /* statistics */
+ struct isis_area *area; /* back pointer to area */
+ int pending; /* already scheduled */
+ unsigned int runcount; /* number of runs since uptime */
+ time_t last_run_timestamp; /* last run timestamp for scheduling */
+ time_t last_run_duration; /* last run duration in msec */
};
+struct isis_spftree * isis_spftree_new (struct isis_area *area);
+void isis_spftree_del (struct isis_spftree *spftree);
+void isis_spftree_adj_del (struct isis_spftree *spftree,
+ struct isis_adjacency *adj);
void spftree_area_init (struct isis_area *area);
+void spftree_area_del (struct isis_area *area);
+void spftree_area_adj_del (struct isis_area *area,
+ struct isis_adjacency *adj);
int isis_spf_schedule (struct isis_area *area, int level);
void isis_spf_cmds_init (void);
#ifdef HAVE_IPV6
diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c
index 3fc717e..bb57bd6 100644
--- a/isisd/isis_tlv.c
+++ b/isisd/isis_tlv.c
@@ -43,13 +43,6 @@
#include "isisd/isis_pdu.h"
#include "isisd/isis_lsp.h"
-extern struct isis *isis;
-
-/*
- * Prototypes.
- */
-int add_tlv (u_char, u_char, u_char *, struct stream *);
-
void
free_tlv (void *val)
{
@@ -75,10 +68,10 @@
list_delete (tlvs->es_neighs);
if (tlvs->lsp_entries)
list_delete (tlvs->lsp_entries);
- if (tlvs->lan_neighs)
- list_delete (tlvs->lan_neighs);
if (tlvs->prefix_neighs)
list_delete (tlvs->prefix_neighs);
+ if (tlvs->lan_neighs)
+ list_delete (tlvs->lan_neighs);
if (tlvs->ipv4_addrs)
list_delete (tlvs->ipv4_addrs);
if (tlvs->ipv4_int_reachs)
@@ -93,7 +86,9 @@
if (tlvs->ipv6_reachs)
list_delete (tlvs->ipv6_reachs);
#endif /* HAVE_IPV6 */
-
+
+ memset (tlvs, 0, sizeof (struct tlvs));
+
return;
}
@@ -103,7 +98,7 @@
*/
int
parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
- u_int32_t * found, struct tlvs *tlvs)
+ u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)
{
u_char type, length;
struct lan_neigh *lan_nei;
@@ -122,7 +117,7 @@
#endif /* HAVE_IPV6 */
u_char virtual;
int value_len, retval = ISIS_OK;
- u_char *pnt = stream;
+ u_char *start = stream, *pnt = stream;
*found = 0;
memset (tlvs, 0, sizeof (struct tlvs));
@@ -443,14 +438,22 @@
if (*expected & TLVFLAG_AUTH_INFO)
{
tlvs->auth_info.type = *pnt;
- tlvs->auth_info.len = length-1;
+ if (length == 0)
+ {
+ zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) "
+ "incorrect.", areatag, type, length);
+ return ISIS_WARNING;
+ }
+ --length;
+ tlvs->auth_info.len = length;
pnt++;
- memcpy (tlvs->auth_info.passwd, pnt, length - 1);
- /* Fill authentication with 0 for later computation
- * of MD5 (RFC 5304, 2)
- */
- memset (pnt, 0, length - 1);
- pnt += length - 1;
+ memcpy (tlvs->auth_info.passwd, pnt, length);
+ /* Return the authentication tlv pos for later computation
+ * of MD5 (RFC 5304, 2)
+ */
+ if (auth_tlv_offset)
+ *auth_tlv_offset += (pnt - start - 3);
+ pnt += length;
}
else
{
@@ -734,10 +737,14 @@
int
add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream)
{
-
- if (STREAM_SIZE (stream) - stream_get_endp (stream) < (unsigned) len + 2)
+ if ((stream_get_size (stream) - stream_get_endp (stream)) <
+ (((unsigned)len) + 2))
{
- zlog_warn ("No room for TLV of type %d", tag);
+ zlog_warn ("No room for TLV of type %d "
+ "(total size %d available %d required %d)",
+ tag, (int)stream_get_size (stream),
+ (int)(stream_get_size (stream) - stream_get_endp (stream)),
+ len+2);
return ISIS_WARNING;
}
@@ -745,7 +752,7 @@
stream_putc (stream, len); /* LENGTH */
stream_put (stream, value, (int) len); /* VALUE */
-#ifdef EXTREME_TLV_DEBUG
+#ifdef EXTREME_DEBUG
zlog_debug ("Added TLV %d len %d", tag, len);
#endif /* EXTREME DEBUG */
return ISIS_OK;
@@ -877,7 +884,7 @@
}
int
-tlv_add_authinfo (char auth_type, char auth_len, u_char *auth_value,
+tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value,
struct stream *stream)
{
u_char value[255];
@@ -1006,7 +1013,6 @@
pos += IPV4_MAX_BYTELEN;
}
-
return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
}
@@ -1027,7 +1033,7 @@
if (pos - value + (5 + prefix_size) > 255)
{
retval =
- add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);
+ add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream);
if (retval != ISIS_OK)
return retval;
pos = value;
@@ -1110,7 +1116,7 @@
/*
* How many times can we add full padding ?
*/
- fullpads = (STREAM_SIZE (stream) - stream_get_endp (stream)) / 257;
+ fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257;
for (i = 0; i < fullpads; i++)
{
if (!stream_putc (stream, (u_char) PADDING)) /* TAG */
@@ -1120,7 +1126,7 @@
stream_put (stream, NULL, 255); /* zero padding */
}
- left = STREAM_SIZE (stream) - stream_get_endp (stream);
+ left = stream_get_size (stream) - stream_get_endp (stream);
if (left < 2)
return ISIS_OK;
diff --git a/isisd/isis_tlv.h b/isisd/isis_tlv.h
index fc9f35f..e092f4d 100644
--- a/isisd/isis_tlv.h
+++ b/isisd/isis_tlv.h
@@ -30,7 +30,7 @@
* Name Value IIH LSP SNP Status
* LAN
* ____________________________________________________________________________
- *
+ *
* Area Addresses 1 y y n ISO10589
* IIS Neighbors 2 n y n ISO10589
* ES Neighbors 3 n y n ISO10589
@@ -39,52 +39,52 @@
* LSP Entries 9 n n y ISO10589
* Authentication 10 y y y ISO10589, RFC3567
* Checksum 12 y n y RFC3358
- * TE IS Reachability 22 n y n RFC3784
+ * TE IS Reachability 22 n y n RFC5305
* IS Alias 24 n y n RFC3786
* IP Int. Reachability 128 n y n RFC1195
* Protocols Supported 129 y y n RFC1195
* IP Ext. Reachability 130 n y n RFC1195
* IDRPI 131 n y y RFC1195
* IP Interface Address 132 y y n RFC1195
- * TE Router ID 134 n y n RFC3784
- * Extended IP Reachability 135 n y n RFC3784
+ * TE Router ID 134 n y n RFC5305
+ * Extended IP Reachability 135 n y n RFC5305
* Dynamic Hostname 137 n y n RFC2763
- * Shared Risk Link Group 138 n y y draft-ietf-isis-gmpls-extensions
+ * Shared Risk Link Group 138 n y y RFC5307
* Restart TLV 211 y n n RFC3847
- * MT IS Reachability 222 n y n draft-ietf-isis-wg-multi-topology
- * MT Supported 229 y y n draft-ietf-isis-wg-multi-topology
- * IPv6 Interface Address 232 y y n draft-ietf-isis_ipv6
- * MT IP Reachability 235 n y n draft-ietf-isis-wg-multi-topology
- * IPv6 IP Reachability 236 n y n draft-ietf-isis_ipv6
- * MT IPv6 IP Reachability 237 n y n draft-ietf-isis-wg-multi-topology
+ * MT IS Reachability 222 n y n RFC5120
+ * MT Supported 229 y y n RFC5120
+ * IPv6 Interface Address 232 y y n RFC5308
+ * MT IP Reachability 235 n y n RFC5120
+ * IPv6 IP Reachability 236 n y n RFC5308
+ * MT IPv6 IP Reachability 237 n y n RFC5120
* P2P Adjacency State 240 y n n RFC3373
* IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence
* Router Capability 242 - - - draft-ietf-isis-caps
*
- *
+ *
* IS Reachability sub-TLVs we (should) support.
* ____________________________________________________________________________
* Name Value Status
* ____________________________________________________________________________
- * Administartive group (color) 3 RFC3784
- * Link Local/Remote Identifiers 4 draft-ietf-isis-gmpls-extensions
- * IPv4 interface address 6 RFC3784
- * IPv4 neighbor address 8 RFC3784
- * Maximum link bandwidth 9 RFC3784
- * Reservable link bandwidth 10 RFC3784
- * Unreserved bandwidth 11 RFC3784
- * TE Default metric 18 RFC3784
- * Link Protection Type 20 draft-ietf-isis-gmpls-extensions
- * Interface Switching Capability 21 draft-ietf-isis-gmpls-extensions
+ * Administartive group (color) 3 RFC5305
+ * Link Local/Remote Identifiers 4 RFC5307
+ * IPv4 interface address 6 RFC5305
+ * IPv4 neighbor address 8 RFC5305
+ * Maximum link bandwidth 9 RFC5305
+ * Reservable link bandwidth 10 RFC5305
+ * Unreserved bandwidth 11 RFC5305
+ * TE Default metric 18 RFC5305
+ * Link Protection Type 20 RFC5307
+ * Interface Switching Capability 21 RFC5307
*
- *
+ *
* IP Reachability sub-TLVs we (should) support.
* ____________________________________________________________________________
* Name Value Status
* ____________________________________________________________________________
- * 32bit administrative tag 1 draft-ietf-isis-admin-tags
- * 64bit administrative tag 2 draft-ietf-isis-admin-tags
- * Management prefix color 117 draft-ietf-isis-wg-multi-topology
+ * 32bit administrative tag 1 RFC5130
+ * 64bit administrative tag 2 RFC5130
+ * Management prefix color 117 RFC5120
*/
#define AREA_ADDRESSES 1
@@ -110,11 +110,14 @@
#define IPV6_REACHABILITY 236
#define WAY3_HELLO 240
+#define AUTH_INFO_HDRLEN 3
+
#define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5)
#define LAN_NEIGHBOURS_LEN 6
#define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */
#define IPV4_REACH_LEN 12
#define IPV6_REACH_LEN 22
+#define TE_IPV4_REACH_LEN 9
/* struct for neighbor */
struct is_neigh
@@ -131,6 +134,15 @@
u_char sub_tlvs_length;
};
+/* Decode and encode three-octet metric into host byte order integer */
+#define GET_TE_METRIC(t) \
+ (((unsigned)(t)->te_metric[0]<<16) | ((t)->te_metric[1]<<8) | \
+ (t)->te_metric[2])
+#define SET_TE_METRIC(t, m) \
+ (((t)->te_metric[0] = (m) >> 16), \
+ ((t)->te_metric[1] = (m) >> 8), \
+ ((t)->te_metric[2] = (m)))
+
/* struct for es neighbors */
struct es_neigh
{
@@ -213,7 +225,6 @@
u_char prefix_len;
u_char prefix[16];
};
-#endif /* HAVE_IPV6 */
/* bits in control_info */
#define CTRL_INFO_DIRECTION 0x80
@@ -223,12 +234,17 @@
#define DISTRIBUTION_INTERNAL 0
#define DISTRIBUTION_EXTERNAL 1
#define CTRL_INFO_SUBTLVS 0x20
+#endif /* HAVE_IPV6 */
/*
* Pointer to each tlv type, filled by parse_tlvs()
*/
struct tlvs
{
+ struct checksum *checksum;
+ struct hostname *hostname;
+ struct nlpids *nlpids;
+ struct te_router_id *router_id;
struct list *area_addrs;
struct list *is_neighs;
struct list *te_is_neighs;
@@ -236,14 +252,10 @@
struct list *lsp_entries;
struct list *prefix_neighs;
struct list *lan_neighs;
- struct checksum *checksum;
- struct nlpids *nlpids;
struct list *ipv4_addrs;
struct list *ipv4_int_reachs;
struct list *ipv4_ext_reachs;
struct list *te_ipv4_reachs;
- struct hostname *hostname;
- struct te_router_id *router_id;
#ifdef HAVE_IPV6
struct list *ipv6_addrs;
struct list *ipv6_reachs;
@@ -281,7 +293,9 @@
void init_tlvs (struct tlvs *tlvs, uint32_t expected);
void free_tlvs (struct tlvs *tlvs);
int parse_tlvs (char *areatag, u_char * stream, int size,
- u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs);
+ u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs,
+ u_int32_t * auth_tlv_offset);
+int add_tlv (u_char, u_char, u_char *, struct stream *);
void free_tlv (void *val);
int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream);
@@ -290,7 +304,7 @@
int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream);
int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream);
int tlv_add_checksum (struct checksum *checksum, struct stream *stream);
-int tlv_add_authinfo (char auth_type, char authlen, u_char *auth_value,
+int tlv_add_authinfo (u_char auth_type, u_char authlen, u_char *auth_value,
struct stream *stream);
int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream);
int tlv_add_in_addr (struct in_addr *, struct stream *stream, u_char tag);
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index d5ccef9..2df7462 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -36,30 +36,37 @@
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_tlv.h"
#include "isisd/isisd.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_csm.h"
+#include "isisd/isis_lsp.h"
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
struct zclient *zclient = NULL;
-extern struct thread_master *master;
-extern struct isis *isis;
-
-struct in_addr router_id_zebra;
-
/* Router-id update message from zebra. */
static int
isis_router_id_update_zebra (int command, struct zclient *zclient,
zebra_size_t length)
{
+ struct isis_area *area;
+ struct listnode *node;
struct prefix router_id;
- zebra_router_id_update_read (zclient->ibuf,&router_id);
- router_id_zebra = router_id.u.prefix4;
+ zebra_router_id_update_read (zclient->ibuf, &router_id);
+ if (isis->router_id == router_id.u.prefix4.s_addr)
+ return 0;
- /* FIXME: Do we react somehow? */
+ isis->router_id = router_id.u.prefix4.s_addr;
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+ if (listcount (area->area_addrs) > 0)
+ lsp_regenerate_schedule (area, area->is_type, 0);
+
return 0;
}
@@ -100,53 +107,28 @@
zlog_debug ("Zebra I/F delete: %s index %d flags %ld metric %d mtu %d",
ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu);
+ isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
/* Cannot call if_delete because we should retain the pseudo interface
in case there is configuration info attached to it. */
if_delete_retain(ifp);
- isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
-
ifp->ifindex = IFINDEX_INTERNAL;
return 0;
}
-static struct interface *
-zebra_interface_if_lookup (struct stream *s)
-{
- char ifname_tmp[INTERFACE_NAMSIZ];
-
- /* Read interface name. */
- stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
-
- /* And look it up. */
- return if_lookup_by_name_len(ifname_tmp,
- strnlen(ifname_tmp, INTERFACE_NAMSIZ));
-}
-
static int
isis_zebra_if_state_up (int command, struct zclient *zclient,
zebra_size_t length)
{
struct interface *ifp;
- ifp = zebra_interface_if_lookup (zclient->ibuf);
+ ifp = zebra_interface_state_read (zclient->ibuf);
- if (!ifp)
+ if (ifp == NULL)
return 0;
- if (if_is_operative (ifp))
- {
- zebra_interface_if_set_value (zclient->ibuf, ifp);
- /* HT: This is wrong actually. We can't assume that circuit exist
- * if we delete circuit during if_state_down event. Needs rethink.
- * TODO */
- isis_circuit_update_params (circuit_scan_by_ifp (ifp), ifp);
- return 0;
- }
-
- zebra_interface_if_set_value (zclient->ibuf, ifp);
isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
return 0;
@@ -157,17 +139,17 @@
zebra_size_t length)
{
struct interface *ifp;
+ struct isis_circuit *circuit;
- ifp = zebra_interface_if_lookup (zclient->ibuf);
+ ifp = zebra_interface_state_read (zclient->ibuf);
if (ifp == NULL)
return 0;
- if (if_is_operative (ifp))
- {
- zebra_interface_if_set_value (zclient->ibuf, ifp);
- isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp);
- }
+ circuit = isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp),
+ ifp);
+ if (circuit)
+ SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
return 0;
}
@@ -251,7 +233,7 @@
struct isis_nexthop *nexthop;
struct listnode *node;
- if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+ if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
if (zclient->redist[ZEBRA_ROUTE_ISIS])
@@ -307,7 +289,8 @@
stream_putw_at (stream, 0, stream_get_endp (stream));
zclient_send_message(zclient);
- SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+ SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+ UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
}
}
@@ -329,7 +312,7 @@
prefix4.prefix = prefix->u.prefix4;
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4, &api);
}
- UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+ UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
return;
}
@@ -347,7 +330,7 @@
struct listnode *node;
struct prefix_ipv6 prefix6;
- if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+ if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
api.type = ZEBRA_ROUTE_ISIS;
@@ -410,7 +393,8 @@
prefix6.prefixlen = prefix->prefixlen;
memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr));
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, &prefix6, &api);
- SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+ SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+ UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
}
XFREE (MTYPE_ISIS_TMP, nexthop_list);
@@ -431,7 +415,7 @@
struct listnode *node;
struct prefix_ipv6 prefix6;
- if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC))
+ if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
api.type = ZEBRA_ROUTE_ISIS;
@@ -488,7 +472,7 @@
prefix6.prefixlen = prefix->prefixlen;
memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr));
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6, &api);
- UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC);
+ UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
XFREE (MTYPE_ISIS_TMP, nexthop_list);
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 20a3280..e8e3d9f 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -27,6 +27,7 @@
#include "command.h"
#include "log.h"
#include "memory.h"
+#include "time.h"
#include "linklist.h"
#include "if.h"
#include "hash.h"
@@ -38,8 +39,9 @@
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
-#include "isisd/isis_circuit.h"
#include "isisd/isis_flags.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_csm.h"
#include "isisd/isisd.h"
#include "isisd/isis_dynhn.h"
#include "isisd/isis_adjacency.h"
@@ -52,7 +54,6 @@
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
#include "isisd/isis_events.h"
-#include "isisd/isis_csm.h"
#ifdef TOPOLOGY_GENERATE
#include "spgrid.h"
@@ -60,19 +61,17 @@
#endif /* TOPOLOGY_GENERATE */
struct isis *isis = NULL;
-extern struct thread_master *master;
/*
* Prototypes.
*/
-void isis_new(unsigned long);
-struct isis_area *isis_area_create(void);
int isis_area_get(struct vty *, const char *);
int isis_area_destroy(struct vty *, const char *);
-int area_net_title(struct vty *, const u_char *);
-int area_clear_net_title(struct vty *, const u_char *);
-int show_clns_neigh(struct vty *, char);
-void print_debug(struct vty *, int, int);
+int area_net_title(struct vty *, const char *);
+int area_clear_net_title(struct vty *, const char *);
+int show_isis_interface_common(struct vty *, const char *ifname, char);
+int show_isis_neighbor_common(struct vty *, const char *id, char);
+int clear_isis_neighbor_common(struct vty *, const char *id);
int isis_config_write(struct vty *);
@@ -85,8 +84,8 @@
* Default values
*/
isis->max_area_addrs = 3;
-
isis->process_id = process_id;
+ isis->router_id = 0;
isis->area_list = list_new ();
isis->init_circ_list = list_new ();
isis->uptime = time (NULL);
@@ -94,6 +93,7 @@
#ifdef HAVE_IPV6
isis->nexthops6 = list_new ();
#endif /* HAVE_IPV6 */
+ dyn_cache_init ();
/*
* uncomment the next line for full debugs
*/
@@ -101,7 +101,7 @@
}
struct isis_area *
-isis_area_create ()
+isis_area_create (const char *area_tag)
{
struct isis_area *area;
@@ -115,36 +115,48 @@
area->is_type = IS_LEVEL_1;
else
area->is_type = IS_LEVEL_1_AND_2;
+
/*
* intialize the databases
*/
- area->lspdb[0] = lsp_db_init ();
- area->lspdb[1] = lsp_db_init ();
+ if (area->is_type & IS_LEVEL_1)
+ {
+ area->lspdb[0] = lsp_db_init ();
+ area->route_table[0] = route_table_init ();
+#ifdef HAVE_IPV6
+ area->route_table6[0] = route_table_init ();
+#endif /* HAVE_IPV6 */
+ }
+ if (area->is_type & IS_LEVEL_2)
+ {
+ area->lspdb[1] = lsp_db_init ();
+ area->route_table[1] = route_table_init ();
+#ifdef HAVE_IPV6
+ area->route_table6[1] = route_table_init ();
+#endif /* HAVE_IPV6 */
+ }
spftree_area_init (area);
- area->route_table[0] = route_table_init ();
- area->route_table[1] = route_table_init ();
-#ifdef HAVE_IPV6
- area->route_table6[0] = route_table_init ();
- area->route_table6[1] = route_table_init ();
-#endif /* HAVE_IPV6 */
+
area->circuit_list = list_new ();
area->area_addrs = list_new ();
THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1);
flags_initialize (&area->flags);
+
/*
* Default values
*/
- area->max_lsp_lifetime[0] = MAX_AGE; /* 1200 */
- area->max_lsp_lifetime[1] = MAX_AGE; /* 1200 */
- area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
- area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
- area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900 */
- area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900 */
+ area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME; /* 1200 */
+ area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME; /* 1200 */
+ area->lsp_refresh[0] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */
+ area->lsp_refresh[1] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */
+ area->lsp_gen_interval[0] = DEFAULT_MIN_LSP_GEN_INTERVAL;
+ area->lsp_gen_interval[1] = DEFAULT_MIN_LSP_GEN_INTERVAL;
area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL;
area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL;
area->dynhostname = 1;
- area->oldmetric = 1;
+ area->oldmetric = 0;
+ area->newmetric = 1;
area->lsp_frag_threshold = 90;
#ifdef TOPOLOGY_GENERATE
memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN);
@@ -153,6 +165,10 @@
/* FIXME: Think of a better way... */
area->min_bcast_mtu = 1497;
+ area->area_tag = strdup (area_tag);
+ listnode_add (isis->area_list, area);
+ area->isis = isis;
+
return area;
}
@@ -185,9 +201,7 @@
return CMD_SUCCESS;
}
- area = isis_area_create ();
- area->area_tag = strdup (area_tag);
- listnode_add (isis->area_list, area);
+ area = isis_area_create (area_tag);
if (isis->debugs & DEBUG_EVENTS)
zlog_debug ("New IS-IS area instance %s", area->area_tag);
@@ -204,50 +218,100 @@
struct isis_area *area;
struct listnode *node, *nnode;
struct isis_circuit *circuit;
+ struct area_addr *addr;
area = isis_area_lookup (area_tag);
if (area == NULL)
{
vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_NO_MATCH;
}
if (area->circuit_list)
{
for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit))
- {
- /* The fact that it's in circuit_list means that it was configured */
- isis_csm_state_change (ISIS_DISABLE, circuit, area);
- isis_circuit_down (circuit);
- isis_circuit_deconfigure (circuit, area);
- }
-
+ {
+ circuit->ip_router = 0;
+#ifdef HAVE_IPV6
+ circuit->ipv6_router = 0;
+#endif
+ isis_csm_state_change (ISIS_DISABLE, circuit, area);
+ }
list_delete (area->circuit_list);
+ area->circuit_list = NULL;
}
- listnode_delete (isis->area_list, area);
+
+ if (area->lspdb[0] != NULL)
+ {
+ lsp_db_destroy (area->lspdb[0]);
+ area->lspdb[0] = NULL;
+ }
+ if (area->lspdb[1] != NULL)
+ {
+ lsp_db_destroy (area->lspdb[1]);
+ area->lspdb[1] = NULL;
+ }
+
+ spftree_area_del (area);
+
+ /* invalidate and validate would delete all routes from zebra */
+ isis_route_invalidate (area);
+ isis_route_validate (area);
+
+ if (area->route_table[0])
+ {
+ route_table_finish (area->route_table[0]);
+ area->route_table[0] = NULL;
+ }
+ if (area->route_table[1])
+ {
+ route_table_finish (area->route_table[1]);
+ area->route_table[1] = NULL;
+ }
+#ifdef HAVE_IPV6
+ if (area->route_table6[0])
+ {
+ route_table_finish (area->route_table6[0]);
+ area->route_table6[0] = NULL;
+ }
+ if (area->route_table6[1])
+ {
+ route_table_finish (area->route_table6[1]);
+ area->route_table6[1] = NULL;
+ }
+#endif /* HAVE_IPV6 */
+
+ for (ALL_LIST_ELEMENTS (area->area_addrs, node, nnode, addr))
+ {
+ list_delete_node (area->area_addrs, node);
+ XFREE (MTYPE_ISIS_AREA_ADDR, addr);
+ }
+ area->area_addrs = NULL;
THREAD_TIMER_OFF (area->t_tick);
- if (area->t_remove_aged)
- thread_cancel (area->t_remove_aged);
THREAD_TIMER_OFF (area->t_lsp_refresh[0]);
THREAD_TIMER_OFF (area->t_lsp_refresh[1]);
- THREAD_TIMER_OFF (area->spftree[0]->t_spf);
- THREAD_TIMER_OFF (area->spftree[1]->t_spf);
+ thread_cancel_event (master, area);
- THREAD_TIMER_OFF (area->t_lsp_l1_regenerate);
- THREAD_TIMER_OFF (area->t_lsp_l2_regenerate);
+ listnode_delete (isis->area_list, area);
+
+ free (area->area_tag);
XFREE (MTYPE_ISIS_AREA, area);
- isis->sysid_set=0;
+ if (listcount (isis->area_list) == 0)
+ {
+ memset (isis->sysid, 0, ISIS_SYS_ID_LEN);
+ isis->sysid_set = 0;
+ }
return CMD_SUCCESS;
}
int
-area_net_title (struct vty *vty, const u_char *net_title)
+area_net_title (struct vty *vty, const char *net_title)
{
struct isis_area *area;
struct area_addr *addr;
@@ -260,7 +324,7 @@
if (!area)
{
vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_NO_MATCH;
}
/* We check that we are not over the maximal number of addresses */
@@ -268,7 +332,7 @@
{
vty_out (vty, "Maximum of area addresses (%d) already reached %s",
isis->max_area_addrs, VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_NOTHING_TODO;
}
addr = XMALLOC (MTYPE_ISIS_AREA_ADDR, sizeof (struct area_addr));
@@ -280,10 +344,18 @@
#endif /* EXTREME_DEBUG */
if (addr->addr_len < 8 || addr->addr_len > 20)
{
- zlog_warn ("area address must be at least 8..20 octets long (%d)",
- addr->addr_len);
+ vty_out (vty, "area address must be at least 8..20 octets long (%d)%s",
+ addr->addr_len, VTY_NEWLINE);
XFREE (MTYPE_ISIS_AREA_ADDR, addr);
- return CMD_WARNING;
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ if (addr->area_addr[addr->addr_len-1] != 0)
+ {
+ vty_out (vty, "nsel byte (last byte) in area address must be 0%s",
+ VTY_NEWLINE);
+ XFREE (MTYPE_ISIS_AREA_ADDR, addr);
+ return CMD_ERR_AMBIGUOUS;
}
if (isis->sysid_set == 0)
@@ -291,7 +363,7 @@
/*
* First area address - get the SystemID for this router
*/
- memcpy (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN), ISIS_SYS_ID_LEN);
+ memcpy (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN);
isis->sysid_set = 1;
if (isis->debugs & DEBUG_EVENTS)
zlog_debug ("Router has SystemID %s", sysid_print (isis->sysid));
@@ -301,20 +373,19 @@
/*
* Check that the SystemID portions match
*/
- if (memcmp (isis->sysid, GETSYSID (addr, ISIS_SYS_ID_LEN),
- ISIS_SYS_ID_LEN))
+ if (memcmp (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN))
{
vty_out (vty,
"System ID must not change when defining additional area"
" addresses%s", VTY_NEWLINE);
XFREE (MTYPE_ISIS_AREA_ADDR, addr);
- return CMD_WARNING;
+ return CMD_ERR_AMBIGUOUS;
}
/* now we see that we don't already have this address */
for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp))
{
- if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) != (addr->addr_len))
+ if ((addrp->addr_len + ISIS_SYS_ID_LEN + ISIS_NSEL_LEN) != (addr->addr_len))
continue;
if (!memcmp (addrp->area_addr, addr->area_addr, addr->addr_len))
{
@@ -322,26 +393,28 @@
return CMD_SUCCESS; /* silent fail */
}
}
-
}
+
/*
* Forget the systemID part of the address
*/
- addr->addr_len -= (ISIS_SYS_ID_LEN + 1);
+ addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN);
listnode_add (area->area_addrs, addr);
/* only now we can safely generate our LSPs for this area */
if (listcount (area->area_addrs) > 0)
{
- lsp_l1_generate (area);
- lsp_l2_generate (area);
+ if (area->is_type & IS_LEVEL_1)
+ lsp_generate (area, IS_LEVEL_1);
+ if (area->is_type & IS_LEVEL_2)
+ lsp_generate (area, IS_LEVEL_2);
}
return CMD_SUCCESS;
}
int
-area_clear_net_title (struct vty *vty, const u_char *net_title)
+area_clear_net_title (struct vty *vty, const char *net_title)
{
struct isis_area *area;
struct area_addr addr, *addrp = NULL;
@@ -352,7 +425,7 @@
if (!area)
{
vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_NO_MATCH;
}
addr.addr_len = dotformat2buff (buff, net_title);
@@ -360,13 +433,13 @@
{
vty_out (vty, "Unsupported area address length %d, should be 8...20 %s",
addr.addr_len, VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_AMBIGUOUS;
}
memcpy (addr.area_addr, buff, (int) addr.addr_len);
for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp))
- if (addrp->addr_len == addr.addr_len &&
+ if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len &&
!memcmp (addrp->area_addr, addr.area_addr, addr.addr_len))
break;
@@ -374,26 +447,36 @@
{
vty_out (vty, "No area address %s for area %s %s", net_title,
area->area_tag, VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_NO_MATCH;
}
listnode_delete (area->area_addrs, addrp);
+ XFREE (MTYPE_ISIS_AREA_ADDR, addrp);
+
+ /*
+ * Last area address - reset the SystemID for this router
+ */
+ if (listcount (area->area_addrs) == 0)
+ {
+ memset (isis->sysid, 0, ISIS_SYS_ID_LEN);
+ isis->sysid_set = 0;
+ if (isis->debugs & DEBUG_EVENTS)
+ zlog_debug ("Router has no SystemID");
+ }
return CMD_SUCCESS;
}
/*
- * 'show clns neighbors' command
+ * 'show isis interface' command
*/
int
-show_clns_neigh (struct vty *vty, char detail)
+show_isis_interface_common (struct vty *vty, const char *ifname, char detail)
{
struct listnode *anode, *cnode;
struct isis_area *area;
struct isis_circuit *circuit;
- struct list *db;
- int i;
if (!isis)
{
@@ -406,92 +489,246 @@
vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE);
if (detail == ISIS_UI_LEVEL_BRIEF)
- vty_out (vty, " System Id Interface L State "
- "Holdtime SNPA%s", VTY_NEWLINE);
+ vty_out (vty, " Interface CircId State Type Level%s",
+ VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
- {
- if (circuit->circ_type == CIRCUIT_T_BROADCAST)
- {
- for (i = 0; i < 2; i++)
- {
- db = circuit->u.bc.adjdb[i];
- if (db && db->count)
- {
- if (detail == ISIS_UI_LEVEL_BRIEF)
- isis_adjdb_iterate (db,
- (void (*)
- (struct isis_adjacency *,
- void *)) isis_adj_print_vty,
- vty);
- if (detail == ISIS_UI_LEVEL_DETAIL)
- isis_adjdb_iterate (db,
- (void (*)
- (struct isis_adjacency *,
- void *))
- isis_adj_print_vty_detail, vty);
- if (detail == ISIS_UI_LEVEL_EXTENSIVE)
- isis_adjdb_iterate (db,
- (void (*)
- (struct isis_adjacency *,
- void *))
- isis_adj_print_vty_extensive,
- vty);
- }
- }
- }
- else if (circuit->circ_type == CIRCUIT_T_P2P &&
- circuit->u.p2p.neighbor)
- {
- if (detail == ISIS_UI_LEVEL_BRIEF)
- isis_adj_p2p_print_vty (circuit->u.p2p.neighbor, vty);
- if (detail == ISIS_UI_LEVEL_DETAIL)
- isis_adj_p2p_print_vty_detail (circuit->u.p2p.neighbor, vty);
- if (detail == ISIS_UI_LEVEL_EXTENSIVE)
- isis_adj_p2p_print_vty_extensive (circuit->u.p2p.neighbor,
- vty);
- }
- }
+ if (!ifname)
+ isis_circuit_print_vty (circuit, vty, detail);
+ else if (strcmp(circuit->interface->name, ifname) == 0)
+ isis_circuit_print_vty (circuit, vty, detail);
}
return CMD_SUCCESS;
}
-DEFUN (show_clns_neighbors,
- show_clns_neighbors_cmd,
- "show clns neighbors",
+DEFUN (show_isis_interface,
+ show_isis_interface_cmd,
+ "show isis interface",
SHOW_STR
- "clns network information\n"
- "CLNS neighbor adjacencies\n")
+ "ISIS network information\n"
+ "ISIS interface\n")
{
- return show_clns_neigh (vty, ISIS_UI_LEVEL_BRIEF);
+ return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_BRIEF);
}
-ALIAS (show_clns_neighbors,
- show_isis_neighbors_cmd,
- "show isis neighbors",
+DEFUN (show_isis_interface_detail,
+ show_isis_interface_detail_cmd,
+ "show isis interface detail",
SHOW_STR
- "IS-IS network information\n"
- "IS-IS neighbor adjacencies\n")
-
-DEFUN (show_clns_neighbors_detail,
- show_clns_neighbors_detail_cmd,
- "show clns neighbors detail",
- SHOW_STR
- "clns network information\n"
- "CLNS neighbor adjacencies\n"
+ "ISIS network information\n"
+ "ISIS interface\n"
"show detailed information\n")
{
- return show_clns_neigh (vty, ISIS_UI_LEVEL_DETAIL);
+ return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_DETAIL);
}
-ALIAS (show_clns_neighbors_detail,
- show_isis_neighbors_detail_cmd,
- "show isis neighbors detail",
+DEFUN (show_isis_interface_arg,
+ show_isis_interface_arg_cmd,
+ "show isis interface WORD",
SHOW_STR
- "IS-IS network information\n"
- "IS-IS neighbor adjacencies\n"
+ "ISIS network information\n"
+ "ISIS interface\n"
+ "ISIS interface name\n")
+{
+ return show_isis_interface_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
+}
+
+/*
+ * 'show isis neighbor' command
+ */
+
+int
+show_isis_neighbor_common (struct vty *vty, const char *id, char detail)
+{
+ struct listnode *anode, *cnode, *node;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct list *adjdb;
+ struct isis_adjacency *adj;
+ struct isis_dynhn *dynhn;
+ u_char sysid[ISIS_SYS_ID_LEN];
+ int i;
+
+ if (!isis)
+ {
+ vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ memset (sysid, 0, ISIS_SYS_ID_LEN);
+ if (id)
+ {
+ if (sysid2buff (sysid, id) == 0)
+ {
+ dynhn = dynhn_find_by_name (id);
+ if (dynhn == NULL)
+ {
+ vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN);
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area))
+ {
+ vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE);
+
+ if (detail == ISIS_UI_LEVEL_BRIEF)
+ vty_out (vty, " System Id Interface L State"
+ " Holdtime SNPA%s", VTY_NEWLINE);
+
+ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit))
+ {
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ adjdb = circuit->u.bc.adjdb[i];
+ if (adjdb && adjdb->count)
+ {
+ for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
+ if (!id || !memcmp (adj->sysid, sysid,
+ ISIS_SYS_ID_LEN))
+ isis_adj_print_vty (adj, vty, detail);
+ }
+ }
+ }
+ else if (circuit->circ_type == CIRCUIT_T_P2P &&
+ circuit->u.p2p.neighbor)
+ {
+ adj = circuit->u.p2p.neighbor;
+ if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN))
+ isis_adj_print_vty (adj, vty, detail);
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * 'clear isis neighbor' command
+ */
+int
+clear_isis_neighbor_common (struct vty *vty, const char *id)
+{
+ struct listnode *anode, *cnode, *cnextnode, *node, *nnode;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct list *adjdb;
+ struct isis_adjacency *adj;
+ struct isis_dynhn *dynhn;
+ u_char sysid[ISIS_SYS_ID_LEN];
+ int i;
+
+ if (!isis)
+ {
+ vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ memset (sysid, 0, ISIS_SYS_ID_LEN);
+ if (id)
+ {
+ if (sysid2buff (sysid, id) == 0)
+ {
+ dynhn = dynhn_find_by_name (id);
+ if (dynhn == NULL)
+ {
+ vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN);
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area))
+ {
+ for (ALL_LIST_ELEMENTS (area->circuit_list, cnode, cnextnode, circuit))
+ {
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ adjdb = circuit->u.bc.adjdb[i];
+ if (adjdb && adjdb->count)
+ {
+ for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj))
+ if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN))
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN,
+ "clear user request");
+ }
+ }
+ }
+ else if (circuit->circ_type == CIRCUIT_T_P2P &&
+ circuit->u.p2p.neighbor)
+ {
+ adj = circuit->u.p2p.neighbor;
+ if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN))
+ isis_adj_state_change (adj, ISIS_ADJ_DOWN,
+ "clear user request");
+ }
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_isis_neighbor,
+ show_isis_neighbor_cmd,
+ "show isis neighbor",
+ SHOW_STR
+ "ISIS network information\n"
+ "ISIS neighbor adjacencies\n")
+{
+ return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_BRIEF);
+}
+
+DEFUN (show_isis_neighbor_detail,
+ show_isis_neighbor_detail_cmd,
+ "show isis neighbor detail",
+ SHOW_STR
+ "ISIS network information\n"
+ "ISIS neighbor adjacencies\n"
"show detailed information\n")
+{
+ return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_DETAIL);
+}
+
+DEFUN (show_isis_neighbor_arg,
+ show_isis_neighbor_arg_cmd,
+ "show isis neighbor WORD",
+ SHOW_STR
+ "ISIS network information\n"
+ "ISIS neighbor adjacencies\n"
+ "System id\n")
+{
+ return show_isis_neighbor_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
+}
+
+DEFUN (clear_isis_neighbor,
+ clear_isis_neighbor_cmd,
+ "clear isis neighbor",
+ CLEAR_STR
+ "Reset ISIS network information\n"
+ "Reset ISIS neighbor adjacencies\n")
+{
+ return clear_isis_neighbor_common (vty, NULL);
+}
+
+DEFUN (clear_isis_neighbor_arg,
+ clear_isis_neighbor_arg_cmd,
+ "clear isis neighbor WORD",
+ CLEAR_STR
+ "ISIS network information\n"
+ "ISIS neighbor adjacencies\n"
+ "System id\n")
+{
+ return clear_isis_neighbor_common (vty, argv[0]);
+}
+
/*
* 'isis debug', 'show debugging'
*/
@@ -535,7 +772,8 @@
VTY_NEWLINE);
if (flags & DEBUG_EVENTS)
vty_out (vty, "IS-IS Event debugging is %s%s", onoffs, VTY_NEWLINE);
-
+ if (flags & DEBUG_PACKET_DUMP)
+ vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs, VTY_NEWLINE);
}
DEFUN (show_debugging,
@@ -617,6 +855,11 @@
vty_out (vty, "debug isis events%s", VTY_NEWLINE);
write++;
}
+ if (flags & DEBUG_PACKET_DUMP)
+ {
+ vty_out (vty, "debug isis packet-dump%s", VTY_NEWLINE);
+ write++;
+ }
return write;
}
@@ -803,7 +1046,6 @@
return CMD_SUCCESS;
}
-
DEFUN (debug_isis_spfstats,
debug_isis_spfstats_cmd,
"debug isis spf-statistics ",
@@ -908,6 +1150,32 @@
return CMD_SUCCESS;
}
+DEFUN (debug_isis_packet_dump,
+ debug_isis_packet_dump_cmd,
+ "debug isis packet-dump",
+ DEBUG_STR
+ "IS-IS information\n"
+ "IS-IS packet dump\n")
+{
+ isis->debugs |= DEBUG_PACKET_DUMP;
+ print_debug (vty, DEBUG_PACKET_DUMP, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_packet_dump,
+ no_debug_isis_packet_dump_cmd,
+ "no debug isis packet-dump",
+ UNDEBUG_STR
+ "IS-IS information\n"
+ "IS-IS packet dump\n")
+{
+ isis->debugs &= ~DEBUG_PACKET_DUMP;
+ print_debug (vty, DEBUG_PACKET_DUMP, 0);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (show_hostname,
show_hostname_cmd,
"show isis hostname",
@@ -920,42 +1188,292 @@
return CMD_SUCCESS;
}
-DEFUN (show_database,
- show_database_cmd,
- "show isis database",
- SHOW_STR "IS-IS information\n" "IS-IS link state database\n")
+static void
+vty_out_timestr(struct vty *vty, time_t uptime)
+{
+ struct tm *tm;
+ time_t difftime = time (NULL);
+ difftime -= uptime;
+ tm = gmtime (&difftime);
+
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+ if (difftime < ONE_DAY_SECOND)
+ vty_out (vty, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (difftime < ONE_WEEK_SECOND)
+ vty_out (vty, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ vty_out (vty, "%02dw%dd%02dh",
+ tm->tm_yday/7,
+ tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ vty_out (vty, " ago");
+}
+
+DEFUN (show_isis_summary,
+ show_isis_summary_cmd,
+ "show isis summary",
+ SHOW_STR "IS-IS information\n" "IS-IS summary\n")
+{
+ struct listnode *node, *node2;
+ struct isis_area *area;
+ struct isis_spftree *spftree;
+ int level;
+
+ if (isis == NULL)
+ {
+ vty_out (vty, "ISIS is not running%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ vty_out (vty, "Process Id : %ld%s", isis->process_id,
+ VTY_NEWLINE);
+ if (isis->sysid_set)
+ vty_out (vty, "System Id : %s%s", sysid_print (isis->sysid),
+ VTY_NEWLINE);
+
+ vty_out (vty, "Up time : ");
+ vty_out_timestr(vty, isis->uptime);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ if (isis->area_list)
+ vty_out (vty, "Number of areas : %d%s", isis->area_list->count,
+ VTY_NEWLINE);
+
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+ {
+ vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+ VTY_NEWLINE);
+
+ if (listcount (area->area_addrs) > 0)
+ {
+ struct area_addr *area_addr;
+ for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node2, area_addr))
+ {
+ vty_out (vty, " Net: %s%s",
+ isonet_print (area_addr->area_addr,
+ area_addr->addr_len + ISIS_SYS_ID_LEN +
+ 1), VTY_NEWLINE);
+ }
+ }
+
+ for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+ {
+ if ((area->is_type & level) == 0)
+ continue;
+
+ vty_out (vty, " Level-%d:%s", level, VTY_NEWLINE);
+ spftree = area->spftree[level - 1];
+ if (spftree->pending)
+ vty_out (vty, " IPv4 SPF: (pending)%s", VTY_NEWLINE);
+ else
+ vty_out (vty, " IPv4 SPF:%s", VTY_NEWLINE);
+
+ vty_out (vty, " minimum interval : %d%s",
+ area->min_spf_interval[level - 1], VTY_NEWLINE);
+
+ vty_out (vty, " last run elapsed : ");
+ vty_out_timestr(vty, spftree->last_run_timestamp);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, " last run duration : %u usec%s",
+ (u_int32_t)spftree->last_run_duration, VTY_NEWLINE);
+
+ vty_out (vty, " run count : %d%s",
+ spftree->runcount, VTY_NEWLINE);
+
+#ifdef HAVE_IPV6
+ spftree = area->spftree6[level - 1];
+ if (spftree->pending)
+ vty_out (vty, " IPv6 SPF: (pending)%s", VTY_NEWLINE);
+ else
+ vty_out (vty, " IPv6 SPF:%s", VTY_NEWLINE);
+
+ vty_out (vty, " minimum interval : %d%s",
+ area->min_spf_interval[level - 1], VTY_NEWLINE);
+
+ vty_out (vty, " last run elapsed : ");
+ vty_out_timestr(vty, spftree->last_run_timestamp);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, " last run duration : %u msec%s",
+ spftree->last_run_duration, VTY_NEWLINE);
+
+ vty_out (vty, " run count : %d%s",
+ spftree->runcount, VTY_NEWLINE);
+#endif
+ }
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+/*
+ * This function supports following display options:
+ * [ show isis database [detail] ]
+ * [ show isis database <sysid> [detail] ]
+ * [ show isis database <hostname> [detail] ]
+ * [ show isis database <sysid>.<pseudo-id> [detail] ]
+ * [ show isis database <hostname>.<pseudo-id> [detail] ]
+ * [ show isis database <sysid>.<pseudo-id>-<fragment-number> [detail] ]
+ * [ show isis database <hostname>.<pseudo-id>-<fragment-number> [detail] ]
+ * [ show isis database detail <sysid> ]
+ * [ show isis database detail <hostname> ]
+ * [ show isis database detail <sysid>.<pseudo-id> ]
+ * [ show isis database detail <hostname>.<pseudo-id> ]
+ * [ show isis database detail <sysid>.<pseudo-id>-<fragment-number> ]
+ * [ show isis database detail <hostname>.<pseudo-id>-<fragment-number> ]
+ */
+static int
+show_isis_database (struct vty *vty, const char *argv, int ui_level)
{
struct listnode *node;
struct isis_area *area;
+ struct isis_lsp *lsp;
+ struct isis_dynhn *dynhn;
+ const char *pos = argv;
+ u_char lspid[ISIS_SYS_ID_LEN+2];
+ char sysid[255];
+ u_char number[3];
int level, lsp_count;
if (isis->area_list->count == 0)
return CMD_SUCCESS;
+ memset (&lspid, 0, ISIS_SYS_ID_LEN);
+ memset (&sysid, 0, 255);
+
+ /*
+ * extract fragment and pseudo id from the string argv
+ * in the forms:
+ * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
+ * (b) <systemid/hostname>.<pseudo-id> or
+ * (c) <systemid/hostname> or
+ * Where systemid is in the form:
+ * xxxx.xxxx.xxxx
+ */
+ if (argv)
+ strncpy (sysid, argv, 254);
+ if (argv && strlen (argv) > 3)
+ {
+ pos = argv + strlen (argv) - 3;
+ if (strncmp (pos, "-", 1) == 0)
+ {
+ memcpy (number, ++pos, 2);
+ lspid[ISIS_SYS_ID_LEN+1] = (u_char) strtol ((char *)number, NULL, 16);
+ pos -= 4;
+ if (strncmp (pos, ".", 1) != 0)
+ return CMD_ERR_AMBIGUOUS;
+ }
+ if (strncmp (pos, ".", 1) == 0)
+ {
+ memcpy (number, ++pos, 2);
+ lspid[ISIS_SYS_ID_LEN] = (u_char) strtol ((char *)number, NULL, 16);
+ sysid[pos - argv - 1] = '\0';
+ }
+ }
+
for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
{
vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
- VTY_NEWLINE);
+ VTY_NEWLINE);
+
for (level = 0; level < ISIS_LEVELS; level++)
- {
- if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
- {
- vty_out (vty, "IS-IS Level-%d link-state database:%s",
- level + 1, VTY_NEWLINE);
+ {
+ if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
+ {
+ lsp = NULL;
+ if (argv != NULL)
+ {
+ /*
+ * Try to find the lsp-id if the argv string is in
+ * the form hostname.<pseudo-id>-<fragment>
+ */
+ if (sysid2buff (lspid, sysid))
+ {
+ lsp = lsp_search (lspid, area->lspdb[level]);
+ }
+ else if ((dynhn = dynhn_find_by_name (sysid)))
+ {
+ memcpy (lspid, dynhn->id, ISIS_SYS_ID_LEN);
+ lsp = lsp_search (lspid, area->lspdb[level]);
+ }
+ else if (strncmp(unix_hostname (), sysid, 15) == 0)
+ {
+ memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN);
+ lsp = lsp_search (lspid, area->lspdb[level]);
+ }
+ }
- lsp_count = lsp_print_all (vty, area->lspdb[level],
- ISIS_UI_LEVEL_BRIEF,
- area->dynhostname);
+ if (lsp != NULL || argv == NULL)
+ {
+ vty_out (vty, "IS-IS Level-%d link-state database:%s",
+ level + 1, VTY_NEWLINE);
- vty_out (vty, "%s %u LSPs%s%s",
- VTY_NEWLINE, lsp_count, VTY_NEWLINE, VTY_NEWLINE);
- }
- }
+ /* print the title in all cases */
+ vty_out (vty, "LSP ID PduLen "
+ "SeqNumber Chksum Holdtime ATT/P/OL%s",
+ VTY_NEWLINE);
+ }
+
+ if (lsp)
+ {
+ if (ui_level == ISIS_UI_LEVEL_DETAIL)
+ lsp_print_detail (lsp, vty, area->dynhostname);
+ else
+ lsp_print (lsp, vty, area->dynhostname);
+ }
+ else if (argv == NULL)
+ {
+ lsp_count = lsp_print_all (vty, area->lspdb[level],
+ ui_level,
+ area->dynhostname);
+
+ vty_out (vty, " %u LSPs%s%s",
+ lsp_count, VTY_NEWLINE, VTY_NEWLINE);
+ }
+ }
+ }
}
return CMD_SUCCESS;
}
+DEFUN (show_database_brief,
+ show_database_cmd,
+ "show isis database",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS link state database\n")
+{
+ return show_isis_database (vty, NULL, ISIS_UI_LEVEL_BRIEF);
+}
+
+DEFUN (show_database_lsp_brief,
+ show_database_arg_cmd,
+ "show isis database WORD",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS link state database\n"
+ "LSP ID\n")
+{
+ return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_BRIEF);
+}
+
+DEFUN (show_database_lsp_detail,
+ show_database_arg_detail_cmd,
+ "show isis database WORD detail",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS link state database\n"
+ "LSP ID\n"
+ "Detailed information\n")
+{
+ return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
+}
+
DEFUN (show_database_detail,
show_database_detail_cmd,
"show isis database detail",
@@ -963,35 +1481,19 @@
"IS-IS information\n"
"IS-IS link state database\n")
{
- struct listnode *node;
- struct isis_area *area;
- int level, lsp_count;
+ return show_isis_database (vty, NULL, ISIS_UI_LEVEL_DETAIL);
+}
- if (isis->area_list->count == 0)
- return CMD_SUCCESS;
-
- for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
- {
- vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
- VTY_NEWLINE);
- for (level = 0; level < ISIS_LEVELS; level++)
- {
- if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0)
- {
- vty_out (vty, "IS-IS Level-%d Link State Database:%s",
- level + 1, VTY_NEWLINE);
-
- lsp_count = lsp_print_all (vty, area->lspdb[level],
- ISIS_UI_LEVEL_DETAIL,
- area->dynhostname);
-
- vty_out (vty, "%s %u LSPs%s%s",
- VTY_NEWLINE, lsp_count, VTY_NEWLINE, VTY_NEWLINE);
- }
- }
- }
-
- return CMD_SUCCESS;
+DEFUN (show_database_detail_lsp,
+ show_database_detail_arg_cmd,
+ "show isis database detail WORD",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS link state database\n"
+ "Detailed information\n"
+ "LSP ID\n")
+{
+ return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL);
}
/*
@@ -1043,10 +1545,11 @@
return area_clear_net_title (vty, argv[0]);
}
-DEFUN (area_passwd,
- area_passwd_cmd,
- "area-password WORD",
+DEFUN (area_passwd_md5,
+ area_passwd_md5_cmd,
+ "area-password md5 WORD",
"Configure the authentication password for an area\n"
+ "Authentication type\n"
"Area password\n")
{
struct isis_area *area;
@@ -1056,16 +1559,75 @@
if (!area)
{
- vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
len = strlen (argv[0]);
if (len > 254)
{
vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_AMBIGUOUS;
}
+
+ area->area_passwd.len = (u_char) len;
+ area->area_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
+ strncpy ((char *)area->area_passwd.passwd, argv[0], 255);
+
+ if (argc > 1)
+ {
+ SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND);
+ if (strncmp(argv[1], "v", 1) == 0)
+ SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
+ else
+ UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
+ }
+ else
+ {
+ UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND);
+ UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
+ }
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (area_passwd_md5,
+ area_passwd_md5_snpauth_cmd,
+ "area-password md5 WORD authenticate snp (send-only|validate)",
+ "Configure the authentication password for an area\n"
+ "Authentication type\n"
+ "Area password\n"
+ "Authentication\n"
+ "SNP PDUs\n"
+ "Send but do not check PDUs on receiving\n"
+ "Send and check PDUs on receiving\n");
+
+DEFUN (area_passwd_clear,
+ area_passwd_clear_cmd,
+ "area-password clear WORD",
+ "Configure the authentication password for an area\n"
+ "Authentication type\n"
+ "Area password\n")
+{
+ struct isis_area *area;
+ int len;
+
+ area = vty->index;
+
+ if (!area)
+ {
+ vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ len = strlen (argv[0]);
+ if (len > 254)
+ {
+ vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
area->area_passwd.len = (u_char) len;
area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
strncpy ((char *)area->area_passwd.passwd, argv[0], 255);
@@ -1083,14 +1645,16 @@
UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND);
UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV);
}
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
return CMD_SUCCESS;
}
-ALIAS (area_passwd,
- area_passwd_snpauth_cmd,
- "area-password WORD authenticate snp (send-only|validate)",
+ALIAS (area_passwd_clear,
+ area_passwd_clear_snpauth_cmd,
+ "area-password clear WORD authenticate snp (send-only|validate)",
"Configure the authentication password for an area\n"
+ "Authentication type\n"
"Area password\n"
"Authentication\n"
"SNP PDUs\n"
@@ -1109,19 +1673,21 @@
if (!area)
{
- vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
memset (&area->area_passwd, 0, sizeof (struct isis_passwd));
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
return CMD_SUCCESS;
}
-DEFUN (domain_passwd,
- domain_passwd_cmd,
- "domain-password WORD",
+DEFUN (domain_passwd_md5,
+ domain_passwd_md5_cmd,
+ "domain-password md5 WORD",
"Set the authentication password for a routing domain\n"
+ "Authentication type\n"
"Routing domain password\n")
{
struct isis_area *area;
@@ -1131,16 +1697,75 @@
if (!area)
{
- vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
len = strlen (argv[0]);
if (len > 254)
{
vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
- return CMD_WARNING;
+ return CMD_ERR_AMBIGUOUS;
}
+
+ area->domain_passwd.len = (u_char) len;
+ area->domain_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
+ strncpy ((char *)area->domain_passwd.passwd, argv[0], 255);
+
+ if (argc > 1)
+ {
+ SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND);
+ if (strncmp(argv[1], "v", 1) == 0)
+ SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
+ else
+ UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
+ }
+ else
+ {
+ UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND);
+ UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
+ }
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (domain_passwd_md5,
+ domain_passwd_md5_snpauth_cmd,
+ "domain-password md5 WORD authenticate snp (send-only|validate)",
+ "Set the authentication password for a routing domain\n"
+ "Authentication type\n"
+ "Routing domain password\n"
+ "Authentication\n"
+ "SNP PDUs\n"
+ "Send but do not check PDUs on receiving\n"
+ "Send and check PDUs on receiving\n");
+
+DEFUN (domain_passwd_clear,
+ domain_passwd_clear_cmd,
+ "domain-password clear WORD",
+ "Set the authentication password for a routing domain\n"
+ "Authentication type\n"
+ "Routing domain password\n")
+{
+ struct isis_area *area;
+ int len;
+
+ area = vty->index;
+
+ if (!area)
+ {
+ vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ len = strlen (argv[0]);
+ if (len > 254)
+ {
+ vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
area->domain_passwd.len = (u_char) len;
area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT;
strncpy ((char *)area->domain_passwd.passwd, argv[0], 255);
@@ -1158,14 +1783,16 @@
UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND);
UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV);
}
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
return CMD_SUCCESS;
}
-ALIAS (domain_passwd,
- domain_passwd_snpauth_cmd,
- "domain-password WORD authenticate snp (send-only|validate)",
+ALIAS (domain_passwd_clear,
+ domain_passwd_clear_snpauth_cmd,
+ "domain-password clear WORD authenticate snp (send-only|validate)",
"Set the authentication password for a routing domain\n"
+ "Authentication type\n"
"Routing domain password\n"
"Authentication\n"
"SNP PDUs\n"
@@ -1174,7 +1801,7 @@
DEFUN (no_domain_passwd,
no_domain_passwd_cmd,
- "no domain-password WORD",
+ "no domain-password",
NO_STR
"Set the authentication password for a routing domain\n")
{
@@ -1184,11 +1811,12 @@
if (!area)
{
- vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
memset (&area->domain_passwd, 0, sizeof (struct isis_passwd));
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
return CMD_SUCCESS;
}
@@ -1208,8 +1836,8 @@
if (!area)
{
- vty_out (vty, "Cant find IS-IS instance%s", VTY_NEWLINE);
- return CMD_WARNING;
+ vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE);
+ return CMD_ERR_NO_MATCH;
}
type = string2circuit_t (argv[0]);
@@ -1240,8 +1868,9 @@
assert (area);
/*
- * Put the is-type back to default. Which is level-1-2 on first
- * circuit for the area level-1 for the rest
+ * Put the is-type back to defaults:
+ * - level-1-2 on first area
+ * - level-1 for the rest
*/
if (listgetdata (listhead (isis->area_list)) == area)
type = IS_LEVEL_1_AND_2;
@@ -1253,6 +1882,36 @@
return CMD_SUCCESS;
}
+static int
+set_lsp_gen_interval (struct vty *vty, struct isis_area *area,
+ uint16_t interval, int level)
+{
+ int lvl;
+
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
+ {
+ if (!(lvl & level))
+ continue;
+
+ if (interval >= area->lsp_refresh[lvl-1])
+ {
+ vty_out (vty, "LSP gen interval %us must be less than "
+ "the LSP refresh interval %us%s",
+ interval, area->lsp_refresh[lvl-1], VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ }
+
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
+ {
+ if (!(lvl & level))
+ continue;
+ area->lsp_gen_interval[lvl-1] = interval;
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (lsp_gen_interval,
lsp_gen_interval_cmd,
"lsp-gen-interval <1-120>",
@@ -1261,15 +1920,12 @@
{
struct isis_area *area;
uint16_t interval;
+ int level;
area = vty->index;
- assert (area);
-
interval = atoi (argv[0]);
- area->lsp_gen_interval[0] = interval;
- area->lsp_gen_interval[1] = interval;
-
- return CMD_SUCCESS;
+ level = IS_LEVEL_1 | IS_LEVEL_2;
+ return set_lsp_gen_interval (vty, area, interval, level);
}
DEFUN (no_lsp_gen_interval,
@@ -1279,14 +1935,13 @@
"Minimum interval between regenerating same LSP\n")
{
struct isis_area *area;
+ uint16_t interval;
+ int level;
area = vty->index;
- assert (area);
-
- area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
- area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
-
- return CMD_SUCCESS;
+ interval = DEFAULT_MIN_LSP_GEN_INTERVAL;
+ level = IS_LEVEL_1 | IS_LEVEL_2;
+ return set_lsp_gen_interval (vty, area, interval, level);
}
ALIAS (no_lsp_gen_interval,
@@ -1305,14 +1960,12 @@
{
struct isis_area *area;
uint16_t interval;
+ int level;
area = vty->index;
- assert (area);
-
interval = atoi (argv[0]);
- area->lsp_gen_interval[0] = interval;
-
- return CMD_SUCCESS;
+ level = IS_LEVEL_1;
+ return set_lsp_gen_interval (vty, area, interval, level);
}
DEFUN (no_lsp_gen_interval_l1,
@@ -1323,13 +1976,13 @@
"Set interval for level 1 only\n")
{
struct isis_area *area;
+ uint16_t interval;
+ int level;
area = vty->index;
- assert (area);
-
- area->lsp_gen_interval[0] = LSP_GEN_INTERVAL_DEFAULT;
-
- return CMD_SUCCESS;
+ interval = DEFAULT_MIN_LSP_GEN_INTERVAL;
+ level = IS_LEVEL_1;
+ return set_lsp_gen_interval (vty, area, interval, level);
}
ALIAS (no_lsp_gen_interval_l1,
@@ -1348,15 +2001,13 @@
"Minimum interval in seconds\n")
{
struct isis_area *area;
- int interval;
+ uint16_t interval;
+ int level;
area = vty->index;
- assert (area);
-
interval = atoi (argv[0]);
- area->lsp_gen_interval[1] = interval;
-
- return CMD_SUCCESS;
+ level = IS_LEVEL_2;
+ return set_lsp_gen_interval (vty, area, interval, level);
}
DEFUN (no_lsp_gen_interval_l2,
@@ -1367,15 +2018,13 @@
"Set interval for level 2 only\n")
{
struct isis_area *area;
- int interval;
+ uint16_t interval;
+ int level;
area = vty->index;
- assert (area);
-
- interval = atoi (argv[0]);
- area->lsp_gen_interval[1] = LSP_GEN_INTERVAL_DEFAULT;
-
- return CMD_SUCCESS;
+ interval = DEFAULT_MIN_LSP_GEN_INTERVAL;
+ level = IS_LEVEL_2;
+ return set_lsp_gen_interval (vty, area, interval, level);
}
ALIAS (no_lsp_gen_interval_l2,
@@ -1386,6 +2035,44 @@
"Set interval for level 2 only\n"
"Minimum interval in seconds\n")
+static int
+validate_metric_style_narrow (struct vty *vty, struct isis_area *area)
+{
+ struct isis_circuit *circuit;
+ struct listnode *node;
+
+ if (! vty)
+ return CMD_ERR_AMBIGUOUS;
+
+ if (! area)
+ {
+ vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit))
+ {
+ if ((area->is_type & IS_LEVEL_1) &&
+ (circuit->is_type & IS_LEVEL_1) &&
+ (circuit->metrics[0].metric_default > MAX_NARROW_LINK_METRIC))
+ {
+ vty_out (vty, "ISIS circuit %s metric is invalid%s",
+ circuit->interface->name, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ if ((area->is_type & IS_LEVEL_2) &&
+ (circuit->is_type & IS_LEVEL_2) &&
+ (circuit->metrics[1].metric_default > MAX_NARROW_LINK_METRIC))
+ {
+ vty_out (vty, "ISIS circuit %s metric is invalid%s",
+ circuit->interface->name, VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (metric_style,
metric_style_cmd,
"metric-style (narrow|transition|wide)",
@@ -1395,6 +2082,7 @@
"Use new style of TLVs to carry wider metric\n")
{
struct isis_area *area;
+ int ret;
area = vty->index;
assert (area);
@@ -1411,6 +2099,10 @@
}
else if (strncmp (argv[0], "n", 1) == 0)
{
+ ret = validate_metric_style_narrow (vty, area);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
area->newmetric = 0;
area->oldmetric = 1;
}
@@ -1425,10 +2117,15 @@
"Use old-style (ISO 10589) or new-style packet formats\n")
{
struct isis_area *area;
+ int ret;
area = vty->index;
assert (area);
+ ret = validate_metric_style_narrow (vty, area);
+ if (ret != CMD_SUCCESS)
+ return ret;
+
/* Default is narrow metric. */
area->newmetric = 0;
area->oldmetric = 1;
@@ -1436,6 +2133,40 @@
return CMD_SUCCESS;
}
+DEFUN (set_overload_bit,
+ set_overload_bit_cmd,
+ "set-overload-bit",
+ "Set overload bit to avoid any transit traffic\n"
+ "Set overload bit\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->overload_bit = LSPBIT_OL;
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_set_overload_bit,
+ no_set_overload_bit_cmd,
+ "no set-overload-bit",
+ "Reset overload bit to accept transit traffic\n"
+ "Reset overload bit\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->overload_bit = 0;
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (dynamic_hostname,
dynamic_hostname_cmd,
"hostname dynamic",
@@ -1447,7 +2178,11 @@
area = vty->index;
assert (area);
- area->dynhostname = 1;
+ if (!area->dynhostname)
+ {
+ area->dynhostname = 1;
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+ }
return CMD_SUCCESS;
}
@@ -1464,7 +2199,11 @@
area = vty->index;
assert (area);
- area->dynhostname = 0;
+ if (area->dynhostname)
+ {
+ area->dynhostname = 0;
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+ }
return CMD_SUCCESS;
}
@@ -1591,7 +2330,360 @@
"Set interval for level 2 only\n"
"Minimum interval between consecutive SPFs in seconds\n")
+static int
+set_lsp_max_lifetime (struct vty *vty, struct isis_area *area,
+ uint16_t interval, int level)
+{
+ int lvl;
+ int set_refresh_interval[ISIS_LEVELS] = {0, 0};
+ uint16_t refresh_interval;
+
+ refresh_interval = interval - 300;
+
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
+ {
+ if (!(lvl & level))
+ continue;
+ if (refresh_interval < area->lsp_refresh[lvl-1])
+ {
+ vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than "
+ "the configured LSP refresh interval %us%s",
+ lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE);
+ vty_out (vty, "Automatically reducing level %d LSP refresh interval "
+ "to %us%s", lvl, refresh_interval, VTY_NEWLINE);
+ set_refresh_interval[lvl-1] = 1;
+
+ if (refresh_interval <= area->lsp_gen_interval[lvl-1])
+ {
+ vty_out (vty, "LSP refresh interval %us must be greater than "
+ "the configured LSP gen interval %us%s",
+ refresh_interval, area->lsp_gen_interval[lvl-1],
+ VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ }
+ }
+
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++)
+ {
+ if (!(lvl & level))
+ continue;
+ area->max_lsp_lifetime[lvl-1] = interval;
+ /* Automatically reducing lsp_refresh_interval to interval - 300 */
+ if (set_refresh_interval[lvl-1])
+ area->lsp_refresh[lvl-1] = refresh_interval;
+ }
+
+ lsp_regenerate_schedule (area, level, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (max_lsp_lifetime,
+ max_lsp_lifetime_cmd,
+ "max-lsp-lifetime <350-65535>",
+ "Maximum LSP lifetime\n"
+ "LSP lifetime in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ level = IS_LEVEL_1 | IS_LEVEL_2;
+ return set_lsp_max_lifetime (vty, area, interval, level);
+}
+
+DEFUN (no_max_lsp_lifetime,
+ no_max_lsp_lifetime_cmd,
+ "no max-lsp-lifetime",
+ NO_STR
+ "LSP lifetime in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = DEFAULT_LSP_LIFETIME;
+ level = IS_LEVEL_1 | IS_LEVEL_2;
+ return set_lsp_max_lifetime (vty, area, interval, level);
+}
+
+ALIAS (no_max_lsp_lifetime,
+ no_max_lsp_lifetime_arg_cmd,
+ "no max-lsp-lifetime <350-65535>",
+ NO_STR
+ "Maximum LSP lifetime\n"
+ "LSP lifetime in seconds\n")
+
+DEFUN (max_lsp_lifetime_l1,
+ max_lsp_lifetime_l1_cmd,
+ "max-lsp-lifetime level-1 <350-65535>",
+ "Maximum LSP lifetime for Level 1 only\n"
+ "LSP lifetime for Level 1 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ level = IS_LEVEL_1;
+ return set_lsp_max_lifetime (vty, area, interval, level);
+}
+
+DEFUN (no_max_lsp_lifetime_l1,
+ no_max_lsp_lifetime_l1_cmd,
+ "no max-lsp-lifetime level-1",
+ NO_STR
+ "LSP lifetime for Level 1 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = DEFAULT_LSP_LIFETIME;
+ level = IS_LEVEL_1;
+ return set_lsp_max_lifetime (vty, area, interval, level);
+}
+
+ALIAS (no_max_lsp_lifetime_l1,
+ no_max_lsp_lifetime_l1_arg_cmd,
+ "no max-lsp-lifetime level-1 <350-65535>",
+ NO_STR
+ "Maximum LSP lifetime for Level 1 only\n"
+ "LSP lifetime for Level 1 only in seconds\n")
+
+DEFUN (max_lsp_lifetime_l2,
+ max_lsp_lifetime_l2_cmd,
+ "max-lsp-lifetime level-2 <350-65535>",
+ "Maximum LSP lifetime for Level 2 only\n"
+ "LSP lifetime for Level 2 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ level = IS_LEVEL_2;
+ return set_lsp_max_lifetime (vty, area, interval, level);
+}
+
+DEFUN (no_max_lsp_lifetime_l2,
+ no_max_lsp_lifetime_l2_cmd,
+ "no max-lsp-lifetime level-2",
+ NO_STR
+ "LSP lifetime for Level 2 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = DEFAULT_LSP_LIFETIME;
+ level = IS_LEVEL_2;
+ return set_lsp_max_lifetime (vty, area, interval, level);
+}
+
+ALIAS (no_max_lsp_lifetime_l2,
+ no_max_lsp_lifetime_l2_arg_cmd,
+ "no max-lsp-lifetime level-2 <350-65535>",
+ NO_STR
+ "Maximum LSP lifetime for Level 2 only\n"
+ "LSP lifetime for Level 2 only in seconds\n")
+
+static int
+set_lsp_refresh_interval (struct vty *vty, struct isis_area *area,
+ uint16_t interval, int level)
+{
+ int lvl;
+
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
+ {
+ if (!(lvl & level))
+ continue;
+ if (interval <= area->lsp_gen_interval[lvl-1])
+ {
+ vty_out (vty, "LSP refresh interval %us must be greater than "
+ "the configured LSP gen interval %us%s",
+ interval, area->lsp_gen_interval[lvl-1],
+ VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ if (interval > (area->max_lsp_lifetime[lvl-1] - 300))
+ {
+ vty_out (vty, "LSP refresh interval %us must be less than "
+ "the configured LSP lifetime %us less 300%s",
+ interval, area->max_lsp_lifetime[lvl-1],
+ VTY_NEWLINE);
+ return CMD_ERR_AMBIGUOUS;
+ }
+ }
+
+ for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl)
+ {
+ if (!(lvl & level))
+ continue;
+ area->lsp_refresh[lvl-1] = interval;
+ }
+ lsp_regenerate_schedule (area, level, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (lsp_refresh_interval,
+ lsp_refresh_interval_cmd,
+ "lsp-refresh-interval <1-65235>",
+ "LSP refresh interval\n"
+ "LSP refresh interval in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ level = IS_LEVEL_1 | IS_LEVEL_2;
+ return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+DEFUN (no_lsp_refresh_interval,
+ no_lsp_refresh_interval_cmd,
+ "no lsp-refresh-interval",
+ NO_STR
+ "LSP refresh interval in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = DEFAULT_MAX_LSP_GEN_INTERVAL;
+ level = IS_LEVEL_1 | IS_LEVEL_2;
+ return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+ALIAS (no_lsp_refresh_interval,
+ no_lsp_refresh_interval_arg_cmd,
+ "no lsp-refresh-interval <1-65235>",
+ NO_STR
+ "LSP refresh interval\n"
+ "LSP refresh interval in seconds\n")
+
+DEFUN (lsp_refresh_interval_l1,
+ lsp_refresh_interval_l1_cmd,
+ "lsp-refresh-interval level-1 <1-65235>",
+ "LSP refresh interval for Level 1 only\n"
+ "LSP refresh interval for Level 1 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ level = IS_LEVEL_1;
+ return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+DEFUN (no_lsp_refresh_interval_l1,
+ no_lsp_refresh_interval_l1_cmd,
+ "no lsp-refresh-interval level-1",
+ NO_STR
+ "LSP refresh interval for Level 1 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = DEFAULT_MAX_LSP_GEN_INTERVAL;
+ level = IS_LEVEL_1;
+ return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+ALIAS (no_lsp_refresh_interval_l1,
+ no_lsp_refresh_interval_l1_arg_cmd,
+ "no lsp-refresh-interval level-1 <1-65235>",
+ NO_STR
+ "LSP refresh interval for Level 1 only\n"
+ "LSP refresh interval for Level 1 only in seconds\n")
+
+DEFUN (lsp_refresh_interval_l2,
+ lsp_refresh_interval_l2_cmd,
+ "lsp-refresh-interval level-2 <1-65235>",
+ "LSP refresh interval for Level 2 only\n"
+ "LSP refresh interval for Level 2 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = atoi (argv[0]);
+ level = IS_LEVEL_2;
+ return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+DEFUN (no_lsp_refresh_interval_l2,
+ no_lsp_refresh_interval_l2_cmd,
+ "no lsp-refresh-interval level-2",
+ NO_STR
+ "LSP refresh interval for Level 2 only in seconds\n")
+{
+ struct isis_area *area;
+ uint16_t interval;
+ int level;
+
+ area = vty->index;
+ interval = DEFAULT_MAX_LSP_GEN_INTERVAL;
+ level = IS_LEVEL_2;
+ return set_lsp_refresh_interval (vty, area, interval, level);
+}
+
+ALIAS (no_lsp_refresh_interval_l2,
+ no_lsp_refresh_interval_l2_arg_cmd,
+ "no lsp-refresh-interval level-2 <1-65235>",
+ NO_STR
+ "LSP refresh interval for Level 2 only\n"
+ "LSP refresh interval for Level 2 only in seconds\n")
+
+DEFUN (log_adj_changes,
+ log_adj_changes_cmd,
+ "log-adjacency-changes",
+ "Log changes in adjacency state\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->log_adj_changes = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_log_adj_changes,
+ no_log_adj_changes_cmd,
+ "no log-adjacency-changes",
+ "Stop logging changes in adjacency state\n")
+{
+ struct isis_area *area;
+
+ area = vty->index;
+ assert (area);
+
+ area->log_adj_changes = 0;
+
+ return CMD_SUCCESS;
+}
+
#ifdef TOPOLOGY_GENERATE
+
DEFUN (topology_generate_grid,
topology_generate_grid_cmd,
"topology generate grid <1-100> <1-100> <1-65000> [param] [param] "
@@ -1623,7 +2715,7 @@
generate_topology_lsps (area);
/* Regenerate L1 LSP to get two way connection to the generated
* topology. */
- lsp_regenerate_schedule (area);
+ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1);
}
return CMD_SUCCESS;
@@ -1633,7 +2725,7 @@
show_isis_generated_topology_cmd,
"show isis generated-topologies",
SHOW_STR
- "CLNS network information\n"
+ "ISIS network information\n"
"Show generated topologies\n")
{
struct isis_area *area;
@@ -1717,183 +2809,9 @@
area->topology_basedynh = strndup (argv[0], 16);
return CMD_SUCCESS;
}
+
#endif /* TOPOLOGY_GENERATE */
-DEFUN (lsp_lifetime,
- lsp_lifetime_cmd,
- "lsp-lifetime <380-65535>",
- "Maximum LSP lifetime\n"
- "LSP lifetime in seconds\n")
-{
- struct isis_area *area;
- uint16_t interval;
-
- area = vty->index;
- assert (area);
-
- interval = atoi (argv[0]);
-
- if (interval < ISIS_MIN_LSP_LIFETIME)
- {
- vty_out (vty, "LSP lifetime (%us) below %us%s",
- interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE);
-
- return CMD_WARNING;
- }
-
-
- area->max_lsp_lifetime[0] = interval;
- area->max_lsp_lifetime[1] = interval;
- area->lsp_refresh[0] = interval - 300;
- area->lsp_refresh[1] = interval - 300;
-
- if (area->t_lsp_refresh[0])
- {
- thread_cancel (area->t_lsp_refresh[0]);
- thread_execute (master, lsp_refresh_l1, area, 0);
- }
-
- if (area->t_lsp_refresh[1])
- {
- thread_cancel (area->t_lsp_refresh[1]);
- thread_execute (master, lsp_refresh_l2, area, 0);
- }
-
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_lsp_lifetime,
- no_lsp_lifetime_cmd,
- "no lsp-lifetime",
- NO_STR
- "LSP lifetime in seconds\n")
-{
- struct isis_area *area;
-
- area = vty->index;
- assert (area);
-
- area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */
- area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */
- area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */
- area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */
-
- return CMD_SUCCESS;
-}
-
-ALIAS (no_lsp_lifetime,
- no_lsp_lifetime_arg_cmd,
- "no lsp-lifetime <380-65535>",
- NO_STR
- "Maximum LSP lifetime\n"
- "LSP lifetime in seconds\n")
-
-DEFUN (lsp_lifetime_l1,
- lsp_lifetime_l1_cmd,
- "lsp-lifetime level-1 <380-65535>",
- "Maximum LSP lifetime for Level 1 only\n"
- "LSP lifetime for Level 1 only in seconds\n")
-{
- struct isis_area *area;
- uint16_t interval;
-
- area = vty->index;
- assert (area);
-
- interval = atoi (argv[0]);
-
- if (interval < ISIS_MIN_LSP_LIFETIME)
- {
- vty_out (vty, "Level-1 LSP lifetime (%us) below %us%s",
- interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE);
-
- return CMD_WARNING;
- }
-
-
- area->max_lsp_lifetime[0] = interval;
- area->lsp_refresh[0] = interval - 300;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_lsp_lifetime_l1,
- no_lsp_lifetime_l1_cmd,
- "no lsp-lifetime level-1",
- NO_STR
- "LSP lifetime for Level 1 only in seconds\n")
-{
- struct isis_area *area;
-
- area = vty->index;
- assert (area);
-
- area->max_lsp_lifetime[0] = MAX_AGE; /* 1200s */
- area->lsp_refresh[0] = MAX_LSP_GEN_INTERVAL; /* 900s */
-
- return CMD_SUCCESS;
-}
-
-ALIAS (no_lsp_lifetime_l1,
- no_lsp_lifetime_l1_arg_cmd,
- "no lsp-lifetime level-1 <380-65535>",
- NO_STR
- "Maximum LSP lifetime for Level 1 only\n"
- "LSP lifetime for Level 1 only in seconds\n")
-
-DEFUN (lsp_lifetime_l2,
- lsp_lifetime_l2_cmd,
- "lsp-lifetime level-2 <380-65535>",
- "Maximum LSP lifetime for Level 2 only\n"
- "LSP lifetime for Level 2 only in seconds\n")
-{
- struct isis_area *area;
- uint16_t interval;
-
- area = vty->index;
- assert (area);
-
- interval = atoi (argv[0]);
-
- if (interval < ISIS_MIN_LSP_LIFETIME)
- {
- vty_out (vty, "Level-2 LSP lifetime (%us) below %us%s",
- interval, ISIS_MIN_LSP_LIFETIME, VTY_NEWLINE);
-
- return CMD_WARNING;
- }
-
- area->max_lsp_lifetime[1] = interval;
- area->lsp_refresh[1] = interval - 300;
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_lsp_lifetime_l2,
- no_lsp_lifetime_l2_cmd,
- "no lsp-lifetime level-2",
- NO_STR
- "LSP lifetime for Level 2 only in seconds\n")
-{
- struct isis_area *area;
-
- area = vty->index;
- assert (area);
-
- area->max_lsp_lifetime[1] = MAX_AGE; /* 1200s */
- area->lsp_refresh[1] = MAX_LSP_GEN_INTERVAL; /* 900s */
-
- return CMD_SUCCESS;
-}
-
-ALIAS (no_lsp_lifetime_l2,
- no_lsp_lifetime_l2_arg_cmd,
- "no lsp-lifetime level-2 <380-65535>",
- NO_STR
- "Maximum LSP lifetime for Level 2 only\n"
- "LSP lifetime for Level 2 only in seconds\n")
-
/* IS-IS configuration write function */
int
isis_config_write (struct vty *vty)
@@ -1939,25 +2857,27 @@
vty_out (vty, " metric-style transition%s", VTY_NEWLINE);
write++;
}
-
+ /* ISIS - overload-bit */
+ if (area->overload_bit)
+ {
+ vty_out (vty, " set-overload-bit%s", VTY_NEWLINE);
+ write++;
+ }
/* ISIS - Area is-type (level-1-2 is default) */
if (area->is_type == IS_LEVEL_1)
{
vty_out (vty, " is-type level-1%s", VTY_NEWLINE);
write++;
}
- else
+ else if (area->is_type == IS_LEVEL_2)
{
- if (area->is_type == IS_LEVEL_2)
- {
- vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE);
- write++;
- }
+ vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE);
+ write++;
}
/* ISIS - Lsp generation interval */
if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1])
{
- if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT)
+ if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL)
{
vty_out (vty, " lsp-gen-interval %d%s",
area->lsp_gen_interval[0], VTY_NEWLINE);
@@ -1966,13 +2886,13 @@
}
else
{
- if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT)
+ if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL)
{
vty_out (vty, " lsp-gen-interval level-1 %d%s",
area->lsp_gen_interval[0], VTY_NEWLINE);
write++;
}
- if (area->lsp_gen_interval[1] != LSP_GEN_INTERVAL_DEFAULT)
+ if (area->lsp_gen_interval[1] != DEFAULT_MIN_LSP_GEN_INTERVAL)
{
vty_out (vty, " lsp-gen-interval level-2 %d%s",
area->lsp_gen_interval[1], VTY_NEWLINE);
@@ -1982,28 +2902,53 @@
/* ISIS - LSP lifetime */
if (area->max_lsp_lifetime[0] == area->max_lsp_lifetime[1])
{
- if (area->max_lsp_lifetime[0] != MAX_AGE)
+ if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME)
{
- vty_out (vty, " lsp-lifetime %u%s", area->max_lsp_lifetime[0],
+ vty_out (vty, " max-lsp-lifetime %u%s", area->max_lsp_lifetime[0],
VTY_NEWLINE);
write++;
}
}
else
{
- if (area->max_lsp_lifetime[0] != MAX_AGE)
+ if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME)
{
- vty_out (vty, " lsp-lifetime level-1 %u%s",
+ vty_out (vty, " max-lsp-lifetime level-1 %u%s",
area->max_lsp_lifetime[0], VTY_NEWLINE);
write++;
}
- if (area->max_lsp_lifetime[1] != MAX_AGE)
+ if (area->max_lsp_lifetime[1] != DEFAULT_LSP_LIFETIME)
{
- vty_out (vty, " lsp-lifetime level-2 %u%s",
+ vty_out (vty, " max-lsp-lifetime level-2 %u%s",
area->max_lsp_lifetime[1], VTY_NEWLINE);
write++;
}
}
+ /* ISIS - LSP refresh interval */
+ if (area->lsp_refresh[0] == area->lsp_refresh[1])
+ {
+ if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL)
+ {
+ vty_out (vty, " lsp-refresh-interval %u%s", area->lsp_refresh[0],
+ VTY_NEWLINE);
+ write++;
+ }
+ }
+ else
+ {
+ if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL)
+ {
+ vty_out (vty, " lsp-refresh-interval level-1 %u%s",
+ area->lsp_refresh[0], VTY_NEWLINE);
+ write++;
+ }
+ if (area->lsp_refresh[1] != DEFAULT_MAX_LSP_GEN_INTERVAL)
+ {
+ vty_out (vty, " lsp-refresh-interval level-2 %u%s",
+ area->lsp_refresh[1], VTY_NEWLINE);
+ write++;
+ }
+ }
/* Minimum SPF interval. */
if (area->min_spf_interval[0] == area->min_spf_interval[1])
{
@@ -2030,9 +2975,9 @@
}
}
/* Authentication passwords. */
- if (area->area_passwd.len > 0)
+ if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
{
- vty_out(vty, " area-password %s", area->area_passwd.passwd);
+ vty_out(vty, " area-password md5 %s", area->area_passwd.passwd);
if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND))
{
vty_out(vty, " authenticate snp ");
@@ -2043,10 +2988,40 @@
}
vty_out(vty, "%s", VTY_NEWLINE);
write++;
- }
- if (area->domain_passwd.len > 0)
+ }
+ else if (area->area_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
+ {
+ vty_out(vty, " area-password clear %s", area->area_passwd.passwd);
+ if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND))
+ {
+ vty_out(vty, " authenticate snp ");
+ if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV))
+ vty_out(vty, "validate");
+ else
+ vty_out(vty, "send-only");
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+ write++;
+ }
+ if (area->domain_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
{
- vty_out(vty, " domain-password %s", area->domain_passwd.passwd);
+ vty_out(vty, " domain-password md5 %s",
+ area->domain_passwd.passwd);
+ if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND))
+ {
+ vty_out(vty, " authenticate snp ");
+ if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV))
+ vty_out(vty, "validate");
+ else
+ vty_out(vty, "send-only");
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+ write++;
+ }
+ else if (area->domain_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
+ {
+ vty_out(vty, " domain-password clear %s",
+ area->domain_passwd.passwd);
if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND))
{
vty_out(vty, " authenticate snp ");
@@ -2059,12 +3034,18 @@
write++;
}
+ if (area->log_adj_changes)
+ {
+ vty_out (vty, " log-adjacency-changes%s", VTY_NEWLINE);
+ write++;
+ }
+
#ifdef TOPOLOGY_GENERATE
if (memcmp (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS,
ISIS_SYS_ID_LEN))
{
vty_out (vty, " topology base-is %s%s",
- sysid_print (area->topology_baseis), VTY_NEWLINE);
+ sysid_print ((u_char *)area->topology_baseis), VTY_NEWLINE);
write++;
}
if (area->topology_basedynh)
@@ -2087,7 +3068,7 @@
return write;
}
-static struct cmd_node isis_node = {
+struct cmd_node isis_node = {
ISIS_NODE,
"%s(config-router)# ",
1
@@ -2099,23 +3080,43 @@
/* Install IS-IS top node */
install_node (&isis_node, isis_config_write);
- install_element (VIEW_NODE, &show_clns_neighbors_cmd);
- install_element (VIEW_NODE, &show_isis_neighbors_cmd);
- install_element (VIEW_NODE, &show_clns_neighbors_detail_cmd);
- install_element (VIEW_NODE, &show_isis_neighbors_detail_cmd);
+ install_element (VIEW_NODE, &show_isis_summary_cmd);
+
+ install_element (VIEW_NODE, &show_isis_interface_cmd);
+ install_element (VIEW_NODE, &show_isis_interface_detail_cmd);
+ install_element (VIEW_NODE, &show_isis_interface_arg_cmd);
+
+ install_element (VIEW_NODE, &show_isis_neighbor_cmd);
+ install_element (VIEW_NODE, &show_isis_neighbor_detail_cmd);
+ install_element (VIEW_NODE, &show_isis_neighbor_arg_cmd);
+ install_element (VIEW_NODE, &clear_isis_neighbor_cmd);
+ install_element (VIEW_NODE, &clear_isis_neighbor_arg_cmd);
install_element (VIEW_NODE, &show_hostname_cmd);
install_element (VIEW_NODE, &show_database_cmd);
+ install_element (VIEW_NODE, &show_database_arg_cmd);
+ install_element (VIEW_NODE, &show_database_arg_detail_cmd);
install_element (VIEW_NODE, &show_database_detail_cmd);
+ install_element (VIEW_NODE, &show_database_detail_arg_cmd);
- install_element (ENABLE_NODE, &show_clns_neighbors_cmd);
- install_element (ENABLE_NODE, &show_isis_neighbors_cmd);
- install_element (ENABLE_NODE, &show_clns_neighbors_detail_cmd);
- install_element (ENABLE_NODE, &show_isis_neighbors_detail_cmd);
+ install_element (ENABLE_NODE, &show_isis_summary_cmd);
+
+ install_element (ENABLE_NODE, &show_isis_interface_cmd);
+ install_element (ENABLE_NODE, &show_isis_interface_detail_cmd);
+ install_element (ENABLE_NODE, &show_isis_interface_arg_cmd);
+
+ install_element (ENABLE_NODE, &show_isis_neighbor_cmd);
+ install_element (ENABLE_NODE, &show_isis_neighbor_detail_cmd);
+ install_element (ENABLE_NODE, &show_isis_neighbor_arg_cmd);
+ install_element (ENABLE_NODE, &clear_isis_neighbor_cmd);
+ install_element (ENABLE_NODE, &clear_isis_neighbor_arg_cmd);
install_element (ENABLE_NODE, &show_hostname_cmd);
install_element (ENABLE_NODE, &show_database_cmd);
+ install_element (ENABLE_NODE, &show_database_arg_cmd);
+ install_element (ENABLE_NODE, &show_database_arg_detail_cmd);
install_element (ENABLE_NODE, &show_database_detail_cmd);
+ install_element (ENABLE_NODE, &show_database_detail_arg_cmd);
install_element (ENABLE_NODE, &show_debugging_cmd);
install_node (&debug_node, config_write_debug);
@@ -2142,6 +3143,8 @@
install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd);
install_element (ENABLE_NODE, &debug_isis_events_cmd);
install_element (ENABLE_NODE, &no_debug_isis_events_cmd);
+ install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd);
+ install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd);
install_element (CONFIG_NODE, &debug_isis_adj_cmd);
install_element (CONFIG_NODE, &no_debug_isis_adj_cmd);
@@ -2165,6 +3168,8 @@
install_element (CONFIG_NODE, &no_debug_isis_rtevents_cmd);
install_element (CONFIG_NODE, &debug_isis_events_cmd);
install_element (CONFIG_NODE, &no_debug_isis_events_cmd);
+ install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd);
+ install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd);
install_element (CONFIG_NODE, &router_isis_cmd);
install_element (CONFIG_NODE, &no_router_isis_cmd);
@@ -2177,12 +3182,16 @@
install_element (ISIS_NODE, &is_type_cmd);
install_element (ISIS_NODE, &no_is_type_cmd);
- install_element (ISIS_NODE, &area_passwd_cmd);
- install_element (ISIS_NODE, &area_passwd_snpauth_cmd);
+ install_element (ISIS_NODE, &area_passwd_md5_cmd);
+ install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd);
+ install_element (ISIS_NODE, &area_passwd_clear_cmd);
+ install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd);
install_element (ISIS_NODE, &no_area_passwd_cmd);
- install_element (ISIS_NODE, &domain_passwd_cmd);
- install_element (ISIS_NODE, &domain_passwd_snpauth_cmd);
+ install_element (ISIS_NODE, &domain_passwd_md5_cmd);
+ install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd);
+ install_element (ISIS_NODE, &domain_passwd_clear_cmd);
+ install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd);
install_element (ISIS_NODE, &no_domain_passwd_cmd);
install_element (ISIS_NODE, &lsp_gen_interval_cmd);
@@ -2205,21 +3214,38 @@
install_element (ISIS_NODE, &no_spf_interval_l2_cmd);
install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd);
- install_element (ISIS_NODE, &lsp_lifetime_cmd);
- install_element (ISIS_NODE, &no_lsp_lifetime_cmd);
- install_element (ISIS_NODE, &no_lsp_lifetime_arg_cmd);
- install_element (ISIS_NODE, &lsp_lifetime_l1_cmd);
- install_element (ISIS_NODE, &no_lsp_lifetime_l1_cmd);
- install_element (ISIS_NODE, &no_lsp_lifetime_l1_arg_cmd);
- install_element (ISIS_NODE, &lsp_lifetime_l2_cmd);
- install_element (ISIS_NODE, &no_lsp_lifetime_l2_cmd);
- install_element (ISIS_NODE, &no_lsp_lifetime_l2_arg_cmd);
+ install_element (ISIS_NODE, &max_lsp_lifetime_cmd);
+ install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd);
+ install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd);
+ install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd);
+ install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd);
+ install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd);
+ install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd);
+ install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd);
+ install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd);
+
+ install_element (ISIS_NODE, &lsp_refresh_interval_cmd);
+ install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd);
+ install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd);
+ install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd);
+ install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd);
+ install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd);
+ install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd);
+ install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd);
+ install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd);
+
+ install_element (ISIS_NODE, &set_overload_bit_cmd);
+ install_element (ISIS_NODE, &no_set_overload_bit_cmd);
install_element (ISIS_NODE, &dynamic_hostname_cmd);
install_element (ISIS_NODE, &no_dynamic_hostname_cmd);
install_element (ISIS_NODE, &metric_style_cmd);
install_element (ISIS_NODE, &no_metric_style_cmd);
+
+ install_element (ISIS_NODE, &log_adj_changes_cmd);
+ install_element (ISIS_NODE, &no_log_adj_changes_cmd);
+
#ifdef TOPOLOGY_GENERATE
install_element (ISIS_NODE, &topology_generate_grid_cmd);
install_element (ISIS_NODE, &topology_baseis_cmd);
@@ -2229,9 +3255,4 @@
install_element (VIEW_NODE, &show_isis_generated_topology_cmd);
install_element (ENABLE_NODE, &show_isis_generated_topology_cmd);
#endif /* TOPOLOGY_GENERATE */
-
- isis_new (0);
- isis_circuit_init ();
- isis_zebra_init ();
- isis_spf_cmds_init ();
}
diff --git a/isisd/isisd.h b/isisd/isisd.h
index b17982e..5db485f 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -40,6 +40,7 @@
u_long process_id;
int sysid_set;
u_char sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */
+ u_int32_t router_id; /* Router ID from zebra */
struct list *area_list; /* list of IS-IS areas */
struct list *init_circ_list;
struct list *nexthops; /* IPv4 next hops from this IS */
@@ -78,6 +79,8 @@
#endif
};
+extern struct isis *isis;
+
struct isis_area
{
struct isis *isis; /* back pointer */
@@ -92,11 +95,8 @@
struct list *circuit_list; /* IS-IS circuits */
struct flags flags;
struct thread *t_tick; /* LSP walker */
- struct thread *t_remove_aged;
- struct thread *t_lsp_l1_regenerate;
- struct thread *t_lsp_l2_regenerate;
- int lsp_regenerate_pending[ISIS_LEVELS];
struct thread *t_lsp_refresh[ISIS_LEVELS];
+ int lsp_regenerate_pending[ISIS_LEVELS];
/*
* Configurables
@@ -114,6 +114,8 @@
struct list *area_addrs;
u_int16_t max_lsp_lifetime[ISIS_LEVELS];
char is_type; /* level-1 level-1-2 or level-2-only */
+ /* are we overloaded? */
+ char overload_bit;
u_int16_t lsp_refresh[ISIS_LEVELS];
/* minimum time allowed before lsp retransmission */
u_int16_t lsp_gen_interval[ISIS_LEVELS];
@@ -122,6 +124,8 @@
/* the percentage of LSP mtu size used, before generating a new frag */
int lsp_frag_threshold;
int ip_circuits;
+ /* logging adjacency changes? */
+ u_char log_adj_changes;
#ifdef HAVE_IPV6
int ipv6_circuits;
#endif /* HAVE_IPV6 */
@@ -130,14 +134,21 @@
#ifdef TOPOLOGY_GENERATE
struct list *topology;
- char topology_baseis[ISIS_SYS_ID_LEN]; /* IS for the first IS emulated. */
+ u_char topology_baseis[ISIS_SYS_ID_LEN]; /* IS for the first IS emulated. */
char *topology_basedynh; /* Dynamic hostname base. */
char top_params[200]; /* FIXME: what is reasonable? */
#endif /* TOPOLOGY_GENERATE */
};
void isis_init (void);
+void isis_new(unsigned long);
+struct isis_area *isis_area_create(const char *);
struct isis_area *isis_area_lookup (const char *);
+int isis_area_get (struct vty *vty, const char *area_tag);
+void print_debug(struct vty *, int, int);
+
+/* Master of threads. */
+extern struct thread_master *master;
#define DEBUG_ADJ_PACKETS (1<<0)
#define DEBUG_CHECKSUM_ERRORS (1<<1)
@@ -151,5 +162,6 @@
#define DEBUG_RTE_EVENTS (1<<9)
#define DEBUG_EVENTS (1<<10)
#define DEBUG_ZEBRA (1<<11)
+#define DEBUG_PACKET_DUMP (1<<12)
#endif /* ISISD_H */
diff --git a/lib/if.c b/lib/if.c
index 1e99ffb..e26aa04 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -146,7 +146,7 @@
(*if_master.if_delete_hook) (ifp);
/* Free connected address list */
- list_delete (ifp->connected);
+ list_delete_all_node (ifp->connected);
}
/* Delete and free interface structure. */
@@ -157,6 +157,8 @@
if_delete_retain(ifp);
+ list_free (ifp->connected);
+
XFREE (MTYPE_IF, ifp);
}
diff --git a/lib/linklist.h b/lib/linklist.h
index cc6867c..f0ae362 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -54,9 +54,9 @@
void (*del) (void *val);
};
-#define listnextnode(X) ((X)->next)
-#define listhead(X) ((X)->head)
-#define listtail(X) ((X)->tail)
+#define listnextnode(X) ((X) ? ((X)->next) : NULL)
+#define listhead(X) ((X) ? ((X)->head) : NULL)
+#define listtail(X) ((X) ? ((X)->tail) : NULL)
#define listcount(X) ((X)->count)
#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
#define listgetdata(X) (assert((X)->data != NULL), (X)->data)
@@ -88,10 +88,10 @@
* It is safe to delete the listnode using this macro.
*/
#define ALL_LIST_ELEMENTS(list,node,nextnode,data) \
- (node) = listhead(list); \
+ (node) = listhead(list), ((data) = NULL); \
(node) != NULL && \
((data) = listgetdata(node),(nextnode) = listnextnode(node), 1); \
- (node) = (nextnode)
+ (node) = (nextnode), ((data) = NULL)
/* read-only list iteration macro.
* Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only
@@ -100,9 +100,9 @@
* of previous macro.
*/
#define ALL_LIST_ELEMENTS_RO(list,node,data) \
- (node) = listhead(list); \
+ (node) = listhead(list), ((data) = NULL);\
(node) != NULL && ((data) = listgetdata(node), 1); \
- (node) = listnextnode(node)
+ (node) = listnextnode(node), ((data) = NULL)
/* these *do not* cleanup list nodes and referenced data, as the functions
* do - these macros simply {de,at}tach a listnode from/to a list.
diff --git a/lib/md5.h b/lib/md5.h
index 3ce83a6..a03bf22 100644
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -83,6 +83,7 @@
} while (0)
/* From RFC 2104 */
-void hmac_md5(unsigned char* text, int text_len, unsigned char* key, int key_len, caddr_t digest);
+void hmac_md5(unsigned char* text, int text_len, unsigned char* key,
+ int key_len, caddr_t digest);
#endif /* ! _LIBZEBRA_MD5_H_*/
diff --git a/lib/memtypes.c b/lib/memtypes.c
index 245c8d8..acbd16b 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -248,6 +248,8 @@
{ MTYPE_ISIS_ROUTE_INFO, "ISIS route info" },
{ MTYPE_ISIS_NEXTHOP, "ISIS nexthop" },
{ MTYPE_ISIS_NEXTHOP6, "ISIS nexthop6" },
+ { MTYPE_ISIS_DICT, "ISIS dictionary" },
+ { MTYPE_ISIS_DICT_NODE, "ISIS dictionary node" },
{ -1, NULL },
};
diff --git a/lib/stream.c b/lib/stream.c
index 983330f..b226a25 100644
--- a/lib/stream.c
+++ b/lib/stream.c
@@ -52,7 +52,7 @@
* using stream_put..._at() functions.
*/
#define STREAM_WARN_OFFSETS(S) \
- zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \
+ zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \
(S), \
(unsigned long) (S)->size, \
(unsigned long) (S)->getp, \
@@ -214,6 +214,20 @@
s->getp = pos;
}
+void
+stream_set_endp (struct stream *s, size_t pos)
+{
+ STREAM_VERIFY_SANE(s);
+
+ if (!GETP_VALID (s, pos))
+ {
+ STREAM_BOUND_WARN (s, "set endp");
+ pos = s->endp;
+ }
+
+ s->endp = pos;
+}
+
/* Forward pointer. */
void
stream_forward_getp (struct stream *s, size_t size)
@@ -934,9 +948,9 @@
if (fifo->head == NULL)
fifo->tail = NULL;
- }
- fifo->count--;
+ fifo->count--;
+ }
return s;
}
diff --git a/lib/stream.h b/lib/stream.h
index 3e4ba7b..f10aa6d 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -146,6 +146,7 @@
extern u_char *stream_get_data (struct stream *);
extern void stream_set_getp (struct stream *, size_t);
+extern void stream_set_endp (struct stream *, size_t);
extern void stream_forward_getp (struct stream *, size_t);
extern void stream_forward_endp (struct stream *, size_t);
diff --git a/lib/zclient.c b/lib/zclient.c
index 3521d99..61c6f73 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -654,24 +654,8 @@
/* Lookup/create interface by name. */
ifp = if_get_by_name_len (ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ));
- /* Read interface's index. */
- ifp->ifindex = stream_getl (s);
+ zebra_interface_if_set_value (s, ifp);
- /* Read interface's value. */
- ifp->status = stream_getc (s);
- ifp->flags = stream_getq (s);
- ifp->metric = stream_getl (s);
- ifp->mtu = stream_getl (s);
- ifp->mtu6 = stream_getl (s);
- ifp->bandwidth = stream_getl (s);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
- stream_get (&ifp->sdl, s, sizeof (ifp->sdl));
-#else
- ifp->hw_addr_len = stream_getl (s);
- if (ifp->hw_addr_len)
- stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
-
return ifp;
}
@@ -699,16 +683,7 @@
if (! ifp)
return NULL;
- /* Read interface's index. */
- ifp->ifindex = stream_getl (s);
-
- /* Read interface's value. */
- ifp->status = stream_getc (s);
- ifp->flags = stream_getq (s);
- ifp->metric = stream_getl (s);
- ifp->mtu = stream_getl (s);
- ifp->mtu6 = stream_getl (s);
- ifp->bandwidth = stream_getl (s);
+ zebra_interface_if_set_value (s, ifp);
return ifp;
}
@@ -758,6 +733,13 @@
ifp->mtu = stream_getl (s);
ifp->mtu6 = stream_getl (s);
ifp->bandwidth = stream_getl (s);
+#ifdef HAVE_STRUCT_SOCKADDR_DL
+ stream_get (&ifp->sdl, s, sizeof (ifp->sdl));
+#else
+ ifp->hw_addr_len = stream_getl (s);
+ if (ifp->hw_addr_len)
+ stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
}
static int
diff --git a/zebra/rib.h b/zebra/rib.h
index 2872fc0..1b85c81 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -225,6 +225,10 @@
extern struct nexthop *nexthop_blackhole_add (struct rib *);
extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *,
struct in_addr *);
+extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *,
+ struct in_addr *,
+ struct in_addr *,
+ unsigned int);
extern void rib_lookup_and_dump (struct prefix_ipv4 *);
extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index f48df2b..73097bf 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -32,6 +32,7 @@
#include "prefix.h"
#include "connected.h"
#include "table.h"
+#include "memory.h"
#include "rib.h"
#include "thread.h"
#include "privs.h"
@@ -426,6 +427,37 @@
}
}
+/* Utility function to parse hardware link-layer address and update ifp */
+static void
+netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp)
+{
+ int i;
+
+ if (tb[IFLA_ADDRESS])
+ {
+ int hw_addr_len;
+
+ hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
+
+ if (hw_addr_len > INTERFACE_HWADDR_MAX)
+ zlog_warn ("Hardware address is too large: %d", hw_addr_len);
+ else
+ {
+ ifp->hw_addr_len = hw_addr_len;
+ memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
+
+ for (i = 0; i < hw_addr_len; i++)
+ if (ifp->hw_addr[i] != 0)
+ break;
+
+ if (i == hw_addr_len)
+ ifp->hw_addr_len = 0;
+ else
+ ifp->hw_addr_len = hw_addr_len;
+ }
+ }
+}
+
/* Called from interface_lookup_netlink(). This function is only used
during bootstrap. */
static int
@@ -436,7 +468,6 @@
struct rtattr *tb[IFLA_MAX + 1];
struct interface *ifp;
char *name;
- int i;
ifi = NLMSG_DATA (h);
@@ -474,30 +505,7 @@
/* Hardware type and address. */
ifp->hw_type = ifi->ifi_type;
-
- if (tb[IFLA_ADDRESS])
- {
- int hw_addr_len;
-
- hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]);
-
- if (hw_addr_len > INTERFACE_HWADDR_MAX)
- zlog_warn ("Hardware address is too large: %d", hw_addr_len);
- else
- {
- ifp->hw_addr_len = hw_addr_len;
- memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len);
-
- for (i = 0; i < hw_addr_len; i++)
- if (ifp->hw_addr[i] != 0)
- break;
-
- if (i == hw_addr_len)
- ifp->hw_addr_len = 0;
- else
- ifp->hw_addr_len = hw_addr_len;
- }
- }
+ netlink_interface_update_hw_addr (tb, ifp);
if_add_update (ifp);
@@ -709,7 +717,6 @@
if (tb[RTA_PREFSRC])
src = RTA_DATA (tb[RTA_PREFSRC]);
- /* Multipath treatment is needed. */
if (tb[RTA_GATEWAY])
gate = RTA_DATA (tb[RTA_GATEWAY]);
@@ -723,7 +730,64 @@
memcpy (&p.prefix, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0, SAFI_UNICAST);
+ if (!tb[RTA_MULTIPATH])
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
+ table, metric, 0, SAFI_UNICAST);
+ else
+ {
+ /* This is a multipath route */
+
+ struct rib *rib;
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ rib->type = ZEBRA_ROUTE_KERNEL;
+ rib->distance = 0;
+ rib->flags = flags;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ for (;;)
+ {
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ rib->nexthop_num++;
+ index = rtnh->rtnh_ifindex;
+ gate = 0;
+ if (rtnh->rtnh_len > sizeof (*rtnh))
+ {
+ memset (tb, 0, sizeof (tb));
+ netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh));
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+ }
+
+ if (gate)
+ {
+ if (index)
+ nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ else
+ nexthop_ipv4_add (rib, gate, src);
+ }
+ else
+ nexthop_ifindex_add (rib, index);
+
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ if (rib->nexthop_num == 0)
+ XFREE (MTYPE_RIB, rib);
+ else
+ rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
+ }
}
#ifdef HAVE_IPV6
if (rtm->rtm_family == AF_INET6)
@@ -867,7 +931,66 @@
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0, SAFI_UNICAST);
+ {
+ if (!tb[RTA_MULTIPATH])
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table,
+ metric, 0, SAFI_UNICAST);
+ else
+ {
+ /* This is a multipath route */
+
+ struct rib *rib;
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
+
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
+
+ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ rib->type = ZEBRA_ROUTE_KERNEL;
+ rib->distance = 0;
+ rib->flags = 0;
+ rib->metric = metric;
+ rib->table = table;
+ rib->nexthop_num = 0;
+ rib->uptime = time (NULL);
+
+ for (;;)
+ {
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
+
+ rib->nexthop_num++;
+ index = rtnh->rtnh_ifindex;
+ gate = 0;
+ if (rtnh->rtnh_len > sizeof (*rtnh))
+ {
+ memset (tb, 0, sizeof (tb));
+ netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh));
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
+ }
+
+ if (gate)
+ {
+ if (index)
+ nexthop_ipv4_ifindex_add (rib, gate, src, index);
+ else
+ nexthop_ipv4_add (rib, gate, src);
+ }
+ else
+ nexthop_ifindex_add (rib, index);
+
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
+
+ if (rib->nexthop_num == 0)
+ XFREE (MTYPE_RIB, rib);
+ else
+ rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST);
+ }
+ }
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST);
}
@@ -960,6 +1083,8 @@
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 1;
+ netlink_interface_update_hw_addr (tb, ifp);
+
/* If new link is added. */
if_add_update (ifp);
}
@@ -970,6 +1095,8 @@
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 1;
+ netlink_interface_update_hw_addr (tb, ifp);
+
if (if_is_operative (ifp))
{
ifp->flags = ifi->ifi_flags & 0x0000fffff;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index f7f4d0a..2fa439c 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -232,7 +232,7 @@
return nexthop;
}
-static struct nexthop *
+struct nexthop *
nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4,
struct in_addr *src, unsigned int ifindex)
{
@@ -1279,14 +1279,30 @@
static void
rib_queue_add (struct zebra_t *zebra, struct route_node *rn)
{
+ char buf[INET_ADDRSTRLEN];
+ assert (zebra && rn);
if (IS_ZEBRA_DEBUG_RIB_Q)
- {
- char buf[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN);
- zlog_info ("%s: %s/%d: work queue added", __func__,
- inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN),
- rn->p.prefixlen);
+ /* Pointless to queue a route_node with no RIB entries to add or remove */
+ if (!rn->info)
+ {
+ zlog_debug ("%s: called for route_node (%p, %d) with no ribs",
+ __func__, rn, rn->lock);
+ zlog_backtrace(LOG_DEBUG);
+ return;
+ }
+
+ if (IS_ZEBRA_DEBUG_RIB_Q)
+ zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen);
+
+ assert (zebra);
+
+ if (zebra->ribq == NULL)
+ {
+ zlog_err ("%s: work_queue does not exist!", __func__);
+ return;
}
/*
@@ -1301,6 +1317,11 @@
work_queue_add (zebra->ribq, zebra->mq);
rib_meta_queue_add (zebra->mq, rn);
+
+ if (IS_ZEBRA_DEBUG_RIB_Q)
+ zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn);
+
+ return;
}
/* Create new meta queue.
@@ -1328,6 +1349,8 @@
static void
rib_queue_init (struct zebra_t *zebra)
{
+ assert (zebra);
+
if (! (zebra->ribq = work_queue_new (zebra->master,
"route_node processing")))
{
@@ -1343,7 +1366,11 @@
zebra->ribq->spec.hold = rib_process_hold_time;
if (!(zebra->mq = meta_queue_new ()))
+ {
zlog_err ("%s: could not initialise meta queue!", __func__);
+ return;
+ }
+ return;
}
/* RIB updates are processed via a queue of pointers to route_nodes.
@@ -2893,6 +2920,62 @@
rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0));
rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0));
}
+
+/* Delete routes learned from a given client. */
+/* TODO(wsun) May need to split the sweep process into multiple batches,
+ * so that the process won't take too long if the table is large. */
+static void
+rib_sweep_client_table (struct route_table *table, int rib_type)
+{
+ struct route_node *rn;
+ struct rib *rib;
+ struct rib *next;
+ int ret = 0;
+
+ if (table)
+ for (rn = route_top (table); rn; rn = route_next (rn))
+ for (rib = rn->info; rib; rib = next)
+ {
+ next = rib->next;
+
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+
+ if (rib->type == rib_type)
+ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED))
+ {
+ /* TODO(wsun) Is this mandatory? What about graceful restart/
+ * non-stop forwarding */
+ ret = rib_uninstall_kernel (rn, rib);
+ if (! ret)
+ rib_delnode (rn, rib);
+ else
+ zlog_err ("%s: could not delete routes from kernel!",
+ __func__);
+ }
+ else
+ {
+ /* Always delete the node. */
+ rib_delnode (rn, rib);
+ }
+ }
+}
+
+/* Sweep all routes learned from a given client from RIB tables. */
+void
+rib_sweep_client_route (struct zserv *client)
+{
+ assert(client);
+ int route_type = client->route_type;
+ if (route_type != ZEBRA_ROUTE_MAX)
+ {
+ zlog_debug ("%s: Removing existing routes from client type %d",
+ __func__, route_type);
+ rib_sweep_client_table (vrf_table (AFI_IP, SAFI_UNICAST, 0), route_type);
+ rib_sweep_client_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0), route_type);
+ }
+}
+
/* Remove specific by protocol routes from 'table'. */
static unsigned long
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 672dee8..b1f539d 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -140,6 +140,30 @@
stream_putw (s, cmd);
}
+static void
+zserv_encode_interface (struct stream *s, struct interface *ifp)
+{
+ /* Interface information. */
+ stream_put (s, ifp->name, INTERFACE_NAMSIZ);
+ stream_putl (s, ifp->ifindex);
+ stream_putc (s, ifp->status);
+ stream_putq (s, ifp->flags);
+ stream_putl (s, ifp->metric);
+ stream_putl (s, ifp->mtu);
+ stream_putl (s, ifp->mtu6);
+ stream_putl (s, ifp->bandwidth);
+#ifdef HAVE_STRUCT_SOCKADDR_DL
+ stream_put (s, &ifp->sdl, sizeof (ifp->sdl));
+#else
+ stream_putl (s, ifp->hw_addr_len);
+ if (ifp->hw_addr_len)
+ stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
+#endif /* HAVE_STRUCT_SOCKADDR_DL */
+
+ /* Write packet size. */
+ stream_putw_at (s, 0, stream_get_endp (s));
+}
+
/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
/*
* This function is called in the following situations:
@@ -163,28 +187,8 @@
s = client->obuf;
stream_reset (s);
- /* Message type. */
zserv_create_header (s, ZEBRA_INTERFACE_ADD);
-
- /* Interface information. */
- stream_put (s, ifp->name, INTERFACE_NAMSIZ);
- stream_putl (s, ifp->ifindex);
- stream_putc (s, ifp->status);
- stream_putq (s, ifp->flags);
- stream_putl (s, ifp->metric);
- stream_putl (s, ifp->mtu);
- stream_putl (s, ifp->mtu6);
- stream_putl (s, ifp->bandwidth);
-#ifdef HAVE_STRUCT_SOCKADDR_DL
- stream_put (s, &ifp->sdl, sizeof (ifp->sdl));
-#else
- stream_putl (s, ifp->hw_addr_len);
- if (ifp->hw_addr_len)
- stream_put (s, ifp->hw_addr, ifp->hw_addr_len);
-#endif /* HAVE_STRUCT_SOCKADDR_DL */
-
- /* Write packet size. */
- stream_putw_at (s, 0, stream_get_endp (s));
+ zserv_encode_interface (s, ifp);
return zebra_server_send_message(client);
}
@@ -201,21 +205,9 @@
s = client->obuf;
stream_reset (s);
-
- zserv_create_header (s, ZEBRA_INTERFACE_DELETE);
-
- /* Interface information. */
- stream_put (s, ifp->name, INTERFACE_NAMSIZ);
- stream_putl (s, ifp->ifindex);
- stream_putc (s, ifp->status);
- stream_putq (s, ifp->flags);
- stream_putl (s, ifp->metric);
- stream_putl (s, ifp->mtu);
- stream_putl (s, ifp->mtu6);
- stream_putl (s, ifp->bandwidth);
- /* Write packet length. */
- stream_putw_at (s, 0, stream_get_endp (s));
+ zserv_create_header (s, ZEBRA_INTERFACE_DELETE);
+ zserv_encode_interface (s, ifp);
return zebra_server_send_message (client);
}
@@ -328,19 +320,7 @@
stream_reset (s);
zserv_create_header (s, cmd);
-
- /* Interface information. */
- stream_put (s, ifp->name, INTERFACE_NAMSIZ);
- stream_putl (s, ifp->ifindex);
- stream_putc (s, ifp->status);
- stream_putq (s, ifp->flags);
- stream_putl (s, ifp->metric);
- stream_putl (s, ifp->mtu);
- stream_putl (s, ifp->mtu6);
- stream_putl (s, ifp->bandwidth);
-
- /* Write packet size. */
- stream_putw_at (s, 0, stream_get_endp (s));
+ zserv_encode_interface (s, ifp);
return zebra_server_send_message(client);
}
@@ -761,6 +741,13 @@
/* Type, flags, message. */
rib->type = stream_getc (s);
+ /* Update client's route type if it is not done yet. */
+ /* It is done here since only zread_ipv4/6_add() and
+ * zread_ipv4/6_delete() decode Zebra messages and retrieve
+ * route types. */
+ if (client->route_type == ZEBRA_ROUTE_MAX)
+ client->route_type = rib->type;
+
rib->flags = stream_getc (s);
message = stream_getc (s);
safi = stream_getw (s);
@@ -798,10 +785,10 @@
case ZEBRA_NEXTHOP_IPV6:
stream_forward_getp (s, IPV6_MAX_BYTELEN);
break;
- case ZEBRA_NEXTHOP_BLACKHOLE:
- nexthop_blackhole_add (rib);
- break;
- }
+ case ZEBRA_NEXTHOP_BLACKHOLE:
+ nexthop_blackhole_add (rib);
+ break;
+ }
}
}
@@ -826,7 +813,7 @@
int i;
struct stream *s;
struct zapi_ipv4 api;
- struct in_addr nexthop;
+ struct in_addr nexthop, *nexthop_p;
unsigned long ifindex;
struct prefix_ipv4 p;
u_char nexthop_num;
@@ -836,6 +823,7 @@
s = client->ibuf;
ifindex = 0;
nexthop.s_addr = 0;
+ nexthop_p = NULL;
/* Type, flags, message. */
api.type = stream_getc (s);
@@ -869,6 +857,7 @@
break;
case ZEBRA_NEXTHOP_IPV4:
nexthop.s_addr = stream_get_ipv4 (s);
+ nexthop_p = &nexthop;
break;
case ZEBRA_NEXTHOP_IPV6:
stream_forward_getp (s, IPV6_MAX_BYTELEN);
@@ -889,7 +878,7 @@
else
api.metric = 0;
- rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex,
+ rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
client->rtm_table, api.safi);
return 0;
}
@@ -935,6 +924,11 @@
/* Type, flags, message. */
api.type = stream_getc (s);
+ /* Update the route type of the client.
+ * Same as in zread_ipv4_add(). */
+ if (client->route_type == ZEBRA_ROUTE_MAX)
+ client->route_type = api.type;
+
api.flags = stream_getc (s);
api.message = stream_getc (s);
api.safi = stream_getw (s);
@@ -1133,6 +1127,14 @@
static void
zebra_client_close (struct zserv *client)
{
+ struct stream *s;
+
+ /* Sweep all routes learned from the client first. */
+ rib_sweep_client_route(client);
+ /* Reset the route type. It may not be necessary since the
+ * whole client will be freed. */
+ client->route_type = ZEBRA_ROUTE_MAX;
+
/* Close file descriptor. */
if (client->sock)
{
@@ -1172,6 +1174,9 @@
/* Make client input/output buffer. */
client->sock = sock;
+ /* Set the default route type to ZEBRA_ROUTE_MAX; it will be updated
+ * once new routes are received. */
+ client->route_type = ZEBRA_ROUTE_MAX;
client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
client->wb = buffer_new(0);
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 5e8bcca..3d7ebbc 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -38,6 +38,10 @@
/* Client file descriptor. */
int sock;
+ /* Client route type. */
+ /* Assuming each client contains only one type of route. */
+ int route_type;
+
/* Input/output buffer to the client. */
struct stream *ibuf;
struct stream *obuf;