]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_adjacency.c
Merge pull request #2576 from pacovn/Coverity_1399228_Logically_dead_code
[mirror_frr.git] / isisd / isis_adjacency.c
CommitLineData
eb5d44eb 1/*
d62a17ae 2 * IS-IS Rout(e)ing protocol - isis_adjacency.c
eb5d44eb 3 * handling of IS-IS adjacencies
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 6 * Tampere University of Technology
eb5d44eb 7 * Institute of Communications Engineering
8 *
d62a17ae 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)
eb5d44eb 12 * any later version.
13 *
d62a17ae 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
eb5d44eb 17 * more details.
896014f4
DL
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
eb5d44eb 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_lsp.h"
47#include "isisd/isis_spf.h"
48#include "isisd/isis_events.h"
206f4aae 49#include "isisd/isis_mt.h"
42fe2621 50#include "isisd/isis_tlvs.h"
eb5d44eb 51
eb5d44eb 52extern struct isis *isis;
53
d7c0a89a 54static struct isis_adjacency *adj_alloc(const uint8_t *id)
eb5d44eb 55{
d62a17ae 56 struct isis_adjacency *adj;
eb5d44eb 57
d62a17ae 58 adj = XCALLOC(MTYPE_ISIS_ADJACENCY, sizeof(struct isis_adjacency));
59 memcpy(adj->sysid, id, ISIS_SYS_ID_LEN);
f390d2c7 60
d62a17ae 61 return adj;
eb5d44eb 62}
63
d7c0a89a 64struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
d62a17ae 65 int level, struct isis_circuit *circuit)
eb5d44eb 66{
d62a17ae 67 struct isis_adjacency *adj;
68 int i;
69
70 adj = adj_alloc(id); /* P2P kludge */
71
d62a17ae 72 if (snpa) {
73 memcpy(adj->snpa, snpa, ETH_ALEN);
74 } else {
75 memset(adj->snpa, ' ', ETH_ALEN);
eb5d44eb 76 }
eb5d44eb 77
d62a17ae 78 adj->circuit = circuit;
79 adj->level = level;
80 adj->flaps = 0;
81 adj->last_flap = time(NULL);
42fe2621 82 adj->threeway_state = ISIS_THREEWAY_DOWN;
d62a17ae 83 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
84 listnode_add(circuit->u.bc.adjdb[level - 1], adj);
85 adj->dischanges[level - 1] = 0;
86 for (i = 0; i < DIS_RECORDS;
87 i++) /* clear N DIS state change records */
88 {
89 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
90 ISIS_UNKNOWN_DIS;
91 adj->dis_record[(i * ISIS_LEVELS) + level - 1]
92 .last_dis_change = time(NULL);
93 }
94 }
95
96 return adj;
eb5d44eb 97}
98
d7c0a89a 99struct isis_adjacency *isis_adj_lookup(const uint8_t *sysid, struct list *adjdb)
eb5d44eb 100{
d62a17ae 101 struct isis_adjacency *adj;
102 struct listnode *node;
eb5d44eb 103
d62a17ae 104 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
105 if (memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
106 return adj;
f390d2c7 107
d62a17ae 108 return NULL;
eb5d44eb 109}
110
d7c0a89a 111struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
d62a17ae 112 struct list *adjdb)
eb5d44eb 113{
d62a17ae 114 struct listnode *node;
115 struct isis_adjacency *adj;
eb5d44eb 116
d62a17ae 117 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
118 if (memcmp(adj->snpa, ssnpa, ETH_ALEN) == 0)
119 return adj;
f390d2c7 120
d62a17ae 121 return NULL;
eb5d44eb 122}
123
d62a17ae 124void isis_delete_adj(void *arg)
eb5d44eb 125{
d62a17ae 126 struct isis_adjacency *adj = arg;
3f045a08 127
d62a17ae 128 if (!adj)
129 return;
f390d2c7 130
d62a17ae 131 THREAD_TIMER_OFF(adj->t_expire);
3f045a08 132
d62a17ae 133 /* remove from SPF trees */
134 spftree_area_adj_del(adj->circuit->area, adj);
13fb40ac 135
0c1bd758
CF
136 if (adj->area_addresses)
137 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
138 if (adj->ipv4_addresses)
139 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
140 if (adj->ipv6_addresses)
141 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
3f045a08 142
d62a17ae 143 adj_mt_finish(adj);
d8fba7d9 144
d62a17ae 145 XFREE(MTYPE_ISIS_ADJACENCY, adj);
146 return;
eb5d44eb 147}
148
d62a17ae 149static const char *adj_state2string(int state)
3f045a08
JB
150{
151
d62a17ae 152 switch (state) {
153 case ISIS_ADJ_INITIALIZING:
154 return "Initializing";
155 case ISIS_ADJ_UP:
156 return "Up";
157 case ISIS_ADJ_DOWN:
158 return "Down";
159 default:
160 return "Unknown";
161 }
162
163 return NULL; /* not reached */
3f045a08
JB
164}
165
42fe2621
CF
166void isis_adj_process_threeway(struct isis_adjacency *adj,
167 struct isis_threeway_adj *tw_adj,
168 enum isis_adj_usage adj_usage)
169{
170 enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN;
171
58e5d748 172 if (tw_adj && !adj->circuit->disable_threeway_adj) {
42fe2621
CF
173 if (tw_adj->state == ISIS_THREEWAY_DOWN) {
174 next_tw_state = ISIS_THREEWAY_INITIALIZING;
175 } else if (tw_adj->state == ISIS_THREEWAY_INITIALIZING) {
176 next_tw_state = ISIS_THREEWAY_UP;
177 } else if (tw_adj->state == ISIS_THREEWAY_UP) {
178 if (adj->threeway_state == ISIS_THREEWAY_DOWN)
179 next_tw_state = ISIS_THREEWAY_DOWN;
180 else
181 next_tw_state = ISIS_THREEWAY_UP;
182 }
183 } else {
184 next_tw_state = ISIS_THREEWAY_UP;
185 }
186
187 if (next_tw_state != adj->threeway_state) {
188 if (isis->debugs & DEBUG_ADJ_PACKETS) {
189 zlog_info("ISIS-Adj (%s): Threeway state change %s to %s",
190 adj->circuit->area->area_tag,
191 isis_threeway_state_name(adj->threeway_state),
192 isis_threeway_state_name(next_tw_state));
193 }
194 }
195
196 if (next_tw_state == ISIS_THREEWAY_DOWN) {
197 isis_adj_state_change(adj, ISIS_ADJ_DOWN, "Neighbor restarted");
198 return;
199 }
200
201 if (next_tw_state == ISIS_THREEWAY_UP) {
202 if (adj->adj_state != ISIS_ADJ_UP) {
203 isis_adj_state_change(adj, ISIS_ADJ_UP, NULL);
204 adj->adj_usage = adj_usage;
205 }
206 }
207
208 adj->threeway_state = next_tw_state;
209}
210
d62a17ae 211void isis_adj_state_change(struct isis_adjacency *adj,
212 enum isis_adj_state new_state, const char *reason)
eb5d44eb 213{
d62a17ae 214 int old_state;
215 int level;
216 struct isis_circuit *circuit;
217 bool del;
218
219 old_state = adj->adj_state;
220 adj->adj_state = new_state;
221
222 circuit = adj->circuit;
223
224 if (isis->debugs & DEBUG_ADJ_PACKETS) {
225 zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
226 circuit->area->area_tag, old_state, new_state,
227 reason ? reason : "unspecified");
228 }
229
230 if (circuit->area->log_adj_changes) {
231 const char *adj_name;
232 struct isis_dynhn *dyn;
233
234 dyn = dynhn_find_by_id(adj->sysid);
235 if (dyn)
af8ac8f9 236 adj_name = dyn->hostname;
d62a17ae 237 else
238 adj_name = sysid_print(adj->sysid);
239
240 zlog_info(
241 "%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s",
242 adj_name, adj->circuit->interface->name,
243 adj_state2string(old_state),
244 adj_state2string(new_state),
245 reason ? reason : "unspecified");
246 }
247
248 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
249 del = false;
250 for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
251 if ((adj->level & level) == 0)
252 continue;
253 if (new_state == ISIS_ADJ_UP) {
254 circuit->upadjcount[level - 1]++;
255 isis_event_adjacency_state_change(adj,
256 new_state);
257 /* update counter & timers for debugging
258 * purposes */
259 adj->last_flap = time(NULL);
260 adj->flaps++;
261 } else if (new_state == ISIS_ADJ_DOWN) {
262 listnode_delete(circuit->u.bc.adjdb[level - 1],
263 adj);
58e16237 264
d62a17ae 265 circuit->upadjcount[level - 1]--;
58e16237
CF
266 if (circuit->upadjcount[level - 1] == 0)
267 isis_circuit_lsp_queue_clean(circuit);
268
d62a17ae 269 isis_event_adjacency_state_change(adj,
270 new_state);
271 del = true;
272 }
273
274 if (circuit->u.bc.lan_neighs[level - 1]) {
275 list_delete_all_node(
276 circuit->u.bc.lan_neighs[level - 1]);
277 isis_adj_build_neigh_list(
278 circuit->u.bc.adjdb[level - 1],
279 circuit->u.bc.lan_neighs[level - 1]);
280 }
281
282 /* On adjacency state change send new pseudo LSP if we
283 * are the DR */
284 if (circuit->u.bc.is_dr[level - 1])
285 lsp_regenerate_schedule_pseudo(circuit, level);
286 }
287
288 if (del)
289 isis_delete_adj(adj);
290
d62a17ae 291 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
292 del = false;
293 for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
294 if ((adj->level & level) == 0)
295 continue;
296 if (new_state == ISIS_ADJ_UP) {
297 circuit->upadjcount[level - 1]++;
298 isis_event_adjacency_state_change(adj,
299 new_state);
300
301 if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
302 send_hello(circuit, level);
303
304 /* update counter & timers for debugging
305 * purposes */
306 adj->last_flap = time(NULL);
307 adj->flaps++;
308
309 /* 7.3.17 - going up on P2P -> send CSNP */
310 /* FIXME: yup, I know its wrong... but i will do
311 * it! (for now) */
312 send_csnp(circuit, level);
313 } else if (new_state == ISIS_ADJ_DOWN) {
314 if (adj->circuit->u.p2p.neighbor == adj)
315 adj->circuit->u.p2p.neighbor = NULL;
316 circuit->upadjcount[level - 1]--;
58e16237
CF
317 if (circuit->upadjcount[level - 1] == 0)
318 isis_circuit_lsp_queue_clean(circuit);
319
d62a17ae 320 isis_event_adjacency_state_change(adj,
321 new_state);
322 del = true;
323 }
324 }
325
326 if (del)
327 isis_delete_adj(adj);
d62a17ae 328 }
329
330 return;
eb5d44eb 331}
332
333
d62a17ae 334void isis_adj_print(struct isis_adjacency *adj)
eb5d44eb 335{
d62a17ae 336 struct isis_dynhn *dyn;
d62a17ae 337
338 if (!adj)
339 return;
340 dyn = dynhn_find_by_id(adj->sysid);
341 if (dyn)
af8ac8f9 342 zlog_debug("%s", dyn->hostname);
d62a17ae 343
344 zlog_debug("SystemId %20s SNPA %s, level %d\nHolding Time %d",
345 sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
346 adj->hold_time);
0c1bd758 347 if (adj->ipv4_address_count) {
d62a17ae 348 zlog_debug("IPv4 Address(es):");
0c1bd758
CF
349 for (unsigned int i = 0; i < adj->ipv4_address_count; i++)
350 zlog_debug("%s", inet_ntoa(adj->ipv4_addresses[i]));
d62a17ae 351 }
352
0c1bd758 353 if (adj->ipv6_address_count) {
d62a17ae 354 zlog_debug("IPv6 Address(es):");
0c1bd758
CF
355 for (unsigned int i = 0; i < adj->ipv6_address_count; i++) {
356 char buf[INET6_ADDRSTRLEN];
357 inet_ntop(AF_INET6, &adj->ipv6_addresses[i], buf,
358 sizeof(buf));
359 zlog_debug("%s", buf);
d62a17ae 360 }
f390d2c7 361 }
d62a17ae 362 zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids));
eb5d44eb 363
d62a17ae 364 return;
eb5d44eb 365}
366
d62a17ae 367int isis_adj_expire(struct thread *thread)
eb5d44eb 368{
d62a17ae 369 struct isis_adjacency *adj;
eb5d44eb 370
d62a17ae 371 /*
372 * Get the adjacency
373 */
374 adj = THREAD_ARG(thread);
375 assert(adj);
376 adj->t_expire = NULL;
eb5d44eb 377
d62a17ae 378 /* trigger the adj expire event */
379 isis_adj_state_change(adj, ISIS_ADJ_DOWN, "holding time expired");
eb5d44eb 380
d62a17ae 381 return 0;
eb5d44eb 382}
383
eb5d44eb 384/*
3f045a08 385 * show isis neighbor [detail]
eb5d44eb 386 */
d62a17ae 387void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
388 char detail)
eb5d44eb 389{
d62a17ae 390 time_t now;
391 struct isis_dynhn *dyn;
392 int level;
d62a17ae 393
394 dyn = dynhn_find_by_id(adj->sysid);
395 if (dyn)
af8ac8f9 396 vty_out(vty, " %-20s", dyn->hostname);
d62a17ae 397 else
398 vty_out(vty, " %-20s", sysid_print(adj->sysid));
399
400 if (detail == ISIS_UI_LEVEL_BRIEF) {
401 if (adj->circuit)
402 vty_out(vty, "%-12s", adj->circuit->interface->name);
403 else
404 vty_out(vty, "NULL circuit!");
405 vty_out(vty, "%-3u", adj->level); /* level */
406 vty_out(vty, "%-13s", adj_state2string(adj->adj_state));
407 now = time(NULL);
408 if (adj->last_upd)
409 vty_out(vty, "%-9llu",
410 (unsigned long long)adj->last_upd
411 + adj->hold_time - now);
412 else
413 vty_out(vty, "- ");
414 vty_out(vty, "%-10s", snpa_print(adj->snpa));
415 vty_out(vty, "\n");
f390d2c7 416 }
d62a17ae 417
418 if (detail == ISIS_UI_LEVEL_DETAIL) {
419 level = adj->level;
420 vty_out(vty, "\n");
421 if (adj->circuit)
422 vty_out(vty, " Interface: %s",
423 adj->circuit->interface->name);
424 else
425 vty_out(vty, " Interface: NULL circuit");
426 vty_out(vty, ", Level: %u", adj->level); /* level */
427 vty_out(vty, ", State: %s", adj_state2string(adj->adj_state));
428 now = time(NULL);
429 if (adj->last_upd)
430 vty_out(vty, ", Expires in %s",
431 time2string(adj->last_upd + adj->hold_time
432 - now));
433 else
434 vty_out(vty, ", Expires in %s",
435 time2string(adj->hold_time));
436 vty_out(vty, "\n");
437 vty_out(vty, " Adjacency flaps: %u", adj->flaps);
438 vty_out(vty, ", Last: %s ago",
439 time2string(now - adj->last_flap));
440 vty_out(vty, "\n");
441 vty_out(vty, " Circuit type: %s",
442 circuit_t2string(adj->circuit_t));
443 vty_out(vty, ", Speaks: %s", nlpid2string(&adj->nlpids));
444 vty_out(vty, "\n");
445 if (adj->mt_count != 1
446 || adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
447 vty_out(vty, " Topologies:\n");
448 for (unsigned int i = 0; i < adj->mt_count; i++)
449 vty_out(vty, " %s\n",
450 isis_mtid2str(adj->mt_set[i]));
451 }
452 vty_out(vty, " SNPA: %s", snpa_print(adj->snpa));
453 if (adj->circuit
454 && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
455 dyn = dynhn_find_by_id(adj->lanid);
456 if (dyn)
af8ac8f9 457 vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
d62a17ae 458 adj->lanid[ISIS_SYS_ID_LEN]);
459 else
460 vty_out(vty, ", LAN id: %s.%02x",
461 sysid_print(adj->lanid),
462 adj->lanid[ISIS_SYS_ID_LEN]);
463
464 vty_out(vty, "\n");
465 vty_out(vty, " LAN Priority: %u",
466 adj->prio[adj->level - 1]);
467
468 vty_out(vty, ", %s, DIS flaps: %u, Last: %s ago",
469 isis_disflag2string(
470 adj->dis_record[ISIS_LEVELS + level - 1]
471 .dis),
472 adj->dischanges[level - 1],
9d303b37
DL
473 time2string(now - (adj->dis_record[ISIS_LEVELS
474 + level - 1]
475 .last_dis_change)));
d62a17ae 476 }
477 vty_out(vty, "\n");
478
0c1bd758 479 if (adj->area_address_count) {
d62a17ae 480 vty_out(vty, " Area Address(es):\n");
0c1bd758
CF
481 for (unsigned int i = 0; i < adj->area_address_count;
482 i++) {
d62a17ae 483 vty_out(vty, " %s\n",
996c9314
LB
484 isonet_print(adj->area_addresses[i]
485 .area_addr,
486 adj->area_addresses[i]
487 .addr_len));
0c1bd758 488 }
d62a17ae 489 }
0c1bd758 490 if (adj->ipv4_address_count) {
d62a17ae 491 vty_out(vty, " IPv4 Address(es):\n");
0c1bd758
CF
492 for (unsigned int i = 0; i < adj->ipv4_address_count;
493 i++)
494 vty_out(vty, " %s\n",
996c9314 495 inet_ntoa(adj->ipv4_addresses[i]));
d62a17ae 496 }
0c1bd758 497 if (adj->ipv6_address_count) {
d62a17ae 498 vty_out(vty, " IPv6 Address(es):\n");
0c1bd758
CF
499 for (unsigned int i = 0; i < adj->ipv6_address_count;
500 i++) {
501 char buf[INET6_ADDRSTRLEN];
502 inet_ntop(AF_INET6, &adj->ipv6_addresses[i],
503 buf, sizeof(buf));
504 vty_out(vty, " %s\n", buf);
d62a17ae 505 }
506 }
507 vty_out(vty, "\n");
f390d2c7 508 }
d62a17ae 509 return;
eb5d44eb 510}
511
d62a17ae 512void isis_adj_build_neigh_list(struct list *adjdb, struct list *list)
eb5d44eb 513{
d62a17ae 514 struct isis_adjacency *adj;
515 struct listnode *node;
516
517 if (!list) {
518 zlog_warn("isis_adj_build_neigh_list(): NULL list");
519 return;
f390d2c7 520 }
521
d62a17ae 522 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
523 if (!adj) {
524 zlog_warn("isis_adj_build_neigh_list(): NULL adj");
525 return;
526 }
527
528 if ((adj->adj_state == ISIS_ADJ_UP
529 || adj->adj_state == ISIS_ADJ_INITIALIZING))
530 listnode_add(list, adj->snpa);
531 }
532 return;
eb5d44eb 533}
534
d62a17ae 535void isis_adj_build_up_list(struct list *adjdb, struct list *list)
eb5d44eb 536{
d62a17ae 537 struct isis_adjacency *adj;
538 struct listnode *node;
539
540 if (adjdb == NULL) {
541 zlog_warn("isis_adj_build_up_list(): adjacency DB is empty");
542 return;
543 }
544
545 if (!list) {
546 zlog_warn("isis_adj_build_up_list(): NULL list");
547 return;
f390d2c7 548 }
549
d62a17ae 550 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
551 if (!adj) {
552 zlog_warn("isis_adj_build_up_list(): NULL adj");
553 return;
554 }
f390d2c7 555
d62a17ae 556 if (adj->adj_state == ISIS_ADJ_UP)
557 listnode_add(list, adj);
558 }
559
560 return;
eb5d44eb 561}
d8fba7d9 562
d62a17ae 563int isis_adj_usage2levels(enum isis_adj_usage usage)
d8fba7d9 564{
d62a17ae 565 switch (usage) {
566 case ISIS_ADJ_LEVEL1:
567 return IS_LEVEL_1;
568 case ISIS_ADJ_LEVEL2:
569 return IS_LEVEL_2;
570 case ISIS_ADJ_LEVEL1AND2:
571 return IS_LEVEL_1 | IS_LEVEL_2;
572 default:
573 break;
574 }
575 return 0;
d8fba7d9 576}