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