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