+ sayonara old_pid!
[jleu-quagga.git] / isisd / isis_adjacency.c
blobaab8d1a3dcede78466332046489a1fc33908ca70
1 /*
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)
12 * any later version.
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.
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.
24 #include <zebra.h>
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"
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"
47 extern struct isis *isis;
49 static struct isis_adjacency *
50 adj_alloc (u_char * id)
52 struct isis_adjacency *adj;
54 adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
55 memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
57 return adj;
60 struct isis_adjacency *
61 isis_new_adj (u_char * id, u_char * snpa, int level,
62 struct isis_circuit *circuit)
64 struct isis_adjacency *adj;
65 int i;
67 adj = adj_alloc (id); /* P2P kludge */
69 if (adj == NULL)
71 zlog_err ("Out of memory!");
72 return NULL;
75 if (snpa) {
76 memcpy (adj->snpa, snpa, 6);
77 } else {
78 memset (adj->snpa, ' ', 6);
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)
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 */
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);
98 return adj;
101 struct isis_adjacency *
102 isis_adj_lookup (u_char * sysid, struct list *adjdb)
104 struct isis_adjacency *adj;
105 struct listnode *node;
107 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
108 if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
109 return adj;
111 return NULL;
114 struct isis_adjacency *
115 isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
117 struct listnode *node;
118 struct isis_adjacency *adj;
120 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
121 if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
122 return adj;
124 return NULL;
127 void
128 isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
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);
136 THREAD_OFF (adj->t_expire);
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
145 XFREE (MTYPE_ISIS_ADJACENCY, adj);
146 return;
149 void
150 isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
151 const char *reason)
153 int old_state;
154 int level = adj->level;
155 struct isis_circuit *circuit;
157 old_state = adj->adj_state;
158 adj->adj_state = state;
160 circuit = adj->circuit;
162 if (isis->debugs & DEBUG_ADJ_PACKETS)
164 zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
165 circuit->area->area_tag,
166 old_state, state, reason ? reason : "unspecified");
169 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
171 if (state == ISIS_ADJ_UP)
172 circuit->upadjcount[level - 1]++;
173 if (state == ISIS_ADJ_DOWN)
175 isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
176 circuit->upadjcount[level - 1]--;
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]);
183 else if (state == ISIS_ADJ_UP)
184 { /* p2p interface */
185 if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
186 send_hello (circuit, 1);
188 /* update counter & timers for debugging purposes */
189 adj->last_flap = time (NULL);
190 adj->flaps++;
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);
197 else if (state == ISIS_ADJ_DOWN)
198 { /* p2p interface */
199 adj->circuit->u.p2p.neighbor = NULL;
200 isis_delete_adj (adj, NULL);
202 return;
206 void
207 isis_adj_print (struct isis_adjacency *adj)
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 */
217 if (!adj)
218 return;
219 dyn = dynhn_find_by_id (adj->sysid);
220 if (dyn)
221 zlog_debug ("%s", dyn->name.name);
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)
228 zlog_debug ("IPv4 Addresses:");
230 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
231 zlog_debug ("%s", inet_ntoa (*ipv4_addr));
234 #ifdef HAVE_IPV6
235 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
237 zlog_debug ("IPv6 Addresses:");
238 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
240 inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
241 zlog_debug ("%s", ip6);
244 #endif /* HAVE_IPV6 */
245 zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids));
247 return;
251 isis_adj_expire (struct thread *thread)
253 struct isis_adjacency *adj;
254 int level;
257 * Get the adjacency
259 adj = THREAD_ARG (thread);
260 assert (adj);
261 level = adj->level;
262 adj->t_expire = NULL;
264 /* trigger the adj expire event */
265 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
267 return 0;
270 static const char *
271 adj_state2string (int state)
274 switch (state)
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";
286 return NULL; /* not reached */
290 * show clns/isis neighbor (detail)
292 static void
293 isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
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;
306 dyn = dynhn_find_by_id (adj->sysid);
307 if (dyn)
308 vty_out (vty, " %-20s", dyn->name.name);
309 else if (adj->sysid)
311 vty_out (vty, " %-20s", sysid_print (adj->sysid));
313 else
315 vty_out (vty, " unknown ");
318 if (detail == ISIS_UI_LEVEL_BRIEF)
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);
335 if (detail == ISIS_UI_LEVEL_DETAIL)
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]);
364 vty_out (vty, "%s Priority: %u",
365 VTY_NEWLINE, adj->prio[adj->level - 1]);
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);
374 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
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);
380 #ifdef HAVE_IPV6
381 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
383 vty_out (vty, " IPv6 Addresses:%s", VTY_NEWLINE);
384 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
386 inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
387 vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
390 #endif /* HAVE_IPV6 */
391 vty_out (vty, "%s", VTY_NEWLINE);
393 return;
396 void
397 isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty)
399 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
402 void
403 isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
405 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
408 void
409 isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
411 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
414 void
415 isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
417 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
420 void
421 isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
423 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
426 void
427 isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
429 isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
432 void
433 isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *,
434 void *), void *arg)
436 struct listnode *node, *nnode;
437 struct isis_adjacency *adj;
439 for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj))
440 (*func) (adj, arg);
443 void
444 isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
446 struct isis_adjacency *adj;
447 struct listnode *node;
449 if (!list)
451 zlog_warn ("isis_adj_build_neigh_list(): NULL list");
452 return;
455 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
457 if (!adj)
459 zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
460 return;
463 if ((adj->adj_state == ISIS_ADJ_UP ||
464 adj->adj_state == ISIS_ADJ_INITIALIZING))
465 listnode_add (list, adj->snpa);
467 return;
470 void
471 isis_adj_build_up_list (struct list *adjdb, struct list *list)
473 struct isis_adjacency *adj;
474 struct listnode *node;
476 if (!list)
478 zlog_warn ("isis_adj_build_up_list(): NULL list");
479 return;
482 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
484 if (!adj)
486 zlog_warn ("isis_adj_build_up_list(): NULL adj");
487 return;
490 if (adj->adj_state == ISIS_ADJ_UP)
491 listnode_add (list, adj);
494 return;