isisd: add Google's changes to IS-IS
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index aab8d1a..10bce3e 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -36,6 +36,7 @@
#include "isisd/include-netbsd/iso.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
#include "isisd/isisd.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_adjacency.h"
@@ -43,6 +44,10 @@
#include "isisd/isis_dr.h"
#include "isisd/isis_dynhn.h"
#include "isisd/isis_pdu.h"
+#include "isisd/isis_tlv.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_events.h"
extern struct isis *isis;
@@ -73,9 +78,9 @@
}
if (snpa) {
- memcpy (adj->snpa, snpa, 6);
+ memcpy (adj->snpa, snpa, ETH_ALEN);
} else {
- memset (adj->snpa, ' ', 6);
+ memset (adj->snpa, ' ', ETH_ALEN);
}
adj->circuit = circuit;
@@ -125,37 +130,60 @@
}
void
-isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
+isis_delete_adj (void *arg)
{
+ struct isis_adjacency *adj = arg;
+
if (!adj)
return;
- /* When we recieve a NULL list, we will know its p2p. */
- if (adjdb)
- listnode_delete (adjdb, adj);
- THREAD_OFF (adj->t_expire);
+ THREAD_TIMER_OFF (adj->t_expire);
+ /* remove from SPF trees */
+ spftree_area_adj_del (adj->circuit->area, adj);
+
+ if (adj->area_addrs)
+ list_delete (adj->area_addrs);
if (adj->ipv4_addrs)
list_delete (adj->ipv4_addrs);
#ifdef HAVE_IPV6
if (adj->ipv6_addrs)
list_delete (adj->ipv6_addrs);
#endif
-
+
XFREE (MTYPE_ISIS_ADJACENCY, adj);
return;
}
+static const char *
+adj_state2string (int state)
+{
+
+ switch (state)
+ {
+ case ISIS_ADJ_INITIALIZING:
+ return "Initializing";
+ case ISIS_ADJ_UP:
+ return "Up";
+ case ISIS_ADJ_DOWN:
+ return "Down";
+ default:
+ return "Unknown";
+ }
+
+ return NULL; /* not reached */
+}
+
void
-isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
+isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
const char *reason)
{
int old_state;
- int level = adj->level;
+ int level;
struct isis_circuit *circuit;
old_state = adj->adj_state;
- adj->adj_state = state;
+ adj->adj_state = new_state;
circuit = adj->circuit;
@@ -163,42 +191,103 @@
{
zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
circuit->area->area_tag,
- old_state, state, reason ? reason : "unspecified");
+ old_state, new_state, reason ? reason : "unspecified");
+ }
+
+ if (circuit->area->log_adj_changes)
+ {
+ const char *adj_name;
+ struct isis_dynhn *dyn;
+
+ dyn = dynhn_find_by_id (adj->sysid);
+ if (dyn)
+ adj_name = (const char *)dyn->name.name;
+ else
+ adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown";
+
+ zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
+ adj_name,
+ adj->circuit ? adj->circuit->interface->name : "no circuit",
+ adj_state2string (old_state),
+ adj_state2string (new_state),
+ reason ? reason : "unspecified");
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST)
{
- if (state == ISIS_ADJ_UP)
- circuit->upadjcount[level - 1]++;
- if (state == ISIS_ADJ_DOWN)
- {
- isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
- circuit->upadjcount[level - 1]--;
- }
+ for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
+ {
+ if ((adj->level & level) == 0)
+ continue;
+ if (new_state == ISIS_ADJ_UP)
+ {
+ circuit->upadjcount[level - 1]++;
+ isis_event_adjacency_state_change (adj, new_state);
+ /* update counter & timers for debugging purposes */
+ adj->last_flap = time (NULL);
+ adj->flaps++;
+ }
+ else if (new_state == ISIS_ADJ_DOWN)
+ {
+ listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
+ circuit->upadjcount[level - 1]--;
+ if (circuit->upadjcount[level - 1] == 0)
+ {
+ /* Clean lsp_queue when no adj is up. */
+ if (circuit->lsp_queue)
+ list_delete_all_node (circuit->lsp_queue);
+ }
+ isis_event_adjacency_state_change (adj, new_state);
+ isis_delete_adj (adj);
+ }
+ list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
+ isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
+ circuit->u.bc.lan_neighs[level - 1]);
- 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_UP)
- { /* p2p interface */
- if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
- send_hello (circuit, 1);
+ 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);
- /* update counter & timers for debugging purposes */
- adj->last_flap = time (NULL);
- adj->flaps++;
+ if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
+ send_hello (circuit, level);
- /* 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);
+ /* update counter & timers for debugging purposes */
+ adj->last_flap = time (NULL);
+ adj->flaps++;
+
+ /* 7.3.17 - going up on P2P -> send CSNP */
+ /* FIXME: yup, I know its wrong... but i will do it! (for now) */
+ send_csnp (circuit, level);
+ }
+ else if (new_state == ISIS_ADJ_DOWN)
+ {
+ if (adj->circuit->u.p2p.neighbor == adj)
+ adj->circuit->u.p2p.neighbor = NULL;
+ circuit->upadjcount[level - 1]--;
+ if (circuit->upadjcount[level - 1] == 0)
+ {
+ /* Clean lsp_queue when no adj is up. */
+ if (circuit->lsp_queue)
+ list_delete_all_node (circuit->lsp_queue);
+ }
+ isis_event_adjacency_state_change (adj, new_state);
+ isis_delete_adj (adj);
+ }
+ }
}
- else if (state == ISIS_ADJ_DOWN)
- { /* p2p interface */
- adj->circuit->u.p2p.neighbor = NULL;
- isis_delete_adj (adj, NULL);
- }
+
return;
}
@@ -225,7 +314,7 @@
snpa_print (adj->snpa), adj->level, adj->hold_time);
if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
{
- zlog_debug ("IPv4 Addresses:");
+ zlog_debug ("IPv4 Address(es):");
for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
zlog_debug ("%s", inet_ntoa (*ipv4_addr));
@@ -234,7 +323,7 @@
#ifdef HAVE_IPV6
if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
{
- zlog_debug ("IPv6 Addresses:");
+ zlog_debug ("IPv6 Address(es):");
for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
{
inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
@@ -251,14 +340,12 @@
isis_adj_expire (struct thread *thread)
{
struct isis_adjacency *adj;
- int level;
/*
* Get the adjacency
*/
adj = THREAD_ARG (thread);
assert (adj);
- level = adj->level;
adj->t_expire = NULL;
/* trigger the adj expire event */
@@ -267,32 +354,12 @@
return 0;
}
-static const char *
-adj_state2string (int state)
-{
-
- switch (state)
- {
- case ISIS_ADJ_INITIALIZING:
- return "Initializing";
- case ISIS_ADJ_UP:
- return "Up";
- case ISIS_ADJ_DOWN:
- return "Down";
- default:
- return "Unknown";
- }
-
- return NULL; /* not reached */
-}
-
/*
- * show clns/isis neighbor (detail)
+ * show isis neighbor [detail]
*/
-static void
-isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
+void
+isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
{
-
#ifdef HAVE_IPV6
struct in6_addr *ipv6_addr;
u_char ip6[INET6_ADDRSTRLEN];
@@ -335,10 +402,11 @@
if (detail == ISIS_UI_LEVEL_DETAIL)
{
level = adj->level;
+ vty_out (vty, "%s", VTY_NEWLINE);
if (adj->circuit)
- vty_out (vty, "%s Interface: %s", VTY_NEWLINE, adj->circuit->interface->name); /* interface name */
+ vty_out (vty, " Interface: %s", adj->circuit->interface->name);
else
- vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
+ vty_out (vty, " Interface: NULL circuit");
vty_out (vty, ", Level: %u", adj->level); /* level */
vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
now = time (NULL);
@@ -347,40 +415,54 @@
time2string (adj->last_upd + adj->hold_time - now));
else
vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
- vty_out (vty, "%s Adjacency flaps: %u", VTY_NEWLINE, adj->flaps);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " Adjacency flaps: %u", adj->flaps);
vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
- vty_out (vty, "%s Circuit type: %s",
- VTY_NEWLINE, circuit_t2string (adj->circuit_t));
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t));
vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
- vty_out (vty, "%s SNPA: %s", VTY_NEWLINE, snpa_print (adj->snpa));
- dyn = dynhn_find_by_id (adj->lanid);
- if (dyn)
- vty_out (vty, ", LAN id: %s.%02x",
- dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
- else
- vty_out (vty, ", LAN id: %s.%02x",
- sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " SNPA: %s", snpa_print (adj->snpa));
+ if (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)
+ {
+ dyn = dynhn_find_by_id (adj->lanid);
+ if (dyn)
+ vty_out (vty, ", LAN id: %s.%02x",
+ dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
+ else
+ vty_out (vty, ", LAN id: %s.%02x",
+ sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
- vty_out (vty, "%s Priority: %u",
- VTY_NEWLINE, adj->prio[adj->level - 1]);
+ vty_out (vty, "%s", VTY_NEWLINE);
+ vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]);
- vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
- isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
- dis), adj->dischanges[level - 1],
- time2string (now -
- (adj->dis_record[ISIS_LEVELS + level - 1].
- last_dis_change)), VTY_NEWLINE);
+ vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
+ isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
+ dis), adj->dischanges[level - 1],
+ time2string (now -
+ (adj->dis_record[ISIS_LEVELS + level - 1].
+ last_dis_change)));
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ if (adj->area_addrs && listcount (adj->area_addrs) > 0)
+ {
+ struct area_addr *area_addr;
+ vty_out (vty, " Area Address(es):%s", VTY_NEWLINE);
+ for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
+ vty_out (vty, " %s%s", isonet_print (area_addr->area_addr,
+ area_addr->addr_len), VTY_NEWLINE);
+ }
if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
{
- vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE);
+ vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
}
#ifdef HAVE_IPV6
if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
{
- vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE);
+ vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE);
for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
{
inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
@@ -394,53 +476,6 @@
}
void
-isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
-}
-
-void
-isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
-}
-
-void
-isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
-}
-
-void
-isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
-}
-
-void
-isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
-}
-
-void
-isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
-{
- isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
-}
-
-void
-isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *,
- void *), void *arg)
-{
- struct listnode *node, *nnode;
- struct isis_adjacency *adj;
-
- for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj))
- (*func) (adj, arg);
-}
-
-void
isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
{
struct isis_adjacency *adj;