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