]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_adjacency.c
*: Add camelCase JSON keys in addition to PascalCase
[mirror_frr.git] / isisd / isis_adjacency.c
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; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include <zebra.h>
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/isis_constants.h"
36 #include "isisd/isis_common.h"
37 #include "isisd/isis_flags.h"
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"
45 #include "isisd/isis_lsp.h"
46 #include "isisd/isis_events.h"
47 #include "isisd/isis_mt.h"
48 #include "isisd/isis_tlvs.h"
49 #include "isisd/fabricd.h"
50 #include "isisd/isis_nb.h"
51
52 DEFINE_MTYPE_STATIC(ISISD, ISIS_ADJACENCY, "ISIS adjacency");
53 DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info");
54
55 static struct isis_adjacency *adj_alloc(struct isis_circuit *circuit,
56 const uint8_t *id)
57 {
58 struct isis_adjacency *adj;
59
60 adj = XCALLOC(MTYPE_ISIS_ADJACENCY, sizeof(struct isis_adjacency));
61 memcpy(adj->sysid, id, ISIS_SYS_ID_LEN);
62
63 adj->snmp_idx = ++circuit->snmp_adj_idx_gen;
64
65 if (circuit->snmp_adj_list == NULL)
66 circuit->snmp_adj_list = list_new();
67
68 adj->snmp_list_node = listnode_add(circuit->snmp_adj_list, adj);
69
70 return adj;
71 }
72
73 struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
74 int level, struct isis_circuit *circuit)
75 {
76 struct isis_adjacency *adj;
77 int i;
78
79 adj = adj_alloc(circuit, id); /* P2P kludge */
80
81 if (snpa) {
82 memcpy(adj->snpa, snpa, ETH_ALEN);
83 } else {
84 memset(adj->snpa, ' ', ETH_ALEN);
85 }
86
87 adj->circuit = circuit;
88 adj->level = level;
89 adj->flaps = 0;
90 adj->last_flap = time(NULL);
91 adj->threeway_state = ISIS_THREEWAY_DOWN;
92 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
93 listnode_add(circuit->u.bc.adjdb[level - 1], adj);
94 adj->dischanges[level - 1] = 0;
95 for (i = 0; i < DIS_RECORDS;
96 i++) /* clear N DIS state change records */
97 {
98 adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis =
99 ISIS_UNKNOWN_DIS;
100 adj->dis_record[(i * ISIS_LEVELS) + level - 1]
101 .last_dis_change = time(NULL);
102 }
103 }
104 adj->adj_sids = list_new();
105 listnode_add(circuit->area->adjacency_list, adj);
106
107 return adj;
108 }
109
110 struct isis_adjacency *isis_adj_lookup(const uint8_t *sysid, struct list *adjdb)
111 {
112 struct isis_adjacency *adj;
113 struct listnode *node;
114
115 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
116 if (memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
117 return adj;
118
119 return NULL;
120 }
121
122 struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
123 struct list *adjdb)
124 {
125 struct listnode *node;
126 struct isis_adjacency *adj;
127
128 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
129 if (memcmp(adj->snpa, ssnpa, ETH_ALEN) == 0)
130 return adj;
131
132 return NULL;
133 }
134
135 struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level,
136 const uint8_t *sysid)
137 {
138 struct isis_adjacency *adj;
139 struct listnode *node;
140
141 for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
142 if (!(adj->level & level))
143 continue;
144
145 if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
146 return adj;
147 }
148
149 return NULL;
150 }
151
152 DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj));
153
154 void isis_delete_adj(void *arg)
155 {
156 struct isis_adjacency *adj = arg;
157
158 if (!adj)
159 return;
160 /* Remove self from snmp list without walking the list*/
161 list_delete_node(adj->circuit->snmp_adj_list, adj->snmp_list_node);
162
163 thread_cancel(&adj->t_expire);
164 if (adj->adj_state != ISIS_ADJ_DOWN)
165 adj->adj_state = ISIS_ADJ_DOWN;
166
167 hook_call(isis_adj_state_change_hook, adj);
168
169 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->area_addresses);
170 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv4_addresses);
171 XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ll_ipv6_addrs);
172
173 adj_mt_finish(adj);
174 list_delete(&adj->adj_sids);
175
176 listnode_delete(adj->circuit->area->adjacency_list, adj);
177 XFREE(MTYPE_ISIS_ADJACENCY, adj);
178 return;
179 }
180
181 static const char *adj_state2string(int state)
182 {
183
184 switch (state) {
185 case ISIS_ADJ_INITIALIZING:
186 return "Initializing";
187 case ISIS_ADJ_UP:
188 return "Up";
189 case ISIS_ADJ_DOWN:
190 return "Down";
191 default:
192 return "Unknown";
193 }
194
195 return NULL; /* not reached */
196 }
197
198 static const char *adj_level2string(int level)
199 {
200 switch (level) {
201 case IS_LEVEL_1:
202 return "level-1";
203 case IS_LEVEL_2:
204 return "level-2";
205 case IS_LEVEL_1_AND_2:
206 return "level-1-2";
207 default:
208 return "unknown";
209 }
210
211 return NULL; /* not reached */
212 }
213
214 void isis_adj_process_threeway(struct isis_adjacency *adj,
215 struct isis_threeway_adj *tw_adj,
216 enum isis_adj_usage adj_usage)
217 {
218 enum isis_threeway_state next_tw_state = ISIS_THREEWAY_DOWN;
219
220 if (tw_adj && !adj->circuit->disable_threeway_adj) {
221 if (tw_adj->state == ISIS_THREEWAY_DOWN) {
222 next_tw_state = ISIS_THREEWAY_INITIALIZING;
223 } else if (tw_adj->state == ISIS_THREEWAY_INITIALIZING) {
224 next_tw_state = ISIS_THREEWAY_UP;
225 } else if (tw_adj->state == ISIS_THREEWAY_UP) {
226 if (adj->threeway_state == ISIS_THREEWAY_DOWN)
227 next_tw_state = ISIS_THREEWAY_DOWN;
228 else
229 next_tw_state = ISIS_THREEWAY_UP;
230 }
231 } else {
232 next_tw_state = ISIS_THREEWAY_UP;
233 }
234
235 if (next_tw_state != adj->threeway_state) {
236 if (IS_DEBUG_ADJ_PACKETS) {
237 zlog_info("ISIS-Adj (%s): Threeway state change %s to %s",
238 adj->circuit->area->area_tag,
239 isis_threeway_state_name(adj->threeway_state),
240 isis_threeway_state_name(next_tw_state));
241 }
242 }
243
244 if (next_tw_state != ISIS_THREEWAY_DOWN)
245 fabricd_initial_sync_hello(adj->circuit);
246
247 if (next_tw_state == ISIS_THREEWAY_DOWN) {
248 isis_adj_state_change(&adj, ISIS_ADJ_DOWN,
249 "Neighbor restarted");
250 return;
251 }
252
253 if (next_tw_state == ISIS_THREEWAY_UP) {
254 if (adj->adj_state != ISIS_ADJ_UP) {
255 isis_adj_state_change(&adj, ISIS_ADJ_UP, NULL);
256 adj->adj_usage = adj_usage;
257 }
258 }
259
260 if (adj->threeway_state != next_tw_state) {
261 send_hello_sched(adj->circuit, 0, TRIGGERED_IIH_DELAY);
262 }
263
264 adj->threeway_state = next_tw_state;
265 }
266 const char *isis_adj_name(const struct isis_adjacency *adj)
267 {
268 if (!adj)
269 return "NONE";
270
271 struct isis_dynhn *dyn;
272
273 dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
274 if (dyn)
275 return dyn->hostname;
276 else
277 return sysid_print(adj->sysid);
278 }
279 void isis_log_adj_change(struct isis_adjacency *adj,
280 enum isis_adj_state old_state,
281 enum isis_adj_state new_state, const char *reason)
282 {
283 zlog_info(
284 "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s",
285 isis_adj_name(adj), adj->circuit->interface->name,
286 adj_level2string(adj->level), adj_state2string(old_state),
287 adj_state2string(new_state), reason ? reason : "unspecified");
288 }
289 void isis_adj_state_change(struct isis_adjacency **padj,
290 enum isis_adj_state new_state, const char *reason)
291 {
292 struct isis_adjacency *adj = *padj;
293 enum isis_adj_state old_state = adj->adj_state;
294 struct isis_circuit *circuit = adj->circuit;
295 bool del = false;
296
297 if (new_state == old_state)
298 return;
299
300 adj->adj_state = new_state;
301 send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
302
303 if (IS_DEBUG_ADJ_PACKETS) {
304 zlog_debug("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
305 circuit->area->area_tag, old_state, new_state,
306 reason ? reason : "unspecified");
307 }
308
309 if (circuit->area->log_adj_changes)
310 isis_log_adj_change(adj, old_state, new_state, reason);
311
312 #ifndef FABRICD
313 /* send northbound notification */
314 isis_notif_adj_state_change(adj, new_state, reason);
315 #endif /* ifndef FABRICD */
316
317 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
318 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
319 if ((adj->level & level) == 0)
320 continue;
321 if (new_state == ISIS_ADJ_UP) {
322 circuit->adj_state_changes++;
323 circuit->upadjcount[level - 1]++;
324 /* update counter & timers for debugging
325 * purposes */
326 adj->last_flap = time(NULL);
327 adj->flaps++;
328 } else if (old_state == ISIS_ADJ_UP) {
329 circuit->adj_state_changes++;
330
331 circuit->upadjcount[level - 1]--;
332 if (circuit->upadjcount[level - 1] == 0)
333 isis_tx_queue_clean(circuit->tx_queue);
334
335 if (new_state == ISIS_ADJ_DOWN) {
336 listnode_delete(
337 circuit->u.bc.adjdb[level - 1],
338 adj);
339
340 del = true;
341 }
342 }
343
344 if (circuit->u.bc.lan_neighs[level - 1]) {
345 list_delete_all_node(
346 circuit->u.bc.lan_neighs[level - 1]);
347 isis_adj_build_neigh_list(
348 circuit->u.bc.adjdb[level - 1],
349 circuit->u.bc.lan_neighs[level - 1]);
350 }
351
352 /* On adjacency state change send new pseudo LSP if we
353 * are the DR */
354 if (circuit->u.bc.is_dr[level - 1])
355 lsp_regenerate_schedule_pseudo(circuit, level);
356 }
357
358 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
359 for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
360 if ((adj->level & level) == 0)
361 continue;
362 if (new_state == ISIS_ADJ_UP) {
363 circuit->upadjcount[level - 1]++;
364
365 /* update counter & timers for debugging
366 * purposes */
367 adj->last_flap = time(NULL);
368 adj->flaps++;
369
370 if (level == IS_LEVEL_1) {
371 thread_add_timer(master, send_l1_csnp,
372 circuit, 0,
373 &circuit->t_send_csnp[0]);
374 } else {
375 thread_add_timer(master, send_l2_csnp,
376 circuit, 0,
377 &circuit->t_send_csnp[1]);
378 }
379 } else if (old_state == ISIS_ADJ_UP) {
380 circuit->upadjcount[level - 1]--;
381 if (circuit->upadjcount[level - 1] == 0)
382 isis_tx_queue_clean(circuit->tx_queue);
383
384 if (new_state == ISIS_ADJ_DOWN) {
385 if (adj->circuit->u.p2p.neighbor == adj)
386 adj->circuit->u.p2p.neighbor =
387 NULL;
388
389 del = true;
390 }
391 }
392 }
393 }
394
395 hook_call(isis_adj_state_change_hook, adj);
396
397 if (del) {
398 isis_delete_adj(adj);
399 *padj = NULL;
400 }
401 }
402
403
404 void isis_adj_print(struct isis_adjacency *adj)
405 {
406 struct isis_dynhn *dyn;
407
408 if (!adj)
409 return;
410 dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
411 if (dyn)
412 zlog_debug("%s", dyn->hostname);
413
414 zlog_debug("SystemId %20s SNPA %s, level %d; Holding Time %d",
415 sysid_print(adj->sysid), snpa_print(adj->snpa), adj->level,
416 adj->hold_time);
417 if (adj->ipv4_address_count) {
418 zlog_debug("IPv4 Address(es):");
419 for (unsigned int i = 0; i < adj->ipv4_address_count; i++)
420 zlog_debug("%pI4", &adj->ipv4_addresses[i]);
421 }
422
423 if (adj->ll_ipv6_count) {
424 zlog_debug("IPv6 Address(es):");
425 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
426 char buf[INET6_ADDRSTRLEN];
427 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
428 sizeof(buf));
429 zlog_debug("%s", buf);
430 }
431 }
432 zlog_debug("Speaks: %s", nlpid2string(&adj->nlpids));
433
434 return;
435 }
436
437 const char *isis_adj_yang_state(enum isis_adj_state state)
438 {
439 switch (state) {
440 case ISIS_ADJ_DOWN:
441 return "down";
442 case ISIS_ADJ_UP:
443 return "up";
444 case ISIS_ADJ_INITIALIZING:
445 return "init";
446 default:
447 return "failed";
448 }
449 }
450
451 int isis_adj_expire(struct thread *thread)
452 {
453 struct isis_adjacency *adj;
454
455 /*
456 * Get the adjacency
457 */
458 adj = THREAD_ARG(thread);
459 assert(adj);
460 adj->t_expire = NULL;
461
462 /* trigger the adj expire event */
463 isis_adj_state_change(&adj, ISIS_ADJ_DOWN, "holding time expired");
464
465 return 0;
466 }
467
468 /*
469 * show isis neighbor [detail]
470 */
471 void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
472 char detail)
473 {
474 time_t now;
475 struct isis_dynhn *dyn;
476 int level;
477
478 vty_out(vty, " %-20s", isis_adj_name(adj));
479
480 if (detail == ISIS_UI_LEVEL_BRIEF) {
481 if (adj->circuit)
482 vty_out(vty, "%-12s", adj->circuit->interface->name);
483 else
484 vty_out(vty, "NULL circuit!");
485 vty_out(vty, "%-3u", adj->level); /* level */
486 vty_out(vty, "%-13s", adj_state2string(adj->adj_state));
487 now = time(NULL);
488 if (adj->last_upd) {
489 if (adj->last_upd + adj->hold_time < now)
490 vty_out(vty, " Expiring");
491 else
492 vty_out(vty, " %-9llu",
493 (unsigned long long)adj->last_upd
494 + adj->hold_time - now);
495 } else
496 vty_out(vty, "- ");
497 vty_out(vty, "%-10s", snpa_print(adj->snpa));
498 vty_out(vty, "\n");
499 }
500
501 if (detail == ISIS_UI_LEVEL_DETAIL) {
502 struct sr_adjacency *sra;
503 struct listnode *anode;
504
505 level = adj->level;
506 vty_out(vty, "\n");
507 if (adj->circuit)
508 vty_out(vty, " Interface: %s",
509 adj->circuit->interface->name);
510 else
511 vty_out(vty, " Interface: NULL circuit");
512 vty_out(vty, ", Level: %u", adj->level); /* level */
513 vty_out(vty, ", State: %s", adj_state2string(adj->adj_state));
514 now = time(NULL);
515 if (adj->last_upd) {
516 if (adj->last_upd + adj->hold_time < now)
517 vty_out(vty, " Expiring");
518 else
519 vty_out(vty, ", Expires in %s",
520 time2string(adj->last_upd
521 + adj->hold_time - now));
522 } else
523 vty_out(vty, ", Expires in %s",
524 time2string(adj->hold_time));
525 vty_out(vty, "\n");
526 vty_out(vty, " Adjacency flaps: %u", adj->flaps);
527 vty_out(vty, ", Last: %s ago",
528 time2string(now - adj->last_flap));
529 vty_out(vty, "\n");
530 vty_out(vty, " Circuit type: %s",
531 circuit_t2string(adj->circuit_t));
532 vty_out(vty, ", Speaks: %s", nlpid2string(&adj->nlpids));
533 vty_out(vty, "\n");
534 if (adj->mt_count != 1
535 || adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
536 vty_out(vty, " Topologies:\n");
537 for (unsigned int i = 0; i < adj->mt_count; i++)
538 vty_out(vty, " %s\n",
539 isis_mtid2str(adj->mt_set[i]));
540 }
541 vty_out(vty, " SNPA: %s", snpa_print(adj->snpa));
542 if (adj->circuit
543 && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
544 dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
545 if (dyn)
546 vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
547 adj->lanid[ISIS_SYS_ID_LEN]);
548 else
549 vty_out(vty, ", LAN id: %s.%02x",
550 sysid_print(adj->lanid),
551 adj->lanid[ISIS_SYS_ID_LEN]);
552
553 vty_out(vty, "\n");
554 vty_out(vty, " LAN Priority: %u",
555 adj->prio[adj->level - 1]);
556
557 vty_out(vty, ", %s, DIS flaps: %u, Last: %s ago",
558 isis_disflag2string(
559 adj->dis_record[ISIS_LEVELS + level - 1]
560 .dis),
561 adj->dischanges[level - 1],
562 time2string(now - (adj->dis_record[ISIS_LEVELS
563 + level - 1]
564 .last_dis_change)));
565 }
566 vty_out(vty, "\n");
567
568 if (adj->area_address_count) {
569 vty_out(vty, " Area Address(es):\n");
570 for (unsigned int i = 0; i < adj->area_address_count;
571 i++) {
572 vty_out(vty, " %s\n",
573 isonet_print(adj->area_addresses[i]
574 .area_addr,
575 adj->area_addresses[i]
576 .addr_len));
577 }
578 }
579 if (adj->ipv4_address_count) {
580 vty_out(vty, " IPv4 Address(es):\n");
581 for (unsigned int i = 0; i < adj->ipv4_address_count;
582 i++)
583 vty_out(vty, " %pI4\n",
584 &adj->ipv4_addresses[i]);
585 }
586 if (adj->ll_ipv6_count) {
587 vty_out(vty, " IPv6 Address(es):\n");
588 for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
589 char buf[INET6_ADDRSTRLEN];
590 inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i],
591 buf, sizeof(buf));
592 vty_out(vty, " %s\n", buf);
593 }
594 }
595 if (adj->global_ipv6_count) {
596 vty_out(vty, " Global IPv6 Address(es):\n");
597 for (unsigned int i = 0; i < adj->global_ipv6_count;
598 i++) {
599 char buf[INET6_ADDRSTRLEN];
600 inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
601 buf, sizeof(buf));
602 vty_out(vty, " %s\n", buf);
603 }
604 }
605 for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
606 const char *adj_type;
607 const char *backup;
608 uint32_t sid;
609
610 switch (sra->adj->circuit->circ_type) {
611 case CIRCUIT_T_BROADCAST:
612 adj_type = "LAN Adjacency-SID";
613 sid = sra->u.ladj_sid->sid;
614 break;
615 case CIRCUIT_T_P2P:
616 adj_type = "Adjacency-SID";
617 sid = sra->u.adj_sid->sid;
618 break;
619 default:
620 continue;
621 }
622 backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
623 : "";
624
625 vty_out(vty, " %s %s%s: %u\n",
626 (sra->nexthop.family == AF_INET) ? "IPv4"
627 : "IPv6",
628 adj_type, backup, sid);
629 }
630 vty_out(vty, "\n");
631 }
632 return;
633 }
634
635 void isis_adj_build_neigh_list(struct list *adjdb, struct list *list)
636 {
637 struct isis_adjacency *adj;
638 struct listnode *node;
639
640 if (!list) {
641 zlog_warn("isis_adj_build_neigh_list(): NULL list");
642 return;
643 }
644
645 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
646 if (!adj) {
647 zlog_warn("isis_adj_build_neigh_list(): NULL adj");
648 return;
649 }
650
651 if ((adj->adj_state == ISIS_ADJ_UP
652 || adj->adj_state == ISIS_ADJ_INITIALIZING))
653 listnode_add(list, adj->snpa);
654 }
655 return;
656 }
657
658 void isis_adj_build_up_list(struct list *adjdb, struct list *list)
659 {
660 struct isis_adjacency *adj;
661 struct listnode *node;
662
663 if (adjdb == NULL) {
664 zlog_warn("isis_adj_build_up_list(): adjacency DB is empty");
665 return;
666 }
667
668 if (!list) {
669 zlog_warn("isis_adj_build_up_list(): NULL list");
670 return;
671 }
672
673 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj)) {
674 if (!adj) {
675 zlog_warn("isis_adj_build_up_list(): NULL adj");
676 return;
677 }
678
679 if (adj->adj_state == ISIS_ADJ_UP)
680 listnode_add(list, adj);
681 }
682
683 return;
684 }
685
686 int isis_adj_usage2levels(enum isis_adj_usage usage)
687 {
688 switch (usage) {
689 case ISIS_ADJ_LEVEL1:
690 return IS_LEVEL_1;
691 case ISIS_ADJ_LEVEL2:
692 return IS_LEVEL_2;
693 case ISIS_ADJ_LEVEL1AND2:
694 return IS_LEVEL_1 | IS_LEVEL_2;
695 default:
696 break;
697 }
698 return 0;
699 }