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