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/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
);
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
;
67 adj
= adj_alloc (id
); /* P2P kludge */
71 zlog_err ("Out of memory!");
76 memcpy (adj
->snpa
, snpa
, 6);
78 memset (adj
->snpa
, ' ', 6);
81 adj
->circuit
= circuit
;
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
93 adj
->dis_record
[(i
* ISIS_LEVELS
) + level
- 1].last_dis_change
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)
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)
128 isis_delete_adj (struct isis_adjacency
*adj
, struct list
*adjdb
)
132 /* When we recieve a NULL list, we will know its p2p. */
134 listnode_delete (adjdb
, adj
);
136 THREAD_OFF (adj
->t_expire
);
139 list_delete (adj
->ipv4_addrs
);
142 list_delete (adj
->ipv6_addrs
);
145 XFREE (MTYPE_ISIS_ADJACENCY
, adj
);
150 isis_adj_state_change (struct isis_adjacency
*adj
, enum isis_adj_state 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
);
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
);
207 isis_adj_print (struct isis_adjacency
*adj
)
209 struct isis_dynhn
*dyn
;
210 struct listnode
*node
;
211 struct in_addr
*ipv4_addr
;
213 struct in6_addr
*ipv6_addr
;
214 u_char ip6
[INET6_ADDRSTRLEN
];
215 #endif /* HAVE_IPV6 */
219 dyn
= dynhn_find_by_id (adj
->sysid
);
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
));
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
));
251 isis_adj_expire (struct thread
*thread
)
253 struct isis_adjacency
*adj
;
259 adj
= THREAD_ARG (thread
);
262 adj
->t_expire
= NULL
;
264 /* trigger the adj expire event */
265 isis_adj_state_change (adj
, ISIS_ADJ_DOWN
, "holding time expired");
271 adj_state2string (int state
)
276 case ISIS_ADJ_INITIALIZING
:
277 return "Initializing";
286 return NULL
; /* not reached */
290 * show clns/isis neighbor (detail)
293 isis_adj_print_vty2 (struct isis_adjacency
*adj
, struct vty
*vty
, char detail
)
297 struct in6_addr
*ipv6_addr
;
298 u_char ip6
[INET6_ADDRSTRLEN
];
299 #endif /* HAVE_IPV6 */
300 struct in_addr
*ip_addr
;
302 struct isis_dynhn
*dyn
;
304 struct listnode
*node
;
306 dyn
= dynhn_find_by_id (adj
->sysid
);
308 vty_out (vty
, " %-20s", dyn
->name
.name
);
311 vty_out (vty
, " %-20s", sysid_print (adj
->sysid
));
315 vty_out (vty
, " unknown ");
318 if (detail
== ISIS_UI_LEVEL_BRIEF
)
321 vty_out (vty
, "%-12s", adj
->circuit
->interface
->name
);
323 vty_out (vty
, "NULL circuit!");
324 vty_out (vty
, "%-3u", adj
->level
); /* level */
325 vty_out (vty
, "%-13s", adj_state2string (adj
->adj_state
));
328 vty_out (vty
, "%-9lu", adj
->last_upd
+ adj
->hold_time
- now
);
331 vty_out (vty
, "%-10s", snpa_print (adj
->snpa
));
332 vty_out (vty
, "%s", VTY_NEWLINE
);
335 if (detail
== ISIS_UI_LEVEL_DETAIL
)
339 vty_out (vty
, "%s Interface: %s", VTY_NEWLINE
, adj
->circuit
->interface
->name
); /* interface name */
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
));
346 vty_out (vty
, ", Expires in %s",
347 time2string (adj
->last_upd
+ adj
->hold_time
- now
));
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
);
358 vty_out (vty
, ", LAN id: %s.%02x",
359 dyn
->name
.name
, adj
->lanid
[ISIS_SYS_ID_LEN
]);
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],
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
);
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
);
397 isis_adj_print_vty (struct isis_adjacency
*adj
, struct vty
*vty
)
399 isis_adj_print_vty2 (adj
, vty
, ISIS_UI_LEVEL_BRIEF
);
403 isis_adj_print_vty_detail (struct isis_adjacency
*adj
, struct vty
*vty
)
405 isis_adj_print_vty2 (adj
, vty
, ISIS_UI_LEVEL_DETAIL
);
409 isis_adj_print_vty_extensive (struct isis_adjacency
*adj
, struct vty
*vty
)
411 isis_adj_print_vty2 (adj
, vty
, ISIS_UI_LEVEL_EXTENSIVE
);
415 isis_adj_p2p_print_vty (struct isis_adjacency
*adj
, struct vty
*vty
)
417 isis_adj_print_vty2 (adj
, vty
, ISIS_UI_LEVEL_BRIEF
);
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
);
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
);
433 isis_adjdb_iterate (struct list
*adjdb
, void (*func
) (struct isis_adjacency
*,
436 struct listnode
*node
, *nnode
;
437 struct isis_adjacency
*adj
;
439 for (ALL_LIST_ELEMENTS (adjdb
, node
, nnode
, adj
))
444 isis_adj_build_neigh_list (struct list
*adjdb
, struct list
*list
)
446 struct isis_adjacency
*adj
;
447 struct listnode
*node
;
451 zlog_warn ("isis_adj_build_neigh_list(): NULL list");
455 for (ALL_LIST_ELEMENTS_RO (adjdb
, node
, adj
))
459 zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
463 if ((adj
->adj_state
== ISIS_ADJ_UP
||
464 adj
->adj_state
== ISIS_ADJ_INITIALIZING
))
465 listnode_add (list
, adj
->snpa
);
471 isis_adj_build_up_list (struct list
*adjdb
, struct list
*list
)
473 struct isis_adjacency
*adj
;
474 struct listnode
*node
;
478 zlog_warn ("isis_adj_build_up_list(): NULL list");
482 for (ALL_LIST_ELEMENTS_RO (adjdb
, node
, adj
))
486 zlog_warn ("isis_adj_build_up_list(): NULL adj");
490 if (adj
->adj_state
== ISIS_ADJ_UP
)
491 listnode_add (list
, adj
);