]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_adjacency.c
frr: Remove HAVE_IPV6 from code base
[mirror_frr.git] / isisd / isis_adjacency.c
CommitLineData
eb5d44eb 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
eb5d44eb 24#include <zebra.h>
eb5d44eb 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"
eb5d44eb 36#include "isisd/isis_constants.h"
37#include "isisd/isis_common.h"
3f045a08 38#include "isisd/isis_flags.h"
eb5d44eb 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"
3f045a08
JB
46#include "isisd/isis_tlv.h"
47#include "isisd/isis_lsp.h"
48#include "isisd/isis_spf.h"
49#include "isisd/isis_events.h"
eb5d44eb 50
eb5d44eb 51extern struct isis *isis;
52
92365889 53static struct isis_adjacency *
02e33d3e 54adj_alloc (const u_char *id)
eb5d44eb 55{
f390d2c7 56 struct isis_adjacency *adj;
eb5d44eb 57
aac372f4 58 adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
f390d2c7 59 memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
60
61 return adj;
eb5d44eb 62}
63
64struct isis_adjacency *
02e33d3e 65isis_new_adj (const u_char * id, const u_char * snpa, int level,
eb5d44eb 66 struct isis_circuit *circuit)
67{
eb5d44eb 68 struct isis_adjacency *adj;
f390d2c7 69 int i;
70
71 adj = adj_alloc (id); /* P2P kludge */
eb5d44eb 72
f390d2c7 73 if (adj == NULL)
74 {
75 zlog_err ("Out of memory!");
76 return NULL;
77 }
eb5d44eb 78
41b36e90 79 if (snpa) {
3f045a08 80 memcpy (adj->snpa, snpa, ETH_ALEN);
41b36e90 81 } else {
3f045a08 82 memset (adj->snpa, ' ', ETH_ALEN);
41b36e90
PJ
83 }
84
eb5d44eb 85 adj->circuit = circuit;
86 adj->level = level;
87 adj->flaps = 0;
88 adj->last_flap = time (NULL);
f390d2c7 89 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
90 {
91 listnode_add (circuit->u.bc.adjdb[level - 1], adj);
92 adj->dischanges[level - 1] = 0;
93 for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */
eb5d44eb 94 {
f390d2c7 95 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
eb5d44eb 96 = ISIS_UNKNOWN_DIS;
f390d2c7 97 adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
98 = time (NULL);
eb5d44eb 99 }
f390d2c7 100 }
eb5d44eb 101
102 return adj;
103}
104
105struct isis_adjacency *
02e33d3e 106isis_adj_lookup (const u_char * sysid, struct list *adjdb)
eb5d44eb 107{
108 struct isis_adjacency *adj;
109 struct listnode *node;
110
1eb8ef25 111 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
112 if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
113 return adj;
f390d2c7 114
eb5d44eb 115 return NULL;
116}
117
eb5d44eb 118struct isis_adjacency *
02e33d3e 119isis_adj_lookup_snpa (const u_char * ssnpa, struct list *adjdb)
eb5d44eb 120{
121 struct listnode *node;
122 struct isis_adjacency *adj;
123
1eb8ef25 124 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
125 if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
126 return adj;
f390d2c7 127
eb5d44eb 128 return NULL;
129}
130
f390d2c7 131void
3f045a08 132isis_delete_adj (void *arg)
eb5d44eb 133{
3f045a08
JB
134 struct isis_adjacency *adj = arg;
135
3fdb2dd9 136 if (!adj)
137 return;
f390d2c7 138
3f045a08
JB
139 THREAD_TIMER_OFF (adj->t_expire);
140
141 /* remove from SPF trees */
142 spftree_area_adj_del (adj->circuit->area, adj);
13fb40ac 143
3f045a08
JB
144 if (adj->area_addrs)
145 list_delete (adj->area_addrs);
eb5d44eb 146 if (adj->ipv4_addrs)
147 list_delete (adj->ipv4_addrs);
eb5d44eb 148 if (adj->ipv6_addrs)
149 list_delete (adj->ipv6_addrs);
3f045a08 150
3fdb2dd9 151 XFREE (MTYPE_ISIS_ADJACENCY, adj);
eb5d44eb 152 return;
153}
154
3f045a08
JB
155static const char *
156adj_state2string (int state)
157{
158
159 switch (state)
160 {
161 case ISIS_ADJ_INITIALIZING:
162 return "Initializing";
163 case ISIS_ADJ_UP:
164 return "Up";
165 case ISIS_ADJ_DOWN:
166 return "Down";
167 default:
168 return "Unknown";
169 }
170
171 return NULL; /* not reached */
172}
173
f390d2c7 174void
3f045a08 175isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state,
1cd80845 176 const char *reason)
eb5d44eb 177{
178 int old_state;
3f045a08 179 int level;
eb5d44eb 180 struct isis_circuit *circuit;
f390d2c7 181
eb5d44eb 182 old_state = adj->adj_state;
3f045a08 183 adj->adj_state = new_state;
eb5d44eb 184
185 circuit = adj->circuit;
f390d2c7 186
187 if (isis->debugs & DEBUG_ADJ_PACKETS)
188 {
529d65b3 189 zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
f390d2c7 190 circuit->area->area_tag,
3f045a08 191 old_state, new_state, reason ? reason : "unspecified");
eb5d44eb 192 }
193
3f045a08 194 if (circuit->area->log_adj_changes)
f390d2c7 195 {
3f045a08
JB
196 const char *adj_name;
197 struct isis_dynhn *dyn;
f390d2c7 198
3f045a08
JB
199 dyn = dynhn_find_by_id (adj->sysid);
200 if (dyn)
201 adj_name = (const char *)dyn->name.name;
202 else
85b123a4 203 adj_name = sysid_print (adj->sysid);
3f045a08
JB
204
205 zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
206 adj_name,
e8aca32f 207 adj->circuit->interface->name,
3f045a08
JB
208 adj_state2string (old_state),
209 adj_state2string (new_state),
210 reason ? reason : "unspecified");
f390d2c7 211 }
3f045a08
JB
212
213 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
214 {
215 for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
216 {
217 if ((adj->level & level) == 0)
218 continue;
219 if (new_state == ISIS_ADJ_UP)
e38e0df0
SV
220 {
221 circuit->upadjcount[level - 1]++;
222 isis_event_adjacency_state_change (adj, new_state);
223 /* update counter & timers for debugging purposes */
224 adj->last_flap = time (NULL);
225 adj->flaps++;
226 }
3f045a08 227 else if (new_state == ISIS_ADJ_DOWN)
e38e0df0
SV
228 {
229 listnode_delete (circuit->u.bc.adjdb[level - 1], adj);
230 circuit->upadjcount[level - 1]--;
231 if (circuit->upadjcount[level - 1] == 0)
232 {
233 /* Clean lsp_queue when no adj is up. */
234 if (circuit->lsp_queue)
235 list_delete_all_node (circuit->lsp_queue);
236 }
237 isis_event_adjacency_state_change (adj, new_state);
238 isis_delete_adj (adj);
239 }
240
241 if (circuit->u.bc.lan_neighs[level - 1])
242 {
243 list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
244 isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
245 circuit->u.bc.lan_neighs[level - 1]);
246 }
3f045a08
JB
247
248 /* On adjacency state change send new pseudo LSP if we are the DR */
249 if (circuit->u.bc.is_dr[level - 1])
250 lsp_regenerate_schedule_pseudo (circuit, level);
251 }
f390d2c7 252 }
3f045a08
JB
253 else if (circuit->circ_type == CIRCUIT_T_P2P)
254 {
255 for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++)
256 {
257 if ((adj->level & level) == 0)
258 continue;
259 if (new_state == ISIS_ADJ_UP)
e38e0df0
SV
260 {
261 circuit->upadjcount[level - 1]++;
262 isis_event_adjacency_state_change (adj, new_state);
3f045a08 263
e38e0df0
SV
264 if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
265 send_hello (circuit, level);
3f045a08 266
e38e0df0
SV
267 /* update counter & timers for debugging purposes */
268 adj->last_flap = time (NULL);
269 adj->flaps++;
3f045a08 270
e38e0df0
SV
271 /* 7.3.17 - going up on P2P -> send CSNP */
272 /* FIXME: yup, I know its wrong... but i will do it! (for now) */
273 send_csnp (circuit, level);
274 }
3f045a08 275 else if (new_state == ISIS_ADJ_DOWN)
e38e0df0
SV
276 {
277 if (adj->circuit->u.p2p.neighbor == adj)
278 adj->circuit->u.p2p.neighbor = NULL;
279 circuit->upadjcount[level - 1]--;
280 if (circuit->upadjcount[level - 1] == 0)
281 {
282 /* Clean lsp_queue when no adj is up. */
283 if (circuit->lsp_queue)
284 list_delete_all_node (circuit->lsp_queue);
285 }
286 isis_event_adjacency_state_change (adj, new_state);
287 isis_delete_adj (adj);
288 }
3f045a08 289 }
f390d2c7 290 }
3f045a08 291
eb5d44eb 292 return;
293}
294
295
296void
297isis_adj_print (struct isis_adjacency *adj)
298{
299 struct isis_dynhn *dyn;
300 struct listnode *node;
301 struct in_addr *ipv4_addr;
eb5d44eb 302 struct in6_addr *ipv6_addr;
f390d2c7 303 u_char ip6[INET6_ADDRSTRLEN];
f390d2c7 304
305 if (!adj)
eb5d44eb 306 return;
307 dyn = dynhn_find_by_id (adj->sysid);
308 if (dyn)
529d65b3 309 zlog_debug ("%s", dyn->name.name);
f390d2c7 310
529d65b3 311 zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
85b123a4
CF
312 sysid_print (adj->sysid), snpa_print (adj->snpa),
313 adj->level, adj->hold_time);
f390d2c7 314 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
315 {
3f045a08 316 zlog_debug ("IPv4 Address(es):");
f390d2c7 317
1eb8ef25 318 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
319 zlog_debug ("%s", inet_ntoa (*ipv4_addr));
eb5d44eb 320 }
f390d2c7 321
f390d2c7 322 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
323 {
3f045a08 324 zlog_debug ("IPv6 Address(es):");
1eb8ef25 325 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
f390d2c7 326 {
f7c43dcb 327 inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
529d65b3 328 zlog_debug ("%s", ip6);
f390d2c7 329 }
eb5d44eb 330 }
529d65b3 331 zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids));
eb5d44eb 332
333 return;
334}
335
f390d2c7 336int
eb5d44eb 337isis_adj_expire (struct thread *thread)
338{
339 struct isis_adjacency *adj;
eb5d44eb 340
341 /*
342 * Get the adjacency
343 */
344 adj = THREAD_ARG (thread);
345 assert (adj);
83fe45e3 346 adj->t_expire = NULL;
eb5d44eb 347
348 /* trigger the adj expire event */
349 isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
350
351 return 0;
352}
353
eb5d44eb 354/*
3f045a08 355 * show isis neighbor [detail]
eb5d44eb 356 */
3f045a08
JB
357void
358isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail)
eb5d44eb 359{
eb5d44eb 360 struct in6_addr *ipv6_addr;
f390d2c7 361 u_char ip6[INET6_ADDRSTRLEN];
eb5d44eb 362 struct in_addr *ip_addr;
363 time_t now;
364 struct isis_dynhn *dyn;
365 int level;
366 struct listnode *node;
367
368 dyn = dynhn_find_by_id (adj->sysid);
369 if (dyn)
370 vty_out (vty, " %-20s", dyn->name.name);
f390d2c7 371 else
0bffa929 372 vty_out (vty, " %-20s", sysid_print (adj->sysid));
f390d2c7 373
374 if (detail == ISIS_UI_LEVEL_BRIEF)
375 {
376 if (adj->circuit)
377 vty_out (vty, "%-12s", adj->circuit->interface->name);
378 else
379 vty_out (vty, "NULL circuit!");
380 vty_out (vty, "%-3u", adj->level); /* level */
381 vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
382 now = time (NULL);
383 if (adj->last_upd)
8f2c16aa
DL
384 vty_out (vty, "%-9llu",
385 (unsigned long long)adj->last_upd + adj->hold_time - now);
f390d2c7 386 else
387 vty_out (vty, "- ");
388 vty_out (vty, "%-10s", snpa_print (adj->snpa));
389 vty_out (vty, "%s", VTY_NEWLINE);
390 }
391
392 if (detail == ISIS_UI_LEVEL_DETAIL)
393 {
394 level = adj->level;
3f045a08 395 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 396 if (adj->circuit)
3f045a08 397 vty_out (vty, " Interface: %s", adj->circuit->interface->name);
f390d2c7 398 else
3f045a08 399 vty_out (vty, " Interface: NULL circuit");
f390d2c7 400 vty_out (vty, ", Level: %u", adj->level); /* level */
401 vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
402 now = time (NULL);
403 if (adj->last_upd)
404 vty_out (vty, ", Expires in %s",
405 time2string (adj->last_upd + adj->hold_time - now));
406 else
407 vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
3f045a08
JB
408 vty_out (vty, "%s", VTY_NEWLINE);
409 vty_out (vty, " Adjacency flaps: %u", adj->flaps);
f390d2c7 410 vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
3f045a08
JB
411 vty_out (vty, "%s", VTY_NEWLINE);
412 vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t));
f390d2c7 413 vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
3f045a08
JB
414 vty_out (vty, "%s", VTY_NEWLINE);
415 vty_out (vty, " SNPA: %s", snpa_print (adj->snpa));
e8aca32f 416 if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST))
3f045a08
JB
417 {
418 dyn = dynhn_find_by_id (adj->lanid);
419 if (dyn)
420 vty_out (vty, ", LAN id: %s.%02x",
421 dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
422 else
423 vty_out (vty, ", LAN id: %s.%02x",
424 sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
425
426 vty_out (vty, "%s", VTY_NEWLINE);
427 vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]);
428
429 vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago",
430 isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
431 dis), adj->dischanges[level - 1],
432 time2string (now -
433 (adj->dis_record[ISIS_LEVELS + level - 1].
434 last_dis_change)));
435 }
436 vty_out (vty, "%s", VTY_NEWLINE);
f390d2c7 437
3f045a08
JB
438 if (adj->area_addrs && listcount (adj->area_addrs) > 0)
439 {
440 struct area_addr *area_addr;
441 vty_out (vty, " Area Address(es):%s", VTY_NEWLINE);
442 for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr))
443 vty_out (vty, " %s%s", isonet_print (area_addr->area_addr,
444 area_addr->addr_len), VTY_NEWLINE);
445 }
f390d2c7 446 if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
447 {
3f045a08 448 vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE);
1eb8ef25 449 for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
450 vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
f390d2c7 451 }
f390d2c7 452 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
453 {
3f045a08 454 vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE);
5d6e2691 455 for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
f390d2c7 456 {
f7c43dcb 457 inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
f390d2c7 458 vty_out (vty, " %s%s", ip6, VTY_NEWLINE);
459 }
460 }
f390d2c7 461 vty_out (vty, "%s", VTY_NEWLINE);
462 }
eb5d44eb 463 return;
464}
465
eb5d44eb 466void
467isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
eb5d44eb 468{
469 struct isis_adjacency *adj;
470 struct listnode *node;
f390d2c7 471
472 if (!list)
473 {
474 zlog_warn ("isis_adj_build_neigh_list(): NULL list");
eb5d44eb 475 return;
476 }
f390d2c7 477
1eb8ef25 478 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
f390d2c7 479 {
f390d2c7 480 if (!adj)
481 {
482 zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
483 return;
484 }
485
486 if ((adj->adj_state == ISIS_ADJ_UP ||
487 adj->adj_state == ISIS_ADJ_INITIALIZING))
488 listnode_add (list, adj->snpa);
489 }
eb5d44eb 490 return;
491}
492
493void
494isis_adj_build_up_list (struct list *adjdb, struct list *list)
495{
496 struct isis_adjacency *adj;
497 struct listnode *node;
498
cd4ab724 499 if (adjdb == NULL) {
500 zlog_warn ("isis_adj_build_up_list(): adjacency DB is empty");
501 return;
502 }
503
f390d2c7 504 if (!list)
505 {
506 zlog_warn ("isis_adj_build_up_list(): NULL list");
eb5d44eb 507 return;
508 }
509
1eb8ef25 510 for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
f390d2c7 511 {
f390d2c7 512 if (!adj)
513 {
514 zlog_warn ("isis_adj_build_up_list(): NULL adj");
515 return;
516 }
517
518 if (adj->adj_state == ISIS_ADJ_UP)
519 listnode_add (list, adj);
520 }
521
eb5d44eb 522 return;
523}