Annotation of embedaddon/quagga/isisd/isis_adjacency.c, revision 1.1.1.2
1.1 misho 1: /*
2: * IS-IS Rout(e)ing protocol - isis_adjacency.c
3: * handling of IS-IS adjacencies
4: *
5: * Copyright (C) 2001,2002 Sampo Saaristo
6: * Tampere University of Technology
7: * Institute of Communications Engineering
8: *
9: * This program is free software; you can redistribute it and/or modify it
10: * under the terms of the GNU General Public Licenseas published by the Free
11: * Software Foundation; either version 2 of the License, or (at your option)
12: * any later version.
13: *
14: * This program is distributed in the hope that it will be useful,but WITHOUT
15: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17: * more details.
18:
19: * You should have received a copy of the GNU General Public License along
20: * with this program; if not, write to the Free Software Foundation, Inc.,
21: * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22: */
23:
24: #include <zebra.h>
25:
26: #include "log.h"
27: #include "memory.h"
28: #include "hash.h"
29: #include "vty.h"
30: #include "linklist.h"
31: #include "thread.h"
32: #include "if.h"
33: #include "stream.h"
34:
35: #include "isisd/dict.h"
36: #include "isisd/include-netbsd/iso.h"
37: #include "isisd/isis_constants.h"
38: #include "isisd/isis_common.h"
1.1.1.2 ! misho 39: #include "isisd/isis_flags.h"
1.1 misho 40: #include "isisd/isisd.h"
41: #include "isisd/isis_circuit.h"
42: #include "isisd/isis_adjacency.h"
43: #include "isisd/isis_misc.h"
44: #include "isisd/isis_dr.h"
45: #include "isisd/isis_dynhn.h"
46: #include "isisd/isis_pdu.h"
1.1.1.2 ! misho 47: #include "isisd/isis_tlv.h"
! 48: #include "isisd/isis_lsp.h"
! 49: #include "isisd/isis_spf.h"
! 50: #include "isisd/isis_events.h"
1.1 misho 51:
52: extern struct isis *isis;
53:
54: static struct isis_adjacency *
55: adj_alloc (u_char * id)
56: {
57: struct isis_adjacency *adj;
58:
59: adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
60: memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
61:
62: return adj;
63: }
64:
65: struct isis_adjacency *
66: isis_new_adj (u_char * id, u_char * snpa, int level,
67: struct isis_circuit *circuit)
68: {
69: struct isis_adjacency *adj;
70: int i;
71:
72: adj = adj_alloc (id); /* P2P kludge */
73:
74: if (adj == NULL)
75: {
76: zlog_err ("Out of memory!");
77: return NULL;
78: }
79:
80: if (snpa) {
1.1.1.2 ! misho 81: memcpy (adj->snpa, snpa, ETH_ALEN);
1.1 misho 82: } else {
1.1.1.2 ! misho 83: memset (adj->snpa, ' ', ETH_ALEN);
1.1 misho 84: }
85:
86: adj->circuit = circuit;
87: adj->level = level;
88: adj->flaps = 0;
89: adj->last_flap = time (NULL);
90: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
91: {
92: listnode_add (circuit->u.bc.adjdb[level - 1], adj);
93: adj->dischanges[level - 1] = 0;
94: for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
95: {
96: adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
97: = ISIS_UNKNOWN_DIS;
98: adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
99: = time (NULL);
100: }
101: }
102:
103: return adj;
104: }
105:
106: struct isis_adjacency *
107: isis_adj_lookup (u_char * sysid, struct list *adjdb)
108: {
109: struct isis_adjacency *adj;
110: struct listnode *node;
111:
112: for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
113: if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
114: return adj;
115:
116: return NULL;
117: }
118:
119: struct isis_adjacency *
120: isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
121: {
122: struct listnode *node;
123: struct isis_adjacency *adj;
124:
125: for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
126: if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
127: return adj;
128:
129: return NULL;
130: }
131:
132: void
1.1.1.2 ! misho 133: isis_delete_adj (void *arg)
1.1 misho 134: {
1.1.1.2 ! misho 135: struct isis_adjacency *adj = arg;
! 136:
1.1 misho 137: if (!adj)
138: return;
139:
1.1.1.2 ! misho 140: THREAD_TIMER_OFF (adj->t_expire);
! 141:
! 142: /* remove from SPF trees */
! 143: spftree_area_adj_del (adj->circuit->area, adj);
1.1 misho 144:
1.1.1.2 ! misho 145: if (adj->area_addrs)
! 146: list_delete (adj->area_addrs);
1.1 misho 147: if (adj->ipv4_addrs)
148: list_delete (adj->ipv4_addrs);
149: #ifdef HAVE_IPV6
150: if (adj->ipv6_addrs)
151: list_delete (adj->ipv6_addrs);
152: #endif
1.1.1.2 ! misho 153:
1.1 misho 154: XFREE (MTYPE_ISIS_ADJACENCY, adj);
155: return;
156: }
157:
1.1.1.2 ! misho 158: static const char *
! 159: adj_state2string (int state)
! 160: {
! 161:
! 162: switch (state)
! 163: {
! 164: case ISIS_ADJ_INITIALIZING:
! 165: return "Initializing";
! 166: case ISIS_ADJ_UP:
! 167: return "Up";
! 168: case ISIS_ADJ_DOWN:
! 169: return "Down";
! 170: default:
! 171: return "Unknown";
! 172: }
! 173:
! 174: return NULL; /* not reached */
! 175: }
! 176:
1.1 misho 177: void
1.1.1.2 ! misho 178: isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
1.1 misho 179: const char *reason)
180: {
181: int old_state;
1.1.1.2 ! misho 182: int level;
1.1 misho 183: struct isis_circuit *circuit;
184:
185: old_state = adj->adj_state;
1.1.1.2 ! misho 186: adj->adj_state = new_state;
1.1 misho 187:
188: circuit = adj->circuit;
189:
190: if (isis->debugs & DEBUG_ADJ_PACKETS)
191: {
192: zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
193: circuit->area->area_tag,
1.1.1.2 ! misho 194: old_state, new_state, reason ? reason : "unspecified");
1.1 misho 195: }
196:
1.1.1.2 ! misho 197: if (circuit->area->log_adj_changes)
1.1 misho 198: {
1.1.1.2 ! misho 199: const char *adj_name;
! 200: struct isis_dynhn *dyn;
! 201:
! 202: dyn = dynhn_find_by_id (adj->sysid);
! 203: if (dyn)
! 204: adj_name = (const char *)dyn->name.name;
! 205: else
! 206: adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown";
! 207:
! 208: zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
! 209: adj_name,
! 210: adj->circuit ? adj->circuit->interface->name : "no circuit",
! 211: adj_state2string (old_state),
! 212: adj_state2string (new_state),
! 213: reason ? reason : "unspecified");
! 214: }
1.1 misho 215:
1.1.1.2 ! misho 216: if (circuit->circ_type == CIRCUIT_T_BROADCAST)
! 217: {
! 218: for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
! 219: {
! 220: if ((adj->level & level) == 0)
! 221: continue;
! 222: if (new_state == ISIS_ADJ_UP)
! 223: {
! 224: circuit->upadjcount[level - 1]++;
! 225: isis_event_adjacency_state_change (adj, new_state);
! 226: /* update counter & timers for debugging purposes */
! 227: adj->last_flap = time (NULL);
! 228: adj->flaps++;
! 229: }
! 230: else if (new_state == ISIS_ADJ_DOWN)
! 231: {
! 232: listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
! 233: circuit->upadjcount[level - 1]--;
! 234: if (circuit->upadjcount[level - 1] == 0)
! 235: {
! 236: /* Clean lsp_queue when no adj is up. */
! 237: if (circuit->lsp_queue)
! 238: list_delete_all_node (circuit->lsp_queue);
! 239: }
! 240: isis_event_adjacency_state_change (adj, new_state);
! 241: isis_delete_adj (adj);
! 242: }
! 243:
! 244: if (circuit->u.bc.lan_neighs[level - 1])
! 245: {
! 246: list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
! 247: isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
! 248: circuit->u.bc.lan_neighs[level - 1]);
! 249: }
! 250:
! 251: /* On adjacency state change send new pseudo LSP if we are the DR */
! 252: if (circuit->u.bc.is_dr[level - 1])
! 253: lsp_regenerate_schedule_pseudo (circuit, level);
! 254: }
! 255: }
! 256: else if (circuit->circ_type == CIRCUIT_T_P2P)
! 257: {
! 258: for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
! 259: {
! 260: if ((adj->level & level) == 0)
! 261: continue;
! 262: if (new_state == ISIS_ADJ_UP)
! 263: {
! 264: circuit->upadjcount[level - 1]++;
! 265: isis_event_adjacency_state_change (adj, new_state);
! 266:
! 267: if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
! 268: send_hello (circuit, level);
! 269:
! 270: /* update counter & timers for debugging purposes */
! 271: adj->last_flap = time (NULL);
! 272: adj->flaps++;
! 273:
! 274: /* 7.3.17 - going up on P2P -> send CSNP */
! 275: /* FIXME: yup, I know its wrong... but i will do it! (for now) */
! 276: send_csnp (circuit, level);
! 277: }
! 278: else if (new_state == ISIS_ADJ_DOWN)
! 279: {
! 280: if (adj->circuit->u.p2p.neighbor == adj)
! 281: adj->circuit->u.p2p.neighbor = NULL;
! 282: circuit->upadjcount[level - 1]--;
! 283: if (circuit->upadjcount[level - 1] == 0)
! 284: {
! 285: /* Clean lsp_queue when no adj is up. */
! 286: if (circuit->lsp_queue)
! 287: list_delete_all_node (circuit->lsp_queue);
! 288: }
! 289: isis_event_adjacency_state_change (adj, new_state);
! 290: isis_delete_adj (adj);
! 291: }
! 292: }
1.1 misho 293: }
1.1.1.2 ! misho 294:
1.1 misho 295: return;
296: }
297:
298:
299: void
300: isis_adj_print (struct isis_adjacency *adj)
301: {
302: struct isis_dynhn *dyn;
303: struct listnode *node;
304: struct in_addr *ipv4_addr;
305: #ifdef HAVE_IPV6
306: struct in6_addr *ipv6_addr;
307: u_char ip6[INET6_ADDRSTRLEN];
308: #endif /* HAVE_IPV6 */
309:
310: if (!adj)
311: return;
312: dyn = dynhn_find_by_id (adj->sysid);
313: if (dyn)
314: zlog_debug ("%s", dyn->name.name);
315:
316: zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
317: adj->sysid ? sysid_print (adj->sysid) : "unknown",
318: snpa_print (adj->snpa), adj->level, adj->hold_time);
319: if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
320: {
1.1.1.2 ! misho 321: zlog_debug ("IPv4 Address(es):");
1.1 misho 322:
323: for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
324: zlog_debug ("%s", inet_ntoa (*ipv4_addr));
325: }
326:
327: #ifdef HAVE_IPV6
328: if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
329: {
1.1.1.2 ! misho 330: zlog_debug ("IPv6 Address(es):");
1.1 misho 331: for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
332: {
333: inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
334: zlog_debug ("%s", ip6);
335: }
336: }
337: #endif /* HAVE_IPV6 */
338: zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids));
339:
340: return;
341: }
342:
343: int
344: isis_adj_expire (struct thread *thread)
345: {
346: struct isis_adjacency *adj;
347:
348: /*
349: * Get the adjacency
350: */
351: adj = THREAD_ARG (thread);
352: assert (adj);
353: adj->t_expire = NULL;
354:
355: /* trigger the adj expire event */
356: isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
357:
358: return 0;
359: }
360:
361: /*
1.1.1.2 ! misho 362: * show isis neighbor [detail]
1.1 misho 363: */
1.1.1.2 ! misho 364: void
! 365: isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
1.1 misho 366: {
367: #ifdef HAVE_IPV6
368: struct in6_addr *ipv6_addr;
369: u_char ip6[INET6_ADDRSTRLEN];
370: #endif /* HAVE_IPV6 */
371: struct in_addr *ip_addr;
372: time_t now;
373: struct isis_dynhn *dyn;
374: int level;
375: struct listnode *node;
376:
377: dyn = dynhn_find_by_id (adj->sysid);
378: if (dyn)
379: vty_out (vty, " %-20s", dyn->name.name);
380: else if (adj->sysid)
381: {
382: vty_out (vty, " %-20s", sysid_print (adj->sysid));
383: }
384: else
385: {
386: vty_out (vty, " unknown ");
387: }
388:
389: if (detail == ISIS_UI_LEVEL_BRIEF)
390: {
391: if (adj->circuit)
392: vty_out (vty, "%-12s", adj->circuit->interface->name);
393: else
394: vty_out (vty, "NULL circuit!");
395: vty_out (vty, "%-3u", adj->level); /* level */
396: vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
397: now = time (NULL);
398: if (adj->last_upd)
399: vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now);
400: else
401: vty_out (vty, "- ");
402: vty_out (vty, "%-10s", snpa_print (adj->snpa));
403: vty_out (vty, "%s", VTY_NEWLINE);
404: }
405:
406: if (detail == ISIS_UI_LEVEL_DETAIL)
407: {
408: level = adj->level;
1.1.1.2 ! misho 409: vty_out (vty, "%s", VTY_NEWLINE);
1.1 misho 410: if (adj->circuit)
1.1.1.2 ! misho 411: vty_out (vty, " Interface: %s", adj->circuit->interface->name);
1.1 misho 412: else
1.1.1.2 ! misho 413: vty_out (vty, " Interface: NULL circuit");
1.1 misho 414: vty_out (vty, ", Level: %u", adj->level); /* level */
415: vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
416: now = time (NULL);
417: if (adj->last_upd)
418: vty_out (vty, ", Expires in %s",
419: time2string (adj->last_upd + adj->hold_time - now));
420: else
421: vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
1.1.1.2 ! misho 422: vty_out (vty, "%s", VTY_NEWLINE);
! 423: vty_out (vty, " Adjacency flaps: %u", adj->flaps);
1.1 misho 424: vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
1.1.1.2 ! misho 425: vty_out (vty, "%s", VTY_NEWLINE);
! 426: vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t));
1.1 misho 427: vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
1.1.1.2 ! misho 428: vty_out (vty, "%s", VTY_NEWLINE);
! 429: vty_out (vty, " SNPA: %s", snpa_print (adj->snpa));
! 430: if (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)
! 431: {
! 432: dyn = dynhn_find_by_id (adj->lanid);
! 433: if (dyn)
! 434: vty_out (vty, ", LAN id: %s.%02x",
! 435: dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
! 436: else
! 437: vty_out (vty, ", LAN id: %s.%02x",
! 438: sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
! 439:
! 440: vty_out (vty, "%s", VTY_NEWLINE);
! 441: vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]);
! 442:
! 443: vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
! 444: isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
! 445: dis), adj->dischanges[level - 1],
! 446: time2string (now -
! 447: (adj->dis_record[ISIS_LEVELS + level - 1].
! 448: last_dis_change)));
! 449: }
! 450: vty_out (vty, "%s", VTY_NEWLINE);
1.1 misho 451:
1.1.1.2 ! misho 452: if (adj->area_addrs && listcount (adj->area_addrs) > 0)
! 453: {
! 454: struct area_addr *area_addr;
! 455: vty_out (vty, " Area Address(es):%s", VTY_NEWLINE);
! 456: for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
! 457: vty_out (vty, " %s%s", isonet_print (area_addr->area_addr,
! 458: area_addr->addr_len), VTY_NEWLINE);
! 459: }
1.1 misho 460: if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
461: {
1.1.1.2 ! misho 462: vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE);
1.1 misho 463: for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
464: vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
465: }
466: #ifdef HAVE_IPV6
467: if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
468: {
1.1.1.2 ! misho 469: vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE);
1.1 misho 470: for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
471: {
472: inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
473: vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
474: }
475: }
476: #endif /* HAVE_IPV6 */
477: vty_out (vty, "%s", VTY_NEWLINE);
478: }
479: return;
480: }
481:
482: void
483: isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
484: {
485: struct isis_adjacency *adj;
486: struct listnode *node;
487:
488: if (!list)
489: {
490: zlog_warn ("isis_adj_build_neigh_list(): NULL list");
491: return;
492: }
493:
494: for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
495: {
496: if (!adj)
497: {
498: zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
499: return;
500: }
501:
502: if ((adj->adj_state == ISIS_ADJ_UP ||
503: adj->adj_state == ISIS_ADJ_INITIALIZING))
504: listnode_add (list, adj->snpa);
505: }
506: return;
507: }
508:
509: void
510: isis_adj_build_up_list (struct list *adjdb, struct list *list)
511: {
512: struct isis_adjacency *adj;
513: struct listnode *node;
514:
515: if (!list)
516: {
517: zlog_warn ("isis_adj_build_up_list(): NULL list");
518: return;
519: }
520:
521: for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
522: {
523: if (!adj)
524: {
525: zlog_warn ("isis_adj_build_up_list(): NULL adj");
526: return;
527: }
528:
529: if (adj->adj_state == ISIS_ADJ_UP)
530: listnode_add (list, adj);
531: }
532:
533: return;
534: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>