blob: 86fed1d9004cb459218a33af8445ac57663b2990 [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
50
51extern struct isis *isis;
52
53
54struct isis_adjacency *
55adj_alloc (u_char *id)
56{
57 struct isis_adjacency *adj;
58
59 adj = XMALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
60 memset (adj, 0, sizeof (struct isis_adjacency));
61 memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
62
63 return adj;
64}
65
66struct isis_adjacency *
67isis_new_adj (u_char *id, u_char *snpa, int level,
68 struct isis_circuit *circuit)
69{
70
71 struct isis_adjacency *adj;
72 int i;
73
74 adj = adj_alloc (id); /* P2P kludge */
75
76 if (adj == NULL){
77 zlog_err ("Out of memory!");
78 return NULL;
79 }
80
81 memcpy (adj->snpa, snpa, 6);
82 adj->circuit = circuit;
83 adj->level = level;
84 adj->flaps = 0;
85 adj->last_flap = time (NULL);
86 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
87 listnode_add (circuit->u.bc.adjdb[level-1], adj);
88 adj->dischanges[level - 1] = 0;
89 for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
90 {
91 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
92 = ISIS_UNKNOWN_DIS;
93 adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
94 = time (NULL);
95 }
96 }
97
98 return adj;
99}
100
101struct isis_adjacency *
102isis_adj_lookup (u_char *sysid, struct list *adjdb)
103{
104 struct isis_adjacency *adj;
105 struct listnode *node;
106
107 for (node = listhead (adjdb); node; nextnode (node)) {
108 adj = getdata (node);
109 if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
110 return adj;
111 }
112
113 return NULL;
114}
115
116
117struct isis_adjacency *
118isis_adj_lookup_snpa (u_char *ssnpa, struct list *adjdb)
119{
120 struct listnode *node;
121 struct isis_adjacency *adj;
122
123 for (node = listhead (adjdb); node; nextnode (node)) {
124 adj = getdata (node);
125 if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
126 return adj;
127 }
128
129 return NULL;
130}
131
132/*
133 * When we recieve a NULL list, we will know its p2p
134 */
135void
136isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
137{
138 struct isis_adjacency *adj2;
139 struct listnode *node;
140
141 if (adjdb) {
142 for (node = listhead (adjdb); node; nextnode (node)) {
143 adj2 = getdata (node);
144 if (adj2 == adj)
145 break;
146 }
hasso2097cd82003-12-23 11:51:08 +0000147 listnode_delete (adjdb, adj);
jardineb5d44e2003-12-23 08:09:43 +0000148 }
149
150 if (adj->ipv4_addrs)
151 list_delete (adj->ipv4_addrs);
152#ifdef HAVE_IPV6
153 if (adj->ipv6_addrs)
154 list_delete (adj->ipv6_addrs);
155#endif
156 if (adj) {
157 XFREE (MTYPE_ISIS_ADJACENCY,adj);
158 } else {
159 zlog_info ("tried to delete a non-existent adjacency");
160 }
161
162
163
164 return;
165}
166
167void
168isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
169 char *reason)
170
171{
172 int old_state;
173 int level = adj->level;
174 struct isis_circuit *circuit;
175
176 old_state = adj->adj_state;
177 adj->adj_state = state;
178
179 circuit = adj->circuit;
180
181 if (isis->debugs & DEBUG_ADJ_PACKETS) {
182 zlog_info ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
183 circuit->area->area_tag,
184 old_state,
185 state,
186 reason ? reason : "unspecified");
187 }
188
189 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
190 if (state == ISIS_ADJ_UP)
191 circuit->upadjcount[level-1]++;
192 if (state == ISIS_ADJ_DOWN) {
193 isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
194 circuit->upadjcount[level-1]--;
195 }
196
197 list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
198 isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
199 circuit->u.bc.lan_neighs[level - 1]);
200 } else if (state == ISIS_ADJ_UP) { /* p2p interface */
201 if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
202 send_hello (circuit, 1);
203
204 /* update counter & timers for debugging purposes */
205 adj->last_flap = time(NULL);
206 adj->flaps++;
207
208 /* 7.3.17 - going up on P2P -> send CSNP */
209 /* FIXME: yup, I know its wrong... but i will do it! (for now) */
210 send_csnp (circuit,1);
211 send_csnp (circuit,2);
212 } else if (state == ISIS_ADJ_DOWN) { /* p2p interface */
213 adj->circuit->u.p2p.neighbor = NULL;
214 isis_delete_adj (adj, NULL);
215 }
216 return;
217}
218
219
220void
221isis_adj_print (struct isis_adjacency *adj)
222{
223 struct isis_dynhn *dyn;
224 struct listnode *node;
225 struct in_addr *ipv4_addr;
226#ifdef HAVE_IPV6
227 struct in6_addr *ipv6_addr;
228 u_char ip6 [INET6_ADDRSTRLEN];
229#endif /* HAVE_IPV6 */
230
231 if(!adj)
232 return;
233 dyn = dynhn_find_by_id (adj->sysid);
234 if (dyn)
235 zlog_info ("%s", dyn->name.name);
236
237 zlog_info ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
238 adj->sysid ? sysid_print (adj->sysid) : "unknown" ,
239 snpa_print (adj->snpa),
240 adj->level, adj->hold_time);
241 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) {
242 zlog_info ("IPv4 Addresses:");
243
244 for (node = listhead (adj->ipv4_addrs); node; nextnode (node)) {
245 ipv4_addr = getdata (node);
246 zlog_info ("%s", inet_ntoa(*ipv4_addr));
247 }
248 }
249
250#ifdef HAVE_IPV6
251 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) {
252 zlog_info ("IPv6 Addresses:");
253 for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) {
254 ipv6_addr = getdata (node);
255 inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
256 zlog_info ("%s", ip6);
257 }
258 }
259#endif /* HAVE_IPV6 */
260 zlog_info ("Speaks: %s", nlpid2string(&adj->nlpids));
261
262
263 return;
264}
265
266int
267isis_adj_expire (struct thread *thread)
268{
269 struct isis_adjacency *adj;
270 int level;
271
272 /*
273 * Get the adjacency
274 */
275 adj = THREAD_ARG (thread);
276 assert (adj);
277 level = adj->level;
hasso83fe45e2004-02-09 11:09:39 +0000278 adj->t_expire = NULL;
jardineb5d44e2003-12-23 08:09:43 +0000279
280 /* trigger the adj expire event */
281 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
282
283 return 0;
284}
285
286const char *
287adj_state2string (int state)
288{
289
290 switch (state) {
291 case ISIS_ADJ_INITIALIZING:
292 return "Initializing";
293 case ISIS_ADJ_UP:
294 return "Up";
295 case ISIS_ADJ_DOWN:
296 return "Down";
297 default:
298 return "Unknown";
299 }
300
301 return NULL; /* not reached */
302}
303
304/*
305 * show clns/isis neighbor (detail)
306 */
307void
308isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
309{
310
311#ifdef HAVE_IPV6
312 struct in6_addr *ipv6_addr;
313 u_char ip6 [INET6_ADDRSTRLEN];
314#endif /* HAVE_IPV6 */
315 struct in_addr *ip_addr;
316 time_t now;
317 struct isis_dynhn *dyn;
318 int level;
319 struct listnode *node;
320
321 dyn = dynhn_find_by_id (adj->sysid);
322 if (dyn)
323 vty_out (vty, " %-20s", dyn->name.name);
324 else if (adj->sysid){
325 vty_out (vty, " %-20s", sysid_print (adj->sysid));
326 } else {
327 vty_out (vty, " unknown ");
328 }
329
330 if (detail == ISIS_UI_LEVEL_BRIEF) {
331 if (adj->circuit)
332 vty_out (vty, "%-12s",adj->circuit->interface->name);
333 else
334 vty_out (vty, "NULL circuit!");
335 vty_out (vty, "%-3u", adj->level); /* level */
336 vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
337 now = time (NULL);
hasso2097cd82003-12-23 11:51:08 +0000338 if (adj->last_upd)
339 vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now);
340 else
341 vty_out (vty, "- ");
jardineb5d44e2003-12-23 08:09:43 +0000342 vty_out (vty, "%-10s", snpa_print (adj->snpa));
343 vty_out (vty, "%s", VTY_NEWLINE);
344 }
345
346 if (detail == ISIS_UI_LEVEL_DETAIL) {
347 level = adj->level;
348 if (adj->circuit)
349 vty_out (vty, "%s Interface: %s",
350 VTY_NEWLINE,
351 adj->circuit->interface->name); /* interface name */
352 else
353 vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
354 vty_out (vty, ", Level: %u", adj->level); /* level */
355 vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
356 now = time (NULL);
hasso2097cd82003-12-23 11:51:08 +0000357 if (adj->last_upd)
358 vty_out (vty, ", Expires in %s",
359 time2string (adj->last_upd + adj->hold_time - now));
360 else
361 vty_out (vty, ", Expires in %s",
362 time2string (adj->hold_time));
jardineb5d44e2003-12-23 08:09:43 +0000363 vty_out (vty, "%s Adjacency flaps: %u",
364 VTY_NEWLINE,
365 adj->flaps);
366 vty_out (vty, ", Last: %s ago", time2string(now - adj->last_flap));
367 vty_out (vty, "%s Circuit type: %s",
368 VTY_NEWLINE,
369 circuit_t2string(adj->circuit_t));
370 vty_out (vty, ", Speaks: %s", nlpid2string(&adj->nlpids));
371 vty_out (vty, "%s SNPA: %s",
372 VTY_NEWLINE,
373 snpa_print (adj->snpa));
374 dyn = dynhn_find_by_id (adj->lanid);
375 if (dyn)
376 vty_out (vty, ", LAN id: %s.%02x",
377 dyn->name.name,
378 adj->lanid[ISIS_SYS_ID_LEN]);
379 else
380 vty_out (vty, ", LAN id: %s.%02x",
381 sysid_print (adj->lanid),
382 adj->lanid[ISIS_SYS_ID_LEN]);
383
384 vty_out (vty, "%s Priority: %u",
385 VTY_NEWLINE,
386 adj->prio[adj->level-1]);
387
388 vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
389 isis_disflag2string(adj->dis_record[ISIS_LEVELS+level-1].dis),
390 adj->dischanges[level-1],
391 time2string (now -
392 (adj->dis_record[ISIS_LEVELS + level - 1].last_dis_change)),
393 VTY_NEWLINE);
394
395 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) {
396 vty_out (vty, " IPv4 Addresses:%s", VTY_NEWLINE);
397 for (node = listhead (adj->ipv4_addrs);node; nextnode (node)) {
398 ip_addr = getdata (node);
399 vty_out (vty, " %s%s", inet_ntoa(*ip_addr), VTY_NEWLINE);
400 }
401 }
402#ifdef HAVE_IPV6
403 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) {
404 vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE);
405 for (node = listhead (adj->ipv6_addrs); node; nextnode (node)) {
406 ipv6_addr = getdata (node);
407 inet_ntop (AF_INET6, ipv6_addr, ip6, INET6_ADDRSTRLEN);
408 vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
409 }
410 }
411#endif /* HAVE_IPV6 */
412 vty_out (vty, "%s", VTY_NEWLINE);
413 }
414 return;
415}
416
417void
418isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty) {
419 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
420}
421
422void
423isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty) {
424 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
425}
426
427void
428isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty) {
429 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
430}
431
432void
433isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
434{
435 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
436}
437
438void
439isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
440{
441 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
442}
443
444void
445isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
446{
447 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
448}
449
450void
451isis_adjdb_iterate (struct list *adjdb, void (*func)(struct isis_adjacency*,
452 void *), void *arg)
453{
454 struct listnode *node;
455 struct isis_adjacency *adj;
456 for (node = listhead (adjdb); node; nextnode (node)) {
457 adj = getdata (node);
458 (*func)(adj, arg);
459 }
460}
461
462void
463isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
464
465{
466 struct isis_adjacency *adj;
467 struct listnode *node;
468
469
470 if (!list) {
471 zlog_warn ("isis_adj_build_neigh_list(): NULL list");
472 return;
473 }
474
475 for (node = listhead (adjdb); node; nextnode (node)) {
476 adj = getdata (node);
477 if (!adj) {
478 zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
479 return;
480 }
481
482 if ((adj->adj_state == ISIS_ADJ_UP ||
483 adj->adj_state == ISIS_ADJ_INITIALIZING))
484 listnode_add (list, adj->snpa);
485 }
486 return;
487}
488
489void
490isis_adj_build_up_list (struct list *adjdb, struct list *list)
491{
492 struct isis_adjacency *adj;
493 struct listnode *node;
494
495 if (!list) {
496 zlog_warn ("isis_adj_build_up_list(): NULL list");
497 return;
498 }
499
500 for (node = listhead (adjdb); node; nextnode (node)) {
501 adj = getdata (node);
502
503 if (!adj) {
504 zlog_warn ("isis_adj_build_up_list(): NULL adj");
505 return;
506 }
507
508 if (adj->adj_state == ISIS_ADJ_UP)
509 listnode_add (list, adj);
510 }
511
512 return;
513}
514