diff options
52 files changed, 7141 insertions, 4053 deletions
diff --git a/isisd/.cvsignore b/isisd/.cvsignore new file mode 100644 index 00000000..26aa85cb --- /dev/null +++ b/isisd/.cvsignore @@ -0,0 +1,12 @@ +Makefile +Makefile.in +*.o +isisd +.deps +isisd.conf +.nfs* +*.lo +*.la +*.libs +.arch-inventory +.arch-ids diff --git a/isisd/AUTHORS b/isisd/AUTHORS index d9f98b22..05fc0a50 100644 --- a/isisd/AUTHORS +++ b/isisd/AUTHORS @@ -1,3 +1,4 @@ -Sampo Saaristo <sambo@cs.tut.fi> -Ofer Wald <ofersf@islands.co.il> -Hannes Gredler <hannes@gredler.at> +Sampo Saaristo <sambo@cs.tut.fi> +Ofer Wald <ofersf@islands.co.il> +Hannes Gredler <hannes@gredler.at> +Subbaiah Venkata <svenkata@google.com> diff --git a/isisd/dict.c b/isisd/dict.c index a78b82ac..35cb924c 100644 --- a/isisd/dict.c +++ b/isisd/dict.c @@ -13,19 +13,16 @@ * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. + * + * $Id$ + * $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 @@ -243,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; @@ -284,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); } /* @@ -307,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); } @@ -810,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); @@ -946,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; @@ -978,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) @@ -1232,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; @@ -1347,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 9395d1c0..93edb7d6 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/include-netbsd/.cvsignore b/isisd/include-netbsd/.cvsignore new file mode 100644 index 00000000..73bcf19d --- /dev/null +++ b/isisd/include-netbsd/.cvsignore @@ -0,0 +1,3 @@ +.arch-inventory +.arch-ids + diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index de34bea9..468b0a69 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,107 @@ 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) - { - listnode_delete (adj->circuit->u.bc.adjdb[level - 1], adj); - 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); + } + + if (circuit->u.bc.lan_neighs[level - 1]) + { + list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); + isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], + circuit->u.bc.lan_neighs[level - 1]); + } + + /* 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 +318,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 +327,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 +344,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 +358,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 +406,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 +419,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 +480,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 99a8bb22..caa3107d 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -44,6 +44,7 @@ enum isis_system_type enum isis_adj_state { + ISIS_ADJ_UNKNOWN, ISIS_ADJ_INITIALIZING, ISIS_ADJ_UP, ISIS_ADJ_DOWN @@ -83,8 +84,10 @@ struct isis_adjacency struct list *area_addrs; /* areaAdressesOfNeighbour */ struct nlpids nlpids; /* protocols spoken ... */ struct list *ipv4_addrs; + struct in_addr router_address; #ifdef HAVE_IPV6 struct list *ipv6_addrs; + struct in6_addr router_address6; #endif /* HAVE_IPV6 */ u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */ int circuit_t; /* from hello PDU hdr */ @@ -103,25 +106,13 @@ struct 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 05f11386..4d5b1651 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 99e2bf6f..c09c3a28 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,25 +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) { - - /* destroy adjacencies */ - if (circuit->u.bc.adjdb[0]) - isis_adjdb_iterate (circuit->u.bc.adjdb[0], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[0]); - if (circuit->u.bc.adjdb[1]) - isis_adjdb_iterate (circuit->u.bc.adjdb[1], (void(*) (struct isis_adjacency *, void *)) isis_delete_adj, circuit->u.bc.adjdb[1]); - /* Remove circuit from area */ - listnode_delete (area->circuit_list, circuit); /* Free the index of SRM and SSN flags */ flags_free_index (&area->flags, circuit->idx); + circuit->idx = 0; + /* Remove circuit from area */ + assert (circuit->area == area); + listnode_delete (area->circuit_list, circuit); + circuit->area = NULL; return; } @@ -166,8 +165,11 @@ 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; } @@ -178,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); @@ -265,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; @@ -274,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); @@ -306,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 @@ -359,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"); + if (circuit->circ_type_config == CIRCUIT_T_P2P) + circuit->circ_type = CIRCUIT_T_P2P; else - memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), - ETH_ALEN); -#endif -#else - if (circuit->interface->hw_addr_len != ETH_ALEN) - { - zlog_warn ("unsupported link layer"); - } - else - { - memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN); - } -#ifdef EXTREME_DEGUG - zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s", - circuit->interface->ifindex, ISO_MTU (circuit), - snpa_print (circuit->u.bc.snpa)); - -#endif /* EXTREME_DEBUG */ -#endif /* HAVE_STRUCT_SOCKADDR_DL */ + circuit->circ_type = CIRCUIT_T_BROADCAST; } else if (if_is_pointopoint (ifp)) { circuit->circ_type = CIRCUIT_T_P2P; } + else if (if_is_loopback (ifp)) + { + circuit->circ_type = CIRCUIT_T_LOOPBACK; + circuit->is_passive = 1; + } else { /* It's normal in case of loopback etc. */ if (isis->debugs & DEBUG_EVENTS) - zlog_debug ("isis_circuit_if_add: unsupported media"); + zlog_debug ("isis_circuit_if_add: unsupported media"); + circuit->circ_type = CIRCUIT_T_UNKNOWN; } + circuit->ip_addrs = list_new (); +#ifdef HAVE_IPV6 + circuit->ipv6_link = list_new (); + circuit->ipv6_non_link = list_new (); +#endif /* HAVE_IPV6 */ + for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) isis_circuit_add_addr (circuit, conn); @@ -432,88 +471,158 @@ 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 */ @@ -524,98 +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->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)); - if (circuit->circuit_is_type & IS_LEVEL_2) + /* 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); } - if (circuit->t_send_psnp[0]) { - THREAD_TIMER_OFF (circuit->t_send_psnp[0]); - } - if (circuit->t_send_psnp[1]) { - THREAD_TIMER_OFF (circuit->t_send_psnp[1]); - } + /* Cancel all active threads */ + THREAD_TIMER_OFF (circuit->t_send_csnp[0]); + THREAD_TIMER_OFF (circuit->t_send_csnp[1]); + THREAD_TIMER_OFF (circuit->t_send_psnp[0]); + THREAD_TIMER_OFF (circuit->t_send_psnp[1]); + THREAD_OFF (circuit->t_read); + + if (circuit->lsp_queue) + { + circuit->lsp_queue->del = NULL; + list_delete (circuit->lsp_queue); + circuit->lsp_queue = NULL; + } + + /* send one gratuitous hello to spead up convergence */ + if (circuit->is_type & IS_LEVEL_1) + send_hello (circuit, IS_LEVEL_1); + if (circuit->is_type & IS_LEVEL_2) + send_hello (circuit, IS_LEVEL_2); + + circuit->upadjcount[0] = 0; + circuit->upadjcount[1] = 0; + /* close the socket */ - close (circuit->fd); + if (circuit->fd) + { + close (circuit->fd); + circuit->fd = 0; + } + + if (circuit->rcv_stream != NULL) + { + stream_free (circuit->rcv_stream); + circuit->rcv_stream = NULL; + } + + if (circuit->snd_stream != NULL) + { + stream_free (circuit->snd_stream); + circuit->snd_stream = NULL; + } + + thread_cancel_event (master, circuit); return; } @@ -640,216 +834,346 @@ 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++; - } - } - } - if (c->passwd.type==ISIS_PASSWD_TYPE_HMAC_MD5) - { - vty_out (vty, " isis password md5 %s%s", c->passwd.passwd, - VTY_NEWLINE); - write++; - } - else - { - if (c->passwd.type==ISIS_PASSWD_TYPE_CLEARTXT) - { - vty_out (vty, " isis password clear %s%s", c->passwd.passwd, - VTY_NEWLINE); - write++; - } - } - - } + /* ISIS - 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; } @@ -862,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; } @@ -927,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 @@ -959,80 +1275,240 @@ 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->ipv6_router = 1; + area->ipv6_circuits++; + circuit_update_nlpids (circuit); - circuit_t = string2circuit_t (argv[0]); + 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; - if (!circuit_t) + 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; + } + + 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; } - 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); + 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; } @@ -1041,26 +1517,20 @@ DEFUN (isis_passwd_md5, isis_passwd_md5_cmd, "isis password md5 WORD", "IS-IS commands\n" - "Configure the authentication password for interface\n" - "Authentication Type\n" - "Password\n") + "Configure the authentication password for a circuit\n" + "Authentication type\n" + "Circuit password\n") { - struct isis_circuit *circuit; - struct interface *ifp; int len; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } circuit->passwd.len = len; circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; @@ -1073,26 +1543,20 @@ DEFUN (isis_passwd_clear, isis_passwd_clear_cmd, "isis password clear WORD", "IS-IS commands\n" - "Configure the authentication password for interface\n" - "Authentication Type\n" - "Password\n") + "Configure the authentication password for a circuit\n" + "Authentication type\n" + "Circuit password\n") { - struct isis_circuit *circuit; - struct interface *ifp; int len; - - ifp = vty->index; - circuit = ifp->info; - if (circuit == NULL) - { - return CMD_WARNING; - } + struct isis_circuit *circuit = isis_circuit_lookup (vty); + if (!circuit) + return CMD_ERR_NO_MATCH; len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); - return CMD_WARNING; + return CMD_ERR_AMBIGUOUS; } circuit->passwd.len = len; circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; @@ -1106,17 +1570,11 @@ 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)); @@ -1130,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; } @@ -1157,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; } @@ -1190,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; } @@ -1217,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; } @@ -1250,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; } @@ -1277,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; } @@ -1303,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; } @@ -1343,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; } @@ -1370,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) + interval = atoi (argv[0]); + if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { - return CMD_WARNING; + vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", + interval, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; } - assert (circuit); - c = *argv[0]; - if (isdigit ((int) c)) - { - interval = atoi (argv[0]); - } - else - interval = HELLO_MINIMAL; /* FIXME: should be calculated */ circuit->hello_interval[0] = (u_int16_t) interval; circuit->hello_interval[1] = (u_int16_t) interval; @@ -1412,27 +1996,19 @@ 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" @@ -1441,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; @@ -1482,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" @@ -1511,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; @@ -1552,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" @@ -1581,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; @@ -1613,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" @@ -1640,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; @@ -1673,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" @@ -1700,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; @@ -1733,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" @@ -1791,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; @@ -1841,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" @@ -1868,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; @@ -1901,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" @@ -1928,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; @@ -1961,153 +2450,285 @@ 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; + + return CMD_SUCCESS; +} - if (!c) +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; + struct isis_circuit *circuit; + /* Clean up the circuit data */ + if (ifp && ifp->info) + { + circuit = ifp->info; + isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area); + isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area); + } + return 0; } @@ -2122,6 +2743,7 @@ isis_circuit_init () /* Install interface node */ install_node (&interface_node, isis_interface_config_write); install_element (CONFIG_NODE, &interface_cmd); + install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); @@ -2130,6 +2752,9 @@ 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); @@ -2150,6 +2775,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); @@ -2171,8 +2802,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); @@ -2183,6 +2815,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 f32d1dda..7ed481dc 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 @@ -65,7 +63,6 @@ struct isis_p2p_info struct isis_circuit { int state; - int connected; u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */ struct isis_area *area; /* back pointer to the area */ struct interface *interface; /* interface info from z */ @@ -79,31 +76,36 @@ struct 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 */ @@ -111,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 */ @@ -142,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 334d3394..d158961b 100644 --- a/isisd/isis_common.h +++ b/isisd/isis_common.h @@ -21,6 +21,9 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef ISIS_COMMON_H +#define ISIS_COMMON_H + /* * Area Address */ @@ -65,11 +68,4 @@ 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 1b75ba6b..bb2c4b40 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 6cdde46a..5d74a71b 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,24 +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; - circuit->connected = 1; - isis_event_circuit_state_change (circuit, 1); + isis_event_circuit_state_change (circuit, circuit->area, 1); listnode_delete (isis->init_circ_list, circuit); break; case IF_UP_FROM_Z: + assert (circuit); zlog_warn ("circuit already connected"); break; case ISIS_DISABLE: zlog_warn ("circuit already disabled"); break; case IF_DOWN_FROM_Z: - isis_circuit_if_del (circuit); + isis_circuit_if_del (circuit, (struct interface *) arg); listnode_delete (isis->init_circ_list, circuit); isis_circuit_del (circuit); circuit = NULL; @@ -131,19 +137,21 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) } break; case C_STATE_CONF: + assert (circuit); switch (event) { case ISIS_ENABLE: zlog_warn ("circuit already enabled"); break; case IF_UP_FROM_Z: - if (!circuit->connected) { - isis_circuit_if_add (circuit, (struct interface *) arg); - isis_circuit_up (circuit); - } + isis_circuit_if_add (circuit, (struct interface *) arg); + if (isis_circuit_up (circuit) != ISIS_OK) + { + isis_circuit_if_del (circuit, (struct interface *) arg); + break; + } circuit->state = C_STATE_UP; - circuit->connected = 1; - isis_event_circuit_state_change (circuit, 1); + isis_event_circuit_state_change (circuit, circuit->area, 1); break; case ISIS_DISABLE: isis_circuit_deconfigure (circuit, (struct isis_area *) arg); @@ -156,6 +164,7 @@ isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) } break; case C_STATE_UP: + assert (circuit); switch (event) { case ISIS_ENABLE: @@ -165,14 +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_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 fe872a95..73b6d3e7 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 8d306c8f..bc6ec119 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 0b758c85..ffb0d503 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 37a7b03c..379c454f 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 43800922..3887b7c5 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,64 @@ isis_event_system_type_change (struct isis_area *area, int newtype) return; /* No change */ switch (area->is_type) - { + { case IS_LEVEL_1: + if (newtype == IS_LEVEL_2) + area_resign_level (area, IS_LEVEL_1); + if (area->lspdb[1] == NULL) - area->lspdb[1] = lsp_db_init (); - lsp_l2_generate (area); + area->lspdb[1] = lsp_db_init (); + if (area->route_table[1] == NULL) + area->route_table[1] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[1] == NULL) + area->route_table6[1] = route_table_init (); +#endif /* HAVE_IPV6 */ break; + case IS_LEVEL_1_AND_2: if (newtype == IS_LEVEL_1) - { - lsp_db_destroy (area->lspdb[1]); - } + area_resign_level (area, IS_LEVEL_2); else - { - lsp_db_destroy (area->lspdb[0]); - } + area_resign_level (area, IS_LEVEL_1); break; + case IS_LEVEL_2: + if (newtype == IS_LEVEL_1) + area_resign_level (area, IS_LEVEL_2); + if (area->lspdb[0] == NULL) - area->lspdb[0] = lsp_db_init (); - lsp_l1_generate (area); + area->lspdb[0] = lsp_db_init (); + if (area->route_table[0] == NULL) + area->route_table[0] = route_table_init (); +#ifdef HAVE_IPV6 + if (area->route_table6[0] == NULL) + area->route_table6[0] = route_table_init (); +#endif /* HAVE_IPV6 */ break; + default: break; - } + } area->is_type = newtype; - for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) - isis_event_circuit_type_change (circuit, newtype); - 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 @@ -142,13 +192,14 @@ circuit_commence_level (struct isis_circuit *circuit, int level) { if (level == 1) { - THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, - isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); + if (! circuit->is_passive) + THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, + isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, - circuit, 2 * circuit->hello_interval[1]); + circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, @@ -160,8 +211,9 @@ circuit_commence_level (struct isis_circuit *circuit, int level) } else { - THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, - isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); + if (! circuit->is_passive) + THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, + isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { @@ -194,6 +246,8 @@ 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 +256,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 +280,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 +302,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 +345,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 +366,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 86bf051f..c252f3de 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 03c91101..ec0eaa4f 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 13dd9e14..e2e42adc 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 fd40bb37..5c1e9931 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,54 +441,40 @@ 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) +static u_int8_t +lsp_bits_generate (int level, int overload_bit) { - uint32_t expected = 0, found; - struct tlvs tlvs; - int retval = 0; - - expected |= TLVFLAG_AUTH_INFO; - retval = parse_tlvs (area->area_tag, stream->data + - ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, - pdulen - ISIS_FIXED_HDR_LEN - - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs); - - if (retval || !(found & TLVFLAG_AUTH_INFO)) - return 1; /* Auth fail (parsing failed or no auth-tlv) */ - - switch (tlvs.auth_info.type) - { - case ISIS_PASSWD_TYPE_HMAC_MD5: - zlog_debug("Got LSP with ISIS_PASSWD_TYPE_HMAC_MD5"); - break; - case ISIS_PASSWD_TYPE_CLEARTXT: - zlog_debug("Got LSP with ISIS_PASSWD_TYPE_CLEARTXT"); - break; - default: - zlog_debug("Unknown authentication type in LSP"); - break; - } - - return 0; - /* return authentication_check (passwd, &tlvs.auth_info);*/ + u_int8_t lsp_bits = 0; + if (level == IS_LEVEL_1) + lsp_bits = IS_LEVEL_1; + else + lsp_bits = IS_LEVEL_1_AND_2; + if (overload_bit) + lsp_bits |= overload_bit; + return lsp_bits; } static void lsp_update_data (struct isis_lsp *lsp, struct stream *stream, - struct isis_area *area) + struct isis_area *area, int level) { uint32_t expected = 0, found; int retval; + /* free the old lsp data */ + lsp_clear_data (lsp); + /* copying only the relevant part of our stream */ + if (lsp->pdu != NULL) + stream_free (lsp->pdu); lsp->pdu = stream_dup (stream); - + /* setting pointers to the correct place */ lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); + lsp->area = area; + lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; lsp->installed = time (NULL); /* @@ -396,8 +483,6 @@ lsp_update_data (struct isis_lsp *lsp, struct stream *stream, expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_IS_NEIGHS; - if ((lsp->lsp_header->lsp_bits & 3) == 3) /* a level 2 LSP */ - expected |= TLVFLAG_PARTITION_DESIG_LEVEL2_IS; expected |= TLVFLAG_NLPID; if (area->dynhostname) expected |= TLVFLAG_DYN_HOSTNAME; @@ -415,57 +500,58 @@ 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)); + isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, + (lsp->lsp_header->lsp_bits & LSPBIT_IST) == + IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1); } + return; } void -lsp_update (struct isis_lsp *lsp, struct isis_link_state_hdr *lsp_hdr, - struct stream *stream, struct isis_area *area, int level) +lsp_update (struct isis_lsp *lsp, struct stream *stream, + struct isis_area *area, int level) { dnode_t *dnode = NULL; - /* Remove old LSP from LSP database. */ + /* Remove old LSP from database. This is required since the + * lsp_update_data will free the lsp->pdu (which has the key, lsp_id) + * and will update it with the new data in the stream. */ dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id); if (dnode) dnode_destroy (dict_delete (area->lspdb[level - 1], dnode)); - /* free the old lsp data */ - XFREE (MTYPE_STREAM_DATA, lsp->pdu); - lsp_clear_data (lsp); - /* rebuild the lsp data */ - lsp_update_data (lsp, stream, area); - - /* 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) { @@ -499,12 +585,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)); @@ -512,7 +594,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 */ @@ -529,9 +611,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; @@ -541,6 +624,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 + } } /* @@ -577,12 +667,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); @@ -594,14 +685,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; @@ -611,11 +706,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) @@ -623,7 +719,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; } @@ -637,22 +738,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); } @@ -669,13 +759,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)); @@ -707,30 +795,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; @@ -751,7 +841,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) @@ -771,11 +861,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; } } @@ -784,33 +874,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); } @@ -823,7 +922,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); } @@ -837,7 +936,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); } @@ -853,11 +952,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); } @@ -867,11 +966,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 */ @@ -880,12 +977,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; } @@ -898,10 +996,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) @@ -909,7 +1003,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++; } @@ -919,7 +1013,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++; } @@ -929,7 +1023,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) \ @@ -948,16 +1042,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))); @@ -969,6 +1079,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) @@ -978,40 +1126,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, + lsp_bits_generate (level, area->overload_bit), 0, level); + lsp->area = area; lsp->own_lsp = 1; lsp_insert (lsp, area->lspdb[level - 1]); listnode_add (lsp0->lspu.frags, lsp); lsp->lspu.zero_lsp = lsp0; - /* - * Copy the authinfo from zero LSP - */ - if (lsp0->tlv_data.auth_info.type) - { - memcpy (&lsp->tlv_data.auth_info, &lsp->tlv_data.auth_info, - sizeof (struct isis_passwd)); - tlv_add_authinfo (lsp->tlv_data.auth_info.type, - lsp->tlv_data.auth_info.len, - lsp->tlv_data.auth_info.passwd, lsp->pdu); - } return lsp; } @@ -1020,7 +1149,7 @@ 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; @@ -1037,8 +1166,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 @@ -1048,6 +1196,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 @@ -1070,7 +1221,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) { @@ -1080,39 +1233,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) { @@ -1121,7 +1248,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); @@ -1131,8 +1258,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); } } @@ -1141,7 +1269,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) { @@ -1192,7 +1320,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) { @@ -1220,6 +1347,7 @@ lsp_build_nonpseudo (struct isis_lsp *lsp, struct isis_area *area) } } } + #ifdef HAVE_IPV6 /* * Add IPv6 reachability of this circuit @@ -1258,7 +1386,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) { @@ -1268,20 +1396,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 (); @@ -1289,21 +1418,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; @@ -1335,21 +1465,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"); } @@ -1367,6 +1490,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!). */ @@ -1376,7 +1500,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); @@ -1421,87 +1546,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) + * Search own LSPs, update holding time and set SRM */ -int -lsp_l1_generate (struct isis_area *area) -{ - THREAD_TIMER_ON (master, area->t_lsp_refresh[0], lsp_refresh_l1, area, - MAX_LSP_GEN_INTERVAL); - - return lsp_generate_non_pseudo (area, 1); -} - -/* - * 7.3.9 Generation of level 2 LSPs (non-pseudonode) - */ -int -lsp_l2_generate (struct isis_area *area) -{ - THREAD_TIMER_ON (master, area->t_lsp_refresh[1], lsp_refresh_l2, area, - MAX_LSP_GEN_INTERVAL); - - return lsp_generate_non_pseudo (area, 2); -} - static int -lsp_non_pseudo_regenerate (struct isis_area *area, int level) +lsp_regenerate (struct isis_area *area, int level) { dict_t *lspdb = area->lspdb[level - 1]; struct isis_lsp *lsp, *frag; struct listnode *node; u_char lspid[ISIS_SYS_ID_LEN + 2]; + u_int16_t rem_lifetime, refresh_time; + + if ((area == NULL) || (area->is_type & level) != level) + return ISIS_ERROR; memset (lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); @@ -1510,180 +1647,148 @@ 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 = lsp_bits_generate (level, area->overload_bit); + rem_lifetime = lsp_rem_lifetime (area, level); + lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_seqnum_update (lsp); - 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 = lsp_bits_generate (level, + area->overload_bit); + /* Set the lifetime values of all the fragments to the same value, + * so that no fragment expires before the lsp is refreshed. + */ + frag->lsp_header->rem_lifetime = htons (rem_lifetime); + lsp_set_all_srmflags (frag); } - 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; - area->t_lsp_l1_regenerate=thread_add_timer (master, lsp_l1_regenerate, area, - MIN_LSP_GEN_INTERVAL - diff); - goto L2; - } + if (diff < area->lsp_gen_interval[lvl - 1]) + { + area->lsp_regenerate_pending[lvl - 1] = 1; + if (lvl == IS_LEVEL_1) + THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], + lsp_l1_refresh, area, + area->lsp_gen_interval[lvl - 1] - diff); + else if (lvl == IS_LEVEL_2) + THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], + lsp_l2_refresh, area, + area->lsp_gen_interval[lvl - 1] - diff); + } else - lsp_non_pseudo_regenerate (area, 1); + { + lsp_regenerate (area, lvl); + } } - /* - * then 2 - */ -L2: - if (area->is_type & IS_LEVEL_2) + + if (all_pseudo) { - lsp = lsp_search (id, area->lspdb[1]); - if (!lsp || area->lsp_regenerate_pending[1]) - return ISIS_OK; - /* - * Throttle avoidance - */ - diff = now - lsp->last_generated; - if (diff < MIN_LSP_GEN_INTERVAL) - { - area->lsp_regenerate_pending[1] = 1; - area->t_lsp_l2_regenerate=thread_add_timer (master, lsp_l2_regenerate, area, - MIN_LSP_GEN_INTERVAL - diff); - return ISIS_OK; - } - else - lsp_non_pseudo_regenerate (area, 2); + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) + lsp_regenerate_schedule_pseudo (circuit, level); } return ISIS_OK; @@ -1706,19 +1811,10 @@ 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) - lsp->lsp_header->lsp_bits |= IS_LEVEL_1; - else - lsp->lsp_header->lsp_bits |= IS_LEVEL_2; + /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ + lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); /* * add self to IS neighbours @@ -1753,12 +1849,12 @@ 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) @@ -1776,7 +1872,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 */ @@ -1792,6 +1888,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); @@ -1800,13 +1897,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); @@ -1818,20 +1909,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; @@ -1841,151 +2001,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 = lsp_bits_generate (level, 0); + rem_lifetime = lsp_rem_lifetime (circuit->area, level); + lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_inc_seqnum (lsp, 0); + lsp->last_generated = time (NULL); + lsp_set_all_srmflags (lsp); + + refresh_time = lsp_refresh_time (lsp, rem_lifetime); + if (level == IS_LEVEL_1) + THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], + lsp_l1_refresh_pseudo, circuit, refresh_time); + else if (level == IS_LEVEL_2) + THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], + lsp_l2_refresh_pseudo, circuit, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { - zlog_debug ("ISIS-Upd (%s): refreshing pseudo LSP L%d %s", - circuit->area->area_tag, level, - rawlspid_print (lsp->lsp_header->lsp_id)); + zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, " + "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", + circuit->area->area_tag, level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->pdu_len), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + refresh_time); } - lsp->last_generated = time (NULL); - ISIS_FLAGS_SET_ALL (lsp->SRMflags); - return ISIS_OK; } -int +/* + * Something has changed or periodic refresh -> regenerate pseudo LSP + */ +static int lsp_l1_refresh_pseudo (struct thread *thread) { struct isis_circuit *circuit; - int retval; - unsigned long ref_time; + u_char id[ISIS_SYS_ID_LEN + 2]; circuit = THREAD_ARG (thread); - if (!circuit->u.bc.is_dr[0]) - return ISIS_ERROR; /* FIXME: purge and such */ - circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL; + circuit->lsp_regenerate_pending[0] = 0; - retval = lsp_pseudo_regenerate (circuit, 1); - - 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; } /* @@ -2003,6 +2166,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 (); @@ -2018,56 +2182,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)) - { - if (circuit->state != C_STATE_UP) - continue; + { + int diff = time (NULL) - circuit->lsp_queue_last_cleared; + if (circuit->lsp_queue == NULL || + diff < MIN_LSP_TRANS_INTERVAL) + continue; for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp)) - { - if (ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) - { - /* FIXME: if same or elder lsp is already in lsp - * queue */ - listnode_add (circuit->lsp_queue, lsp); - thread_add_event (master, send_lsp, circuit, 0); - } - } - } - } - list_delete_all_node (lsp_list); - } + { + if (circuit->upadjcount[lsp->level - 1] && + ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) + { + /* Add the lsp only if it is not already in lsp + * queue */ + if (! listnode_lookup (circuit->lsp_queue, lsp)) + { + listnode_add (circuit->lsp_queue, lsp); + thread_add_event (master, send_lsp, circuit, 0); + } + } + } + } + list_delete_all_node (lsp_list); + } + } } list_delete (lsp_list); @@ -2076,22 +2271,45 @@ 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; } @@ -2109,27 +2327,36 @@ 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->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? 1 : 2; - lsp->pdu = stream_new (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); + lsp->area = area; + lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? + IS_LEVEL_1 : IS_LEVEL_2; + /* FIXME: Should be minimal mtu? */ + lsp->pdu = stream_new (1500); lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu); - fill_fixed_hdr (lsp->isis_header, (lsp->level == 1) ? L1_LINK_STATE + fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); + stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* - * Retain only LSP header - */ - lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); - /* * Set the remaining lifetime to 0 */ lsp->lsp_header->rem_lifetime = 0; + + /* + * Add and update the authentication info if its present + */ + lsp_auth_add (lsp); + lsp_auth_update (lsp); + + /* + * Update the PDU length to header plus any authentication TLV. + */ + lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); + /* * Put the lsp into LSPdb */ @@ -2138,17 +2365,36 @@ 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); @@ -2157,7 +2403,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", @@ -2167,14 +2413,14 @@ 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_bits_generate (level, + lsp->area->overload_bit); + rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); + lsp->lsp_header->rem_lifetime = htons (rem_lifetime); + refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, - isis_jitter (ref_time, MAX_LSP_GEN_JITTER)); + lsp->area->lsp_refresh[0]); return ISIS_OK; } @@ -2187,16 +2433,16 @@ 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++) { @@ -2206,12 +2452,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); @@ -2220,12 +2467,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]); } } @@ -2342,8 +2587,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 (); @@ -2354,8 +2597,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 8d648d05..6e7f745d 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,7 +52,6 @@ struct isis_lsp #endif /* used for 60 second counting when rem_lifetime is zero */ int age_out; - /* FIXME: For now only topology LSP's use this. Is it helpful for others? */ struct isis_area *area; struct tlvs tlv_data; /* Simplifies TLV access */ }; @@ -67,37 +60,32 @@ 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); @@ -114,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 15d85d6d..7bb84d8f 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -34,7 +34,6 @@ #include "privs.h" #include "sigevent.h" #include "filter.h" -#include "zclient.h" #include "isisd/dict.h" #include "include-netbsd/iso.h" @@ -44,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" @@ -67,23 +69,22 @@ 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 }; /* isisd options */ struct option longopts[] = { - {"daemon", no_argument, NULL, 'd'}, + {"daemon", no_argument, NULL, 'd'}, {"config_file", required_argument, NULL, 'f'}, - {"pid_file", required_argument, NULL, 'i'}, - {"socket", required_argument, NULL, 'z'}, - {"vty_addr", required_argument, NULL, 'A'}, - {"vty_port", required_argument, NULL, 'P'}, - {"user", required_argument, NULL, 'u'}, - {"group", required_argument, NULL, 'g'}, - {"version", no_argument, NULL, 'v'}, - {"dryrun", no_argument, NULL, 'C'}, - {"help", no_argument, NULL, 'h'}, + {"pid_file", required_argument, NULL, 'i'}, + {"vty_addr", required_argument, NULL, 'A'}, + {"vty_port", required_argument, NULL, 'P'}, + {"user", required_argument, NULL, 'u'}, + {"group", required_argument, NULL, 'g'}, + {"version", no_argument, NULL, 'v'}, + {"dryrun", no_argument, NULL, 'C'}, + {"help", no_argument, NULL, 'h'}, {0} }; @@ -132,7 +133,6 @@ Daemon which manages IS-IS routing\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ --z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ @@ -154,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 @@ -249,7 +252,7 @@ main (int argc, char **argv, char **envp) /* Command line argument treatment. */ while (1) { - opt = getopt_long (argc, argv, "df:i:z:hA:p:P:u:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "df:i:hA:p:P:u:g:vC", longopts, 0); if (opt == EOF) break; @@ -267,9 +270,6 @@ main (int argc, char **argv, char **envp) case 'i': pid_file = optarg; break; - case 'z': - zclient_serv_path_set (optarg); - break; case 'A': vty_addr = optarg; break; @@ -325,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 6b565bcb..968fa05f 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 d5003a8e..0cd65a66 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 d67df31b..497fad20 100644 --- a/isisd/isis_pdu.c +++ b/isisd/isis_pdu.c @@ -39,12 +39,12 @@ #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" +#include "isisd/isis_flags.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_dr.h" -#include "isisd/isis_flags.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" @@ -54,9 +54,6 @@ #include "isisd/isis_csm.h" #include "isisd/isis_events.h" -extern struct thread_master *master; -extern struct isis *isis; - #define ISIS_MINIMUM_FIXED_HDR_LEN 15 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ @@ -65,7 +62,7 @@ extern struct isis *isis; #endif /* PNBBY */ /* Utility mask array. */ -static const u_char maskbit[] = { +static u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; @@ -169,44 +166,152 @@ accept_level (int level, int circuit_t) return retval; } - /* * Verify authentication information * Support cleartext and HMAC MD5 authentication */ -int -authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit* c) +static int +authentication_check (struct isis_passwd *remote, struct isis_passwd *local, + struct stream *stream, uint32_t auth_tlv_offset) { unsigned char digest[ISIS_AUTH_MD5_SIZE]; - if (c->passwd.type) - { - switch (c->passwd.type) - { - case ISIS_PASSWD_TYPE_HMAC_MD5: - /* HMAC MD5 (RFC 3567) */ - /* MD5 computation according to RFC 2104 */ - hmac_md5(c->rcv_stream->data, stream_get_endp(c->rcv_stream), (unsigned char *) &(local->passwd), c->passwd.len, (unsigned char *) &digest); - return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE); - break; - case ISIS_PASSWD_TYPE_CLEARTXT: - /* Cleartext (ISO 10589) */ - if (local->len != remote->len) - return 1; /* Auth fail () - passwd len mismatch */ - return memcmp (local->passwd, remote->passwd, local->len); + /* 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_warn ("Unsupported authentication type"); - break; + zlog_err ("Unsupported authentication type"); + return ISIS_ERROR; + } + + /* Authentication pass when no authentication is configured */ + return ISIS_OK; +} + +static int +lsp_authentication_check (struct stream *stream, struct isis_area *area, + int level, struct isis_passwd *passwd) +{ + struct isis_link_state_hdr *hdr; + uint32_t expected = 0, found = 0, auth_tlv_offset = 0; + uint16_t checksum, rem_lifetime, pdu_len; + struct tlvs tlvs; + int retval = ISIS_OK; + + hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream)); + pdu_len = ntohs (hdr->pdu_len); + expected |= TLVFLAG_AUTH_INFO; + auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN; + retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN, + pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); + + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, " + "cksum 0x%04x, lifetime %us, len %u", + area->area_tag, level, rawlspid_print (hdr->lsp_id), + ntohl (hdr->seq_num), ntohs (hdr->checksum), + ntohs (hdr->rem_lifetime), pdu_len); + if ((isis->debugs & DEBUG_UPDATE_PACKETS) && + (isis->debugs & DEBUG_PACKET_DUMP)) + zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream)); + return retval; + } + + if (!(found & TLVFLAG_AUTH_INFO)) + { + zlog_err ("No authentication tlv in LSP"); + return ISIS_ERROR; } + + if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT && + tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) + { + zlog_err ("Unknown authentication type in LSP"); + return ISIS_ERROR; } - return 0; /* Authentication pass when no authentication is configured */ + + /* + * RFC 5304 set checksum and remaining lifetime to zero before + * verification and reset to old values after verification. + */ + checksum = hdr->checksum; + rem_lifetime = hdr->rem_lifetime; + hdr->checksum = 0; + hdr->rem_lifetime = 0; + retval = authentication_check (&tlvs.auth_info, passwd, stream, + auth_tlv_offset); + hdr->checksum = checksum; + hdr->rem_lifetime = rem_lifetime; + + return retval; } /* * Processing helper functions */ static void +del_addr (void *val) +{ + XFREE (MTYPE_ISIS_TMP, val); +} + +static void +tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) +{ + struct listnode *node; + struct area_addr *area_addr, *malloced; + + if (adj->area_addrs) + { + adj->area_addrs->del = del_addr; + list_delete (adj->area_addrs); + } + adj->area_addrs = list_new (); + if (tlvs->area_addrs) + { + for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr)) + { + malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr)); + memcpy (malloced, area_addr, sizeof (struct area_addr)); + listnode_add (adj->area_addrs, malloced); + } + } +} + +static void tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) { int i; @@ -227,12 +332,6 @@ 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; @@ -240,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 (); @@ -264,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 (); @@ -297,9 +396,26 @@ 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; + uint16_t pdu_len; struct tlvs tlvs; + if (isis->debugs & DEBUG_ADJ_PACKETS) + { + zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", + circuit->area->area_tag, circuit->interface->name, + circuit_t2string (circuit->is_type), circuit->circuit_id); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->rcv_stream), + stream_get_endp (circuit->rcv_stream)); + } + + if (circuit->circ_type != CIRCUIT_T_P2P) + { + zlog_warn ("p2p hello on non p2p circuit"); + return ISIS_WARNING; + } + if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN) { @@ -324,42 +440,25 @@ 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; - - /* hdr.circuit_t = stream_getc (stream); - stream_get (hdr.source_id, stream, ISIS_SYS_ID_LEN); - hdr.hold_time = stream_getw (stream); - hdr.pdu_len = stream_getw (stream); - hdr.local_id = stream_getc (stream); */ + pdu_len = ntohs (hdr->pdu_len); - /* - * My interpertation of the ISO, if no adj exists we will create one for - * the circuit - */ - - if (isis->debugs & DEBUG_ADJ_PACKETS) + if (pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) { - 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)); + zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " + "invalid pdu length %d", + circuit->area->area_tag, circuit->interface->name, pdu_len); + return ISIS_WARNING; } - adj = circuit->u.p2p.neighbor; - if (!adj) - { - adj = isis_new_adj (hdr->source_id, NULL, 0, circuit); - if (adj == NULL) - return ISIS_ERROR; - circuit->u.p2p.neighbor = adj; - isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); - adj->sys_type = ISIS_SYSTYPE_UNKNOWN; - } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, pdu_len); - /* 8.2.6 Monitoring point-to-point adjacencies */ - adj->hold_time = ntohs (hdr->hold_time); - adj->last_upd = time (NULL); + stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); /* * Lets get the TLVS now @@ -370,37 +469,93 @@ 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); + pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, + &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { + zlog_warn ("parse_tlvs() failed"); free_tlvs (&tlvs); return retval; }; + if (!(found & TLVFLAG_AREA_ADDRS)) + { + zlog_warn ("No Area addresses TLV in P2P IS to IS hello"); + free_tlvs (&tlvs); + return ISIS_WARNING; + } + /* 8.2.5.1 c) Authentication */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&tlvs.auth_info, &circuit->passwd, circuit)) - { - isis_event_auth_failure (circuit->area->area_tag, - "P2P hello authentication failure", - hdr->source_id); - return ISIS_OK; - } + authentication_check (&tlvs.auth_info, &circuit->passwd, + circuit->rcv_stream, auth_tlv_offset)) + { + isis_event_auth_failure (circuit->area->area_tag, + "P2P hello authentication failure", + hdr->source_id); + free_tlvs (&tlvs); + return ISIS_OK; + } + } + + /* + * check if it's own interface ip match iih ip addrs + */ + if ((found & TLVFLAG_IPV4_ADDR) == 0 || + ip_match (circuit->ip_addrs, tlvs.ipv4_addrs) == 0) + { + zlog_warn ("ISIS-Adj: No usable IP interface addresses " + "in LAN IIH from %s\n", circuit->interface->name); + free_tlvs (&tlvs); + return ISIS_WARNING; + } + + /* + * My interpertation of the ISO, if no adj exists we will create one for + * the circuit + */ + adj = circuit->u.p2p.neighbor; + if (!adj || adj->level != hdr->circuit_t) + { + if (!adj) + { + adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit); + if (adj == NULL) + return ISIS_ERROR; + } + else + { + adj->level = hdr->circuit_t; + } + circuit->u.p2p.neighbor = adj; + isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); + adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } + /* 8.2.6 Monitoring point-to-point adjacencies */ + adj->hold_time = ntohs (hdr->hold_time); + adj->last_upd = time (NULL); + /* we do this now because the adj may not survive till the end... */ + tlvs_to_adj_area_addrs (&tlvs, adj); + + /* which protocol are spoken ??? */ + if (found & TLVFLAG_NLPID) + tlvs_to_adj_nlpids (&tlvs, adj); /* we need to copy addresses to the adj */ - tlvs_to_adj_ipv4_addrs (&tlvs, adj); + if (found & TLVFLAG_IPV4_ADDR) + tlvs_to_adj_ipv4_addrs (&tlvs, adj); #ifdef HAVE_IPV6 - tlvs_to_adj_ipv6_addrs (&tlvs, adj); + if (found & TLVFLAG_IPV6_ADDR) + tlvs_to_adj_ipv6_addrs (&tlvs, adj); #endif /* HAVE_IPV6 */ /* lets take care of the expiry */ @@ -435,6 +590,7 @@ 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) @@ -521,6 +677,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) || @@ -553,7 +710,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) { @@ -579,6 +736,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) @@ -631,6 +789,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 */ @@ -654,7 +817,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, pdu_len); + } free_tlvs (&tlvs); @@ -670,11 +841,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) { @@ -689,7 +877,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) { @@ -721,13 +909,33 @@ 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) || + hdr.pdu_len > stream_get_endp (circuit->rcv_stream)) + { + zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " + "invalid pdu length %d", + circuit->area->area_tag, circuit->interface->name, + hdr.pdu_len); + return ISIS_WARNING; + } + + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, hdr.pdu_len); + + if (hdr.circuit_t != IS_LEVEL_1 && + hdr.circuit_t != IS_LEVEL_2 && + hdr.circuit_t != IS_LEVEL_1_AND_2 && + (level & hdr.circuit_t) == 0) { - zlog_warn ("Level %d LAN Hello with Circuit Type %d", level, - hdr.circuit_t); + zlog_err ("Level %d LAN Hello with Circuit Type %d", level, + hdr.circuit_t); return ISIS_ERROR; } + /* * Then get the tlvs */ @@ -738,10 +946,12 @@ 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) { @@ -761,21 +971,24 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || - authentication_check (&tlvs.auth_info, &circuit->passwd, circuit)) - { - isis_event_auth_failure (circuit->area->area_tag, - "LAN hello authentication failure", - hdr.source_id); - retval = ISIS_WARNING; - goto out; - } + authentication_check (&tlvs.auth_info, &circuit->passwd, + circuit->rcv_stream, auth_tlv_offset)) + { + isis_event_auth_failure (circuit->area->area_tag, + "LAN hello authentication failure", + hdr.source_id); + retval = ISIS_WARNING; + goto out; + } } /* * Accept the level 1 adjacency only if a match between local and * remote area addresses is found */ - if (level == 1 && !area_match (circuit->area->area_addrs, tlvs.area_addrs)) + if (listcount (circuit->area->area_addrs) == 0 || + (level == IS_LEVEL_1 && + area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { @@ -802,43 +1015,49 @@ 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) @@ -847,7 +1066,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); } @@ -855,7 +1074,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); } @@ -868,6 +1087,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); @@ -886,7 +1107,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 @@ -894,31 +1115,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); @@ -940,8 +1178,18 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) int retval = ISIS_OK, comp = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_passwd *passwd; + uint16_t pdu_len; + + 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)); + } - /* Sanity check - FIXME: move to correct place */ if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN) { @@ -951,28 +1199,56 @@ process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) /* Reference the header */ hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream); + pdu_len = ntohs (hdr->pdu_len); + + /* lsp length check */ + if (pdu_len < ISIS_LSP_HDR_LEN || + pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) + { + zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", + circuit->area->area_tag, + rawlspid_print (hdr->lsp_id), pdu_len); + + return ISIS_WARNING; + } + + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, pdu_len); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " - "lifetime %us, len %lu, on %s", + "lifetime %us, len %u, on %s", circuit->area->area_tag, level, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), - /* FIXME: use %z when we stop supporting old compilers. */ - (unsigned long) stream_get_endp (circuit->rcv_stream), + pdu_len, circuit->interface->name); } - assert (ntohs (hdr->pdu_len) > ISIS_LSP_HDR_LEN); + /* lsp is_type check */ + if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 && + (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) + { + zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x", + circuit->area->area_tag, + rawlspid_print (hdr->lsp_id), hdr->lsp_bits); + /* continue as per RFC1122 Be liberal in what you accept, and + * conservative in what you send */ + } /* Checksum sanity check - FIXME: move to correct place */ /* 12 = sysid+pdu+remtime */ if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4, - ntohs (hdr->pdu_len) - 12, &hdr->checksum)) + pdu_len - 12, &hdr->checksum)) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", circuit->area->area_tag, @@ -993,13 +1269,13 @@ 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; } @@ -1009,12 +1285,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); @@ -1035,7 +1311,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) { @@ -1052,7 +1327,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 { @@ -1063,13 +1337,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 */ @@ -1096,10 +1372,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 */ @@ -1123,38 +1398,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; } @@ -1174,25 +1436,19 @@ dontcheckadj: * has information that the current sequence number for source S is * "greater" than that held by S, ... */ - else if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) + if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) { /* 7.3.16.1 */ - lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1); - - fletcher_checksum (STREAM_DATA (lsp->pdu) + 12, - ntohs (lsp->lsp_header->pdu_len) - 12, 12); - - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq " "0x%08x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (lsp->lsp_header->seq_num)); - lsp->lsp_header->rem_lifetime = - htons (isis_jitter - (circuit->area->max_lsp_lifetime[level - 1], - MAX_AGE_JITTER)); } + /* If the received LSP is older or equal, + * resend the LSP which will act as ACK */ + lsp_set_all_srmflags (lsp); } else { @@ -1201,22 +1457,6 @@ dontcheckadj: /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */ if ((!lsp || comp == LSP_NEWER)) { - int regenerate = (lsp == NULL); - /* i */ - if (lsp) - { -#ifdef EXTREME_DEBUG - zlog_debug ("level %d number is - %ld", level, - circuit->area->lspdb[level - 1]->dict_nodecount); -#endif /* EXTREME DEBUG */ - lsp_search_and_destroy (hdr->lsp_id, - circuit->area->lspdb[level - 1]); - /* exists, so we overwrite */ -#ifdef EXTREME_DEBUG - zlog_debug ("level %d number is - %ld", level, - circuit->area->lspdb[level - 1]->dict_nodecount); -#endif /* EXTREME DEBUG */ - } /* * If this lsp is a frag, need to see if we have zero lsp present */ @@ -1227,18 +1467,24 @@ 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_insert (lsp, circuit->area->lspdb[level - 1]); + /* i */ + if (!lsp) + { + lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, + pdu_len, lsp0, + circuit->area, level); + lsp_insert (lsp, circuit->area->lspdb[level - 1]); + } + else /* exists, so we overwrite */ + { + lsp_update (lsp, circuit->rcv_stream, circuit->area, level); + } /* ii */ - ISIS_FLAGS_SET_ALL (lsp->SRMflags); + lsp_set_all_srmflags (lsp); /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); @@ -1246,19 +1492,14 @@ dontcheckadj: if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); /* FIXME: v) */ - if (regenerate && circuit->u.bc.is_dr[level - 1]) { - lsp_l1_pseudo_generate (circuit); - } } /* 7.3.15.1 e) 2) LSP equal to the one in db */ else if (comp == LSP_EQUAL) { ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); - lsp_update (lsp, hdr, circuit->rcv_stream, circuit->area, level); + lsp_update (lsp, circuit->rcv_stream, circuit->area, level); if (circuit->circ_type != CIRCUIT_T_BROADCAST) - { - ISIS_SET_FLAG (lsp->SSNflags, circuit); - } + ISIS_SET_FLAG (lsp->SSNflags, circuit); } /* 7.3.15.1 e) 3) LSP older than the one in db */ else @@ -1267,7 +1508,6 @@ dontcheckadj: ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } - return retval; } @@ -1284,11 +1524,11 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, int retval = ISIS_OK; int cmp, own_lsp; char typechar = ' '; - int len; + uint16_t pdu_len; struct isis_adjacency *adj; struct isis_complete_seqnum_hdr *chdr = NULL; struct isis_partial_seqnum_hdr *phdr = NULL; - uint32_t found = 0, expected = 0; + uint32_t found = 0, expected = 0, auth_tlv_offset = 0; struct isis_lsp *lsp; struct lsp_entry *entry; struct listnode *node, *nnode; @@ -1303,12 +1543,14 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, typechar = 'C'; chdr = (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - circuit->rcv_stream->getp += ISIS_CSNP_HDRLEN; - len = ntohs (chdr->pdu_len); - if (len < ISIS_CSNP_HDRLEN) + stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN); + pdu_len = ntohs (chdr->pdu_len); + if (pdu_len < ISIS_CSNP_HDRLEN || + pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) { - zlog_warn ("Received a CSNP with bogus length!"); - return ISIS_OK; + zlog_warn ("Received a CSNP with bogus length %d", pdu_len); + return ISIS_WARNING; } } else @@ -1316,15 +1558,24 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit, typechar = 'P'; phdr = (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); - circuit->rcv_stream->getp += ISIS_PSNP_HDRLEN; - len = ntohs (phdr->pdu_len); - if (len < ISIS_PSNP_HDRLEN) + stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN); + pdu_len = ntohs (phdr->pdu_len); + if (pdu_len < ISIS_PSNP_HDRLEN || + pdu_len > ISO_MTU(circuit) || + pdu_len > stream_get_endp (circuit->rcv_stream)) { - zlog_warn ("Received a CSNP with bogus length!"); - return ISIS_OK; + zlog_warn ("Received a CSNP with bogus length %d", pdu_len); + return ISIS_WARNING; } } + /* + * Set the stream endp to PDU length, ignoring additional padding + * introduced by transport chips. + */ + if (pdu_len < stream_get_endp (circuit->rcv_stream)) + stream_set_endp (circuit->rcv_stream, pdu_len); + /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ if (circuit->ext_domain) { @@ -1338,7 +1589,7 @@ 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, " @@ -1347,26 +1598,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 */ @@ -1396,7 +1644,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 */ @@ -1408,10 +1659,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); + pdu_len - stream_get_getp (circuit->rcv_stream), + &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { @@ -1420,7 +1673,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; @@ -1428,16 +1681,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 (&tlvs.auth_info, passwd, circuit)) - { - isis_event_auth_failure (circuit->area->area_tag, - "SNP authentication" " failure", - phdr ? phdr->source_id : chdr->source_id); - return ISIS_OK; - } - } + { + if (!(found & TLVFLAG_AUTH_INFO) || + authentication_check (&tlvs.auth_info, passwd, + circuit->rcv_stream, auth_tlv_offset)) + { + isis_event_auth_failure (circuit->area->area_tag, + "SNP authentication" " failure", + phdr ? phdr->source_id : + chdr->source_id); + free_tlvs (&tlvs); + return ISIS_OK; + } + } } /* debug isis snp-packets */ @@ -1477,19 +1733,18 @@ 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)); @@ -1498,8 +1753,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); } } } @@ -1512,7 +1767,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); } } @@ -1523,7 +1780,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, @@ -1546,11 +1804,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); @@ -1560,6 +1817,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) @@ -1574,10 +1841,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; } @@ -1601,6 +1878,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... */ @@ -1665,7 +1952,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; @@ -1676,7 +1962,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; } @@ -1685,28 +1971,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 */ @@ -1737,6 +2006,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)) @@ -1797,9 +2074,6 @@ isis_receive (struct thread *thread) circuit = THREAD_ARG (thread); assert (circuit); - if (!circuit->area) - return ISIS_OK; - if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); else @@ -1814,8 +2088,11 @@ 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; } @@ -1849,10 +2126,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; } @@ -1927,14 +2207,13 @@ 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; - char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; - + unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; + unsigned long len_pointer, length, auth_tlv_offset = 0; u_int32_t interval; - unsigned long len_pointer, length, auth_tlv; int retval; - if (circuit->state != C_STATE_UP || circuit->interface == NULL) - return ISIS_WARNING; + if (circuit->is_passive) + return ISIS_OK; if (circuit->interface->mtu == 0) { @@ -1948,7 +2227,7 @@ 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 @@ -1963,12 +2242,9 @@ send_hello (struct isis_circuit *circuit, int level) memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr)); interval = circuit->hello_multiplier[level - 1] * circuit->hello_interval[level - 1]; - /* If we are the DIS then hello interval is divided by three, as is the hold-timer */ - if (circuit->u.bc.is_dr[level - 1]) - interval=interval/3; if (interval > USHRT_MAX) interval = USHRT_MAX; - hello_hdr.circuit_t = circuit->circuit_is_type; + hello_hdr.circuit_t = circuit->is_type; memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); hello_hdr.hold_time = htons ((u_int16_t) interval); @@ -1985,13 +2261,13 @@ 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); @@ -2000,68 +2276,73 @@ send_hello (struct isis_circuit *circuit, int level) } /* - * Then the variable length part + * Then the variable length part. */ /* add circuit password */ - /* Cleartext */ - if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) - if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, circuit->passwd.len, - circuit->passwd.passwd, circuit->snd_stream)) - return ISIS_WARNING; + switch (circuit->passwd.type) + { + /* Cleartext */ + case ISIS_PASSWD_TYPE_CLEARTXT: + if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, + circuit->passwd.passwd, circuit->snd_stream)) + return ISIS_WARNING; + break; - /* or HMAC MD5 */ - if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) - { + /* HMAC MD5 */ + case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later overwrite the MD5 hash */ - auth_tlv = stream_get_endp (circuit->snd_stream); + auth_tlv_offset = stream_get_endp (circuit->snd_stream); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); - if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, - hmac_md5_hash, circuit->snd_stream)) - return ISIS_WARNING; + if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE, + hmac_md5_hash, circuit->snd_stream)) + return ISIS_WARNING; + break; + + default: + break; + } + + /* Area Addresses TLV */ + if (listcount (circuit->area->area_addrs) == 0) + return ISIS_WARNING; + if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) + return ISIS_WARNING; + + /* LAN Neighbors TLV */ + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] && + listcount (circuit->u.bc.lan_neighs[0]) > 0) + if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], + circuit->snd_stream)) + return ISIS_WARNING; + if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] && + listcount (circuit->u.bc.lan_neighs[1]) > 0) + if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], + circuit->snd_stream)) + return ISIS_WARNING; } /* Protocols Supported TLV */ if (circuit->nlpids.count > 0) if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream)) return ISIS_WARNING; - - /* Area Addresses TLV */ - assert (circuit->area); - if (circuit->area->area_addrs && circuit->area->area_addrs->count > 0) - if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) - return ISIS_WARNING; - /* IP interface Address TLV */ - if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) + if (circuit->ip_router && circuit->ip_addrs && + listcount (circuit->ip_addrs) > 0) if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) return ISIS_WARNING; #ifdef HAVE_IPV6 /* IPv6 Interface Address TLV */ if (circuit->ipv6_router && circuit->ipv6_link && - circuit->ipv6_link->count > 0) + listcount (circuit->ipv6_link) > 0) if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream)) return ISIS_WARNING; #endif /* HAVE_IPV6 */ - /* Restart signaling, vendor C sends it too */ - retval = add_tlv (211, 3, 0, circuit->snd_stream); - - /* LAN Neighbors TLV */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - { - if (level == 1 && circuit->u.bc.lan_neighs[0]->count > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], - circuit->snd_stream)) - return ISIS_WARNING; - if (level == 2 && circuit->u.bc.lan_neighs[1]->count > 0) - if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], - circuit->snd_stream)) - return ISIS_WARNING; - } - - if (circuit->u.bc.pad_hellos) + if (circuit->pad_hellos) if (tlv_add_padding (circuit->snd_stream)) return ISIS_WARNING; @@ -2072,16 +2353,15 @@ send_hello (struct isis_circuit *circuit, int 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(circuit->snd_stream->data, stream_get_endp(circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash); + hmac_md5 (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream), + (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, + (caddr_t) &hmac_md5_hash); /* Copy the hash into the stream */ - memcpy(circuit->snd_stream->data+auth_tlv+3,hmac_md5_hash,ISIS_AUTH_MD5_SIZE); + memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, + hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } - retval = circuit->tx (circuit, level); - if (retval) - zlog_warn ("sending of LAN Level %d Hello failed", level); - - /* DEBUG_ADJ_PACKETS */ if (isis->debugs & DEBUG_ADJ_PACKETS) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) @@ -2089,24 +2369,26 @@ 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 @@ -2114,32 +2396,20 @@ send_lan_l1_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; - unsigned long next_hello; circuit = THREAD_ARG (thread); assert (circuit); - - if (!circuit->area) { - return ISIS_OK; - } - - /* Pseudonode sends hellos three times more than the other nodes */ - if (circuit->u.bc.is_dr[0]) - next_hello=circuit->hello_interval[0]/3+1; - else - next_hello=circuit->hello_interval[0]; - circuit->u.bc.t_send_lan_hello[0] = NULL; if (circuit->u.bc.run_dr_elect[0]) retval = isis_dr_elect (circuit, 1); - retval = send_lan_hello (circuit, 1); + retval = send_hello (circuit, 1); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, - isis_jitter (next_hello, IIH_JITTER)); + isis_jitter (circuit->hello_interval[0], IIH_JITTER)); return retval; } @@ -2149,32 +2419,20 @@ send_lan_l2_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; - unsigned long next_hello; circuit = THREAD_ARG (thread); assert (circuit); - - if (!circuit->area) { - return ISIS_OK; - } - - /* Pseudonode sends hellos three times more than the other nodes */ - if (circuit->u.bc.is_dr[1]) - next_hello=circuit->hello_interval[1]/3+1; - else - next_hello=circuit->hello_interval[1]; - circuit->u.bc.t_send_lan_hello[1] = NULL; if (circuit->u.bc.run_dr_elect[1]) retval = isis_dr_elect (circuit, 2); - retval = send_lan_hello (circuit, 2); + retval = send_hello (circuit, 2); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], send_lan_l2_hello, circuit, - isis_jitter (next_hello, IIH_JITTER)); + isis_jitter (circuit->hello_interval[1], IIH_JITTER)); return retval; } @@ -2204,11 +2462,18 @@ 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 (level == 1) + if (circuit->snd_stream == NULL) + circuit->snd_stream = stream_new (ISO_MTU (circuit)); + else + stream_reset (circuit->snd_stream); + + if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM, circuit->snd_stream); else @@ -2232,84 +2497,244 @@ 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); + return lsp_count; +} + +/* * FIXME: support multiple CSNPs */ int send_csnp (struct isis_circuit *circuit, int level) { - int retval = ISIS_OK; u_char start[ISIS_SYS_ID_LEN + 2]; u_char stop[ISIS_SYS_ID_LEN + 2]; struct list *list = NULL; struct listnode *node; struct isis_lsp *lsp; + u_char num_lsps, loop = 1; + int i, retval = ISIS_OK; - if (circuit->state != C_STATE_UP || circuit->interface == NULL) - return ISIS_WARNING; + if (circuit->area->lspdb[level - 1] == NULL || + dict_count (circuit->area->lspdb[level - 1]) == 0) + return retval; memset (start, 0x00, ISIS_SYS_ID_LEN + 2); memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); - if (circuit->area->lspdb[level - 1] && - dict_count (circuit->area->lspdb[level - 1]) > 0) + num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit); + + while (loop) { list = list_new (); - lsp_build_list (start, stop, list, circuit->area->lspdb[level - 1]); - - if (circuit->snd_stream == NULL) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); + lsp_build_list (start, stop, num_lsps, list, + circuit->area->lspdb[level - 1]); + /* + * Update the stop lsp_id before encoding this CSNP. + */ + if (listcount (list) < num_lsps) + { + memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); + } else - stream_reset (circuit->snd_stream); + { + node = listtail (list); + lsp = listgetdata (node); + memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); + } retval = build_csnp (level, start, stop, list, circuit); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed", + circuit->area->area_tag, level, circuit->interface->name); + list_delete (list); + return retval; + } if (isis->debugs & DEBUG_SNP_PACKETS) - { - zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld", - circuit->area->area_tag, level, circuit->interface->name, - /* FIXME: use %z when we stop supporting old compilers. */ - (unsigned long) STREAM_SIZE (circuit->snd_stream)); - for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) - { - zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," - " cksum 0x%04x, lifetime %us", - circuit->area->area_tag, - rawlspid_print (lsp->lsp_header->lsp_id), - ntohl (lsp->lsp_header->seq_num), - ntohs (lsp->lsp_header->checksum), - ntohs (lsp->lsp_header->rem_lifetime)); - } - } + { + zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld", + circuit->area->area_tag, level, circuit->interface->name, + stream_get_endp (circuit->snd_stream)); + for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) + { + zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," + " cksum 0x%04x, lifetime %us", + circuit->area->area_tag, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime)); + } + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream)); + } + + retval = circuit->tx (circuit, level); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed", + circuit->area->area_tag, level, + circuit->interface->name); + list_delete (list); + return retval; + } + /* + * Start lsp_id of the next CSNP should be one plus the + * stop lsp_id in this current CSNP. + */ + memcpy (start, stop, ISIS_SYS_ID_LEN + 2); + loop = 0; + for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) + { + if (start[i] < (u_char)0xff) + { + start[i] += 1; + loop = 1; + break; + } + } + memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); list_delete (list); - - if (retval == ISIS_OK) - retval = circuit->tx (circuit, level); } + return retval; } @@ -2325,7 +2750,9 @@ send_l1_csnp (struct thread *thread) circuit->t_send_csnp[0] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) + { send_csnp (circuit, 1); + } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, isis_jitter (circuit->csnp_interval[0], CSNP_JITTER)); @@ -2345,7 +2772,9 @@ send_l2_csnp (struct thread *thread) circuit->t_send_csnp[1] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) + { send_csnp (circuit, 2); + } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, isis_jitter (circuit->csnp_interval[1], CSNP_JITTER)); @@ -2359,12 +2788,19 @@ 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 (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_PARTIAL_SEQ_NUM, circuit->snd_stream); else @@ -2383,20 +2819,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) { @@ -2413,10 +2869,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; } @@ -2427,57 +2895,74 @@ 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->state != C_STATE_UP || circuit->interface == NULL) - return ISIS_WARNING; - - 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 (circuit->area->lspdb[level - 1] == NULL || + dict_count (circuit->area->lspdb[level - 1]) == 0) + return ISIS_OK; - if (listcount (list) > 0) - { - if (circuit->snd_stream == NULL) - circuit->snd_stream = stream_new (ISO_MTU (circuit)); - else - stream_reset (circuit->snd_stream); + if (! circuit->snd_stream) + return ISIS_ERROR; + 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; @@ -2536,90 +3021,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 || circuit->interface == NULL) - return ISIS_WARNING; + if (circuit->state != C_STATE_UP || circuit->is_passive == 1) + { + return retval; + } lsp = listgetdata ((node = listhead (circuit->lsp_queue))); /* * Do not send if levels do not match */ - if (!(lsp->level & circuit->circuit_is_type)) - goto dontsend; + if (!(lsp->level & circuit->is_type)) + { + list_delete_node (circuit->lsp_queue, node); + return retval; + } /* * Do not send if we do not have adjacencies in state up on the circuit */ if (circuit->upadjcount[lsp->level - 1] == 0) - goto dontsend; - /* only send if it needs sending */ - if ((time (NULL) - lsp->last_sent) >= - circuit->area->lsp_gen_interval[lsp->level - 1]) { + 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); + /* copy our lsp to the send buffer */ + stream_copy (circuit->snd_stream, lsp->pdu); - retval = circuit->tx (circuit, lsp->level); + if (isis->debugs & DEBUG_UPDATE_PACKETS) + { + zlog_debug + ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," + " lifetime %us on %s", circuit->area->area_tag, lsp->level, + rawlspid_print (lsp->lsp_header->lsp_id), + ntohl (lsp->lsp_header->seq_num), + ntohs (lsp->lsp_header->checksum), + ntohs (lsp->lsp_header->rem_lifetime), + circuit->interface->name); + if (isis->debugs & DEBUG_PACKET_DUMP) + zlog_dump_data (STREAM_DATA (circuit->snd_stream), + stream_get_endp (circuit->snd_stream)); + } + + retval = circuit->tx (circuit, lsp->level); + if (retval != ISIS_OK) + { + zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed", + circuit->area->area_tag, lsp->level, + circuit->interface->name); + return retval; + } - /* - * If the sending succeeded, we can del the lsp from circuits - * lsp_queue - */ - if (retval == ISIS_OK) - { - list_delete_node (circuit->lsp_queue, node); + /* + * If the sending succeeded, we can del the lsp from circuits + * lsp_queue + */ + list_delete_node (circuit->lsp_queue, node); - /* - * On broadcast circuits also the SRMflag can be cleared - */ - if (circuit->circ_type == CIRCUIT_T_BROADCAST) - ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); + /* 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); - 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) + * On broadcast circuits also the SRMflag can be cleared */ - if (listcount (circuit->lsp_queue) > 0) - thread_add_timer (master, send_lsp, circuit, 1); -#endif + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); return retval; } @@ -2638,8 +3113,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 @@ -2664,7 +3139,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 c4c38e22..3eca7319 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 @@ -114,7 +114,7 @@ struct isis_fixed_hdr * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Holding Time | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ - * | PDU Lenght | 2 + * | PDU Length | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | R | Priority | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -142,7 +142,7 @@ struct isis_lan_hello_hdr * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Holding Time + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + PDU Lenght + 2 + * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Local Circuit ID | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -186,12 +186,23 @@ 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 /* * L1 and L2 IS to IS complete sequence numbers PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ - * + PDU Lenght + 2 + * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len + 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ @@ -241,6 +252,8 @@ 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,7 +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); -#define ISIS_AUTH_MD5_SIZE 16U -int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit *c); - #endif /* _ZEBRA_ISIS_PDU_H */ diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 8a5c3ed0..42947b22 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; @@ -232,19 +231,16 @@ isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) LLC_LEN, MSG_PEEK, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); - if (!circuit->area) { - return ISIS_OK; - } - if (bytesread < 0) { - zlog_warn ("isis_recv_packet_bcast(): fd %d, recvfrom (): %s", - circuit->fd, safe_strerror (errno)); - zlog_warn ("circuit is %s", circuit->interface->name); - zlog_warn ("circuit fd %d", circuit->fd); - zlog_warn ("bytesread %d", bytesread); + zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, " + "recvfrom(): %s", + circuit->interface->name, circuit->fd, bytesread, + safe_strerror (errno)); /* get rid of the packet */ - bytesread = read (circuit->fd, discard_buff, sizeof (discard_buff)); + bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), + MSG_DONTWAIT, (struct sockaddr *) &s_addr, + (socklen_t *) &addr_len); return ISIS_WARNING; } /* @@ -253,15 +249,22 @@ 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); @@ -289,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; } @@ -313,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 */ @@ -325,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); @@ -336,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; } @@ -351,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 1286486c..c99d9583 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -36,6 +36,7 @@ #include "isis_constants.h" #include "isis_common.h" +#include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" @@ -48,9 +49,6 @@ #include "isis_route.h" #include "isis_zebra.h" -extern struct isis *isis; -extern struct thread_master *master; - static struct isis_nexthop * isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) { @@ -246,6 +244,7 @@ adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj) { nh = isis_nexthop_create (ipv4_addr, adj->circuit->interface->ifindex); + nh->router_address = adj->router_address; listnode_add (nexthops, nh); } } @@ -269,6 +268,7 @@ adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj) { nh6 = isis_nexthop6_create (ipv6_addr, adj->circuit->interface->ifindex); + nh6->router_address6 = adj->router_address6; listnode_add (nexthops6, nh6); } } @@ -276,8 +276,8 @@ adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj) #endif /* HAVE_IPV6 */ static struct isis_route_info * -isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, - struct list *adjacencies) +isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth, + struct list *adjacencies) { struct isis_route_info *rinfo; struct isis_adjacency *adj; @@ -290,18 +290,34 @@ isis_route_info_new (uint32_t cost, uint32_t depth, u_char family, return NULL; } - if (family == AF_INET) + if (prefix->family == AF_INET) { rinfo->nexthops = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) - adjinfo2nexthop (rinfo->nexthops, adj); + { + /* check for force resync this route */ + if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) + SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + /* update neighbor router address */ + if (depth == 2 && prefix->prefixlen == 32) + adj->router_address = prefix->u.prefix4; + adjinfo2nexthop (rinfo->nexthops, adj); + } } #ifdef HAVE_IPV6 - if (family == AF_INET6) + if (prefix->family == AF_INET6) { rinfo->nexthops6 = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) - adjinfo2nexthop6 (rinfo->nexthops6, adj); + { + /* check for force resync this route */ + if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) + SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); + /* update neighbor router address */ + if (depth == 2 && prefix->prefixlen == 128) + adj->router_address6 = prefix->u.prefix6; + adjinfo2nexthop6 (rinfo->nexthops6, adj); + } } #endif /* HAVE_IPV6 */ @@ -353,18 +369,25 @@ 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 +409,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, @@ -459,7 +423,7 @@ isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, /* for debugs */ prefix2str (prefix, (char *) buff, BUFSIZ); - rinfo_new = isis_route_info_new (cost, depth, family, adjacencies); + rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies); if (!rinfo_new) { zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!", @@ -479,68 +443,32 @@ 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 +498,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 +528,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 +636,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 4eac79b8..5adea229 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -30,6 +30,7 @@ struct isis_nexthop6 { unsigned int ifindex; struct in6_addr ip6; + struct in6_addr router_address6; unsigned int lock; }; #endif /* HAVE_IPV6 */ @@ -38,13 +39,15 @@ struct isis_nexthop { unsigned int ifindex; struct in_addr ip; + struct in_addr router_address; unsigned int lock; }; struct isis_route_info { -#define ISIS_ROUTE_FLAG_ZEBRA_SYNC 0x01 -#define ISIS_ROUTE_FLAG_ACTIVE 0x02 +#define ISIS_ROUTE_FLAG_ACTIVE 0x01 /* active route for the prefix */ +#define ISIS_ROUTE_FLAG_ZEBRA_SYNCED 0x02 /* set when route synced to zebra */ +#define ISIS_ROUTE_FLAG_ZEBRA_RESYNC 0x04 /* set when route needs to sync */ u_char flag; u_int32_t cost; u_int32_t depth; @@ -59,6 +62,9 @@ struct 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 cff0fa3f..558d3910 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 5d0b161f..198104a9 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,265 @@ 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->last_run_timestamp = 0; + tree->last_run_duration = 0; + tree->runcount = 0; + tree->pending = 0; + return tree; +} + +void isis_spftree_del (struct isis_spftree *spftree) { + THREAD_TIMER_OFF (spftree->t_spf); + spftree->tents->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->tents); + spftree->tents = NULL; spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->paths); + spftree->paths = NULL; XFREE (MTYPE_ISIS_SPFTREE, spftree); return; } -#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) +{ + struct isis_lsp *lsp; + u_char lspid[ISIS_SYS_ID_LEN + 2]; + + memcpy (lspid, sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID (lspid) = 0; + LSP_FRAGMENT (lspid) = 0; + lsp = lsp_search (lspid, area->lspdb[level - 1]); + if (lsp && lsp->lsp_header->rem_lifetime != 0) + return lsp; + return NULL; } /* * Add this IS to the root of SPT */ -static void -isis_spf_add_self (struct isis_spftree *spftree, struct isis_area *area, - int level) +static struct isis_vertex * +isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid) { struct isis_vertex *vertex; struct isis_lsp *lsp; - u_char lspid[ISIS_SYS_ID_LEN + 2]; #ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; #endif /* EXTREME_DEBUG */ - memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); - LSP_PSEUDO_ID (lspid) = 0; - LSP_FRAGMENT (lspid) = 0; - - lsp = lsp_search (lspid, area->lspdb[level - 1]); + lsp = isis_root_system_lsp (spftree->area, level, sysid); if (lsp == NULL) zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level); - if (!area->oldmetric) - vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_TE_IS); + if (!spftree->area->oldmetric) + vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS); else - vertex = isis_vertex_new (isis->sysid, VTYPE_NONPSEUDO_IS); - - vertex->lsp = lsp; + vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS); listnode_add (spftree->paths, vertex); @@ -338,7 +450,7 @@ 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,26 +502,40 @@ 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 */ if (list_isempty (spftree->tents)) @@ -417,8 +543,8 @@ isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, listnode_add (spftree->tents, vertex); return vertex; } - - /* XXX: This cant use the standard ALL_LIST_ELEMENT macro */ + + /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */ for (node = listhead (spftree->tents); node; node = listnextnode (node)) { v = listgetdata (node); @@ -427,35 +553,24 @@ 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; @@ -471,40 +586,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); @@ -517,16 +657,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; } @@ -537,11 +687,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; } @@ -551,10 +713,10 @@ 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, - struct isis_adjacency *adj) + u_char *root_sysid, struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; - u_int16_t dist; + uint32_t dist; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipreach; @@ -564,114 +726,121 @@ 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->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, adj, family); - } - } - if (lsp->tlv_data.te_is_neighs) - { - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, - te_is_neigh)) - { - uint32_t metric; - if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) - continue; - memcpy (&metric, te_is_neigh->te_metric, 3); - dist = cost + ntohl (metric << 8); - vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS - : VTYPE_NONPSEUDO_TE_IS; - process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, - depth + 1, adj, family); - } - } - if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) - { - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, - node, ipreach)) - { - dist = cost + ipreach->metrics.metric_default; - vtype = VTYPE_IPREACH_INTERNAL; - prefix.u.prefix4 = ipreach->prefix; - prefix.prefixlen = ip_masklen (ipreach->mask); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - adj, family); - } - } + 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, - adj, family); - } - } - if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs) - { - prefix.family = AF_INET; - for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, - node, te_ipv4_reach)) - { - dist = cost + ntohl (te_ipv4_reach->te_metric); - vtype = VTYPE_IPREACH_TE; - prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start, - te_ipv4_reach->control); - prefix.prefixlen = (te_ipv4_reach->control & 0x3F); - process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, - adj, family); - } - } + 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, - 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); @@ -689,14 +858,16 @@ lspfragloop: static int isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, - struct isis_lsp *lsp, uint16_t cost, + struct isis_lsp *lsp, uint32_t cost, uint16_t depth, int family, - struct isis_adjacency *adj) + u_char *root_sysid, + struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; enum vertextype vtype; + uint32_t dist; pseudofragloop: @@ -707,41 +878,36 @@ 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 ((depth > 0 || isis_find_vertex - (spftree->tents, (void *) is_neigh->neigh_id, vtype) == NULL) - && isis_find_vertex (spftree->paths, (void *) is_neigh->neigh_id, - vtype) == NULL) - { - /* C.2.5 i) */ - isis_spf_add2tent (spftree, vtype, is_neigh->neigh_id, adj, - cost, depth, family); - } + dist = cost + is_neigh->metrics.metric_default; + vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS + : VTYPE_NONPSEUDO_IS; + process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, + depth + 1, family, parent); } if (lsp->tlv_data.te_is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) { - vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS - : VTYPE_NONPSEUDO_TE_IS; /* Two way connectivity */ - if (!memcmp (te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN)) + if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; - if ((depth > 0 || isis_find_vertex - (spftree->tents, (void *) te_is_neigh->neigh_id, vtype) == NULL) - && isis_find_vertex (spftree->paths, (void *) te_is_neigh->neigh_id, - vtype) == NULL) - { - /* C.2.5 i) */ - isis_spf_add2tent (spftree, vtype, te_is_neigh->neigh_id, adj, - cost, depth, family); - } + dist = cost + GET_TE_METRIC(te_is_neigh); + vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS + : VTYPE_NONPSEUDO_TE_IS; + process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, + depth + 1, family, parent); } if (fragnode == NULL) @@ -759,10 +925,10 @@ 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 +939,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 +966,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 +979,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,40 +1001,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]); - if (!lsp) - zlog_warn ("No lsp found for IS adjacency"); + lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); + if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) + zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency " + "L%d on %s (ID %u)", + rawlspid_print (lsp_id), level, + circuit->interface->name, circuit->circuit_id); break; case ISIS_SYSTYPE_UNKNOWN: default: zlog_warn ("isis_spf_preload_tent unknow adj type"); } - anode = listnextnode (anode); } list_delete (adj_list); /* @@ -875,23 +1045,36 @@ 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"); - } - else if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) - { - zlog_warn ("ISIS-Spf: No lsp found for DR"); + zlog_warn ("ISIS-Spf: No adjacency found from root " + "to L%d DR %s on %s (ID %d)", + level, rawlspid_print (lsp_id), + circuit->interface->name, circuit->circuit_id); + continue; } - else + lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); + if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { - isis_spf_process_pseudo_lsp (spftree, lsp, - circuit->te_metric[level - 1], 0, family, adj); - + 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) { @@ -902,28 +1085,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; @@ -935,25 +1126,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; @@ -966,23 +1162,27 @@ 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 isis_adjacency *adj = NULL; struct route_table *table = NULL; - struct route_node *rode; - struct isis_route_info *rinfo; + struct timespec time_now; + unsigned long long start_time, end_time; + + /* Get time that can't roll backwards. */ + clock_gettime(CLOCK_MONOTONIC, &time_now); + start_time = time_now.tv_sec; + start_time = (start_time * 1000000) + (time_now.tv_nsec / 1000); if (family == AF_INET) spftree = area->spftree[level - 1]; @@ -990,8 +1190,8 @@ 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) @@ -1001,71 +1201,66 @@ 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; } while (listcount (spftree->tents) > 0) { - /* C.2.7 a) 1) */ node = listhead (spftree->tents); vertex = listgetdata (node); - /* C.2.7 a) 2) */ - list_delete_node (spftree->tents, node); - - /* C.2.7 a) 3) */ - if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type)) - continue; - add_to_paths (spftree, vertex, area, level); - - if (vertex->type == VTYPE_PSEUDO_IS || - vertex->type == VTYPE_NONPSEUDO_IS || - vertex->type == VTYPE_PSEUDO_TE_IS || - vertex->type == VTYPE_NONPSEUDO_TE_IS ) - { - if (listcount(vertex->Adj_N) == 0) { - continue; - } - adj = listgetdata(vertex->Adj_N->head); +#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); + add_to_paths (spftree, vertex, level); + switch (vertex->type) + { + case VTYPE_PSEUDO_IS: + case VTYPE_NONPSEUDO_IS: + case VTYPE_PSEUDO_TE_IS: + case VTYPE_NONPSEUDO_TE_IS: memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, area->lspdb[level - 1]); - if (lsp) + if (lsp && lsp->lsp_header->rem_lifetime != 0) { if (LSP_PSEUDO_ID (lsp_id)) { isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family, adj); + vertex->depth, family, sysid, + vertex); } else { isis_spf_process_lsp (spftree, lsp, vertex->d_N, - vertex->depth, family, adj); + vertex->depth, family, sysid, vertex); } } else @@ -1073,13 +1268,21 @@ 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); - spftree->lastrun = time (NULL); + isis_route_validate (area); spftree->pending = 0; + spftree->runcount++; + spftree->last_run_timestamp = time (NULL); + clock_gettime(CLOCK_MONOTONIC, &time_now); + end_time = time_now.tv_sec; + end_time = (end_time * 1000000) + (time_now.tv_nsec / 1000); + spftree->last_run_duration = end_time - start_time; + return retval; } @@ -1094,6 +1297,7 @@ 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)) { @@ -1107,10 +1311,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; } @@ -1125,6 +1326,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)) { @@ -1137,10 +1339,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; } @@ -1148,53 +1347,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); + time_t now = time (NULL); + int diff = now - spftree->last_run_timestamp; - if (spftree->pending) - return retval; + assert (diff >= 0); + assert (area->is_type & level); - diff = now - spftree->lastrun; - - /* FIXME: let's wait a minute before doing the SPF */ - if (now - isis->uptime < 60 || isis->uptime == 0) - { - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, 60); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, 60); + 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 configured min_spf_interval before doing the SPF */ + if (diff >= area->min_spf_interval[level-1]) + return isis_run_spf (area, level, AF_INET, isis->sysid); - spftree->pending = 1; - } + if (level == 1) + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, + area->min_spf_interval[0] - diff); else - { - spftree->pending = 0; - retval = isis_run_spf (area, level, AF_INET); - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); - } + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, + area->min_spf_interval[1] - diff); - return retval; + if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", + area->area_tag, level, area->min_spf_interval[level-1] - diff); + + spftree->pending = 1; + + return ISIS_OK; } #ifdef HAVE_IPV6 @@ -1208,11 +1394,12 @@ 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; } @@ -1220,10 +1407,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; } @@ -1238,6 +1422,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)) { @@ -1250,10 +1435,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; } @@ -1263,104 +1445,110 @@ isis_spf_schedule6 (struct isis_area *area, int level) { int retval = ISIS_OK; struct isis_spftree *spftree = area->spftree6[level - 1]; - time_t diff, now = time (NULL); + time_t now = time (NULL); + time_t diff = now - spftree->last_run_timestamp; - if (spftree->pending) - return retval; + assert (diff >= 0); + assert (area->is_type & level); - diff = now - spftree->lastrun; + 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); - /* 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); + if (spftree->pending) + return ISIS_OK; - spftree->pending = 1; - return retval; - } - THREAD_TIMER_OFF (spftree->t_spf); - if (diff < MINIMUM_SPF_INTERVAL) - { - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, - MINIMUM_SPF_INTERVAL - diff); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, - MINIMUM_SPF_INTERVAL - diff); + /* wait configured min_spf_interval before doing the SPF */ + if (diff >= area->min_spf_interval[level-1]) + return isis_run_spf (area, level, AF_INET6, isis->sysid); - spftree->pending = 1; - } + if (level == 1) + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, + area->min_spf_interval[0] - diff); else - { - spftree->pending = 0; - retval = isis_run_spf (area, level, AF_INET6); + THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, + area->min_spf_interval[1] - diff); - if (level == 1) - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); - else - THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, - isis_jitter (PERIODIC_SPF_INTERVAL, 10)); - } + if (isis->debugs & DEBUG_SPF_EVENTS) + zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", + area->area_tag, level, area->min_spf_interval[level-1] - diff); + + spftree->pending = 1; return retval; } #endif static void -isis_print_paths (struct vty *vty, struct list *paths) +isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid) { struct listnode *node; + struct listnode *anode; struct isis_vertex *vertex; - struct isis_dynhn *dyn, *nh_dyn = NULL; struct isis_adjacency *adj; -#if 0 u_char buff[255]; -#endif /* 0 */ - vty_out (vty, "System Id Metric Next-Hop" - " Interface SNPA%s", VTY_NEWLINE); + vty_out (vty, "Vertex Type Metric " + "Next-Hop Interface Parent%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) { + if (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); } } @@ -1390,7 +1578,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] @@ -1399,10 +1588,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; @@ -1432,7 +1624,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] @@ -1440,9 +1633,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; @@ -1472,7 +1667,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] @@ -1480,9 +1676,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 6bdab2da..aa543b70 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -54,25 +54,33 @@ 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 */ + unsigned int runcount; /* number of runs since uptime */ + time_t last_run_timestamp; /* last run timestamp for scheduling */ + time_t last_run_duration; /* last run duration in msec */ }; +struct isis_spftree * isis_spftree_new (struct isis_area *area); +void isis_spftree_del (struct isis_spftree *spftree); +void isis_spftree_adj_del (struct isis_spftree *spftree, + struct isis_adjacency *adj); void spftree_area_init (struct isis_area *area); +void spftree_area_del (struct isis_area *area); +void spftree_area_adj_del (struct isis_area *area, + struct isis_adjacency *adj); int isis_spf_schedule (struct isis_area *area, int level); void isis_spf_cmds_init (void); #ifdef HAVE_IPV6 diff --git a/isisd/isis_tlv.c b/isisd/isis_tlv.c index 3fc717e3..bb57bd6b 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,14 +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); - /* Fill authentication with 0 for later computation - * of MD5 (RFC 5304, 2) - */ - memset (pnt, 0, length - 1); - pnt += length - 1; + memcpy (tlvs->auth_info.passwd, pnt, length); + /* Return the authentication tlv pos for later computation + * of MD5 (RFC 5304, 2) + */ + if (auth_tlv_offset) + *auth_tlv_offset += (pnt - start - 3); + pnt += length; } else { @@ -734,10 +737,14 @@ 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; } @@ -745,7 +752,7 @@ add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream) stream_putc (stream, len); /* LENGTH */ stream_put (stream, value, (int) len); /* VALUE */ -#ifdef EXTREME_TLV_DEBUG +#ifdef EXTREME_DEBUG zlog_debug ("Added TLV %d len %d", tag, len); #endif /* EXTREME DEBUG */ return ISIS_OK; @@ -877,7 +884,7 @@ 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]; @@ -1006,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); } @@ -1027,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; @@ -1110,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 */ @@ -1120,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 fc9f35f8..e092f4d6 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 d5ccef9e..467122f6 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]) @@ -274,8 +256,6 @@ isis_zebra_route_add_ipv4 (struct prefix *prefix, stream_putc (stream, flags); /* message */ stream_putc (stream, message); - /* SAFI */ - stream_putw (stream, SAFI_UNICAST); /* prefix information */ psize = PSIZE (prefix->prefixlen); stream_putc (stream, prefix->prefixlen); @@ -307,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); } } @@ -323,13 +304,12 @@ isis_zebra_route_del_ipv4 (struct prefix *prefix, api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; - api.safi = SAFI_UNICAST; prefix4.family = AF_INET; prefix4.prefixlen = prefix->prefixlen; prefix4.prefix = prefix->u.prefix4; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4, &api); } - UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNC); + UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); return; } @@ -347,13 +327,12 @@ 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; api.flags = 0; api.message = 0; - api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); @@ -410,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); @@ -431,13 +411,12 @@ 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; api.flags = 0; api.message = 0; - api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.nexthop_num = listcount (route_info->nexthops6); @@ -488,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 20a32809..e8e3d9f0 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -27,6 +27,7 @@ #include "command.h" #include "log.h" #include "memory.h" +#include "time.h" #include "linklist.h" #include "if.h" #include "hash.h" @@ -38,8 +39,9 @@ #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" -#include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" +#include "isisd/isis_circuit.h" +#include "isisd/isis_csm.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_adjacency.h" @@ -52,7 +54,6 @@ #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" #include "isisd/isis_events.h" -#include "isisd/isis_csm.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" @@ -60,19 +61,17 @@ 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 *); @@ -85,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); @@ -94,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 */ @@ -101,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; @@ -115,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); @@ -153,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; } @@ -185,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); @@ -204,50 +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_csm_state_change (ISIS_DISABLE, circuit, area); - isis_circuit_down (circuit); - isis_circuit_deconfigure (circuit, area); - } - + { + circuit->ip_router = 0; +#ifdef HAVE_IPV6 + circuit->ipv6_router = 0; +#endif + isis_csm_state_change (ISIS_DISABLE, circuit, area); + } list_delete (area->circuit_list); + area->circuit_list = NULL; } - listnode_delete (isis->area_list, area); + + if (area->lspdb[0] != NULL) + { + lsp_db_destroy (area->lspdb[0]); + area->lspdb[0] = NULL; + } + if (area->lspdb[1] != NULL) + { + lsp_db_destroy (area->lspdb[1]); + area->lspdb[1] = NULL; + } + + spftree_area_del (area); + + /* invalidate and validate would delete all routes from zebra */ + isis_route_invalidate (area); + isis_route_validate (area); + + if (area->route_table[0]) + { + route_table_finish (area->route_table[0]); + area->route_table[0] = NULL; + } + if (area->route_table[1]) + { + route_table_finish (area->route_table[1]); + area->route_table[1] = NULL; + } +#ifdef HAVE_IPV6 + if (area->route_table6[0]) + { + route_table_finish (area->route_table6[0]); + area->route_table6[0] = NULL; + } + if (area->route_table6[1]) + { + route_table_finish (area->route_table6[1]); + area->route_table6[1] = NULL; + } +#endif /* HAVE_IPV6 */ + + for (ALL_LIST_ELEMENTS (area->area_addrs, node, nnode, addr)) + { + list_delete_node (area->area_addrs, node); + XFREE (MTYPE_ISIS_AREA_ADDR, addr); + } + area->area_addrs = NULL; THREAD_TIMER_OFF (area->t_tick); - if (area->t_remove_aged) - thread_cancel (area->t_remove_aged); THREAD_TIMER_OFF (area->t_lsp_refresh[0]); THREAD_TIMER_OFF (area->t_lsp_refresh[1]); - THREAD_TIMER_OFF (area->spftree[0]->t_spf); - THREAD_TIMER_OFF (area->spftree[1]->t_spf); + thread_cancel_event (master, area); + + listnode_delete (isis->area_list, area); - THREAD_TIMER_OFF (area->t_lsp_l1_regenerate); - THREAD_TIMER_OFF (area->t_lsp_l2_regenerate); + free (area->area_tag); XFREE (MTYPE_ISIS_AREA, area); - isis->sysid_set=0; + if (listcount (isis->area_list) == 0) + { + memset (isis->sysid, 0, ISIS_SYS_ID_LEN); + isis->sysid_set = 0; + } return CMD_SUCCESS; } int -area_net_title (struct vty *vty, const u_char *net_title) +area_net_title (struct vty *vty, const char *net_title) { struct isis_area *area; struct area_addr *addr; @@ -260,7 +324,7 @@ 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 */ @@ -268,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)); @@ -280,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_WARNING; + return CMD_ERR_AMBIGUOUS; + } + + if (addr->area_addr[addr->addr_len-1] != 0) + { + vty_out (vty, "nsel byte (last byte) in area address must be 0%s", + VTY_NEWLINE); + XFREE (MTYPE_ISIS_AREA_ADDR, addr); + return CMD_ERR_AMBIGUOUS; } if (isis->sysid_set == 0) @@ -291,7 +363,7 @@ 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)); @@ -301,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)) { @@ -322,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; @@ -352,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); @@ -360,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; @@ -374,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) { @@ -406,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_clns_neigh (vty, ISIS_UI_LEVEL_DETAIL); + return show_isis_interface_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } -ALIAS (show_clns_neighbors_detail, - show_isis_neighbors_detail_cmd, - "show isis neighbors detail", +/* + * 'show isis neighbor' command + */ + +int +show_isis_neighbor_common (struct vty *vty, const char *id, char detail) +{ + struct listnode *anode, *cnode, *node; + struct isis_area *area; + struct isis_circuit *circuit; + struct list *adjdb; + struct isis_adjacency *adj; + struct isis_dynhn *dynhn; + u_char sysid[ISIS_SYS_ID_LEN]; + int i; + + if (!isis) + { + vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + memset (sysid, 0, ISIS_SYS_ID_LEN); + if (id) + { + if (sysid2buff (sysid, id) == 0) + { + dynhn = dynhn_find_by_name (id); + if (dynhn == NULL) + { + vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); + return CMD_SUCCESS; + } + memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); + } + } + + for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) + { + vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE); + + if (detail == ISIS_UI_LEVEL_BRIEF) + vty_out (vty, " System Id Interface L State" + " Holdtime SNPA%s", VTY_NEWLINE); + + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) + { + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + for (i = 0; i < 2; i++) + { + adjdb = circuit->u.bc.adjdb[i]; + if (adjdb && adjdb->count) + { + for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) + if (!id || !memcmp (adj->sysid, sysid, + ISIS_SYS_ID_LEN)) + isis_adj_print_vty (adj, vty, detail); + } + } + } + else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) + { + adj = circuit->u.p2p.neighbor; + if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_print_vty (adj, vty, detail); + } + } + } + + return CMD_SUCCESS; +} + +/* + * 'clear isis neighbor' command + */ +int +clear_isis_neighbor_common (struct vty *vty, const char *id) +{ + struct listnode *anode, *cnode, *cnextnode, *node, *nnode; + struct isis_area *area; + struct isis_circuit *circuit; + struct list *adjdb; + struct isis_adjacency *adj; + struct isis_dynhn *dynhn; + u_char sysid[ISIS_SYS_ID_LEN]; + int i; + + if (!isis) + { + vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + memset (sysid, 0, ISIS_SYS_ID_LEN); + if (id) + { + if (sysid2buff (sysid, id) == 0) + { + dynhn = dynhn_find_by_name (id); + if (dynhn == NULL) + { + vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); + return CMD_SUCCESS; + } + memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); + } + } + + for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) + { + for (ALL_LIST_ELEMENTS (area->circuit_list, cnode, cnextnode, circuit)) + { + if (circuit->circ_type == CIRCUIT_T_BROADCAST) + { + for (i = 0; i < 2; i++) + { + adjdb = circuit->u.bc.adjdb[i]; + if (adjdb && adjdb->count) + { + for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj)) + if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_state_change (adj, ISIS_ADJ_DOWN, + "clear user request"); + } + } + } + else if (circuit->circ_type == CIRCUIT_T_P2P && + circuit->u.p2p.neighbor) + { + adj = circuit->u.p2p.neighbor; + if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) + isis_adj_state_change (adj, ISIS_ADJ_DOWN, + "clear user request"); + } + } + } + + return CMD_SUCCESS; +} + +DEFUN (show_isis_neighbor, + show_isis_neighbor_cmd, + "show isis neighbor", + SHOW_STR + "ISIS network information\n" + "ISIS neighbor adjacencies\n") +{ + return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_BRIEF); +} + +DEFUN (show_isis_neighbor_detail, + show_isis_neighbor_detail_cmd, + "show isis neighbor detail", SHOW_STR - "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, + "clear isis neighbor WORD", + CLEAR_STR + "ISIS network information\n" + "ISIS neighbor adjacencies\n" + "System id\n") +{ + return clear_isis_neighbor_common (vty, argv[0]); +} + /* * 'isis debug', 'show debugging' */ @@ -535,7 +772,8 @@ 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, @@ -617,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; } @@ -803,7 +1046,6 @@ DEFUN (no_debug_isis_spfevents, return CMD_SUCCESS; } - DEFUN (debug_isis_spfstats, debug_isis_spfstats_cmd, "debug isis spf-statistics ", @@ -908,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", @@ -920,80 +1188,314 @@ 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 elapsed : "); + vty_out_timestr(vty, spftree->last_run_timestamp); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " last run duration : %u usec%s", + (u_int32_t)spftree->last_run_duration, VTY_NEWLINE); + + vty_out (vty, " run count : %d%s", + spftree->runcount, VTY_NEWLINE); + +#ifdef HAVE_IPV6 + spftree = area->spftree6[level - 1]; + if (spftree->pending) + vty_out (vty, " IPv6 SPF: (pending)%s", VTY_NEWLINE); + else + vty_out (vty, " IPv6 SPF:%s", VTY_NEWLINE); + + vty_out (vty, " minimum interval : %d%s", + area->min_spf_interval[level - 1], VTY_NEWLINE); + + vty_out (vty, " last run elapsed : "); + vty_out_timestr(vty, spftree->last_run_timestamp); + vty_out (vty, "%s", VTY_NEWLINE); + + vty_out (vty, " last run duration : %u msec%s", + spftree->last_run_duration, VTY_NEWLINE); + + vty_out (vty, " run count : %d%s", + spftree->runcount, VTY_NEWLINE); +#endif } + } + vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } -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[255]; + u_char number[3]; int level, lsp_count; if (isis->area_list->count == 0) return CMD_SUCCESS; + memset (&lspid, 0, ISIS_SYS_ID_LEN); + memset (&sysid, 0, 255); + + /* + * extract fragment and pseudo id from the string argv + * in the forms: + * (a) <systemid/hostname>.<pseudo-id>-<framenent> or + * (b) <systemid/hostname>.<pseudo-id> or + * (c) <systemid/hostname> or + * Where systemid is in the form: + * xxxx.xxxx.xxxx + */ + if (argv) + strncpy (sysid, argv, 254); + if (argv && strlen (argv) > 3) + { + pos = argv + strlen (argv) - 3; + if (strncmp (pos, "-", 1) == 0) + { + memcpy (number, ++pos, 2); + lspid[ISIS_SYS_ID_LEN+1] = (u_char) strtol ((char *)number, NULL, 16); + pos -= 4; + if (strncmp (pos, ".", 1) != 0) + return CMD_ERR_AMBIGUOUS; + } + if (strncmp (pos, ".", 1) == 0) + { + memcpy (number, ++pos, 2); + lspid[ISIS_SYS_ID_LEN] = (u_char) strtol ((char *)number, NULL, 16); + sysid[pos - argv - 1] = '\0'; + } + } + for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", - VTY_NEWLINE); - for (level = 0; level < ISIS_LEVELS; level++) - { - if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) - { - vty_out (vty, "IS-IS Level-%d Link State Database:%s", - level + 1, VTY_NEWLINE); - - lsp_count = lsp_print_all (vty, area->lspdb[level], - ISIS_UI_LEVEL_DETAIL, - area->dynhostname); + VTY_NEWLINE); - 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 */ @@ -1043,10 +1545,11 @@ 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; @@ -1056,16 +1559,75 @@ 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_HMAC_MD5; + strncpy ((char *)area->area_passwd.passwd, argv[0], 255); + + if (argc > 1) + { + SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); + if (strncmp(argv[1], "v", 1) == 0) + SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); + else + UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); + } + else + { + UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); + UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); + } + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + +ALIAS (area_passwd_md5, + area_passwd_md5_snpauth_cmd, + "area-password md5 WORD authenticate snp (send-only|validate)", + "Configure the authentication password for an area\n" + "Authentication type\n" + "Area password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n"); + +DEFUN (area_passwd_clear, + area_passwd_clear_cmd, + "area-password clear WORD", + "Configure the authentication password for an area\n" + "Authentication type\n" + "Area password\n") +{ + struct isis_area *area; + int len; + + area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + len = strlen (argv[0]); + if (len > 254) + { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + area->area_passwd.len = (u_char) len; area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->area_passwd.passwd, argv[0], 255); @@ -1083,14 +1645,16 @@ 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" @@ -1109,19 +1673,21 @@ 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, - domain_passwd_cmd, - "domain-password WORD", +DEFUN (domain_passwd_md5, + domain_passwd_md5_cmd, + "domain-password md5 WORD", "Set the authentication password for a routing domain\n" + "Authentication type\n" "Routing domain password\n") { struct isis_area *area; @@ -1131,16 +1697,75 @@ 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_HMAC_MD5; + strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); + + if (argc > 1) + { + SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); + if (strncmp(argv[1], "v", 1) == 0) + SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); + else + UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); + } + else + { + UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); + UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); + } + lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return CMD_SUCCESS; +} + +ALIAS (domain_passwd_md5, + domain_passwd_md5_snpauth_cmd, + "domain-password md5 WORD authenticate snp (send-only|validate)", + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Routing domain password\n" + "Authentication\n" + "SNP PDUs\n" + "Send but do not check PDUs on receiving\n" + "Send and check PDUs on receiving\n"); + +DEFUN (domain_passwd_clear, + domain_passwd_clear_cmd, + "domain-password clear WORD", + "Set the authentication password for a routing domain\n" + "Authentication type\n" + "Routing domain password\n") +{ + struct isis_area *area; + int len; + + area = vty->index; + + if (!area) + { + vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); + return CMD_ERR_NO_MATCH; + } + + len = strlen (argv[0]); + if (len > 254) + { + vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + area->domain_passwd.len = (u_char) len; area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); @@ -1158,14 +1783,16 @@ 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" @@ -1174,7 +1801,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") { @@ -1184,11 +1811,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; } @@ -1208,8 +1836,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]); @@ -1240,8 +1868,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; @@ -1253,6 +1882,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>", @@ -1261,15 +1920,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, @@ -1279,14 +1935,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, @@ -1305,14 +1960,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, @@ -1323,13 +1976,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, @@ -1348,15 +2001,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, @@ -1367,15 +2018,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, @@ -1386,6 +2035,44 @@ ALIAS (no_lsp_gen_interval_l2, "Set interval for level 2 only\n" "Minimum interval in seconds\n") +static int +validate_metric_style_narrow (struct vty *vty, struct isis_area *area) +{ + struct isis_circuit *circuit; + struct listnode *node; + + if (! vty) + return CMD_ERR_AMBIGUOUS; + + if (! area) + { + vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + + for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) + { + if ((area->is_type & IS_LEVEL_1) && + (circuit->is_type & IS_LEVEL_1) && + (circuit->metrics[0].metric_default > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + if ((area->is_type & IS_LEVEL_2) && + (circuit->is_type & IS_LEVEL_2) && + (circuit->metrics[1].metric_default > MAX_NARROW_LINK_METRIC)) + { + vty_out (vty, "ISIS circuit %s metric is invalid%s", + circuit->interface->name, VTY_NEWLINE); + return CMD_ERR_AMBIGUOUS; + } + } + + return CMD_SUCCESS; +} + DEFUN (metric_style, metric_style_cmd, "metric-style (narrow|transition|wide)", @@ -1395,6 +2082,7 @@ DEFUN (metric_style, "Use new style of TLVs to carry wider metric\n") { struct isis_area *area; + int ret; area = vty->index; assert (area); @@ -1411,6 +2099,10 @@ DEFUN (metric_style, } else if (strncmp (argv[0], "n", 1) == 0) { + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + area->newmetric = 0; area->oldmetric = 1; } @@ -1425,10 +2117,15 @@ DEFUN (no_metric_style, "Use old-style (ISO 10589) or new-style packet formats\n") { struct isis_area *area; + int ret; area = vty->index; assert (area); + ret = validate_metric_style_narrow (vty, area); + if (ret != CMD_SUCCESS) + return ret; + /* Default is narrow metric. */ area->newmetric = 0; area->oldmetric = 1; @@ -1436,6 +2133,40 @@ 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", @@ -1447,7 +2178,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; } @@ -1464,7 +2199,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; } @@ -1591,7 +2330,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] " @@ -1623,7 +2715,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; @@ -1633,7 +2725,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; @@ -1717,182 +2809,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 @@ -1939,25 +2857,27 @@ isis_config_write (struct vty *vty) vty_out (vty, " metric-style transition%s", VTY_NEWLINE); write++; } - + /* ISIS - overload-bit */ + if (area->overload_bit) + { + vty_out (vty, " set-overload-bit%s", VTY_NEWLINE); + write++; + } /* ISIS - Area is-type (level-1-2 is default) */ if (area->is_type == IS_LEVEL_1) { vty_out (vty, " is-type level-1%s", VTY_NEWLINE); write++; } - else + else if (area->is_type == IS_LEVEL_2) { - if (area->is_type == IS_LEVEL_2) - { - vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE); - write++; - } + vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE); + write++; } /* ISIS - Lsp generation interval */ if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1]) { - if (area->lsp_gen_interval[0] != LSP_GEN_INTERVAL_DEFAULT) + if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval %d%s", area->lsp_gen_interval[0], VTY_NEWLINE); @@ -1966,13 +2886,13 @@ 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); @@ -1982,28 +2902,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]) { @@ -2030,9 +2975,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 "); @@ -2043,10 +3002,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 "); @@ -2059,12 +3034,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) @@ -2087,7 +3068,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 @@ -2099,23 +3080,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); @@ -2142,6 +3143,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); @@ -2165,6 +3168,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); @@ -2177,12 +3182,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); @@ -2205,21 +3214,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); @@ -2229,9 +3255,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 b17982e2..5db485f4 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,11 +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; - struct thread *t_lsp_l1_regenerate; - struct thread *t_lsp_l2_regenerate; - int lsp_regenerate_pending[ISIS_LEVELS]; struct thread *t_lsp_refresh[ISIS_LEVELS]; + int lsp_regenerate_pending[ISIS_LEVELS]; /* * Configurables @@ -114,6 +114,8 @@ struct 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]; @@ -122,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 */ @@ -130,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) @@ -151,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/isisd/topology/.cvsignore b/isisd/topology/.cvsignore new file mode 100644 index 00000000..b0ae823b --- /dev/null +++ b/isisd/topology/.cvsignore @@ -0,0 +1,9 @@ +Makefile +Makefile.in +*.o +tags +TAGS +.deps +.nfs* +.arch-inventory +.arch-ids @@ -146,7 +146,7 @@ if_delete_retain (struct interface *ifp) (*if_master.if_delete_hook) (ifp); /* Free connected address list */ - list_delete (ifp->connected); + list_delete_all_node (ifp->connected); } /* Delete and free interface structure. */ @@ -157,6 +157,8 @@ if_delete (struct interface *ifp) if_delete_retain(ifp); + list_free (ifp->connected); + XFREE (MTYPE_IF, ifp); } diff --git a/lib/linklist.h b/lib/linklist.h index cc6867cd..f0ae3625 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -54,9 +54,9 @@ struct list void (*del) (void *val); }; -#define listnextnode(X) ((X)->next) -#define listhead(X) ((X)->head) -#define listtail(X) ((X)->tail) +#define listnextnode(X) ((X) ? ((X)->next) : NULL) +#define listhead(X) ((X) ? ((X)->head) : NULL) +#define listtail(X) ((X) ? ((X)->tail) : NULL) #define listcount(X) ((X)->count) #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) #define listgetdata(X) (assert((X)->data != NULL), (X)->data) @@ -88,10 +88,10 @@ extern void list_add_list (struct list *, struct list *); * It is safe to delete the listnode using this macro. */ #define ALL_LIST_ELEMENTS(list,node,nextnode,data) \ - (node) = listhead(list); \ + (node) = listhead(list), ((data) = NULL); \ (node) != NULL && \ ((data) = listgetdata(node),(nextnode) = listnextnode(node), 1); \ - (node) = (nextnode) + (node) = (nextnode), ((data) = NULL) /* read-only list iteration macro. * Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only @@ -100,9 +100,9 @@ extern void list_add_list (struct list *, struct list *); * of previous macro. */ #define ALL_LIST_ELEMENTS_RO(list,node,data) \ - (node) = listhead(list); \ + (node) = listhead(list), ((data) = NULL);\ (node) != NULL && ((data) = listgetdata(node), 1); \ - (node) = listnextnode(node) + (node) = listnextnode(node), ((data) = NULL) /* these *do not* cleanup list nodes and referenced data, as the functions * do - these macros simply {de,at}tach a listnode from/to a list. @@ -83,6 +83,7 @@ do { \ } while (0) /* From RFC 2104 */ -void hmac_md5(unsigned char* text, int text_len, unsigned char* key, int key_len, caddr_t digest); +void hmac_md5(unsigned char* text, int text_len, unsigned char* key, + int key_len, caddr_t digest); #endif /* ! _LIBZEBRA_MD5_H_*/ diff --git a/lib/memtypes.c b/lib/memtypes.c index cd39c996..2ded1d6c 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -247,6 +247,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 }, }; diff --git a/lib/stream.c b/lib/stream.c index 983330ff..b226a25e 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -52,7 +52,7 @@ * using stream_put..._at() functions. */ #define STREAM_WARN_OFFSETS(S) \ - zlog_warn ("&(struct stream): %p, size: %lu, endp: %lu, getp: %lu\n", \ + zlog_warn ("&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \ (S), \ (unsigned long) (S)->size, \ (unsigned long) (S)->getp, \ @@ -214,6 +214,20 @@ stream_set_getp (struct stream *s, size_t pos) s->getp = pos; } +void +stream_set_endp (struct stream *s, size_t pos) +{ + STREAM_VERIFY_SANE(s); + + if (!GETP_VALID (s, pos)) + { + STREAM_BOUND_WARN (s, "set endp"); + pos = s->endp; + } + + s->endp = pos; +} + /* Forward pointer. */ void stream_forward_getp (struct stream *s, size_t size) @@ -934,9 +948,9 @@ stream_fifo_pop (struct stream_fifo *fifo) if (fifo->head == NULL) fifo->tail = NULL; - } - fifo->count--; + fifo->count--; + } return s; } diff --git a/lib/stream.h b/lib/stream.h index 3e4ba7b4..f10aa6d4 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -146,6 +146,7 @@ extern size_t stream_get_size (struct stream *); extern u_char *stream_get_data (struct stream *); extern void stream_set_getp (struct stream *, size_t); +extern void stream_set_endp (struct stream *, size_t); extern void stream_forward_getp (struct stream *, size_t); extern void stream_forward_endp (struct stream *, size_t); diff --git a/lib/zclient.c b/lib/zclient.c index 3521d99e..61c6f730 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -654,24 +654,8 @@ zebra_interface_add_read (struct stream *s) /* Lookup/create interface by name. */ ifp = if_get_by_name_len (ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ)); - /* Read interface's index. */ - ifp->ifindex = stream_getl (s); + zebra_interface_if_set_value (s, ifp); - /* Read interface's value. */ - ifp->status = stream_getc (s); - ifp->flags = stream_getq (s); - ifp->metric = stream_getl (s); - ifp->mtu = stream_getl (s); - ifp->mtu6 = stream_getl (s); - ifp->bandwidth = stream_getl (s); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_get (&ifp->sdl, s, sizeof (ifp->sdl)); -#else - ifp->hw_addr_len = stream_getl (s); - if (ifp->hw_addr_len) - stream_get (ifp->hw_addr, s, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ - return ifp; } @@ -699,16 +683,7 @@ zebra_interface_state_read (struct stream *s) if (! ifp) return NULL; - /* Read interface's index. */ - ifp->ifindex = stream_getl (s); - - /* Read interface's value. */ - ifp->status = stream_getc (s); - ifp->flags = stream_getq (s); - ifp->metric = stream_getl (s); - ifp->mtu = stream_getl (s); - ifp->mtu6 = stream_getl (s); - ifp->bandwidth = stream_getl (s); + zebra_interface_if_set_value (s, ifp); return ifp; } @@ -758,6 +733,13 @@ zebra_interface_if_set_value (struct stream *s, struct interface *ifp) ifp->mtu = stream_getl (s); ifp->mtu6 = stream_getl (s); ifp->bandwidth = stream_getl (s); +#ifdef HAVE_STRUCT_SOCKADDR_DL + stream_get (&ifp->sdl, s, sizeof (ifp->sdl)); +#else + ifp->hw_addr_len = stream_getl (s); + if (ifp->hw_addr_len) + stream_get (ifp->hw_addr, s, ifp->hw_addr_len); +#endif /* HAVE_STRUCT_SOCKADDR_DL */ } static int diff --git a/zebra/rib.h b/zebra/rib.h index 2872fc03..1b85c81e 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -225,6 +225,10 @@ extern struct nexthop *nexthop_ifname_add (struct rib *, char *); extern struct nexthop *nexthop_blackhole_add (struct rib *); extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, struct in_addr *); +extern struct nexthop *nexthop_ipv4_ifindex_add (struct rib *, + struct in_addr *, + struct in_addr *, + unsigned int); extern void rib_lookup_and_dump (struct prefix_ipv4 *); extern void rib_lookup_and_pushup (struct prefix_ipv4 *); extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index f48df2bf..73097bf6 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -32,6 +32,7 @@ #include "prefix.h" #include "connected.h" #include "table.h" +#include "memory.h" #include "rib.h" #include "thread.h" #include "privs.h" @@ -426,6 +427,37 @@ netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, } } +/* Utility function to parse hardware link-layer address and update ifp */ +static void +netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp) +{ + int i; + + if (tb[IFLA_ADDRESS]) + { + int hw_addr_len; + + hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]); + + if (hw_addr_len > INTERFACE_HWADDR_MAX) + zlog_warn ("Hardware address is too large: %d", hw_addr_len); + else + { + ifp->hw_addr_len = hw_addr_len; + memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len); + + for (i = 0; i < hw_addr_len; i++) + if (ifp->hw_addr[i] != 0) + break; + + if (i == hw_addr_len) + ifp->hw_addr_len = 0; + else + ifp->hw_addr_len = hw_addr_len; + } + } +} + /* Called from interface_lookup_netlink(). This function is only used during bootstrap. */ static int @@ -436,7 +468,6 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; - int i; ifi = NLMSG_DATA (h); @@ -474,30 +505,7 @@ netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) /* Hardware type and address. */ ifp->hw_type = ifi->ifi_type; - - if (tb[IFLA_ADDRESS]) - { - int hw_addr_len; - - hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]); - - if (hw_addr_len > INTERFACE_HWADDR_MAX) - zlog_warn ("Hardware address is too large: %d", hw_addr_len); - else - { - ifp->hw_addr_len = hw_addr_len; - memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len); - - for (i = 0; i < hw_addr_len; i++) - if (ifp->hw_addr[i] != 0) - break; - - if (i == hw_addr_len) - ifp->hw_addr_len = 0; - else - ifp->hw_addr_len = hw_addr_len; - } - } + netlink_interface_update_hw_addr (tb, ifp); if_add_update (ifp); @@ -709,7 +717,6 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); - /* Multipath treatment is needed. */ if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); @@ -723,7 +730,64 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0, SAFI_UNICAST); + if (!tb[RTA_MULTIPATH]) + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, + table, metric, 0, SAFI_UNICAST); + else + { + /* This is a multipath route */ + + struct rib *rib; + struct rtnexthop *rtnh = + (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); + + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + rib->type = ZEBRA_ROUTE_KERNEL; + rib->distance = 0; + rib->flags = flags; + rib->metric = metric; + rib->table = table; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + for (;;) + { + if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) + break; + + rib->nexthop_num++; + index = rtnh->rtnh_ifindex; + gate = 0; + if (rtnh->rtnh_len > sizeof (*rtnh)) + { + memset (tb, 0, sizeof (tb)); + netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), + rtnh->rtnh_len - sizeof (*rtnh)); + if (tb[RTA_GATEWAY]) + gate = RTA_DATA (tb[RTA_GATEWAY]); + } + + if (gate) + { + if (index) + nexthop_ipv4_ifindex_add (rib, gate, src, index); + else + nexthop_ipv4_add (rib, gate, src); + } + else + nexthop_ifindex_add (rib, index); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + if (rib->nexthop_num == 0) + XFREE (MTYPE_RIB, rib); + else + rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); + } } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) @@ -867,7 +931,66 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0, SAFI_UNICAST); + { + if (!tb[RTA_MULTIPATH]) + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, + metric, 0, SAFI_UNICAST); + else + { + /* This is a multipath route */ + + struct rib *rib; + struct rtnexthop *rtnh = + (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); + + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + rib->type = ZEBRA_ROUTE_KERNEL; + rib->distance = 0; + rib->flags = 0; + rib->metric = metric; + rib->table = table; + rib->nexthop_num = 0; + rib->uptime = time (NULL); + + for (;;) + { + if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) + break; + + rib->nexthop_num++; + index = rtnh->rtnh_ifindex; + gate = 0; + if (rtnh->rtnh_len > sizeof (*rtnh)) + { + memset (tb, 0, sizeof (tb)); + netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), + rtnh->rtnh_len - sizeof (*rtnh)); + if (tb[RTA_GATEWAY]) + gate = RTA_DATA (tb[RTA_GATEWAY]); + } + + if (gate) + { + if (index) + nexthop_ipv4_ifindex_add (rib, gate, src, index); + else + nexthop_ipv4_add (rib, gate, src); + } + else + nexthop_ifindex_add (rib, index); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + if (rib->nexthop_num == 0) + XFREE (MTYPE_RIB, rib); + else + rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); + } + } else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); } @@ -960,6 +1083,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; + netlink_interface_update_hw_addr (tb, ifp); + /* If new link is added. */ if_add_update (ifp); } @@ -970,6 +1095,8 @@ netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; + netlink_interface_update_hw_addr (tb, ifp); + if (if_is_operative (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f7f4d0a2..2fa439c0 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -232,7 +232,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) return nexthop; } -static struct nexthop * +struct nexthop * nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src, unsigned int ifindex) { @@ -1279,14 +1279,30 @@ rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { + char buf[INET_ADDRSTRLEN]; + assert (zebra && rn); if (IS_ZEBRA_DEBUG_RIB_Q) + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + + /* Pointless to queue a route_node with no RIB entries to add or remove */ + if (!rn->info) { - char buf[INET6_ADDRSTRLEN]; + zlog_debug ("%s: called for route_node (%p, %d) with no ribs", + __func__, rn, rn->lock); + zlog_backtrace(LOG_DEBUG); + return; + } + + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); - zlog_info ("%s: %s/%d: work queue added", __func__, - inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN), - rn->p.prefixlen); + assert (zebra); + + if (zebra->ribq == NULL) + { + zlog_err ("%s: work_queue does not exist!", __func__); + return; } /* @@ -1301,6 +1317,11 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) work_queue_add (zebra->ribq, zebra->mq); rib_meta_queue_add (zebra->mq, rn); + + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn); + + return; } /* Create new meta queue. @@ -1328,6 +1349,8 @@ meta_queue_new (void) static void rib_queue_init (struct zebra_t *zebra) { + assert (zebra); + if (! (zebra->ribq = work_queue_new (zebra->master, "route_node processing"))) { @@ -1343,7 +1366,11 @@ rib_queue_init (struct zebra_t *zebra) zebra->ribq->spec.hold = rib_process_hold_time; if (!(zebra->mq = meta_queue_new ())) + { zlog_err ("%s: could not initialise meta queue!", __func__); + return; + } + return; } /* RIB updates are processed via a queue of pointers to route_nodes. @@ -2893,6 +2920,62 @@ rib_sweep_route (void) rib_sweep_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); rib_sweep_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); } + +/* Delete routes learned from a given client. */ +/* TODO(wsun) May need to split the sweep process into multiple batches, + * so that the process won't take too long if the table is large. */ +static void +rib_sweep_client_table (struct route_table *table, int rib_type) +{ + struct route_node *rn; + struct rib *rib; + struct rib *next; + int ret = 0; + + if (table) + for (rn = route_top (table); rn; rn = route_next (rn)) + for (rib = rn->info; rib; rib = next) + { + next = rib->next; + + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == rib_type) + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + { + /* TODO(wsun) Is this mandatory? What about graceful restart/ + * non-stop forwarding */ + ret = rib_uninstall_kernel (rn, rib); + if (! ret) + rib_delnode (rn, rib); + else + zlog_err ("%s: could not delete routes from kernel!", + __func__); + } + else + { + /* Always delete the node. */ + rib_delnode (rn, rib); + } + } +} + +/* Sweep all routes learned from a given client from RIB tables. */ +void +rib_sweep_client_route (struct zserv *client) +{ + assert(client); + int route_type = client->route_type; + if (route_type != ZEBRA_ROUTE_MAX) + { + zlog_debug ("%s: Removing existing routes from client type %d", + __func__, route_type); + rib_sweep_client_table (vrf_table (AFI_IP, SAFI_UNICAST, 0), route_type); + rib_sweep_client_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0), route_type); + } +} + /* Remove specific by protocol routes from 'table'. */ static unsigned long diff --git a/zebra/zserv.c b/zebra/zserv.c index 672dee88..b1f539d3 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -140,6 +140,30 @@ zserv_create_header (struct stream *s, uint16_t cmd) stream_putw (s, cmd); } +static void +zserv_encode_interface (struct stream *s, struct interface *ifp) +{ + /* Interface information. */ + stream_put (s, ifp->name, INTERFACE_NAMSIZ); + stream_putl (s, ifp->ifindex); + stream_putc (s, ifp->status); + stream_putq (s, ifp->flags); + stream_putl (s, ifp->metric); + stream_putl (s, ifp->mtu); + stream_putl (s, ifp->mtu6); + stream_putl (s, ifp->bandwidth); +#ifdef HAVE_STRUCT_SOCKADDR_DL + stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); +#else + stream_putl (s, ifp->hw_addr_len); + if (ifp->hw_addr_len) + stream_put (s, ifp->hw_addr, ifp->hw_addr_len); +#endif /* HAVE_STRUCT_SOCKADDR_DL */ + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); +} + /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ /* * This function is called in the following situations: @@ -163,28 +187,8 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset (s); - /* Message type. */ zserv_create_header (s, ZEBRA_INTERFACE_ADD); - - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); -#ifdef HAVE_STRUCT_SOCKADDR_DL - stream_put (s, &ifp->sdl, sizeof (ifp->sdl)); -#else - stream_putl (s, ifp->hw_addr_len); - if (ifp->hw_addr_len) - stream_put (s, ifp->hw_addr, ifp->hw_addr_len); -#endif /* HAVE_STRUCT_SOCKADDR_DL */ - - /* Write packet size. */ - stream_putw_at (s, 0, stream_get_endp (s)); + zserv_encode_interface (s, ifp); return zebra_server_send_message(client); } @@ -201,21 +205,9 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) s = client->obuf; stream_reset (s); - - zserv_create_header (s, ZEBRA_INTERFACE_DELETE); - - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); - /* Write packet length. */ - stream_putw_at (s, 0, stream_get_endp (s)); + zserv_create_header (s, ZEBRA_INTERFACE_DELETE); + zserv_encode_interface (s, ifp); return zebra_server_send_message (client); } @@ -328,19 +320,7 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) stream_reset (s); zserv_create_header (s, cmd); - - /* Interface information. */ - stream_put (s, ifp->name, INTERFACE_NAMSIZ); - stream_putl (s, ifp->ifindex); - stream_putc (s, ifp->status); - stream_putq (s, ifp->flags); - stream_putl (s, ifp->metric); - stream_putl (s, ifp->mtu); - stream_putl (s, ifp->mtu6); - stream_putl (s, ifp->bandwidth); - - /* Write packet size. */ - stream_putw_at (s, 0, stream_get_endp (s)); + zserv_encode_interface (s, ifp); return zebra_server_send_message(client); } @@ -761,6 +741,13 @@ zread_ipv4_add (struct zserv *client, u_short length) /* Type, flags, message. */ rib->type = stream_getc (s); + /* Update client's route type if it is not done yet. */ + /* It is done here since only zread_ipv4/6_add() and + * zread_ipv4/6_delete() decode Zebra messages and retrieve + * route types. */ + if (client->route_type == ZEBRA_ROUTE_MAX) + client->route_type = rib->type; + rib->flags = stream_getc (s); message = stream_getc (s); safi = stream_getw (s); @@ -798,10 +785,10 @@ zread_ipv4_add (struct zserv *client, u_short length) case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; - case ZEBRA_NEXTHOP_BLACKHOLE: - nexthop_blackhole_add (rib); - break; - } + case ZEBRA_NEXTHOP_BLACKHOLE: + nexthop_blackhole_add (rib); + break; + } } } @@ -826,7 +813,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) int i; struct stream *s; struct zapi_ipv4 api; - struct in_addr nexthop; + struct in_addr nexthop, *nexthop_p; unsigned long ifindex; struct prefix_ipv4 p; u_char nexthop_num; @@ -836,6 +823,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) s = client->ibuf; ifindex = 0; nexthop.s_addr = 0; + nexthop_p = NULL; /* Type, flags, message. */ api.type = stream_getc (s); @@ -869,6 +857,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); + nexthop_p = &nexthop; break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); @@ -889,7 +878,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) else api.metric = 0; - rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, + rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, client->rtm_table, api.safi); return 0; } @@ -935,6 +924,11 @@ zread_ipv6_add (struct zserv *client, u_short length) /* Type, flags, message. */ api.type = stream_getc (s); + /* Update the route type of the client. + * Same as in zread_ipv4_add(). */ + if (client->route_type == ZEBRA_ROUTE_MAX) + client->route_type = api.type; + api.flags = stream_getc (s); api.message = stream_getc (s); api.safi = stream_getw (s); @@ -1133,6 +1127,14 @@ zebra_score_rib (int client_sock) static void zebra_client_close (struct zserv *client) { + struct stream *s; + + /* Sweep all routes learned from the client first. */ + rib_sweep_client_route(client); + /* Reset the route type. It may not be necessary since the + * whole client will be freed. */ + client->route_type = ZEBRA_ROUTE_MAX; + /* Close file descriptor. */ if (client->sock) { @@ -1172,6 +1174,9 @@ zebra_client_create (int sock) /* Make client input/output buffer. */ client->sock = sock; + /* Set the default route type to ZEBRA_ROUTE_MAX; it will be updated + * once new routes are received. */ + client->route_type = ZEBRA_ROUTE_MAX; client->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); client->wb = buffer_new(0); diff --git a/zebra/zserv.h b/zebra/zserv.h index 5e8bccac..3d7ebbcd 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -38,6 +38,10 @@ struct zserv /* Client file descriptor. */ int sock; + /* Client route type. */ + /* Assuming each client contains only one type of route. */ + int route_type; + /* Input/output buffer to the client. */ struct stream *ibuf; struct stream *obuf; |