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"
39: #include "isisd/isis_flags.h"
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"
47: #include "isisd/isis_tlv.h"
48: #include "isisd/isis_lsp.h"
49: #include "isisd/isis_spf.h"
50: #include "isisd/isis_events.h"
51:
52: extern struct isis *isis;
53:
54: static struct isis_adjacency *
55: adj_alloc (const 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 (const u_char * id, const 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) {
81: memcpy (adj->snpa, snpa, ETH_ALEN);
82: } else {
83: memset (adj->snpa, ' ', ETH_ALEN);
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 (const 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 (const 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
133: isis_delete_adj (void *arg)
134: {
135: struct isis_adjacency *adj = arg;
136:
137: if (!adj)
138: return;
139:
140: THREAD_TIMER_OFF (adj->t_expire);
141:
142: /* remove from SPF trees */
143: spftree_area_adj_del (adj->circuit->area, adj);
144:
145: if (adj->area_addrs)
146: list_delete (adj->area_addrs);
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
153:
154: XFREE (MTYPE_ISIS_ADJACENCY, adj);
155: return;
156: }
157:
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:
177: void
178: isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
179: const char *reason)
180: {
181: int old_state;
182: int level;
183: struct isis_circuit *circuit;
184:
185: old_state = adj->adj_state;
186: adj->adj_state = new_state;
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,
194: old_state, new_state, reason ? reason : "unspecified");
195: }
196:
197: if (circuit->area->log_adj_changes)
198: {
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 = sysid_print (adj->sysid);
207:
208: zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
209: adj_name,
210: adj->circuit->interface->name,
211: adj_state2string (old_state),
212: adj_state2string (new_state),
213: reason ? reason : "unspecified");
214: }
215:
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: }
293: }
294:
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: sysid_print (adj->sysid), snpa_print (adj->snpa),
318: adj->level, adj->hold_time);
319: if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
320: {
321: zlog_debug ("IPv4 Address(es):");
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: {
330: zlog_debug ("IPv6 Address(es):");
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: /*
362: * show isis neighbor [detail]
363: */
364: void
365: isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
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
381: vty_out (vty, " %-20s", sysid_print (adj->sysid));
382:
383: if (detail == ISIS_UI_LEVEL_BRIEF)
384: {
385: if (adj->circuit)
386: vty_out (vty, "%-12s", adj->circuit->interface->name);
387: else
388: vty_out (vty, "NULL circuit!");
389: vty_out (vty, "%-3u", adj->level); /* level */
390: vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
391: now = time (NULL);
392: if (adj->last_upd)
393: vty_out (vty, "%-9llu",
394: (unsigned long long)adj->last_upd + adj->hold_time - now);
395: else
396: vty_out (vty, "- ");
397: vty_out (vty, "%-10s", snpa_print (adj->snpa));
398: vty_out (vty, "%s", VTY_NEWLINE);
399: }
400:
401: if (detail == ISIS_UI_LEVEL_DETAIL)
402: {
403: level = adj->level;
404: vty_out (vty, "%s", VTY_NEWLINE);
405: if (adj->circuit)
406: vty_out (vty, " Interface: %s", adj->circuit->interface->name);
407: else
408: vty_out (vty, " Interface: NULL circuit");
409: vty_out (vty, ", Level: %u", adj->level); /* level */
410: vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
411: now = time (NULL);
412: if (adj->last_upd)
413: vty_out (vty, ", Expires in %s",
414: time2string (adj->last_upd + adj->hold_time - now));
415: else
416: vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
417: vty_out (vty, "%s", VTY_NEWLINE);
418: vty_out (vty, " Adjacency flaps: %u", adj->flaps);
419: vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
420: vty_out (vty, "%s", VTY_NEWLINE);
421: vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t));
422: vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
423: vty_out (vty, "%s", VTY_NEWLINE);
424: vty_out (vty, " SNPA: %s", snpa_print (adj->snpa));
425: if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST))
426: {
427: dyn = dynhn_find_by_id (adj->lanid);
428: if (dyn)
429: vty_out (vty, ", LAN id: %s.%02x",
430: dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
431: else
432: vty_out (vty, ", LAN id: %s.%02x",
433: sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
434:
435: vty_out (vty, "%s", VTY_NEWLINE);
436: vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]);
437:
438: vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
439: isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
440: dis), adj->dischanges[level - 1],
441: time2string (now -
442: (adj->dis_record[ISIS_LEVELS + level - 1].
443: last_dis_change)));
444: }
445: vty_out (vty, "%s", VTY_NEWLINE);
446:
447: if (adj->area_addrs && listcount (adj->area_addrs) > 0)
448: {
449: struct area_addr *area_addr;
450: vty_out (vty, " Area Address(es):%s", VTY_NEWLINE);
451: for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
452: vty_out (vty, " %s%s", isonet_print (area_addr->area_addr,
453: area_addr->addr_len), VTY_NEWLINE);
454: }
455: if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
456: {
457: vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE);
458: for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
459: vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
460: }
461: #ifdef HAVE_IPV6
462: if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
463: {
464: vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE);
465: for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
466: {
467: inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
468: vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
469: }
470: }
471: #endif /* HAVE_IPV6 */
472: vty_out (vty, "%s", VTY_NEWLINE);
473: }
474: return;
475: }
476:
477: void
478: isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
479: {
480: struct isis_adjacency *adj;
481: struct listnode *node;
482:
483: if (!list)
484: {
485: zlog_warn ("isis_adj_build_neigh_list(): NULL list");
486: return;
487: }
488:
489: for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
490: {
491: if (!adj)
492: {
493: zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
494: return;
495: }
496:
497: if ((adj->adj_state == ISIS_ADJ_UP ||
498: adj->adj_state == ISIS_ADJ_INITIALIZING))
499: listnode_add (list, adj->snpa);
500: }
501: return;
502: }
503:
504: void
505: isis_adj_build_up_list (struct list *adjdb, struct list *list)
506: {
507: struct isis_adjacency *adj;
508: struct listnode *node;
509:
510: if (!list)
511: {
512: zlog_warn ("isis_adj_build_up_list(): NULL list");
513: return;
514: }
515:
516: for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
517: {
518: if (!adj)
519: {
520: zlog_warn ("isis_adj_build_up_list(): NULL adj");
521: return;
522: }
523:
524: if (adj->adj_state == ISIS_ADJ_UP)
525: listnode_add (list, adj);
526: }
527:
528: return;
529: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>