Annotation of embedaddon/quagga/isisd/isis_adjacency.c, revision 1.1.1.3
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,
1.1.1.3 ! misho 210: adj->circuit->interface->name,
1.1.1.2 misho 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));
1.1.1.3 ! misho 430: if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST))
1.1.1.2 misho 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>