2 * IS-IS Rout(e)ing protocol - isis_adjacency.c
3 * handling of IS-IS adjacencies
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
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)
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
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.
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/isis_flags.h"
40 #include "isisd/isisd.h"
41 #include "isisd/isis_circuit.h"
42 #include "isisd/isis_adjacency.h"
43 #include "isisd/isis_misc.h"
44 #include "isisd/isis_dr.h"
45 #include "isisd/isis_dynhn.h"
46 #include "isisd/isis_pdu.h"
47 #include "isisd/isis_tlv.h"
48 #include "isisd/isis_lsp.h"
49 #include "isisd/isis_spf.h"
50 #include "isisd/isis_events.h"
52 extern struct isis *isis;
54 static struct isis_adjacency *
55 adj_alloc (const u_char *id)
57 struct isis_adjacency *adj;
59 adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
60 memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
65 struct isis_adjacency *
66 isis_new_adj (const u_char * id, const u_char * snpa, int level,
67 struct isis_circuit *circuit)
69 struct isis_adjacency *adj;
72 adj = adj_alloc (id); /* P2P kludge */
76 zlog_err ("Out of memory!");
81 memcpy (adj->snpa, snpa, ETH_ALEN);
83 memset (adj->snpa, ' ', ETH_ALEN);
86 adj->circuit = circuit;
89 adj->last_flap = time (NULL);
90 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
92 listnode_add (circuit->u.bc.adjdb[level - 1], adj);
93 adj->dischanges[level - 1] = 0;
94 for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
96 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
98 adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
106 struct isis_adjacency *
107 isis_adj_lookup (const u_char * sysid, struct list *adjdb)
109 struct isis_adjacency *adj;
110 struct listnode *node;
112 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
113 if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
119 struct isis_adjacency *
120 isis_adj_lookup_snpa (const u_char * ssnpa, struct list *adjdb)
122 struct listnode *node;
123 struct isis_adjacency *adj;
125 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
126 if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
133 isis_delete_adj (void *arg)
135 struct isis_adjacency *adj = arg;
140 THREAD_TIMER_OFF (adj->t_expire);
142 /* remove from SPF trees */
143 spftree_area_adj_del (adj->circuit->area, adj);
146 list_delete (adj->area_addrs);
148 list_delete (adj->ipv4_addrs);
151 list_delete (adj->ipv6_addrs);
154 XFREE (MTYPE_ISIS_ADJACENCY, adj);
159 adj_state2string (int state)
164 case ISIS_ADJ_INITIALIZING:
165 return "Initializing";
174 return NULL; /* not reached */
178 isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
183 struct isis_circuit *circuit;
185 old_state = adj->adj_state;
186 adj->adj_state = new_state;
188 circuit = adj->circuit;
190 if (isis->debugs & DEBUG_ADJ_PACKETS)
192 zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
193 circuit->area->area_tag,
194 old_state, new_state, reason ? reason : "unspecified");
197 if (circuit->area->log_adj_changes)
199 const char *adj_name;
200 struct isis_dynhn *dyn;
202 dyn = dynhn_find_by_id (adj->sysid);
204 adj_name = (const char *)dyn->name.name;
206 adj_name = sysid_print (adj->sysid);
208 zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
210 adj->circuit->interface->name,
211 adj_state2string (old_state),
212 adj_state2string (new_state),
213 reason ? reason : "unspecified");
216 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
218 for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
220 if ((adj->level & level) == 0)
222 if (new_state == ISIS_ADJ_UP)
224 circuit->upadjcount[level - 1]++;
225 isis_event_adjacency_state_change (adj, new_state);
226 /* update counter & timers for debugging purposes */
227 adj->last_flap = time (NULL);
230 else if (new_state == ISIS_ADJ_DOWN)
232 listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
233 circuit->upadjcount[level - 1]--;
234 if (circuit->upadjcount[level - 1] == 0)
236 /* Clean lsp_queue when no adj is up. */
237 if (circuit->lsp_queue)
238 list_delete_all_node (circuit->lsp_queue);
240 isis_event_adjacency_state_change (adj, new_state);
241 isis_delete_adj (adj);
244 if (circuit->u.bc.lan_neighs[level - 1])
246 list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
247 isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
248 circuit->u.bc.lan_neighs[level - 1]);
251 /* On adjacency state change send new pseudo LSP if we are the DR */
252 if (circuit->u.bc.is_dr[level - 1])
253 lsp_regenerate_schedule_pseudo (circuit, level);
256 else if (circuit->circ_type == CIRCUIT_T_P2P)
258 for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
260 if ((adj->level & level) == 0)
262 if (new_state == ISIS_ADJ_UP)
264 circuit->upadjcount[level - 1]++;
265 isis_event_adjacency_state_change (adj, new_state);
267 if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
268 send_hello (circuit, level);
270 /* update counter & timers for debugging purposes */
271 adj->last_flap = time (NULL);
274 /* 7.3.17 - going up on P2P -> send CSNP */
275 /* FIXME: yup, I know its wrong... but i will do it! (for now) */
276 send_csnp (circuit, level);
278 else if (new_state == ISIS_ADJ_DOWN)
280 if (adj->circuit->u.p2p.neighbor == adj)
281 adj->circuit->u.p2p.neighbor = NULL;
282 circuit->upadjcount[level - 1]--;
283 if (circuit->upadjcount[level - 1] == 0)
285 /* Clean lsp_queue when no adj is up. */
286 if (circuit->lsp_queue)
287 list_delete_all_node (circuit->lsp_queue);
289 isis_event_adjacency_state_change (adj, new_state);
290 isis_delete_adj (adj);
300 isis_adj_print (struct isis_adjacency *adj)
302 struct isis_dynhn *dyn;
303 struct listnode *node;
304 struct in_addr *ipv4_addr;
306 struct in6_addr *ipv6_addr;
307 u_char ip6[INET6_ADDRSTRLEN];
308 #endif /* HAVE_IPV6 */
312 dyn = dynhn_find_by_id (adj->sysid);
314 zlog_debug ("%s", dyn->name.name);
316 zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
317 sysid_print (adj->sysid), snpa_print (adj->snpa),
318 adj->level, adj->hold_time);
319 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
321 zlog_debug ("IPv4 Address(es):");
323 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
324 zlog_debug ("%s", inet_ntoa (*ipv4_addr));
328 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
330 zlog_debug ("IPv6 Address(es):");
331 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
333 inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
334 zlog_debug ("%s", ip6);
337 #endif /* HAVE_IPV6 */
338 zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids));
344 isis_adj_expire (struct thread *thread)
346 struct isis_adjacency *adj;
351 adj = THREAD_ARG (thread);
353 adj->t_expire = NULL;
355 /* trigger the adj expire event */
356 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
362 * show isis neighbor [detail]
365 isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
368 struct in6_addr *ipv6_addr;
369 u_char ip6[INET6_ADDRSTRLEN];
370 #endif /* HAVE_IPV6 */
371 struct in_addr *ip_addr;
373 struct isis_dynhn *dyn;
375 struct listnode *node;
377 dyn = dynhn_find_by_id (adj->sysid);
379 vty_out (vty, " %-20s", dyn->name.name);
381 vty_out (vty, " %-20s", sysid_print (adj->sysid));
383 if (detail == ISIS_UI_LEVEL_BRIEF)
386 vty_out (vty, "%-12s", adj->circuit->interface->name);
388 vty_out (vty, "NULL circuit!");
389 vty_out (vty, "%-3u", adj->level); /* level */
390 vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
393 vty_out (vty, "%-9llu",
394 (unsigned long long)adj->last_upd + adj->hold_time - now);
397 vty_out (vty, "%-10s", snpa_print (adj->snpa));
398 vty_out (vty, "%s", VTY_NEWLINE);
401 if (detail == ISIS_UI_LEVEL_DETAIL)
404 vty_out (vty, "%s", VTY_NEWLINE);
406 vty_out (vty, " Interface: %s", adj->circuit->interface->name);
408 vty_out (vty, " Interface: NULL circuit");
409 vty_out (vty, ", Level: %u", adj->level); /* level */
410 vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
413 vty_out (vty, ", Expires in %s",
414 time2string (adj->last_upd + adj->hold_time - now));
416 vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
417 vty_out (vty, "%s", VTY_NEWLINE);
418 vty_out (vty, " Adjacency flaps: %u", adj->flaps);
419 vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
420 vty_out (vty, "%s", VTY_NEWLINE);
421 vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t));
422 vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
423 vty_out (vty, "%s", VTY_NEWLINE);
424 vty_out (vty, " SNPA: %s", snpa_print (adj->snpa));
425 if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST))
427 dyn = dynhn_find_by_id (adj->lanid);
429 vty_out (vty, ", LAN id: %s.%02x",
430 dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
432 vty_out (vty, ", LAN id: %s.%02x",
433 sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
435 vty_out (vty, "%s", VTY_NEWLINE);
436 vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]);
438 vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
439 isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
440 dis), adj->dischanges[level - 1],
442 (adj->dis_record[ISIS_LEVELS + level - 1].
445 vty_out (vty, "%s", VTY_NEWLINE);
447 if (adj->area_addrs && listcount (adj->area_addrs) > 0)
449 struct area_addr *area_addr;
450 vty_out (vty, " Area Address(es):%s", VTY_NEWLINE);
451 for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
452 vty_out (vty, " %s%s", isonet_print (area_addr->area_addr,
453 area_addr->addr_len), VTY_NEWLINE);
455 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
457 vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE);
458 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
459 vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
462 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
464 vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE);
465 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
467 inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
468 vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
471 #endif /* HAVE_IPV6 */
472 vty_out (vty, "%s", VTY_NEWLINE);
478 isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
480 struct isis_adjacency *adj;
481 struct listnode *node;
485 zlog_warn ("isis_adj_build_neigh_list(): NULL list");
489 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
493 zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
497 if ((adj->adj_state == ISIS_ADJ_UP ||
498 adj->adj_state == ISIS_ADJ_INITIALIZING))
499 listnode_add (list, adj->snpa);
505 isis_adj_build_up_list (struct list *adjdb, struct list *list)
507 struct isis_adjacency *adj;
508 struct listnode *node;
511 zlog_warn ("isis_adj_build_up_list(): adjacency DB is empty");
517 zlog_warn ("isis_adj_build_up_list(): NULL list");
521 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
525 zlog_warn ("isis_adj_build_up_list(): NULL adj");
529 if (adj->adj_state == ISIS_ADJ_UP)
530 listnode_add (list, adj);