blob: 3770ebded84476a8036c137a655c81569e90a04c [file] [log] [blame]
jardineb5d44e2003-12-23 08:09:43 +00001/*
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 <stdio.h>
25#include <limits.h>
26#include <string.h>
27#include <zebra.h>
jardineb5d44e2003-12-23 08:09:43 +000028
29#include "log.h"
30#include "memory.h"
31#include "hash.h"
32#include "vty.h"
33#include "linklist.h"
34#include "thread.h"
35#include "if.h"
36#include "stream.h"
37
38#include "isisd/dict.h"
39#include "isisd/include-netbsd/iso.h"
40#include "isisd/isis_constants.h"
41#include "isisd/isis_common.h"
42#include "isisd/isisd.h"
43#include "isisd/isis_circuit.h"
44#include "isisd/isis_adjacency.h"
45#include "isisd/isis_misc.h"
46#include "isisd/isis_dr.h"
47#include "isisd/isis_dynhn.h"
48#include "isisd/isis_pdu.h"
49
jardineb5d44e2003-12-23 08:09:43 +000050extern struct isis *isis;
51
jardineb5d44e2003-12-23 08:09:43 +000052struct isis_adjacency *
hassof390d2c2004-09-10 20:48:21 +000053adj_alloc (u_char * id)
jardineb5d44e2003-12-23 08:09:43 +000054{
hassof390d2c2004-09-10 20:48:21 +000055 struct isis_adjacency *adj;
jardineb5d44e2003-12-23 08:09:43 +000056
hassof390d2c2004-09-10 20:48:21 +000057 adj = XMALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
58 memset (adj, 0, sizeof (struct isis_adjacency));
59 memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
60
61 return adj;
jardineb5d44e2003-12-23 08:09:43 +000062}
63
64struct isis_adjacency *
hassof390d2c2004-09-10 20:48:21 +000065isis_new_adj (u_char * id, u_char * snpa, int level,
jardineb5d44e2003-12-23 08:09:43 +000066 struct isis_circuit *circuit)
67{
jardineb5d44e2003-12-23 08:09:43 +000068 struct isis_adjacency *adj;
hassof390d2c2004-09-10 20:48:21 +000069 int i;
jardineb5d44e2003-12-23 08:09:43 +000070
hassof390d2c2004-09-10 20:48:21 +000071 adj = adj_alloc (id); /* P2P kludge */
72
73 if (adj == NULL)
74 {
75 zlog_err ("Out of memory!");
76 return NULL;
77 }
jardineb5d44e2003-12-23 08:09:43 +000078
79 memcpy (adj->snpa, snpa, 6);
80 adj->circuit = circuit;
81 adj->level = level;
82 adj->flaps = 0;
83 adj->last_flap = time (NULL);
hassof390d2c2004-09-10 20:48:21 +000084 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
85 {
86 listnode_add (circuit->u.bc.adjdb[level - 1], adj);
87 adj->dischanges[level - 1] = 0;
88 for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
jardineb5d44e2003-12-23 08:09:43 +000089 {
hassof390d2c2004-09-10 20:48:21 +000090 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
jardineb5d44e2003-12-23 08:09:43 +000091 = ISIS_UNKNOWN_DIS;
hassof390d2c2004-09-10 20:48:21 +000092 adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
93 = time (NULL);
jardineb5d44e2003-12-23 08:09:43 +000094 }
hassof390d2c2004-09-10 20:48:21 +000095 }
jardineb5d44e2003-12-23 08:09:43 +000096
97 return adj;
98}
99
100struct isis_adjacency *
hassof390d2c2004-09-10 20:48:21 +0000101isis_adj_lookup (u_char * sysid, struct list *adjdb)
jardineb5d44e2003-12-23 08:09:43 +0000102{
103 struct isis_adjacency *adj;
104 struct listnode *node;
105
hassof390d2c2004-09-10 20:48:21 +0000106 for (node = listhead (adjdb); node; nextnode (node))
107 {
108 adj = getdata (node);
109 if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
110 return adj;
111 }
112
jardineb5d44e2003-12-23 08:09:43 +0000113 return NULL;
114}
115
116
117struct isis_adjacency *
hassof390d2c2004-09-10 20:48:21 +0000118isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
jardineb5d44e2003-12-23 08:09:43 +0000119{
120 struct listnode *node;
121 struct isis_adjacency *adj;
122
hassof390d2c2004-09-10 20:48:21 +0000123 for (node = listhead (adjdb); node; nextnode (node))
124 {
125 adj = getdata (node);
126 if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
127 return adj;
128 }
129
jardineb5d44e2003-12-23 08:09:43 +0000130 return NULL;
131}
132
133/*
134 * When we recieve a NULL list, we will know its p2p
135 */
hassof390d2c2004-09-10 20:48:21 +0000136void
jardineb5d44e2003-12-23 08:09:43 +0000137isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
138{
139 struct isis_adjacency *adj2;
140 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000141
142 if (adjdb)
143 {
144 for (node = listhead (adjdb); node; nextnode (node))
145 {
146 adj2 = getdata (node);
147 if (adj2 == adj)
148 break;
149 }
150 listnode_delete (adjdb, adj);
jardineb5d44e2003-12-23 08:09:43 +0000151 }
hassof390d2c2004-09-10 20:48:21 +0000152
jardineb5d44e2003-12-23 08:09:43 +0000153 if (adj->ipv4_addrs)
154 list_delete (adj->ipv4_addrs);
155#ifdef HAVE_IPV6
156 if (adj->ipv6_addrs)
157 list_delete (adj->ipv6_addrs);
158#endif
hassof390d2c2004-09-10 20:48:21 +0000159 if (adj)
160 {
161 XFREE (MTYPE_ISIS_ADJACENCY, adj);
162 }
163 else
164 {
165 zlog_info ("tried to delete a non-existent adjacency");
166 }
jardineb5d44e2003-12-23 08:09:43 +0000167
168 return;
169}
170
hassof390d2c2004-09-10 20:48:21 +0000171void
172isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
173 char *reason)
jardineb5d44e2003-12-23 08:09:43 +0000174{
175 int old_state;
176 int level = adj->level;
177 struct isis_circuit *circuit;
hassof390d2c2004-09-10 20:48:21 +0000178
jardineb5d44e2003-12-23 08:09:43 +0000179 old_state = adj->adj_state;
180 adj->adj_state = state;
181
182 circuit = adj->circuit;
jardineb5d44e2003-12-23 08:09:43 +0000183
hassof390d2c2004-09-10 20:48:21 +0000184 if (isis->debugs & DEBUG_ADJ_PACKETS)
185 {
186 zlog_info ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
187 circuit->area->area_tag,
188 old_state, state, reason ? reason : "unspecified");
jardineb5d44e2003-12-23 08:09:43 +0000189 }
190
hassof390d2c2004-09-10 20:48:21 +0000191 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
192 {
193 if (state == ISIS_ADJ_UP)
194 circuit->upadjcount[level - 1]++;
195 if (state == ISIS_ADJ_DOWN)
196 {
197 isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
198 circuit->upadjcount[level - 1]--;
199 }
jardineb5d44e2003-12-23 08:09:43 +0000200
hassof390d2c2004-09-10 20:48:21 +0000201 list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
202 isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
203 circuit->u.bc.lan_neighs[level - 1]);
204 }
205 else if (state == ISIS_ADJ_UP)
206 { /* p2p interface */
207 if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
208 send_hello (circuit, 1);
209
210 /* update counter & timers for debugging purposes */
211 adj->last_flap = time (NULL);
212 adj->flaps++;
213
214 /* 7.3.17 - going up on P2P -> send CSNP */
215 /* FIXME: yup, I know its wrong... but i will do it! (for now) */
216 send_csnp (circuit, 1);
217 send_csnp (circuit, 2);
218 }
219 else if (state == ISIS_ADJ_DOWN)
220 { /* p2p interface */
221 adj->circuit->u.p2p.neighbor = NULL;
222 isis_delete_adj (adj, NULL);
223 }
jardineb5d44e2003-12-23 08:09:43 +0000224 return;
225}
226
227
228void
229isis_adj_print (struct isis_adjacency *adj)
230{
231 struct isis_dynhn *dyn;
232 struct listnode *node;
233 struct in_addr *ipv4_addr;
hassof390d2c2004-09-10 20:48:21 +0000234#ifdef HAVE_IPV6
jardineb5d44e2003-12-23 08:09:43 +0000235 struct in6_addr *ipv6_addr;
hassof390d2c2004-09-10 20:48:21 +0000236 u_char ip6[INET6_ADDRSTRLEN];
jardineb5d44e2003-12-23 08:09:43 +0000237#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000238
239 if (!adj)
jardineb5d44e2003-12-23 08:09:43 +0000240 return;
241 dyn = dynhn_find_by_id (adj->sysid);
242 if (dyn)
243 zlog_info ("%s", dyn->name.name);
jardineb5d44e2003-12-23 08:09:43 +0000244
hassof390d2c2004-09-10 20:48:21 +0000245 zlog_info ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
246 adj->sysid ? sysid_print (adj->sysid) : "unknown",
247 snpa_print (adj->snpa), adj->level, adj->hold_time);
248 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
249 {
250 zlog_info ("IPv4 Addresses:");
251
252 for (node = listhead (adj->ipv4_addrs); node; nextnode (node))
253 {
254 ipv4_addr = getdata (node);
255 zlog_info ("%s", inet_ntoa (*ipv4_addr));
256 }
jardineb5d44e2003-12-23 08:09:43 +0000257 }
hassof390d2c2004-09-10 20:48:21 +0000258
259#ifdef HAVE_IPV6
260 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
261 {
262 zlog_info ("IPv6 Addresses:");
263 for (node = listhead (adj->ipv6_addrs); node; nextnode (node))
264 {
265 ipv6_addr = getdata (node);
266 inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
267 zlog_info ("%s", ip6);
268 }
269 }
jardineb5d44e2003-12-23 08:09:43 +0000270#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000271 zlog_info ("Speaks: %s", nlpid2string (&adj->nlpids));
jardineb5d44e2003-12-23 08:09:43 +0000272
273 return;
274}
275
hassof390d2c2004-09-10 20:48:21 +0000276int
jardineb5d44e2003-12-23 08:09:43 +0000277isis_adj_expire (struct thread *thread)
278{
279 struct isis_adjacency *adj;
280 int level;
281
282 /*
283 * Get the adjacency
284 */
285 adj = THREAD_ARG (thread);
286 assert (adj);
287 level = adj->level;
hasso83fe45e2004-02-09 11:09:39 +0000288 adj->t_expire = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000289
290 /* trigger the adj expire event */
291 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
292
293 return 0;
294}
295
296const char *
297adj_state2string (int state)
298{
hassof390d2c2004-09-10 20:48:21 +0000299
300 switch (state)
301 {
302 case ISIS_ADJ_INITIALIZING:
303 return "Initializing";
304 case ISIS_ADJ_UP:
305 return "Up";
306 case ISIS_ADJ_DOWN:
307 return "Down";
308 default:
309 return "Unknown";
310 }
311
312 return NULL; /* not reached */
jardineb5d44e2003-12-23 08:09:43 +0000313}
314
315/*
316 * show clns/isis neighbor (detail)
317 */
318void
319isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
320{
321
322#ifdef HAVE_IPV6
323 struct in6_addr *ipv6_addr;
hassof390d2c2004-09-10 20:48:21 +0000324 u_char ip6[INET6_ADDRSTRLEN];
jardineb5d44e2003-12-23 08:09:43 +0000325#endif /* HAVE_IPV6 */
326 struct in_addr *ip_addr;
327 time_t now;
328 struct isis_dynhn *dyn;
329 int level;
330 struct listnode *node;
331
332 dyn = dynhn_find_by_id (adj->sysid);
333 if (dyn)
334 vty_out (vty, " %-20s", dyn->name.name);
hassof390d2c2004-09-10 20:48:21 +0000335 else if (adj->sysid)
336 {
337 vty_out (vty, " %-20s", sysid_print (adj->sysid));
jardineb5d44e2003-12-23 08:09:43 +0000338 }
hassof390d2c2004-09-10 20:48:21 +0000339 else
340 {
341 vty_out (vty, " unknown ");
jardineb5d44e2003-12-23 08:09:43 +0000342 }
hassof390d2c2004-09-10 20:48:21 +0000343
344 if (detail == ISIS_UI_LEVEL_BRIEF)
345 {
346 if (adj->circuit)
347 vty_out (vty, "%-12s", adj->circuit->interface->name);
348 else
349 vty_out (vty, "NULL circuit!");
350 vty_out (vty, "%-3u", adj->level); /* level */
351 vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
352 now = time (NULL);
353 if (adj->last_upd)
354 vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now);
355 else
356 vty_out (vty, "- ");
357 vty_out (vty, "%-10s", snpa_print (adj->snpa));
358 vty_out (vty, "%s", VTY_NEWLINE);
359 }
360
361 if (detail == ISIS_UI_LEVEL_DETAIL)
362 {
363 level = adj->level;
364 if (adj->circuit)
365 vty_out (vty, "%s Interface: %s", VTY_NEWLINE, adj->circuit->interface->name); /* interface name */
366 else
367 vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
368 vty_out (vty, ", Level: %u", adj->level); /* level */
369 vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
370 now = time (NULL);
371 if (adj->last_upd)
372 vty_out (vty, ", Expires in %s",
373 time2string (adj->last_upd + adj->hold_time - now));
374 else
375 vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
376 vty_out (vty, "%s Adjacency flaps: %u", VTY_NEWLINE, adj->flaps);
377 vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
378 vty_out (vty, "%s Circuit type: %s",
379 VTY_NEWLINE, circuit_t2string (adj->circuit_t));
380 vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
381 vty_out (vty, "%s SNPA: %s", VTY_NEWLINE, snpa_print (adj->snpa));
382 dyn = dynhn_find_by_id (adj->lanid);
383 if (dyn)
384 vty_out (vty, ", LAN id: %s.%02x",
385 dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
386 else
387 vty_out (vty, ", LAN id: %s.%02x",
388 sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
389
390 vty_out (vty, "%s Priority: %u",
391 VTY_NEWLINE, adj->prio[adj->level - 1]);
392
393 vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
394 isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
395 dis), adj->dischanges[level - 1],
396 time2string (now -
397 (adj->dis_record[ISIS_LEVELS + level - 1].
398 last_dis_change)), VTY_NEWLINE);
399
400 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
401 {
402 vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE);
403 for (node = listhead (adj->ipv4_addrs); node; nextnode (node))
404 {
405 ip_addr = getdata (node);
406 vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
407 }
408 }
409#ifdef HAVE_IPV6
410 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
411 {
412 vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE);
413 for (node = listhead (adj->ipv6_addrs); node; nextnode (node))
414 {
415 ipv6_addr = getdata (node);
416 inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
417 vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
418 }
419 }
jardineb5d44e2003-12-23 08:09:43 +0000420#endif /* HAVE_IPV6 */
hassof390d2c2004-09-10 20:48:21 +0000421 vty_out (vty, "%s", VTY_NEWLINE);
422 }
jardineb5d44e2003-12-23 08:09:43 +0000423 return;
424}
425
426void
hassof390d2c2004-09-10 20:48:21 +0000427isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty)
428{
jardineb5d44e2003-12-23 08:09:43 +0000429 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
430}
431
432void
hassof390d2c2004-09-10 20:48:21 +0000433isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
434{
jardineb5d44e2003-12-23 08:09:43 +0000435 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
436}
437
438void
hassof390d2c2004-09-10 20:48:21 +0000439isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
440{
jardineb5d44e2003-12-23 08:09:43 +0000441 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
442}
443
444void
445isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
446{
447 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
448}
449
hassof390d2c2004-09-10 20:48:21 +0000450void
451isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
jardineb5d44e2003-12-23 08:09:43 +0000452{
453 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
454}
455
hassof390d2c2004-09-10 20:48:21 +0000456void
jardineb5d44e2003-12-23 08:09:43 +0000457isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
458{
459 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
460}
461
462void
hassof390d2c2004-09-10 20:48:21 +0000463isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *,
464 void *), void *arg)
jardineb5d44e2003-12-23 08:09:43 +0000465{
466 struct listnode *node;
467 struct isis_adjacency *adj;
hassof390d2c2004-09-10 20:48:21 +0000468 for (node = listhead (adjdb); node; nextnode (node))
469 {
470 adj = getdata (node);
471 (*func) (adj, arg);
472 }
jardineb5d44e2003-12-23 08:09:43 +0000473}
474
475void
476isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
jardineb5d44e2003-12-23 08:09:43 +0000477{
478 struct isis_adjacency *adj;
479 struct listnode *node;
hassof390d2c2004-09-10 20:48:21 +0000480
481 if (!list)
482 {
483 zlog_warn ("isis_adj_build_neigh_list(): NULL list");
jardineb5d44e2003-12-23 08:09:43 +0000484 return;
485 }
hassof390d2c2004-09-10 20:48:21 +0000486
487 for (node = listhead (adjdb); node; nextnode (node))
488 {
489 adj = getdata (node);
490 if (!adj)
491 {
492 zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
493 return;
494 }
495
496 if ((adj->adj_state == ISIS_ADJ_UP ||
497 adj->adj_state == ISIS_ADJ_INITIALIZING))
498 listnode_add (list, adj->snpa);
499 }
jardineb5d44e2003-12-23 08:09:43 +0000500 return;
501}
502
503void
504isis_adj_build_up_list (struct list *adjdb, struct list *list)
505{
506 struct isis_adjacency *adj;
507 struct listnode *node;
508
hassof390d2c2004-09-10 20:48:21 +0000509 if (!list)
510 {
511 zlog_warn ("isis_adj_build_up_list(): NULL list");
jardineb5d44e2003-12-23 08:09:43 +0000512 return;
513 }
514
hassof390d2c2004-09-10 20:48:21 +0000515 for (node = listhead (adjdb); node; nextnode (node))
516 {
517 adj = getdata (node);
518
519 if (!adj)
520 {
521 zlog_warn ("isis_adj_build_up_list(): NULL adj");
522 return;
523 }
524
525 if (adj->adj_state == ISIS_ADJ_UP)
526 listnode_add (list, adj);
527 }
528
jardineb5d44e2003-12-23 08:09:43 +0000529 return;
530}