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