]>
git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_adjacency.c
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 (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 (u_char
* id
, 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 (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 (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
= adj
->sysid
? sysid_print (adj
->sysid
) : "unknown";
208 zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
210 adj
->circuit
? adj
->circuit
->interface
->name
: "no circuit",
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 adj
->sysid
? sysid_print (adj
->sysid
) : "unknown",
318 snpa_print (adj
->snpa
), 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
);
382 vty_out (vty
, " %-20s", sysid_print (adj
->sysid
));
386 vty_out (vty
, " unknown ");
389 if (detail
== ISIS_UI_LEVEL_BRIEF
)
392 vty_out (vty
, "%-12s", adj
->circuit
->interface
->name
);
394 vty_out (vty
, "NULL circuit!");
395 vty_out (vty
, "%-3u", adj
->level
); /* level */
396 vty_out (vty
, "%-13s", adj_state2string (adj
->adj_state
));
399 vty_out (vty
, "%-9lu", adj
->last_upd
+ adj
->hold_time
- now
);
402 vty_out (vty
, "%-10s", snpa_print (adj
->snpa
));
403 vty_out (vty
, "%s", VTY_NEWLINE
);
406 if (detail
== ISIS_UI_LEVEL_DETAIL
)
409 vty_out (vty
, "%s", VTY_NEWLINE
);
411 vty_out (vty
, " Interface: %s", adj
->circuit
->interface
->name
);
413 vty_out (vty
, " Interface: NULL circuit");
414 vty_out (vty
, ", Level: %u", adj
->level
); /* level */
415 vty_out (vty
, ", State: %s", adj_state2string (adj
->adj_state
));
418 vty_out (vty
, ", Expires in %s",
419 time2string (adj
->last_upd
+ adj
->hold_time
- now
));
421 vty_out (vty
, ", Expires in %s", time2string (adj
->hold_time
));
422 vty_out (vty
, "%s", VTY_NEWLINE
);
423 vty_out (vty
, " Adjacency flaps: %u", adj
->flaps
);
424 vty_out (vty
, ", Last: %s ago", time2string (now
- adj
->last_flap
));
425 vty_out (vty
, "%s", VTY_NEWLINE
);
426 vty_out (vty
, " Circuit type: %s", circuit_t2string (adj
->circuit_t
));
427 vty_out (vty
, ", Speaks: %s", nlpid2string (&adj
->nlpids
));
428 vty_out (vty
, "%s", VTY_NEWLINE
);
429 vty_out (vty
, " SNPA: %s", snpa_print (adj
->snpa
));
430 if (adj
->circuit
->circ_type
== CIRCUIT_T_BROADCAST
)
432 dyn
= dynhn_find_by_id (adj
->lanid
);
434 vty_out (vty
, ", LAN id: %s.%02x",
435 dyn
->name
.name
, adj
->lanid
[ISIS_SYS_ID_LEN
]);
437 vty_out (vty
, ", LAN id: %s.%02x",
438 sysid_print (adj
->lanid
), adj
->lanid
[ISIS_SYS_ID_LEN
]);
440 vty_out (vty
, "%s", VTY_NEWLINE
);
441 vty_out (vty
, " LAN Priority: %u", adj
->prio
[adj
->level
- 1]);
443 vty_out (vty
, ", %s, DIS flaps: %u, Last: %s ago",
444 isis_disflag2string (adj
->dis_record
[ISIS_LEVELS
+ level
- 1].
445 dis
), adj
->dischanges
[level
- 1],
447 (adj
->dis_record
[ISIS_LEVELS
+ level
- 1].
450 vty_out (vty
, "%s", VTY_NEWLINE
);
452 if (adj
->area_addrs
&& listcount (adj
->area_addrs
) > 0)
454 struct area_addr
*area_addr
;
455 vty_out (vty
, " Area Address(es):%s", VTY_NEWLINE
);
456 for (ALL_LIST_ELEMENTS_RO (adj
->area_addrs
, node
, area_addr
))
457 vty_out (vty
, " %s%s", isonet_print (area_addr
->area_addr
,
458 area_addr
->addr_len
), VTY_NEWLINE
);
460 if (adj
->ipv4_addrs
&& listcount (adj
->ipv4_addrs
) > 0)
462 vty_out (vty
, " IPv4 Address(es):%s", VTY_NEWLINE
);
463 for (ALL_LIST_ELEMENTS_RO (adj
->ipv4_addrs
, node
, ip_addr
))
464 vty_out (vty
, " %s%s", inet_ntoa (*ip_addr
), VTY_NEWLINE
);
467 if (adj
->ipv6_addrs
&& listcount (adj
->ipv6_addrs
) > 0)
469 vty_out (vty
, " IPv6 Address(es):%s", VTY_NEWLINE
);
470 for (ALL_LIST_ELEMENTS_RO (adj
->ipv6_addrs
, node
, ipv6_addr
))
472 inet_ntop (AF_INET6
, ipv6_addr
, (char *)ip6
, INET6_ADDRSTRLEN
);
473 vty_out (vty
, " %s%s", ip6
, VTY_NEWLINE
);
476 #endif /* HAVE_IPV6 */
477 vty_out (vty
, "%s", VTY_NEWLINE
);
483 isis_adj_build_neigh_list (struct list
*adjdb
, struct list
*list
)
485 struct isis_adjacency
*adj
;
486 struct listnode
*node
;
490 zlog_warn ("isis_adj_build_neigh_list(): NULL list");
494 for (ALL_LIST_ELEMENTS_RO (adjdb
, node
, adj
))
498 zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
502 if ((adj
->adj_state
== ISIS_ADJ_UP
||
503 adj
->adj_state
== ISIS_ADJ_INITIALIZING
))
504 listnode_add (list
, adj
->snpa
);
510 isis_adj_build_up_list (struct list
*adjdb
, struct list
*list
)
512 struct isis_adjacency
*adj
;
513 struct listnode
*node
;
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
);