diff options
| author | Josh Bailey <joshb@google.com> | 2012-03-24 08:35:20 -0700 | 
|---|---|---|
| committer | Avneesh Sachdev <avneesh@opensourcerouting.org> | 2012-04-07 13:54:37 -0700 | 
| commit | 3f045a08812525505e165deea99a79447b44506b (patch) | |
| tree | a5c944b0584e0e5a14908a2ac9476637e7c1d7e6 | |
| parent | 6902c69aa30a73ecd70ef8941518b541ca02b878 (diff) | |
isisd: add Google's changes to IS-IS
37 files changed, 6622 insertions, 3718 deletions
diff --git a/isisd/dict.c b/isisd/dict.c index 6c3e1e7fdd..35cb924ca6 100644 --- a/isisd/dict.c +++ b/isisd/dict.c @@ -18,17 +18,11 @@   * $Name$   */ -#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 @@ -246,7 +240,7 @@ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node)  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; @@ -287,7 +281,7 @@ void dict_set_allocator(dict_t *dict, dnode_alloc_t al,  void dict_destroy(dict_t *dict)  {      assert (dict_isempty(dict)); -    free(dict); +    XFREE(MTYPE_ISIS_DICT, dict);  }  /* @@ -310,9 +304,6 @@ void dict_free_nodes(dict_t *dict)  void dict_free(dict_t *dict)  { -#ifdef KAZLIB_OBSOLESCENT_DEBUG -    assert ("call to obsolescent function dict_free()" && 0); -#endif      dict_free_nodes(dict);  } @@ -813,7 +804,7 @@ dnode_t *dict_delete(dict_t *dict, dnode_t *delete)  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); @@ -949,17 +940,17 @@ int dict_contains(dict_t *dict, dnode_t *node)  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; @@ -981,7 +972,7 @@ dnode_t *dnode_init(dnode_t *dnode, void *data)  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) @@ -1235,7 +1226,7 @@ static int comparef(const void *key1, const void *key2)  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; @@ -1350,7 +1341,7 @@ int main(void)  	"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 9395d1c080..93edb7d603 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 unsigned long dictcount_t;  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 dnode_t *(*dnode_alloc_t)(void *);  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 @@ typedef struct dict_t {      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_next(dict_load_t *, dnode_t *, const void *);  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 aab8d1a3dc..10bce3e8ab 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 @@ isis_new_adj (u_char * id, u_char * snpa, int level,      }    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 @@ isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)  }  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,103 @@ isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,      {        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->circ_type == CIRCUIT_T_BROADCAST) +  if (circuit->area->log_adj_changes)      { -      if (state == ISIS_ADJ_UP) -	circuit->upadjcount[level - 1]++; -      if (state == ISIS_ADJ_DOWN) -	{ -	  isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]); -	  circuit->upadjcount[level - 1]--; -	} +      const char *adj_name; +      struct isis_dynhn *dyn; -      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]); +      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");      } -  else if (state == ISIS_ADJ_UP) -    {				/* p2p interface */ -      if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) -	send_hello (circuit, 1); - -      /* 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, 1); -      send_csnp (circuit, 2); + +  if (circuit->circ_type == CIRCUIT_T_BROADCAST) +    { +      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]); + +        /* 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 (state == ISIS_ADJ_DOWN) -    {				/* p2p interface */ -      adj->circuit->u.p2p.neighbor = NULL; -      isis_delete_adj (adj, NULL); +  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); + +	    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); +	  } +      }      } +    return;  } @@ -225,7 +314,7 @@ isis_adj_print (struct isis_adjacency *adj)  	      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 +323,7 @@ isis_adj_print (struct isis_adjacency *adj)  #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 +340,12 @@ int  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 +354,12 @@ isis_adj_expire (struct thread *thread)    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 +402,11 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)    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 +415,54 @@ isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)  		 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    Priority: %u", -	       VTY_NEWLINE, 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", 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", VTY_NEWLINE); +        vty_out (vty, "    LAN Priority: %u", adj->prio[adj->level - 1]); + +        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 +476,6 @@ 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) -{ -  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 99a8bb2287..04a9250592 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -103,25 +103,13 @@ struct isis_adjacency *isis_adj_lookup_snpa (u_char * ssnpa,  					     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 05f11386c4..4d5b165131 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -301,7 +301,16 @@ int  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 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)  	  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 d2923b5751..cb439e8774 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 @@ isis_circuit_new ()    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,20 +136,20 @@ isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)    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)  { - -  /* 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;  } @@ -161,8 +165,11 @@ circuit_lookup_by_ifp (struct interface *ifp, struct list *list)    for (ALL_LIST_ELEMENTS_RO (list, node, circuit))      if (circuit->interface == ifp) -      return circuit; -   +      { +        assert (ifp->info == circuit); +        return circuit; +      } +    return NULL;  } @@ -173,83 +180,77 @@ circuit_scan_by_ifp (struct interface *ifp)    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); @@ -260,6 +261,16 @@ isis_circuit_add_addr (struct isis_circuit *circuit,  #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; @@ -269,7 +280,7 @@ isis_circuit_add_addr (struct isis_circuit *circuit,        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); @@ -301,20 +312,20 @@ isis_circuit_del_addr (struct isis_circuit *circuit,        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 @@ -354,72 +365,105 @@ isis_circuit_del_addr (struct isis_circuit *circuit,        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 = ifp->ifindex % 255;	/* FIXME: Why not ? */ +  circuit->circuit_id = isis_circuit_id_gen (ifp); +  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"); -      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"); -	} +      if (circuit->circ_type_config == CIRCUIT_T_P2P) +        circuit->circ_type = CIRCUIT_T_P2P;        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); @@ -427,88 +471,158 @@ isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)  }  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) -    { -      zlog_warn ("changing circuit_id %d->%d", circuit->circuit_id, -		 ifp->ifindex); -      circuit->circuit_id = ifp->ifindex % 255; -    } +  assert (circuit->interface == ifp); -  /* 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) -    { -      zlog_warn ("unsupported link layer"); -    } -  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 +  /* destroy addresses */ +  for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) +    isis_circuit_del_addr (circuit, conn); -  if (if_is_broadcast (ifp)) +  if (circuit->ip_addrs)      { -      circuit->circ_type = CIRCUIT_T_BROADCAST; +      assert (listcount(circuit->ip_addrs) == 0); +      list_delete (circuit->ip_addrs); +      circuit->ip_addrs = NULL;      } -  else if (if_is_pointopoint (ifp)) + +#ifdef HAVE_IPV6 +  if (circuit->ipv6_link)      { -      circuit->circ_type = CIRCUIT_T_P2P; +      assert (listcount(circuit->ipv6_link) == 0); +      list_delete (circuit->ipv6_link); +      circuit->ipv6_link = NULL;      } -  else + +  if (circuit->ipv6_non_link)      { -      zlog_warn ("isis_circuit_update_params: unsupported media"); +      assert (listcount(circuit->ipv6_non_link) == 0); +      list_delete (circuit->ipv6_non_link); +      circuit->ipv6_non_link = NULL;      } +#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) +{ +  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)  { -  circuit->interface->info = NULL; +  assert (circuit != NULL); +  assert (ifp != NULL); +  assert (circuit->interface == ifp); +  assert (ifp->info == circuit);    circuit->interface = NULL; +  ifp->info = NULL; +} -  return; +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); +                    } +                } +            } +        } +    }  } -void +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         */ @@ -519,91 +633,183 @@ isis_circuit_up (struct isis_circuit *circuit)        /* 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) -    { -      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_1) +    THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, +                     isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); -  if (circuit->circuit_is_type & IS_LEVEL_2) +  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[1], send_l2_psnp, circuit, -		       isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); +      isis_circuit_down (circuit); +      return retv;      } -  /* 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);      } + +  /* 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;  } @@ -628,201 +834,346 @@ circuit_update_nlpids (struct isis_circuit *circuit)    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 - 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 - 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 - 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 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++; -		    } -		} -	    } - -	} +          /* 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 */ +          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 - 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 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 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;  } @@ -835,58 +1186,45 @@ DEFUN (ip_router_isis,         "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)) -    { -#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 */ -    } - -  /* this is here for ciscopability */ -  if (!area) +  /* Prevent more than one area per circuit */ +  circuit = circuit_scan_by_ifp (ifp); +  if (circuit)      { -      /* FIXME: Find the way to warn only vty users. */ -      /* vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); */ -      return CMD_WARNING; +      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; +        }      } -  if (!c) +  if (isis_area_get (vty, argv[0]) != CMD_SUCCESS)      { -      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 */ +      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); +      return CMD_ERR_NO_MATCH;      } +  area = vty->index; -  if (!c) -    return CMD_WARNING; +  circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); +  isis_circuit_if_bind (circuit, ifp); -  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;  } @@ -900,28 +1238,33 @@ DEFUN (no_ip_router_isis,         "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 @@ -932,107 +1275,288 @@ DEFUN (no_ip_router_isis,    return CMD_SUCCESS;  } -DEFUN (isis_circuit_type, -       isis_circuit_type_cmd, -       "isis circuit-type (level-1|level-1-2|level-2-only)", -       "IS-IS commands\n" -       "Configure circuit type for interface\n" -       "Level-1 only adjacencies are formed\n" -       "Level-1-2 adjacencies are formed\n" -       "Level-2 only adjacencies are formed\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")  {    struct isis_circuit *circuit;    struct interface *ifp; -  int circuit_t; -  int is_type; +  struct isis_area *area; -  ifp = vty->index; -  circuit = ifp->info; -  /* UGLY - will remove l8r */ -  if (circuit == NULL) +  ifp = (struct interface *) vty->index; +  assert (ifp); + +  /* Prevent more than one area per circuit */ +  circuit = circuit_scan_by_ifp (ifp); +  if (circuit)      { -      return CMD_WARNING; +      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; +      }      } -  /* XXX what to do when ip_router_isis is not executed */ -  if (circuit->area == NULL) -    return CMD_WARNING; +  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; -  assert (circuit); +  circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); +  isis_circuit_if_bind (circuit, ifp); -  circuit_t = string2circuit_t (argv[0]); +  circuit->ipv6_router = 1; +  area->ipv6_circuits++; +  circuit_update_nlpids (circuit); -  if (!circuit_t) +  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, "Unknown circuit-type %s", VTY_NEWLINE); -      return CMD_SUCCESS; +      vty_out (vty, "Invalid interface %s", VTY_NEWLINE); +      return CMD_ERR_NO_MATCH;      } -  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); +  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      { -      vty_out (vty, "invalid circuit level for area %s.%s", -	       circuit->area->area_tag, VTY_NEWLINE); +      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_circuit_type, -       no_isis_circuit_type_cmd, -       "no isis circuit-type (level-1|level-1-2|level-2-only)", +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)", +       "IS-IS commands\n"         "Configure circuit type for interface\n"         "Level-1 only adjacencies are formed\n"         "Level-1-2 adjacencies are formed\n"         "Level-2 only adjacencies are formed\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; +  int circuit_type; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  circuit_type = string2circuit_t (argv[0]); +  if (!circuit_type)      { -      return CMD_WARNING; +      vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); +  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); +      return CMD_ERR_AMBIGUOUS; +    } +  isis_event_circuit_type_change (circuit, circuit_type); + +  return CMD_SUCCESS; +} + +DEFUN (no_isis_circuit_type, +       no_isis_circuit_type_cmd, +       "no isis circuit-type (level-1|level-1-2|level-2-only)", +       NO_STR +       "IS-IS commands\n" +       "Configure circuit type for interface\n" +       "Level-1 only adjacencies are formed\n" +       "Level-1-2 adjacencies are formed\n" +       "Level-2 only adjacencies are formed\n") +{ +  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;  } -DEFUN (isis_passwd, -       isis_passwd_cmd, -       "isis password WORD", +DEFUN (isis_passwd_md5, +       isis_passwd_md5_cmd, +       "isis password md5 WORD",         "IS-IS commands\n" -       "Configure the authentication password for interface\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; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  len = strlen (argv[0]); +  if (len > 254)      { -      return CMD_WARNING; +      vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } +  circuit->passwd.len = len; +  circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; +  strncpy ((char *)circuit->passwd.passwd, argv[0], 255); + +  return CMD_SUCCESS; +} + +DEFUN (isis_passwd_clear, +       isis_passwd_clear_cmd, +       "isis password clear WORD", +       "IS-IS commands\n" +       "Configure the authentication password for a circuit\n" +       "Authentication type\n" +       "Circuit password\n") +{ +  int len; +  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; @@ -1046,24 +1570,17 @@ DEFUN (no_isis_passwd,         "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));    return CMD_SUCCESS;  } -  DEFUN (isis_priority,         isis_priority_cmd,         "isis priority <0-127>", @@ -1071,22 +1588,21 @@ DEFUN (isis_priority,         "Set priority for Designated Router election\n"         "Priority value\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp;    int prio; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  prio = atoi (argv[0]); +  if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid priority %d - should be <0-127>%s", +               prio, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); -  prio = atoi (argv[0]); - -  circuit->u.bc.priority[0] = prio; -  circuit->u.bc.priority[1] = prio; +  circuit->priority[0] = prio; +  circuit->priority[1] = prio;    return CMD_SUCCESS;  } @@ -1098,19 +1614,12 @@ DEFUN (no_isis_priority,         "IS-IS commands\n"         "Set priority for Designated Router election\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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;  } @@ -1131,21 +1640,20 @@ DEFUN (isis_priority_l1,         "Priority value\n"         "Specify priority for level-1 routing\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp;    int prio; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  prio = atoi (argv[0]); +  if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid priority %d - should be <0-127>%s", +               prio, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); - -  prio = atoi (argv[0]); -  circuit->u.bc.priority[0] = prio; +  circuit->priority[0] = prio;    return CMD_SUCCESS;  } @@ -1158,18 +1666,11 @@ DEFUN (no_isis_priority_l1,         "Set priority for Designated Router election\n"         "Specify priority for level-1 routing\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  circuit->u.bc.priority[0] = DEFAULT_PRIORITY; +  circuit->priority[0] = DEFAULT_PRIORITY;    return CMD_SUCCESS;  } @@ -1191,21 +1692,20 @@ DEFUN (isis_priority_l2,         "Priority value\n"         "Specify priority for level-2 routing\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp;    int prio; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  prio = atoi (argv[0]); +  if (prio < MIN_PRIORITY || prio > MAX_PRIORITY)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid priority %d - should be <0-127>%s", +               prio, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); -  prio = atoi (argv[0]); - -  circuit->u.bc.priority[1] = prio; +  circuit->priority[1] = prio;    return CMD_SUCCESS;  } @@ -1218,18 +1718,11 @@ DEFUN (no_isis_priority_l2,         "Set priority for Designated Router election\n"         "Specify priority for level-2 routing\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  circuit->u.bc.priority[1] = DEFAULT_PRIORITY; +  circuit->priority[1] = DEFAULT_PRIORITY;    return CMD_SUCCESS;  } @@ -1244,36 +1737,49 @@ ALIAS (no_isis_priority_l2,         "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; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  met = atoi (argv[0]); + +  /* RFC3787 section 5.1 */ +  if (circuit->area && circuit->area->oldmetric == 1 && +      met > MAX_NARROW_LINK_METRIC)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid metric %d - should be <0-63> " +               "when narrow metric type enabled%s", +               met, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); -  met = atoi (argv[0]); +  /* 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;  } @@ -1284,21 +1790,17 @@ DEFUN (no_isis_metric,         "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;  } @@ -1311,34 +1813,175 @@ ALIAS (no_isis_metric,         "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) -    { -      return CMD_WARNING; -    } -  assert (circuit); -  c = *argv[0]; -  if (isdigit ((int) c)) +  interval = atoi (argv[0]); +  if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)      { -      interval = atoi (argv[0]); +      vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", +               interval, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  else -    interval = HELLO_MINIMAL;	/* FIXME: should be calculated */    circuit->hello_interval[0] = (u_int16_t) interval;    circuit->hello_interval[1] = (u_int16_t) interval; @@ -1353,27 +1996,19 @@ DEFUN (no_isis_hello_interval,         "IS-IS commands\n"         "Set Hello interval\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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" @@ -1382,33 +2017,25 @@ ALIAS (no_isis_hello_interval,  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; - -  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; -  c = *argv[0]; -  if (isdigit ((int) c)) +  interval = atoi (argv[0]); +  if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)      { -      interval = atoi (argv[0]); +      vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", +               interval, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  else -    interval = HELLO_MINIMAL;    circuit->hello_interval[0] = (u_int16_t) interval; @@ -1423,26 +2050,18 @@ DEFUN (no_isis_hello_interval_l1,         "Set Hello interval\n"         "Specify hello-interval for level-1 IIHs\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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" @@ -1452,33 +2071,25 @@ ALIAS (no_isis_hello_interval_l1,  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; - -  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; -  c = *argv[0]; -  if (isdigit ((int) c)) +  interval = atoi (argv[0]); +  if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL)      { -      interval = atoi (argv[0]); +      vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", +               interval, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  else -    interval = HELLO_MINIMAL;    circuit->hello_interval[1] = (u_int16_t) interval; @@ -1493,26 +2104,18 @@ DEFUN (no_isis_hello_interval_l2,         "Set Hello interval\n"         "Specify hello-interval for level-2 IIHs\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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" @@ -1522,24 +2125,23 @@ ALIAS (no_isis_hello_interval_l2,  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; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  mult = atoi (argv[0]); +  if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", +               mult, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); - -  mult = atoi (argv[0]);    circuit->hello_multiplier[0] = (u_int16_t) mult;    circuit->hello_multiplier[1] = (u_int16_t) mult; @@ -1554,26 +2156,19 @@ DEFUN (no_isis_hello_multiplier,         "IS-IS commands\n"         "Set multiplier for Hello holding time\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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" @@ -1581,25 +2176,24 @@ ALIAS (no_isis_hello_multiplier,  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; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  mult = atoi (argv[0]); +  if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", +               mult, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); - -  mult = atoi (argv[0]);    circuit->hello_multiplier[0] = (u_int16_t) mult; @@ -1614,25 +2208,18 @@ DEFUN (no_isis_hello_multiplier_l1,         "Set multiplier for Hello holding time\n"         "Specify hello multiplier for level-1 IIHs\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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" @@ -1641,25 +2228,24 @@ ALIAS (no_isis_hello_multiplier_l1,  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; +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  ifp = vty->index; -  circuit = ifp->info; -  if (circuit == NULL) +  mult = atoi (argv[0]); +  if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", +               mult, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); - -  mult = atoi (argv[0]);    circuit->hello_multiplier[1] = (u_int16_t) mult; @@ -1674,57 +2260,43 @@ DEFUN (no_isis_hello_multiplier_l2,         "Set multiplier for Hello holding time\n"         "Specify hello multiplier for level-2 IIHs\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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; - -  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; -  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" @@ -1732,42 +2304,34 @@ DEFUN (no_isis_hello,         "Pad hello packets\n"         "<cr>\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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; +  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 = atol (argv[0]); +  if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", +               interval, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); - -  interval = atol (argv[0]);    circuit->csnp_interval[0] = (u_int16_t) interval;    circuit->csnp_interval[1] = (u_int16_t) interval; @@ -1782,26 +2346,19 @@ DEFUN (no_csnp_interval,         "IS-IS commands\n"         "Set CSNP interval in seconds\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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" @@ -1809,25 +2366,24 @@ ALIAS (no_csnp_interval,  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; +  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 = atol (argv[0]); +  if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", +               interval, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); - -  interval = atol (argv[0]);    circuit->csnp_interval[0] = (u_int16_t) interval; @@ -1842,25 +2398,18 @@ DEFUN (no_csnp_interval_l1,         "Set CSNP interval in seconds\n"         "Specify interval for level-1 CSNPs\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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" @@ -1869,25 +2418,24 @@ ALIAS (no_csnp_interval_l1,  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; +  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 = atol (argv[0]); +  if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL)      { -      return CMD_WARNING; +      vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", +               interval, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  assert (circuit); - -  interval = atol (argv[0]);    circuit->csnp_interval[1] = (u_int16_t) interval; @@ -1902,153 +2450,276 @@ DEFUN (no_csnp_interval_l2,         "Set CSNP interval in seconds\n"         "Specify interval for level-2 CSNPs\n")  { -  struct isis_circuit *circuit; -  struct interface *ifp; - -  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; -  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); +  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; +    } -  area = isis_area_lookup (argv[0]); +  circuit->psnp_interval[0] = (u_int16_t) interval; +  circuit->psnp_interval[1] = (u_int16_t) interval; -  /* Prevent more than one circuit per interface */ -  if (area) -    c = circuit_lookup_by_ifp (ifp, area->circuit_list); -  else -    c = NULL; +  return CMD_SUCCESS; +} -  if (c && (ifp->info != NULL)) -    { -      if (c->ipv6_router == 1) -	{ -	  vty_out (vty, "ISIS circuit is already defined for IPv6%s", -		   VTY_NEWLINE); -	  return CMD_WARNING; -	} -    } +DEFUN (no_psnp_interval, +       no_psnp_interval_cmd, +       "no isis psnp-interval", +       NO_STR +       "IS-IS commands\n" +       "Set PSNP interval in seconds\n") +{ +  struct isis_circuit *circuit = isis_circuit_lookup (vty); +  if (!circuit) +    return CMD_ERR_NO_MATCH; -  /* this is here for ciscopability */ -  if (!area) -    { -      vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); -      return CMD_WARNING; -    } +  circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; +  circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; -  if (!c) +  return CMD_SUCCESS; +} + +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)      { -      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; +      vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", +               interval, VTY_NEWLINE); +      return CMD_ERR_AMBIGUOUS;      } -  if (!c) -    return CMD_WARNING; +  circuit->psnp_interval[0] = (u_int16_t) interval; -  c->ipv6_router = 1; -  area->ipv6_circuits++; -  circuit_update_nlpids (c); +  return CMD_SUCCESS; +} -  vty->node = INTERFACE_NODE; +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;  } -DEFUN (no_ipv6_router_isis, -       no_ipv6_router_isis_cmd, -       "no ipv6 router isis WORD", +ALIAS (no_psnp_interval_l1, +       no_psnp_interval_l1_arg_cmd, +       "no isis psnp-interval <1-120> level-1",         NO_STR -       "IPv6 interface subcommands\n" -       "IPv6 Router interface commands\n" -       "IS-IS Routing for IPv6\n" -       "Routing process tag\n") -{ -  struct isis_circuit *c; -  struct interface *ifp; -  struct isis_area *area; +       "IS-IS commands\n" +       "Set PSNP interval in seconds\n" +       "PSNP interval value\n" +       "Specify interval for level-1 PSNPs\n") -  ifp = (struct interface *) vty->index; -  /* UGLY - will remove l8r -     if (circuit == NULL) { -     return CMD_WARNING; -     } */ -  assert (ifp); +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; -  area = isis_area_lookup (argv[0]); -  if (!area) +  interval = atol (argv[0]); +  if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL)      { -      vty_out (vty, "Can't find ISIS instance %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;      } -  c = circuit_lookup_by_ifp (ifp, area->circuit_list); -  if (!c) -    return CMD_WARNING; +  circuit->psnp_interval[1] = (u_int16_t) interval; -  c->ipv6_router = 0; -  area->ipv6_circuits--; -  if (c->ip_router == 0) -    isis_csm_state_change (ISIS_DISABLE, c, area); +  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;  } -#endif /* HAVE_IPV6 */ -static struct cmd_node interface_node = { +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;    return 0;  } @@ -2071,10 +2742,14 @@ isis_circuit_init ()    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); -  install_element (INTERFACE_NODE, &isis_passwd_cmd); +  install_element (INTERFACE_NODE, &isis_passwd_clear_cmd); +  install_element (INTERFACE_NODE, &isis_passwd_md5_cmd);    install_element (INTERFACE_NODE, &no_isis_passwd_cmd);    install_element (INTERFACE_NODE, &isis_priority_cmd); @@ -2090,6 +2765,12 @@ isis_circuit_init ()    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); @@ -2111,8 +2792,9 @@ isis_circuit_init ()    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); @@ -2123,6 +2805,19 @@ isis_circuit_init ()    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 a7e719f605..7ed481dc2e 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -52,8 +52,6 @@ struct isis_bcast_info    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 @@ -78,31 +76,36 @@ struct isis_circuit    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 */ @@ -110,24 +113,17 @@ struct isis_circuit    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     */ @@ -141,25 +137,30 @@ struct isis_circuit  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 2633855609..d158961b99 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   */ @@ -35,6 +38,7 @@ struct isis_passwd    u_char len;  #define ISIS_PASSWD_TYPE_UNUSED   0  #define ISIS_PASSWD_TYPE_CLEARTXT 1 +#define ISIS_PASSWD_TYPE_HMAC_MD5 54  #define ISIS_PASSWD_TYPE_PRIVATE  255    u_char type;    /* Authenticate SNPs? */ @@ -64,11 +68,4 @@ struct nlpids    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 1b75ba6b16..bb2c4b4061 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 +#define ISIS_LEVELS                   2 +#define ISIS_LEVEL1                   1 +#define ISIS_LEVEL2                   2 +  /*   * Default values - * ISO - 10589 - * Section 7.3.21 - Parameters + * ISO - 10589 Section 7.3.21 - Parameters + * RFC 4444   */  #define MAX_AGE                       1200  #define ZERO_AGE_LIFETIME             60 -#define MAX_LSP_GEN_INTERVAL          900 -#define MIN_LSP_GEN_INTERVAL          30 +#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 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 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 HELLO_INTERVAL                10 -#define HELLO_MINIMAL HELLO_INTERVAL -#define HELLO_MULTIPLIER              3 +#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 80d0c90663..5d74a71be9 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 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)      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,23 +107,29 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)  	}        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; -	  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; @@ -130,6 +137,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)  	}        break;      case C_STATE_CONF: +      assert (circuit);        switch (event)  	{  	case ISIS_ENABLE: @@ -137,9 +145,13 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)  	  break;  	case IF_UP_FROM_Z:  	  isis_circuit_if_add (circuit, (struct interface *) arg); -	  isis_circuit_up (circuit); +	  if (isis_circuit_up (circuit) != ISIS_OK) +            { +              isis_circuit_if_del (circuit, (struct interface *) arg); +	      break; +            }  	  circuit->state = C_STATE_UP; -	  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); @@ -152,6 +164,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)  	}        break;      case C_STATE_UP: +      assert (circuit);        switch (event)  	{  	case ISIS_ENABLE: @@ -161,15 +174,18 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg)  	  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_if_del (circuit); +	  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 fe872a952b..73b6d3e7b2 100644 --- a/isisd/isis_dlpi.c +++ b/isisd/isis_dlpi.c @@ -442,12 +442,12 @@ open_dlpi_dev (struct isis_circuit *circuit)     * 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 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)    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 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)    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 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)    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 8d306c8f55..bc6ec11962 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 @@ isis_dr_elect (struct isis_circuit *circuit, int level)    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 @@ isis_dr_elect (struct isis_circuit *circuit, int level)    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 @@ isis_dr_elect (struct isis_circuit *circuit, int level)        /*         * 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 @@ isis_dr_resign (struct isis_circuit *circuit, int level)    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 @@ isis_dr_commence (struct isis_circuit *circuit, int level)        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 @@ isis_dr_commence (struct isis_circuit *circuit, int level)        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 @@ isis_dr_commence (struct isis_circuit *circuit, int level)        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 @@ isis_dr_commence (struct isis_circuit *circuit, int level)        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 0b758c856e..ffb0d503fb 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 @@ static int dyn_cache_cleanup (struct thread *);  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 @@ dyn_cache_cleanup (struct thread *thread)    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 @@ dynhn_find_by_id (u_char * id)    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 @@ isis_dynhn_insert (u_char * id, struct hostname *hostname, int level)    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 37a7b03c0e..379c454fc5 100644 --- a/isisd/isis_dynhn.h +++ b/isisd/isis_dynhn.h @@ -33,7 +33,9 @@ struct isis_dynhn  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 4380092243..750a4c3847 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 @@ extern struct isis *isis;  */  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,45 +127,71 @@ isis_event_system_type_change (struct isis_area *area, int newtype)      return;			/* No change */    switch (area->is_type) -    { +  {      case IS_LEVEL_1: -      if (area->lspdb[1] == NULL) -	area->lspdb[1] = lsp_db_init (); -      lsp_l2_generate (area); +      if (newtype == IS_LEVEL_2) +      { +        area_resign_level (area, IS_LEVEL_1); +      } +      else +      { +        if (area->lspdb[1] == NULL) +          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 (area->lspdb[0] == NULL) -	area->lspdb[0] = lsp_db_init (); -      lsp_l1_generate (area); +      if (newtype == IS_LEVEL_1) +      { +        area_resign_level (area, IS_LEVEL_2); +      } +      else +      { +        if (area->lspdb[0] == NULL) +          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); -  spftree_area_init (area); -  lsp_regenerate_schedule (area); +  /* 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); +  } -  return; -} +  spftree_area_init (area); -void -isis_event_area_addr_change (struct isis_area *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;  }  static void @@ -148,7 +205,7 @@ circuit_commence_level (struct isis_circuit *circuit, int level)        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, @@ -194,6 +251,8 @@ circuit_resign_level (struct isis_circuit *circuit, int level)        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 +261,19 @@ circuit_resign_level (struct isis_circuit *circuit, int level)  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 +285,7 @@ isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype)        return;      } -  switch (circuit->circuit_is_type) +  switch (circuit->is_type)      {      case IS_LEVEL_1:        if (newtype == IS_LEVEL_2) @@ -243,8 +307,8 @@ isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype)        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 +350,7 @@ isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate)  		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 +371,7 @@ isis_event_dis_status_change (struct thread *thread)      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 86bf051f33..c252f3def9 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 03c91101fc..ec0eaa4f82 100644 --- a/isisd/isis_flags.c +++ b/isisd/isis_flags.c @@ -36,11 +36,11 @@ flags_initialize (struct flags *flags)    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 @@ flags_get_index (struct flags *flags)    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 @@ flags_get_index (struct flags *flags)  }  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 13dd9e1456..e2e42adcc9 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 */ -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); +/* + * Flags structure for SSN and SRM flags + */ +struct flags +{ +  int maxindex; +  struct list *free_idcs; +}; +void flags_initialize (struct flags *flags); +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 50289db39f..f71794323e 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 @@ lsp_search (u_char * id, dict_t * lspdb)    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 @@ lsp_clear_data (struct isis_lsp *lsp)    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 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,      {        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 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,      {        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 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,    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 @@ lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num,    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 @@ lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num)    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,39 +441,27 @@ lsp_seqnum_update (struct isis_lsp *lsp0)    return;  } -int -isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area, -			 int pdulen, struct isis_passwd *passwd) -{ -  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) */ - -  return authentication_check (passwd, &tlvs.auth_info); -} -  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);    /* @@ -400,57 +489,59 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream,    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); +  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) +    { +      zlog_warn ("Could not parse LSP"); +      return; +    } -  if (found & TLVFLAG_DYN_HOSTNAME) +  if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname))      { -      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));      } +  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); - -  /* set the new values for lsp header */ -  memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); +  lsp_update_data (lsp, stream, area, level); -  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)      { @@ -484,12 +575,8 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,        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)); @@ -497,7 +584,7 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,      (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 */ @@ -514,9 +601,10 @@ lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num,    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; @@ -526,6 +614,13 @@ void  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 +    }  }  /* @@ -562,12 +657,13 @@ lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id,  }  /* - * 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); @@ -579,14 +675,18 @@ lsp_build_list (u_char * start_id, u_char * stop_id,    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; @@ -596,11 +696,12 @@ lsp_build_list (u_char * start_id, u_char * stop_id,   * 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) @@ -608,7 +709,12 @@ lsp_build_list_ssn (struct isis_circuit *circuit, struct list *list,        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;      } @@ -622,22 +728,11 @@ lsp_set_time (struct isis_lsp *lsp)    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);  } @@ -654,13 +749,11 @@ lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag)      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)); @@ -692,30 +785,32 @@ lsp_bits2string (u_char * lsp_bits)  }  /* 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; @@ -736,7 +831,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)    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) @@ -756,11 +851,11 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)  	    {  	    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;  	    }  	} @@ -769,33 +864,42 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)    /* 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);        } @@ -808,7 +912,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)  	      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);      } @@ -822,7 +926,7 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)  	      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);      } @@ -838,11 +942,11 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)        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);      } @@ -852,11 +956,9 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)    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 */ @@ -865,12 +967,13 @@ lsp_print_detail (dnode_t * node, struct vty *vty, char dynhost)  			       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;  } @@ -883,10 +986,6 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)    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) @@ -894,7 +993,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)  	  /* 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++;  	} @@ -904,7 +1003,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)        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++;  	} @@ -914,7 +1013,7 @@ lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost)  }  #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) \ @@ -933,16 +1032,32 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,    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))); @@ -954,6 +1069,44 @@ lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to,    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) @@ -963,40 +1116,21 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,    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, +                 area->is_type | 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;  } @@ -1005,7 +1139,7 @@ lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area,   * 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; @@ -1022,8 +1156,27 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  #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 @@ -1033,6 +1186,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)    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 @@ -1055,7 +1211,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  	    NLPID_IPV6;  	}  #endif /* HAVE_IPV6 */ +      tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu);      } +    /* Dynamic Hostname */    if (area->dynhostname)      { @@ -1065,39 +1223,13 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)        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)  	{ @@ -1106,7 +1238,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  	}        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); @@ -1116,8 +1248,9 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  	{  	  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);  	}      } @@ -1126,7 +1259,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  #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)  	{ @@ -1177,7 +1310,6 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  					    (ipv4->prefix.s_addr));  		  listnode_add (tlv_data.ipv4_int_reachs, ipreach);  		} -	      tlv_data.ipv4_int_reachs->del = free_tlv;  	    }  	  if (area->newmetric)  	    { @@ -1205,6 +1337,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  		}  	    }  	} +  #ifdef HAVE_IPV6        /*         * Add IPv6 reachability of this circuit @@ -1243,7 +1376,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)        switch (circuit->circ_type)  	{  	case CIRCUIT_T_BROADCAST: -	  if (level & circuit->circuit_is_type) +	  if (level & circuit->is_type)  	    {  	      if (area->oldmetric)  		{ @@ -1253,20 +1386,21 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  		      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 (); @@ -1274,21 +1408,22 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  		    }  		  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; @@ -1320,21 +1455,14 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  		  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");  	} @@ -1352,6 +1480,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  	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!). */ @@ -1361,7 +1490,8 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  	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); @@ -1406,87 +1536,99 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area)  	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) -	{ -	  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; +  oldlsp = lsp_search (lspid, area->lspdb[level - 1]); +  if (oldlsp) +    { +      /* 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; + +  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); -      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); -    } - -  /* DEBUG_ADJ_PACKETS */ -  if (isis->debugs & DEBUG_ADJ_PACKETS) +  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) - */ -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) + * Search own LSPs, update holding time and set SRM   */ -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); @@ -1495,180 +1637,147 @@ lsp_non_pseudo_regenerate (struct isis_area *area, int level)    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 = area->is_type | area->overload_bit; +  rem_lifetime = lsp_rem_lifetime (area, level); +  lsp->lsp_header->rem_lifetime = htons (rem_lifetime);    lsp_seqnum_update (lsp); -  if (isis->debugs & DEBUG_UPDATE_PACKETS) +  lsp->last_generated = time (NULL); +  lsp_set_all_srmflags (lsp); +  for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag))      { -      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)); +      frag->lsp_header->lsp_bits = area->is_type | 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);      } -  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)) +  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)      { -      frag->lsp_header->rem_lifetime = htons (isis_jitter -					      (area-> -					       max_lsp_lifetime[level - 1], -					       MAX_AGE_JITTER)); -      ISIS_FLAGS_SET_ALL (frag->SRMflags); +      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);      } -  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); - -  ref_time = area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? -    MAX_LSP_GEN_INTERVAL : area->lsp_refresh[0]; +  area->lsp_regenerate_pending[0] = 0; -  THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area, -		   isis_jitter (ref_time, MAX_AGE_JITTER)); +  if ((area->is_type & IS_LEVEL_1) == 0) +    return ISIS_ERROR; -  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; -	  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; -	  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; @@ -1691,16 +1800,10 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,    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) +  /* RFC3787  section 4 SHOULD not set overload bit in pseudo LSPs */ +  if (level == IS_LEVEL_1)      lsp->lsp_header->lsp_bits |= IS_LEVEL_1;    else      lsp->lsp_header->lsp_bits |= IS_LEVEL_2; @@ -1738,12 +1841,12 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,    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) @@ -1761,7 +1864,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,  		  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 */ @@ -1777,6 +1880,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,  	    }  	}      } +  list_delete (adj_list);    /* Reset endp of stream to overwrite only TLV part of it. */    stream_reset (lsp->pdu); @@ -1785,13 +1889,7 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,    /*     * 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); @@ -1803,20 +1901,89 @@ lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit,      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;  } +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_pseudo_regenerate (struct isis_circuit *circuit, int level) +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; @@ -1826,151 +1993,154 @@ lsp_pseudo_regenerate (struct isis_circuit *circuit, int level)    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 = circuit->area->is_type; +  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); - -  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; -} - -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)); +  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; +    } -  return lsp_regenerate_schedule (circuit->area); +  return lsp_regenerate_pseudo (circuit, IS_LEVEL_1);  } -int +static int  lsp_l2_refresh_pseudo (struct thread *thread)  {    struct isis_circuit *circuit; -  int retval; -  unsigned long ref_time; -  circuit = THREAD_ARG (thread); +  u_char id[ISIS_SYS_ID_LEN + 2]; -  if (!circuit->u.bc.is_dr[1]) -    return ISIS_ERROR;		/* FIXME: purge and such */ +  circuit = THREAD_ARG (thread);    circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL; +  circuit->lsp_regenerate_pending[1] = 0; -  retval = lsp_pseudo_regenerate (circuit, 2); - -  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)); +  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; +    } -  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; - -  memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); -  LSP_FRAGMENT (id) = 0; -  LSP_PSEUDO_ID (id) = circuit->circuit_id; - -  if (lsp_search (id, circuit->area->lspdb[1])) -    return lsp_pseudo_regenerate (circuit, 2); +  u_char lsp_id[ISIS_SYS_ID_LEN + 2]; +  time_t now, diff; +  int lvl; -  lsp = lsp_new (id, circuit->area->max_lsp_lifetime[1], -		 1, circuit->area->is_type, 0, 2); +  if (circuit == NULL || +      circuit->circ_type != CIRCUIT_T_BROADCAST || +      circuit->state != C_STATE_UP) +    return ISIS_OK; -  lsp_build_pseudo (lsp, 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); -  ref_time = circuit->area->lsp_refresh[1] > MAX_LSP_GEN_INTERVAL ? -    MAX_LSP_GEN_INTERVAL : circuit->area->lsp_refresh[1]; +  for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) +    { +      if (!((level & lvl) && (circuit->is_type & lvl))) +        continue; +      if (circuit->u.bc.is_dr[lvl - 1] == 0 || +          circuit->lsp_regenerate_pending[lvl - 1]) +        continue; -  lsp->own_lsp = 1; -  lsp_insert (lsp, circuit->area->lspdb[1]); -  ISIS_FLAGS_SET_ALL (lsp->SRMflags); +      lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]); +      if (!lsp) +        continue; -  THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[1], -		   lsp_l2_refresh_pseudo, circuit, -		   isis_jitter (ref_time, MAX_AGE_JITTER)); +      /* +       * 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); +        } +    } -  return lsp_regenerate_schedule (circuit->area); +  return ISIS_OK;  }  /* @@ -1988,6 +2158,7 @@ lsp_tick (struct thread *thread)    struct listnode *lspnode, *cnode;    dnode_t *dnode, *dnode_next;    int level; +  u_int16_t rem_lifetime;    lsp_list = list_new (); @@ -2003,54 +2174,87 @@ lsp_tick (struct thread *thread)    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) -		{ - -		  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)); +        { +          for (dnode = dict_first (area->lspdb[level]); +               dnode != NULL; dnode = dnode_next) +            { +              dnode_next = dict_next (area->lspdb[level], dnode); +              lsp = dnode_get (dnode); + +              /* +               * 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; -	    } - -	  /* -	   * Send LSPs on circuits indicated by the SRMflags -	   */ -	  if (listcount (lsp_list) > 0) -	    { +                  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) +            {                for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) -		{ +                { +                  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); @@ -2059,22 +2263,45 @@ lsp_tick (struct thread *thread)  }  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;  } @@ -2092,27 +2319,35 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,    /*     * 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->area = area;    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); +  /* 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     */ @@ -2121,17 +2356,36 @@ lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,    /*     * 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); @@ -2140,7 +2394,7 @@ top_lsp_refresh (struct thread *thread)    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", @@ -2150,14 +2404,13 @@ top_lsp_refresh (struct thread *thread)    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)); - -  ref_time = lsp->area->lsp_refresh[0] > MAX_LSP_GEN_INTERVAL ? -    MAX_LSP_GEN_INTERVAL : lsp->area->lsp_refresh[0]; +  lsp->lsp_header->lsp_bits = lsp->area->is_type | lsp->area->overload_bit; +  rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); +  lsp->lsp_header->rem_lifetime = htons (rem_lifetime); +  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;  } @@ -2170,16 +2423,16 @@ generate_topology_lsps (struct isis_area *area)    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++)      { @@ -2189,12 +2442,13 @@ generate_topology_lsps (struct isis_area *area)        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); @@ -2203,12 +2457,10 @@ generate_topology_lsps (struct isis_area *area)        /* 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]);      }  } @@ -2325,8 +2577,6 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,        if (area->newmetric)  	{ -	  uint32_t metric; -  	  if (tlv_data.te_is_neighs == NULL)  	    {  	      tlv_data.te_is_neighs = list_new (); @@ -2337,8 +2587,7 @@ build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area,  		  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 adbde78efd..6e7f745d2a 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 isis_lsp      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,8 +52,6 @@ struct isis_lsp  #endif    /* used for 60 second counting when rem_lifetime is zero */    int age_out; -  struct isis_adjacency *adj; -  /* 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 */  }; @@ -68,37 +60,32 @@ dict_t *lsp_db_init (void);  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); @@ -115,13 +102,18 @@ void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr,  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 c5e824c192..7bb84d8fc2 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -43,6 +43,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" @@ -66,7 +69,7 @@ struct zebra_privs_t isisd_privs = {    .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  }; @@ -151,7 +154,10 @@ reload ()    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 @@ -319,28 +325,31 @@ main (int argc, char **argv, char **envp)    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 6b565bcbe2..968fa05fe3 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 @@ isonet_print (u_char * from, int len)   * 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 @@ dotformat2buff (u_char * buff, const u_char * dotted)   * 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 @@ speaks (struct nlpids *nlpids, int family)   * 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 @@ string2circuit_t (const u_char * str)  }  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 @@ unix_hostname (void)  {    static struct utsname names;    const char *hostname; -  extern struct host host;    hostname = host.name;    if (!hostname) @@ -509,3 +547,87 @@ unix_hostname (void)    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 d5003a8e68..0cd65a66ae 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 @@ struct in_addr newprefix2inaddr (u_char * prefix_start,   * 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 *rawlspid_print (u_char *);  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 @@ const char *unix_hostname (void);  /*   * 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 a2ab0649d1..fe943bbaa8 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -29,21 +29,22 @@  #include "log.h"  #include "stream.h"  #include "vty.h" -#include "hash.c" +#include "hash.h"  #include "prefix.h"  #include "if.h"  #include "checksum.h" +#include "md5.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_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" @@ -53,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 */ @@ -168,32 +166,152 @@ accept_level (int level, int circuit_t)    return retval;  } -int -authentication_check (struct isis_passwd *one, struct isis_passwd *theother) +/* + * Verify authentication information + * Support cleartext and HMAC MD5 authentication + */ +static int +authentication_check (struct isis_passwd *remote, struct isis_passwd *local, +                      struct stream *stream, uint32_t auth_tlv_offset)  { -  if (one->type != theother->type) +  unsigned char digest[ISIS_AUTH_MD5_SIZE]; + +  /* 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: +      /* 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_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; +  struct tlvs tlvs; +  int retval = ISIS_OK; + +  hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream)); +  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, +                       ntohs (hdr->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), ntohs (hdr->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_warn ("Unsupported authentication type %d", theother->type); -      return 1;			/* Auth fail (different authentication types) */ +      zlog_err ("No authentication tlv in LSP"); +      return ISIS_ERROR;      } -  switch (one->type) + +  if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT && +      tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5)      { -    case ISIS_PASSWD_TYPE_CLEARTXT: -      if (one->len != theother->len) -	return 1;		/* Auth fail () - passwd len mismatch */ -      return memcmp (one->passwd, theother->passwd, one->len); -      break; -    default: -      zlog_warn ("Unsupported authentication type"); -      break; +      zlog_err ("Unknown authentication type in LSP"); +      return ISIS_ERROR;      } -  return 0;			/* Auth pass */ + +  /* +   * 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; @@ -214,12 +332,6 @@ tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj)  }  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; @@ -227,7 +339,7 @@ tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)    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 (); @@ -251,7 +363,7 @@ tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj)    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 (); @@ -284,9 +396,25 @@ process_p2p_hello (struct isis_circuit *circuit)    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;    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)      { @@ -311,7 +439,7 @@ process_p2p_hello (struct isis_circuit *circuit)     * Get the header     */    hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); -  circuit->rcv_stream->getp += ISIS_P2PHELLO_HDRLEN; +  stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN);    /*  hdr.circuit_t = stream_getc (stream);       stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN); @@ -319,35 +447,15 @@ process_p2p_hello (struct isis_circuit *circuit)       hdr.pdu_len   = stream_getw (stream);       hdr.local_id  = stream_getc (stream); */ -  /* -   * My interpertation of the ISO, if no adj exists we will create one for  -   * the circuit -   */ - -  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) +  if (ntohs (hdr->pdu_len) > ISO_MTU(circuit))      { -      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; +      zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " +                 "invalid pdu length %d", +                 circuit->area->area_tag, circuit->interface->name, +                 ntohs (hdr->pdu_len)); +      return ISIS_WARNING;      } -  /* 8.2.6 Monitoring point-to-point adjacencies */ -  adj->hold_time = ntohs (hdr->hold_time); -  adj->last_upd = time (NULL); -    /*     * Lets get the TLVS now     */ @@ -357,37 +465,94 @@ process_p2p_hello (struct isis_circuit *circuit)    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); +		       - 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 (&circuit->passwd, &tlvs.auth_info)) -	{ -	  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 */ @@ -422,6 +587,7 @@ process_p2p_hello (struct isis_circuit *circuit)  		{  		  /* (7) reject - wrong system type event */  		  zlog_warn ("wrongSystemType"); +                  free_tlvs (&tlvs);  		  return ISIS_WARNING;	/* Reject */  		}  	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1) @@ -508,6 +674,7 @@ process_p2p_hello (struct isis_circuit *circuit)  		{  		  /* (5) reject - wrong system type event */  		  zlog_warn ("wrongSystemType"); +                  free_tlvs (&tlvs);  		  return ISIS_WARNING;	/* Reject */  		}  	      else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || @@ -540,7 +707,7 @@ process_p2p_hello (struct isis_circuit *circuit)  	}      }    /* 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)  	{ @@ -566,6 +733,7 @@ process_p2p_hello (struct isis_circuit *circuit)  		{  		  /* (6) reject - Area Mismatch event */  		  zlog_warn ("AreaMismatch"); +                  free_tlvs (&tlvs);  		  return ISIS_WARNING;	/* Reject */  		}  	      else if (adj->adj_usage == ISIS_ADJ_LEVEL1) @@ -618,6 +786,11 @@ process_p2p_hello (struct isis_circuit *circuit)  	    }  	}      } +  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 */ @@ -641,7 +814,15 @@ process_p2p_hello (struct isis_circuit *circuit)      }    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, ntohs (hdr->pdu_len)); +    }    free_tlvs (&tlvs); @@ -657,11 +838,28 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)    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)      { @@ -676,7 +874,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)        return ISIS_WARNING;      } -  if (!accept_level (level, circuit->circuit_is_type)) +  if (!accept_level (level, circuit->is_type))      {        if (isis->debugs & DEBUG_ADJ_PACKETS)  	{ @@ -708,13 +906,25 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)    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))      { -      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); +      hdr.pdu_len = stream_get_endp (circuit->rcv_stream); +    } + +  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     */ @@ -725,10 +935,12 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)    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)      { @@ -744,24 +956,28 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)        goto out;      } +  /* Verify authentication, either cleartext of HMAC MD5 */    if (circuit->passwd.type)      {        if (!(found & TLVFLAG_AUTH_INFO) || -	  authentication_check (&circuit->passwd, &tlvs.auth_info)) -	{ -	  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)  	{ @@ -788,43 +1004,49 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)    /*     * 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) @@ -833,7 +1055,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)        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);  	  } @@ -841,7 +1063,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)        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);  	  } @@ -854,6 +1076,8 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)    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); @@ -872,7 +1096,7 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)    /* 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 @@ -880,31 +1104,48 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)     */    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); @@ -927,7 +1168,16 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)    u_char lspid[ISIS_SYS_ID_LEN + 2];    struct isis_passwd *passwd; -  /* 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)      { @@ -941,19 +1191,26 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)    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),  +		  ntohs (hdr->pdu_len),  		  circuit->interface->name);      } -  assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN); +  if (ntohs (hdr->pdu_len) <= ISIS_LSP_HDR_LEN || +      ntohs (hdr->pdu_len)  > ISO_MTU(circuit)) +    { +      zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", +		  circuit->area->area_tag, +		  rawlspid_print (hdr->lsp_id), ntohs (hdr->pdu_len)); + +      return ISIS_WARNING; +    }    /* Checksum sanity check - FIXME: move to correct place */    /* 12 = sysid+pdu+remtime */ @@ -979,13 +1236,13 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)      }    /* 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;      } @@ -995,12 +1252,12 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)    /* 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); @@ -1021,7 +1278,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)    /* 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)      { @@ -1038,7 +1294,6 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)  	  return ISIS_WARNING;	/* Silently discard */  	}      } -    /* for non broadcast, we just need to find same level adj */    else      { @@ -1049,13 +1304,15 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa)  	}        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  */ @@ -1082,10 +1339,9 @@ dontcheckadj:  	      /* 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 */ @@ -1109,38 +1365,25 @@ dontcheckadj:  		  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;      } @@ -1163,21 +1406,13 @@ dontcheckadj:        else 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)); +          lsp_set_all_srmflags (lsp);  	  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));  	}      }    else @@ -1187,21 +1422,6 @@ dontcheckadj:        /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */        if ((!lsp || comp == LSP_NEWER))  	{ -	  /* 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  	   */ @@ -1212,19 +1432,24 @@ dontcheckadj:  	      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->adj = adj; -	  lsp_insert (lsp, circuit->area->lspdb[level - 1]); +	  /* i */ +	  if (!lsp) +            { +	      lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, +                                             ntohs (hdr->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); @@ -1237,11 +1462,9 @@ dontcheckadj:        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 @@ -1250,8 +1473,6 @@ dontcheckadj:  	  ISIS_CLEAR_FLAG (lsp->SSNflags, circuit);  	}      } -  if (lsp) -    lsp->adj = adj;    return retval;  } @@ -1268,11 +1489,11 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,    int retval = ISIS_OK;    int cmp, own_lsp;    char typechar = ' '; -  int len; +  unsigned int 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; @@ -1289,9 +1510,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  	(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) +      if (len < ISIS_CSNP_HDRLEN || len > ISO_MTU(circuit))  	{ -	  zlog_warn ("Received a CSNP with bogus length!"); +	  zlog_warn ("Received a CSNP with bogus length %d", len);  	  return ISIS_OK;  	}      } @@ -1302,9 +1523,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  	(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) +      if (len < ISIS_PSNP_HDRLEN || len > ISO_MTU(circuit))  	{ -	  zlog_warn ("Received a CSNP with bogus length!"); +	  zlog_warn ("Received a CSNP with bogus length %d", len);  	  return ISIS_OK;  	}      } @@ -1322,7 +1543,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,      }    /* 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, " @@ -1331,26 +1552,23 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  		  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 */ @@ -1380,7 +1598,10 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,    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  */ @@ -1392,10 +1613,12 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,    /* 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); +		       &expected, &found, &tlvs, &auth_tlv_offset);    if (retval > ISIS_WARNING)      { @@ -1404,7 +1627,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,        return retval;      } -  if (level == 1) +  if (level == IS_LEVEL_1)      passwd = &circuit->area->area_passwd;    else      passwd = &circuit->area->domain_passwd; @@ -1412,16 +1635,19 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,    if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV))      {        if (passwd->type) -	{ -	  if (!(found & TLVFLAG_AUTH_INFO) || -	      authentication_check (passwd, &tlvs.auth_info)) -	    { -	      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 */ @@ -1461,19 +1687,18 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  	    /* 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)); @@ -1482,8 +1707,8 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  		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);  		  }  	      }  	  } @@ -1496,7 +1721,9 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  	      {  		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);  	      }  	  } @@ -1507,7 +1734,8 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,    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, @@ -1530,11 +1758,10 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  	}        /* 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); @@ -1544,6 +1771,16 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,  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) @@ -1558,10 +1795,20 @@ process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa)  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;      } @@ -1585,6 +1832,16 @@ process_is_hello (struct isis_circuit *circuit)    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...     */ @@ -1649,7 +1906,6 @@ static int  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; @@ -1660,7 +1916,7 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)    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;      } @@ -1669,28 +1925,11 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)     */    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; -    } -  else -    { -      stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); +      zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp); +      return ISIS_ERROR;      } +  stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); +    /*     * and then process it     */ @@ -1721,6 +1960,14 @@ isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa)        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)) @@ -1795,8 +2042,11 @@ isis_receive (struct thread *thread)    /*      * 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;  } @@ -1830,10 +2080,13 @@ isis_receive (struct thread *thread)    /*      * 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;  } @@ -1908,11 +2161,14 @@ send_hello (struct isis_circuit *circuit, int level)    struct isis_fixed_hdr fixed_hdr;    struct isis_lan_hello_hdr hello_hdr;    struct isis_p2p_hello_hdr p2p_hello_hdr; - +  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;    int retval; +  if (circuit->is_passive) +    return ISIS_OK; +    if (circuit->interface->mtu == 0)      {        zlog_warn ("circuit has zero MTU"); @@ -1925,7 +2181,7 @@ send_hello (struct isis_circuit *circuit, int level)      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 @@ -1942,7 +2198,7 @@ send_hello (struct isis_circuit *circuit, int level)      circuit->hello_interval[level - 1];    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); @@ -1959,13 +2215,13 @@ send_hello (struct isis_circuit *circuit, int level)      }    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); @@ -1974,27 +2230,49 @@ send_hello (struct isis_circuit *circuit, int level)      }    /* -   * Then the variable length part  +   * Then the variable length part.     */ +    /* add circuit password */ -  if (circuit->passwd.type) -    if (tlv_add_authinfo (circuit->passwd.type, 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; + +    /* 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 (circuit->passwd.type, ISIS_AUTH_MD5_SIZE, +                            hmac_md5_hash, circuit->snd_stream)) +        return ISIS_WARNING; +      break; + +    default: +      break; +  } +    /*  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; +  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 == 1 && circuit->u.bc.lan_neighs[0]->count > 0) +      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 == 2 && circuit->u.bc.lan_neighs[1]->count > 0) +      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; @@ -2005,19 +2283,20 @@ send_hello (struct isis_circuit *circuit, int level)      if (tlv_add_nlpid (&circuit->nlpids, 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 */ -  if (circuit->u.bc.pad_hellos) +  if (circuit->pad_hellos)      if (tlv_add_padding (circuit->snd_stream))        return ISIS_WARNING; @@ -2025,11 +2304,18 @@ send_hello (struct isis_circuit *circuit, int level)    /* Update PDU length */    stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length); -  retval = circuit->tx (circuit, level); -  if (retval) -    zlog_warn ("sending of LAN Level %d Hello failed", level); +  /* For HMAC MD5 we need to compute the md5 hash and store it */ +  if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) +    { +      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 (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, +              hmac_md5_hash, ISIS_AUTH_MD5_SIZE); +    } -  /* DEBUG_ADJ_PACKETS */    if (isis->debugs & DEBUG_ADJ_PACKETS)      {        if (circuit->circ_type == CIRCUIT_T_BROADCAST) @@ -2037,24 +2323,26 @@ send_hello (struct isis_circuit *circuit, int level)  	  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 @@ -2070,7 +2358,7 @@ send_lan_l1_hello (struct thread *thread)    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], @@ -2093,7 +2381,7 @@ send_lan_l2_hello (struct thread *thread)    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], @@ -2128,11 +2416,18 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,  {    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 (circuit->snd_stream == NULL) +    circuit->snd_stream = stream_new (ISO_MTU (circuit)); +  else +    stream_reset (circuit->snd_stream); -  if (level == 1) +  if (level == IS_LEVEL_1)      fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM,  			      circuit->snd_stream);    else @@ -2156,81 +2451,243 @@ build_csnp (int level, u_char * start, u_char * stop, struct list *lsps,    /*     * 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) -    { -      retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); +  { +    switch (passwd->type) +    { +      /* 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); +} + +/*   * 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->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;  } @@ -2284,12 +2741,19 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)    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 @@ -2308,20 +2772,40 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)     * 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) -    { -      retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); +  { +    switch (passwd->type) +    { +      /* 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)      { @@ -2338,10 +2822,22 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)      }    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;  } @@ -2352,54 +2848,71 @@ build_psnp (int level, struct isis_circuit *circuit, struct list *lsps)  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->circ_type == CIRCUIT_T_BROADCAST && -       !circuit->u.bc.is_dr[level - 1]) || -      circuit->circ_type != CIRCUIT_T_BROADCAST) -    { +  if (circuit->circ_type == CIRCUIT_T_BROADCAST && +      circuit->u.bc.is_dr[level - 1]) +    return ISIS_OK; -      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) -	    { -	      if (circuit->snd_stream == NULL) -		circuit->snd_stream = stream_new (ISO_MTU (circuit)); -	      else -		stream_reset (circuit->snd_stream); +  if (circuit->area->lspdb[level - 1] == NULL || +      dict_count (circuit->area->lspdb[level - 1]) == 0) +    return ISIS_OK; +  num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit); -	      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)); +  while (1) +    { +      list = list_new (); +      lsp_build_list_ssn (circuit, num_lsps, list, +                          circuit->area->lspdb[level - 1]); + +      if (listcount (list) == 0) +        { +          list_delete (list); +          return ISIS_OK; +        } + +      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; +        } -	      retval = build_psnp (level, circuit, list); -	      if (retval == ISIS_OK) -		retval = circuit->tx (circuit, level); +      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)); +        } + +      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; +        } -	      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; @@ -2458,90 +2971,80 @@ send_lsp (struct thread *thread)    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) -    { -      lsp = listgetdata ((node = listhead (circuit->lsp_queue))); +  if (circuit->state != C_STATE_UP || circuit->is_passive == 1) +  { +    return retval; +  } -      /* -       * Do not send if levels do not match -       */ -      if (!(lsp->level & circuit->circuit_is_type)) -	goto dontsend; +  lsp = listgetdata ((node = listhead (circuit->lsp_queue))); -      /* -       * 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]) -	{ +  /* +   * Do not send if levels do not match +   */ +  if (!(lsp->level & circuit->is_type)) +    { +      list_delete_node (circuit->lsp_queue, node); +      return retval; +    } -	  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); +  /* +   * Do not send if we do not have adjacencies in state up on the circuit +   */ +  if (circuit->upadjcount[lsp->level - 1] == 0) +    { +      list_delete_node (circuit->lsp_queue, node); +      return retval; +    } -	  retval = circuit->tx (circuit, lsp->level); +  /* copy our lsp to the send buffer */ +  stream_copy (circuit->snd_stream, lsp->pdu); -	  /* -	   * If the sending succeeded, we can del the lsp from circuits -	   * lsp_queue -	   */ -	  if (retval == ISIS_OK) -	    { -	      list_delete_node (circuit->lsp_queue, node); +  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; +    } -	      /* -	       * On broadcast circuits also the SRMflag can be cleared -	       */ -	      if (circuit->circ_type == CIRCUIT_T_BROADCAST) -		ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); +  /* +   * If the sending succeeded, we can del the lsp from circuits +   * lsp_queue +   */ +  list_delete_node (circuit->lsp_queue, node); -	      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); -	} -#if 0 -      /* -       * If there are still LSPs send next one after lsp-interval (33 msecs) -       */ -      if (listcount (circuit->lsp_queue) > 0) -	thread_add_timer (master, send_lsp, circuit, 1); -#endif -    } +  /* 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;  } @@ -2560,8 +3063,8 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,    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 @@ -2586,7 +3089,10 @@ ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit,    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 95c1ee4ffb..9e215535e4 100644 --- a/isisd/isis_pdu.h +++ b/isisd/isis_pdu.h @@ -95,7 +95,7 @@ struct isis_fixed_hdr    u_char version2;    u_char reserved;    u_char max_area_addrs; -}; +} __attribute__ ((packed));  #define ISIS_FIXED_HDR_LEN 8 @@ -186,6 +186,17 @@ struct isis_link_state_hdr  } __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  /* @@ -241,6 +252,8 @@ int isis_receive (struct thread *thread);  #define ISIS_SNP_PSNP_FLAG 0  #define ISIS_SNP_CSNP_FLAG 1 +#define ISIS_AUTH_MD5_SIZE       16U +  /*   * Sending functions   */ @@ -258,8 +271,4 @@ int ack_lsp (struct isis_link_state_hdr *hdr,  void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type);  int send_hello (struct isis_circuit *circuit, int level); - -int authentication_check (struct isis_passwd *one, -			  struct isis_passwd *theother); -  #endif /* _ZEBRA_ISIS_PDU_H */ diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 9e4165e35b..42947b22cd 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -134,7 +134,7 @@ open_packet_socket (struct isis_circuit *circuit)    circuit->fd = fd; -  if (circuit->circ_type == CIRCUIT_T_BROADCAST) +  if (if_is_broadcast (circuit->interface))      {        /*         * Join to multicast groups @@ -142,24 +142,22 @@ open_packet_socket (struct isis_circuit *circuit)         * 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 @@ isis_sock_init (struct isis_circuit *circuit)        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; @@ -234,13 +233,14 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)    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;      }    /* @@ -249,15 +249,22 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa)    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); @@ -285,9 +292,11 @@ isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)    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;      } @@ -309,6 +318,9 @@ isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa)  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     */ @@ -321,7 +333,10 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)    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); @@ -332,14 +347,17 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)    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;  } @@ -347,7 +365,6 @@ isis_send_pdu_bcast (struct isis_circuit *circuit, int level)  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 1286486cec..96d8df8fa1 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)  { @@ -294,14 +292,24 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family,      {        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); +          adjinfo2nexthop (rinfo->nexthops, adj); +        }      }  #ifdef HAVE_IPV6    if (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); +          adjinfo2nexthop6 (rinfo->nexthops6, adj); +        }      }  #endif /* HAVE_IPV6 */ @@ -353,18 +361,25 @@ isis_route_info_same (struct isis_route_info *new,  #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 +401,6 @@ isis_route_info_same (struct isis_route_info *new,    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, @@ -479,68 +435,32 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth,    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 +490,7 @@ isis_route_delete (struct prefix *prefix, struct route_table *table)        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 +520,12 @@ isis_route_validate_table (struct isis_area *area, struct route_table *table)        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 +628,55 @@ isis_route_validate_merge (struct isis_area *area, int family)  /* 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_merge (area, AF_INET); +    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); -validate_ipv6:  #ifdef HAVE_IPV6    if (area->is_type == IS_LEVEL_1) +    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 + +  /* 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))      { -      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; -    } +      if (rode->info == NULL) +        continue; +      rinfo = rode->info; -  isis_route_validate_merge (area, AF_INET6); -#endif +      UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); +    } +} -  return ISIS_OK; +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 4eac79b863..1312400c86 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -43,8 +43,9 @@ struct isis_nexthop  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 +60,9 @@ struct isis_route_info *isis_route_create (struct prefix *prefix,  					   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 cff0fa3ff9..558d391023 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 5d7e9da425..a91742b62a 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 @@ remove_excess_adjs (struct list *adjs)    return;  } -#ifdef EXTREME_DEBUG  static const char *  vtype2string (enum vertextype vtype)  { @@ -164,12 +160,12 @@ vid2string (struct isis_vertex *vertex, u_char * buff)      {      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,149 +182,260 @@ vid2string (struct isis_vertex *vertex, u_char * buff)    return (char *) buff;  } -#endif /* EXTREME_DEBUG */ -static struct isis_spftree * -isis_spftree_new () +static struct isis_vertex * +isis_vertex_new (void *id, enum vertextype vtype)  { -  struct isis_spftree *tree; +  struct isis_vertex *vertex; -  tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree)); -  if (tree == NULL) +  vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); +  if (vertex == NULL)      { -      zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!"); +      zlog_err ("isis_vertex_new Out of memory!");        return NULL;      } -  tree->tents = list_new (); -  tree->paths = list_new (); -  return tree; +  vertex->type = vtype; +  switch (vtype) +    { +    case VTYPE_ES: +    case VTYPE_NONPSEUDO_IS: +    case VTYPE_NONPSEUDO_TE_IS: +      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN); +      break; +    case VTYPE_PSEUDO_IS: +    case VTYPE_PSEUDO_TE_IS: +      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1); +      break; +    case VTYPE_IPREACH_INTERNAL: +    case VTYPE_IPREACH_EXTERNAL: +    case VTYPE_IPREACH_TE: +#ifdef HAVE_IPV6 +    case VTYPE_IP6REACH_INTERNAL: +    case VTYPE_IP6REACH_EXTERNAL: +#endif /* HAVE_IPV6 */ +      memcpy (&vertex->N.prefix, (struct prefix *) id, +	      sizeof (struct prefix)); +      break; +    default: +      zlog_err ("WTF!"); +    } + +  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;  } -#if 0 /* HT: Not used yet. */  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->lastrun = 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;  } -#endif  + +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) && area->spftree[0] == NULL) -    { -      area->spftree[0] = isis_spftree_new (); +  if (area->is_type & IS_LEVEL_1) +  { +    if (area->spftree[0] == NULL) +      area->spftree[0] = isis_spftree_new (area);  #ifdef HAVE_IPV6 -      area->spftree6[0] = isis_spftree_new (); +    if (area->spftree6[0] == NULL) +      area->spftree6[0] = isis_spftree_new (area);  #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 (); +  if (area->is_type & IS_LEVEL_2) +  { +    if (area->spftree[1] == NULL) +      area->spftree[1] = isis_spftree_new (area);  #ifdef HAVE_IPV6 -      area->spftree6[1] = isis_spftree_new (); +    if (area->spftree6[1] == NULL) +      area->spftree6[1] = isis_spftree_new (area);  #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) +void +spftree_area_del (struct isis_area *area)  { -  struct isis_vertex *vertex; - -  vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); -  if (vertex == NULL) +  if (area->is_type & IS_LEVEL_1) +  { +    if (area->spftree[0] != NULL)      { -      zlog_err ("isis_vertex_new Out of memory!"); -      return 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 +  } -  vertex->type = vtype; -  switch (vtype) +  if (area->is_type & IS_LEVEL_2) +  { +    if (area->spftree[1] != NULL)      { -    case VTYPE_ES: -    case VTYPE_NONPSEUDO_IS: -    case VTYPE_NONPSEUDO_TE_IS: -      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN); -      break; -    case VTYPE_PSEUDO_IS: -    case VTYPE_PSEUDO_TE_IS: -      memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1); -      break; -    case VTYPE_IPREACH_INTERNAL: -    case VTYPE_IPREACH_EXTERNAL: -    case VTYPE_IPREACH_TE: +      isis_spftree_del (area->spftree[1]); +      area->spftree[1] = NULL; +    }  #ifdef HAVE_IPV6 -    case VTYPE_IP6REACH_INTERNAL: -    case VTYPE_IP6REACH_EXTERNAL: -#endif /* HAVE_IPV6 */ -      memcpy (&vertex->N.prefix, (struct prefix *) id, -	      sizeof (struct prefix)); -      break; -    default: -      zlog_err ("WTF!"); +    if (area->spftree[1] != NULL) +    { +      isis_spftree_del (area->spftree6[1]); +      area->spftree6[1] = NULL;      } +#endif +  } -  vertex->Adj_N = list_new (); +  return; +} -  return vertex; +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) +{ +  u_char lspid[ISIS_SYS_ID_LEN + 2]; + +  memcpy (lspid, sysid, ISIS_SYS_ID_LEN); +  LSP_PSEUDO_ID (lspid) = 0; +  LSP_FRAGMENT (lspid) = 0; +  return (lsp_search (lspid, area->lspdb[level - 1]));  }  /*   * 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 +445,7 @@ isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area,  	      vertex->depth, vertex->d_N);  #endif /* EXTREME_DEBUG */ -  return; +  return vertex;  }  static struct isis_vertex * @@ -390,34 +497,49 @@ isis_find_vertex (struct list *list, void *id, enum vertextype vtype)   */  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 */ -  listnode_add (spftree->tents, vertex); +    if (list_isempty (spftree->tents))      {        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); @@ -426,35 +548,24 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype,  	  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; @@ -470,40 +581,65 @@ isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype,  	  /*       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); @@ -516,16 +652,26 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,      {        /*        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;  	} @@ -536,11 +682,23 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,  	}        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;  } @@ -549,10 +707,11 @@ process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id,   */  static int  isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, -		      uint32_t cost, uint16_t depth, int family) +		      uint32_t cost, uint16_t depth, int family, +		      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; @@ -562,117 +721,121 @@ isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp,  #ifdef HAVE_IPV6    struct ipv6_reachability *ip6reach;  #endif /* HAVE_IPV6 */ +  static const u_char null_sysid[ISIS_SYS_ID_LEN]; - -  if (!lsp->adj) -    return ISIS_WARNING; -  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;      } +#ifdef EXTREME_DEBUG +      zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id)); +#endif /* EXTREME_DEBUG */ +    if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) +  { +    if (lsp->tlv_data.is_neighs)      { -      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, lsp->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, lsp->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, -			 lsp->adj, family); -	    } -	} +      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_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, -			 lsp->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, -			 lsp->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); +      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)); -	      process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, -			 lsp->adj, family); -	    } -	} -#endif /* 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); @@ -690,13 +853,16 @@ lspfragloop:  static int  isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, -			     struct isis_lsp *lsp, uint16_t cost, -			     uint16_t depth, int family) +			     struct isis_lsp *lsp, uint32_t cost, +			     uint16_t depth, int family, +			     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 +873,36 @@ pseudofragloop:        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 (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, lsp->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 (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, lsp->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 +920,10 @@ pseudofragloop:  }  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 +934,16 @@ isis_spf_preload_tent (struct isis_spftree *spftree,    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 +961,9 @@ isis_spf_preload_tent (struct isis_spftree *spftree,  	    {  	      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 +974,9 @@ isis_spf_preload_tent (struct isis_spftree *spftree,  	    {  	      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,43 +996,41 @@ isis_spf_preload_tent (struct isis_spftree *spftree,  			    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]); +		  lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]);  		  if (!lsp) -		    zlog_warn ("No lsp found for IS adjacency"); -		  /*          else { -		     isis_spf_process_lsp (spftree, lsp, vertex->d_N, 1, family); -		     } */ +                    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);  	  /* @@ -878,23 +1040,36 @@ isis_spf_preload_tent (struct isis_spftree *spftree,  	    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;  	    } +	  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"); -	    } -	  else -	    { -	      isis_spf_process_pseudo_lsp (spftree, lsp, -				  circuit->te_metric[level - 1], 0, family); - +	      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;  	    } +	  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)  	{ @@ -905,28 +1080,36 @@ isis_spf_preload_tent (struct isis_spftree *spftree,  	    {  	    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; @@ -938,25 +1121,30 @@ isis_spf_preload_tent (struct isis_spftree *spftree,   */  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; @@ -969,22 +1157,20 @@ init_spt (struct isis_spftree *spftree)    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 route_table *table = NULL; -  struct route_node *rode; -  struct isis_route_info *rinfo;    if (family == AF_INET)      spftree = area->spftree[level - 1]; @@ -992,8 +1178,8 @@ isis_run_spf (struct isis_area *area, int level, int family)    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) @@ -1003,30 +1189,28 @@ isis_run_spf (struct isis_area *area, int level, int family)      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;      } @@ -1034,14 +1218,22 @@ isis_run_spf (struct isis_area *area, int level, int family)      {        node = listhead (spftree->tents);        vertex = listgetdata (node); -      /* Remove from tent list */ + +#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); -      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) -	{ +      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]); @@ -1050,13 +1242,13 @@ isis_run_spf (struct isis_area *area, int level, int family)  	      if (LSP_PSEUDO_ID (lsp_id))  		{  		  isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, -					       vertex->depth, family); - +					       vertex->depth, family, sysid, +					       vertex);  		}  	      else  		{  		  isis_spf_process_lsp (spftree, lsp, vertex->d_N, -					vertex->depth, family); +					vertex->depth, family, sysid, vertex);  		}  	    }  	  else @@ -1064,12 +1256,15 @@ isis_run_spf (struct isis_area *area, int level, int family)  	      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); +  isis_route_validate (area);    spftree->lastrun = time (NULL); +  spftree->runcount++;    spftree->pending = 0;    return retval; @@ -1085,6 +1280,7 @@ isis_run_spf_l1 (struct thread *thread)    assert (area);    area->spftree[0]->t_spf = NULL; +  area->spftree[0]->pending = 0;    if (!(area->is_type & IS_LEVEL_1))      { @@ -1098,10 +1294,7 @@ isis_run_spf_l1 (struct thread *thread)      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;  } @@ -1116,6 +1309,7 @@ isis_run_spf_l2 (struct thread *thread)    assert (area);    area->spftree[1]->t_spf = NULL; +  area->spftree[1]->pending = 0;    if (!(area->is_type & IS_LEVEL_2))      { @@ -1128,10 +1322,7 @@ isis_run_spf_l2 (struct thread *thread)      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;  } @@ -1139,53 +1330,40 @@ isis_run_spf_l2 (struct thread *thread)  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); - -  if (spftree->pending) -    return retval; +  time_t now = time (NULL); +  int diff = now - spftree->lastrun; -  diff = now - spftree->lastrun; +  assert (diff >= 0); +  assert (area->is_type & level); -  /* 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); +  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); -      spftree->pending = 1; -      return retval; -    } +  if (spftree->pending) +    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 MINIMUM_SPF_INTERVAL before doing the SPF */ +  if (diff >= MINIMUM_SPF_INTERVAL) +      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, +                     MINIMUM_SPF_INTERVAL - 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, +                     MINIMUM_SPF_INTERVAL - 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, MINIMUM_SPF_INTERVAL - diff); + +  spftree->pending = 1; + +  return ISIS_OK;  }  #ifdef HAVE_IPV6 @@ -1199,11 +1377,12 @@ isis_run_spf6_l1 (struct thread *thread)    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;      } @@ -1211,10 +1390,7 @@ isis_run_spf6_l1 (struct thread *thread)      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;  } @@ -1229,6 +1405,7 @@ isis_run_spf6_l2 (struct thread *thread)    assert (area);    area->spftree6[1]->t_spf = NULL; +  area->spftree6[1]->pending = 0;    if (!(area->is_type & IS_LEVEL_2))      { @@ -1241,10 +1418,7 @@ isis_run_spf6_l2 (struct thread *thread)      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;  } @@ -1259,22 +1433,14 @@ isis_spf_schedule6 (struct isis_area *area, int level)    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_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); +  /* FIXME: let's wait MINIMUM_SPF_INTERVAL before doing the SPF */ +  if (now - isis->uptime < MINIMUM_SPF_INTERVAL || isis->uptime == 0) +      diff = 0; +  else +      diff = now - spftree->lastrun; +    if (diff < MINIMUM_SPF_INTERVAL)      {        if (level == 1) @@ -1288,15 +1454,7 @@ isis_spf_schedule6 (struct isis_area *area, int level)      }    else      { -      spftree->pending = 0; -      retval = isis_run_spf (area, level, AF_INET6); - -      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)); +      retval = isis_run_spf (area, level, AF_INET6, isis->sysid);      }    return retval; @@ -1304,54 +1462,73 @@ isis_spf_schedule6 (struct isis_area *area, int level)  #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 (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 ", "", "", ""); +	    } +	    vty_out (vty, "%-20s %-9s ", +		     print_sys_hostname (adj->sysid), +		     adj->circuit->interface->name); +	    ++rows; +	  } +	} +	if (rows == 0) +	  vty_out (vty, "%-30s ", ""); +      } -  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); +      /* 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 -	{ -	  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); -	    } -	  else -	    { -	      vty_out (vty, "%s              %u %s", dyn ? dyn->name.name : -		       (const u_char *) rawlspid_print (vertex->N.id), -		       vertex->d_N, VTY_NEWLINE); +      } else { +	vty_out (vty, "  NULL "); +      } + +#if 0 +      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);  	    }  	} -#if 0 -      vty_out (vty, "%s %s %u %s", vtype2string (vertex->type), -	       vid2string (vertex, buff), vertex->d_N, VTY_NEWLINE);  #endif +      vty_out (vty, "%s", VTY_NEWLINE);      }  } @@ -1381,7 +1558,8 @@ DEFUN (show_isis_topology,  	    {  	      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] @@ -1390,10 +1568,13 @@ DEFUN (show_isis_topology,  	      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; @@ -1423,7 +1604,8 @@ DEFUN (show_isis_topology_l1,  	{  	  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] @@ -1431,9 +1613,11 @@ DEFUN (show_isis_topology_l1,  	{  	  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; @@ -1463,7 +1647,8 @@ DEFUN (show_isis_topology_l2,  	{  	  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] @@ -1471,9 +1656,11 @@ DEFUN (show_isis_topology_l2,  	{  	  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 6bdab2da6b..f31b510569 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -54,25 +54,32 @@ struct isis_vertex      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 */ +  time_t lastrun;		/* for scheduling */ +  unsigned int runcount;        /* number of runs since uptime */  }; +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 94fa65ed32..bb57bd6be4 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 @@ free_tlvs (struct tlvs *tlvs)      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 @@ free_tlvs (struct tlvs *tlvs)    if (tlvs->ipv6_reachs)      list_delete (tlvs->ipv6_reachs);  #endif /* HAVE_IPV6 */ -   + +  memset (tlvs, 0, sizeof (struct tlvs)); +    return;  } @@ -103,7 +98,7 @@ 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 * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset)  {    u_char type, length;    struct lan_neigh *lan_nei; @@ -122,7 +117,7 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,  #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,10 +438,22 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,  	  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); -	      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  	    { @@ -730,10 +737,14 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,  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;      } @@ -873,12 +884,12 @@ tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream)  }  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];    u_char *pos = value; -  *pos++ = ISIS_PASSWD_TYPE_CLEARTXT; +  *pos++ = auth_type;    memcpy (pos, auth_value, auth_len);    return add_tlv (AUTH_INFO, auth_len + 1, value, stream); @@ -1002,7 +1013,6 @@ tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream)        pos += IPV4_MAX_BYTELEN;      } -    return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream);  } @@ -1023,7 +1033,7 @@ tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream)        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; @@ -1106,7 +1116,7 @@ tlv_add_padding (struct stream *stream)    /*     * 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 */ @@ -1116,7 +1126,7 @@ tlv_add_padding (struct stream *stream)        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 fc9f35f8ab..e092f4d6d2 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 @@ struct te_is_neigh    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 @@ struct ipv6_reachability    u_char prefix_len;    u_char prefix[16];  }; -#endif /* HAVE_IPV6 */  /* bits in control_info */  #define CTRL_INFO_DIRECTION    0x80 @@ -223,12 +234,17 @@ struct ipv6_reachability  #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 tlvs    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 @@ struct tlvs  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_te_is_neighs (struct list *te_is_neighs, struct stream *stream);  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 9ee5ffc5d2..467122f658 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; + +  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); -  /* FIXME: Do we react somehow? */    return 0;  } @@ -100,53 +107,28 @@ isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)      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 @@ isis_zebra_if_state_down (int command, struct zclient *zclient,  			  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 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix,    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]) @@ -305,7 +287,8 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix,        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);      }  } @@ -326,7 +309,7 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix,        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;  } @@ -344,7 +327,7 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix,    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; @@ -406,7 +389,8 @@ isis_zebra_route_add_ipv6 (struct prefix *prefix,        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); @@ -427,7 +411,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix,    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; @@ -483,7 +467,7 @@ isis_zebra_route_del_ipv6 (struct prefix *prefix,        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 1e84a1cedb..6cbb85b1b6 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" @@ -59,19 +61,17 @@ u_char DEFAULT_TOPOLOGY_BASEIS[6] = { 0xFE, 0xED, 0xFE, 0xED, 0x00, 0x00 };  #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 *); @@ -84,8 +84,8 @@ isis_new (unsigned long process_id)     * 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); @@ -93,6 +93,7 @@ isis_new (unsigned long process_id)  #ifdef HAVE_IPV6    isis->nexthops6 = list_new ();  #endif /* HAVE_IPV6 */ +  dyn_cache_init ();    /*     * uncomment the next line for full debugs     */ @@ -100,7 +101,7 @@ isis_new (unsigned long process_id)  }  struct isis_area * -isis_area_create () +isis_area_create (const char *area_tag)  {    struct isis_area *area; @@ -114,36 +115,48 @@ isis_area_create ()      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 (); - -  spftree_area_init (area); -  area->route_table[0] = route_table_init (); -  area->route_table[1] = route_table_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[0] = route_table_init (); -  area->route_table6[1] = route_table_init (); +      area->route_table6[1] = route_table_init ();  #endif /* HAVE_IPV6 */ +    } + +  spftree_area_init (area); +    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); @@ -152,6 +165,10 @@ isis_area_create ()    /* 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;  } @@ -184,9 +201,7 @@ isis_area_get (struct vty *vty, const char *area_tag)        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); @@ -203,40 +218,100 @@ isis_area_destroy (struct vty *vty, const char *area_tag)    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_circuit_deconfigure (circuit, area); -	  isis_circuit_del (circuit); -	} -       +        { +          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_cancel_event (master, area); + +  listnode_delete (isis->area_list, area); + +  free (area->area_tag); +    XFREE (MTYPE_ISIS_AREA, area); +  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; @@ -249,7 +324,7 @@ area_net_title (struct vty *vty, const u_char *net_title)    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 */ @@ -257,7 +332,7 @@ area_net_title (struct vty *vty, const u_char *net_title)      {        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)); @@ -269,10 +344,18 @@ area_net_title (struct vty *vty, const u_char *net_title)  #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_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_WARNING; +      return CMD_ERR_AMBIGUOUS;      }    if (isis->sysid_set == 0) @@ -280,7 +363,7 @@ area_net_title (struct vty *vty, const u_char *net_title)        /*         * 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)); @@ -290,20 +373,19 @@ area_net_title (struct vty *vty, const u_char *net_title)        /*         * 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))  	    { @@ -311,26 +393,28 @@ area_net_title (struct vty *vty, const u_char *net_title)  	      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; @@ -341,7 +425,7 @@ area_clear_net_title (struct vty *vty, const u_char *net_title)    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); @@ -349,13 +433,13 @@ area_clear_net_title (struct vty *vty, const u_char *net_title)      {        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; @@ -363,26 +447,36 @@ area_clear_net_title (struct vty *vty, const u_char *net_title)      {        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)      { @@ -395,92 +489,246 @@ show_clns_neigh (struct vty *vty, char detail)        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") +       "ISIS network information\n" +       "ISIS interface\n" +       "show detailed information\n") +{ +  return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_DETAIL); +} -DEFUN (show_clns_neighbors_detail, -       show_clns_neighbors_detail_cmd, -       "show clns neighbors detail", +DEFUN (show_isis_interface_arg, +       show_isis_interface_arg_cmd, +       "show isis interface WORD",         SHOW_STR -       "clns network information\n" -       "CLNS neighbor adjacencies\n" -       "show detailed information\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_clns_neigh (vty, ISIS_UI_LEVEL_DETAIL); +  return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_BRIEF);  } -ALIAS (show_clns_neighbors_detail, -       show_isis_neighbors_detail_cmd, -       "show isis neighbors detail", +DEFUN (show_isis_neighbor_detail, +       show_isis_neighbor_detail_cmd, +       "show isis neighbor detail",         SHOW_STR -       "IS-IS network information\n" -       "IS-IS neighbor adjacencies\n" +       "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, +       "claer 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'   */ @@ -524,7 +772,8 @@ print_debug (struct vty *vty, int flags, int onoff)  	     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, @@ -606,6 +855,11 @@ config_write_debug (struct vty *vty)        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;  } @@ -792,7 +1046,6 @@ DEFUN (no_debug_isis_spfevents,    return CMD_SUCCESS;  } -  DEFUN (debug_isis_spfstats,         debug_isis_spfstats_cmd,         "debug isis spf-statistics ", @@ -897,6 +1150,32 @@ DEFUN (no_debug_isis_events,    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", @@ -909,80 +1188,312 @@ DEFUN (show_hostname,    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 listnode *node; +  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; -  int level, lsp_count; +  struct isis_spftree *spftree; +  int level; -  if (isis->area_list->count == 0) +  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)      { -      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); +      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); +      } +    } -	      lsp_count = lsp_print_all (vty, area->lspdb[level], -					 ISIS_UI_LEVEL_BRIEF, -					 area->dynhostname); +    for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) +    { +      if ((area->is_type & level) == 0) +        continue; -	      vty_out (vty, "%s    %u LSPs%s%s", -		       VTY_NEWLINE, lsp_count, VTY_NEWLINE, VTY_NEWLINE); -	    } -	} +      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          : "); +      vty_out_timestr(vty, spftree->lastrun); +      vty_out (vty, "%s", 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          : "); +      vty_out_timestr(vty, spftree->lastrun); +      vty_out (vty, "%s", VTY_NEWLINE); + +      vty_out (vty, "      run count         : %d%s", +          spftree->runcount, VTY_NEWLINE); +#endif      } +  } +  vty_out (vty, "%s", VTY_NEWLINE);    return CMD_SUCCESS;  } -DEFUN (show_database_detail, -       show_database_detail_cmd, -       "show isis database detail", -       SHOW_STR -       "IS-IS information\n" -       "IS-IS link state database\n") +/* + * 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[15]; /* len of xxxx.xxxx.xxxx + place for #0 termination */ +  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, 15); + +  if (argv) +    { +      strncpy (sysid, argv, 15); +      sysid[14] = '\0'; +    } + +  /* +   * 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 && 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); -      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); +               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); -	    } -	} +      for (level = 0; level < ISIS_LEVELS; level++) +        { +          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]); +                    } +                } + +              if (lsp != NULL || argv == NULL) +                { +                  vty_out (vty, "IS-IS Level-%d link-state database:%s", +                           level + 1, 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", +       SHOW_STR +       "IS-IS information\n" +       "IS-IS link state database\n") +{ +  return show_isis_database (vty, NULL, ISIS_UI_LEVEL_DETAIL); +} + +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); +} +  /*    * 'router isis' command    */ @@ -1032,10 +1543,69 @@ DEFUN (no_net,    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; +  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_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; @@ -1045,16 +1615,17 @@ DEFUN (area_passwd,    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_CLEARTXT;    strncpy ((char *)area->area_passwd.passwd, argv[0], 255); @@ -1072,14 +1643,16 @@ DEFUN (area_passwd,        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" @@ -1098,19 +1671,79 @@ DEFUN (no_area_passwd,    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_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; +  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_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;  } -DEFUN (domain_passwd, -       domain_passwd_cmd, -       "domain-password WORD", +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; @@ -1120,16 +1753,17 @@ DEFUN (domain_passwd,    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_CLEARTXT;    strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); @@ -1147,14 +1781,16 @@ DEFUN (domain_passwd,        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" @@ -1163,7 +1799,7 @@ ALIAS (domain_passwd,  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")  { @@ -1173,11 +1809,12 @@ DEFUN (no_domain_passwd,    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;  } @@ -1197,8 +1834,8 @@ DEFUN (is_type,    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]); @@ -1229,8 +1866,9 @@ DEFUN (no_is_type,    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; @@ -1242,6 +1880,36 @@ DEFUN (no_is_type,    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>", @@ -1250,15 +1918,12 @@ DEFUN (lsp_gen_interval,  {    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, @@ -1268,14 +1933,13 @@ DEFUN (no_lsp_gen_interval,         "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, @@ -1294,14 +1958,12 @@ DEFUN (lsp_gen_interval_l1,  {    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, @@ -1312,13 +1974,13 @@ DEFUN (no_lsp_gen_interval_l1,         "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, @@ -1337,15 +1999,13 @@ DEFUN (lsp_gen_interval_l2,         "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, @@ -1356,15 +2016,13 @@ DEFUN (no_lsp_gen_interval_l2,         "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, @@ -1384,6 +2042,8 @@ DEFUN (metric_style,         "Use new style of TLVs to carry wider metric\n")  {    struct isis_area *area; +  struct isis_circuit *circuit; +  struct listnode *node;    area = vty->index;    assert (area); @@ -1400,6 +2060,25 @@ DEFUN (metric_style,      }    else if (strncmp (argv[0], "n", 1) == 0)      { +      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; +            } +        }        area->newmetric = 0;        area->oldmetric = 1;      } @@ -1425,6 +2104,40 @@ DEFUN (no_metric_style,    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", @@ -1436,7 +2149,11 @@ DEFUN (dynamic_hostname,    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;  } @@ -1453,7 +2170,11 @@ DEFUN (no_dynamic_hostname,    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;  } @@ -1580,7 +2301,360 @@ ALIAS (no_spf_interval,         "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] " @@ -1612,7 +2686,7 @@ DEFUN (topology_generate_grid,        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; @@ -1622,7 +2696,7 @@ DEFUN (show_isis_generated_topology,         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; @@ -1706,182 +2780,8 @@ DEFUN (topology_basedynh,    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") +#endif /* TOPOLOGY_GENERATE */  /* IS-IS configuration write function */  int @@ -1919,34 +2819,36 @@ isis_config_write (struct vty *vty)  	    vty_out (vty, " no hostname dynamic%s", VTY_NEWLINE);  	    write++;  	  } -	/* ISIS - Metric-Style - when true displays wide */ -	if (area->newmetric) +	/* ISIS - Metric-Style - when true displays narrow */ +	if (area->oldmetric)  	  { -	    if (!area->oldmetric) -	      vty_out (vty, " metric-style wide%s", VTY_NEWLINE); +	    if (!area->newmetric) +	      vty_out (vty, " metric-style narrow%s", VTY_NEWLINE);  	    else  	      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); @@ -1955,13 +2857,13 @@ isis_config_write (struct vty *vty)  	  }  	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); @@ -1971,28 +2873,53 @@ isis_config_write (struct vty *vty)  	/* 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])  	  { @@ -2019,9 +2946,23 @@ isis_config_write (struct vty *vty)  	      }  	  }  	/* 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 "); +		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++;  +	  } +        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 "); @@ -2032,10 +2973,26 @@ isis_config_write (struct vty *vty)  	      }  	    vty_out(vty, "%s", VTY_NEWLINE);  	    write++;  -	  }   -	if (area->domain_passwd.len > 0) +          } +	if (area->domain_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) +	  { +            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 %s", area->domain_passwd.passwd); +	    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 "); @@ -2048,12 +3005,18 @@ isis_config_write (struct vty *vty)  	    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) @@ -2076,7 +3039,7 @@ isis_config_write (struct vty *vty)    return write;  } -static struct cmd_node isis_node = { +struct cmd_node isis_node = {    ISIS_NODE,    "%s(config-router)# ",    1 @@ -2088,23 +3051,43 @@ isis_init ()    /* 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_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_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_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); @@ -2131,6 +3114,8 @@ isis_init ()    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); @@ -2154,6 +3139,8 @@ isis_init ()    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); @@ -2166,12 +3153,16 @@ isis_init ()    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); @@ -2194,21 +3185,38 @@ isis_init ()    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); @@ -2218,9 +3226,4 @@ isis_init ()    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 2277f27c68..5db485f472 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -40,6 +40,7 @@ struct isis    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 @@ struct isis  #endif  }; +extern struct isis *isis; +  struct isis_area  {    struct isis *isis;				  /* back pointer */ @@ -92,9 +95,8 @@ struct isis_area    struct list *circuit_list;	/* IS-IS circuits */    struct flags flags;    struct thread *t_tick;	/* LSP walker */ -  struct thread *t_remove_aged; -  int lsp_regenerate_pending[ISIS_LEVELS];    struct thread *t_lsp_refresh[ISIS_LEVELS]; +  int lsp_regenerate_pending[ISIS_LEVELS];    /*     * Configurables  @@ -112,6 +114,8 @@ struct isis_area    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]; @@ -120,6 +124,8 @@ struct isis_area    /* 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 */ @@ -128,14 +134,21 @@ struct isis_area  #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) @@ -149,5 +162,6 @@ struct isis_area *isis_area_lookup (const char *);  #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/memtypes.c b/lib/memtypes.c index 5902067182..69beb1c954 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -242,6 +242,8 @@ struct memory_list memory_list_isis[] =    { 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 },  };  | 
