]>
Commit | Line | Data |
---|---|---|
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 | 51 | extern struct isis *isis; |
52 | ||
92365889 | 53 | static struct isis_adjacency * |
02e33d3e | 54 | adj_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 | ||
64 | struct isis_adjacency * | |
02e33d3e | 65 | isis_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 | ||
105 | struct isis_adjacency * | |
02e33d3e | 106 | isis_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 | 118 | struct isis_adjacency * |
02e33d3e | 119 | isis_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 | 131 | void |
3f045a08 | 132 | isis_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 |
155 | static const char * |
156 | adj_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 | 174 | void |
3f045a08 | 175 | isis_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 | ||
296 | void | |
297 | isis_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 | 336 | int |
eb5d44eb | 337 | isis_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 |
357 | void |
358 | isis_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 | 466 | void |
467 | isis_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 | ||
493 | void | |
494 | isis_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 | } |