blob: f3ac9eaaeba5c753a076a99a0a1fcd8b6ccad631 [file] [log] [blame]
paul2d598362003-01-17 23:48:42 +00001/*
2 * OSPF version 2 Neighbor State Machine
3 * From RFC2328 [OSPF Version 2]
4 * Copyright (C) 1999, 2000 Toshiaki Takada
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24#include <zebra.h>
25
26#include "thread.h"
27#include "memory.h"
28#include "hash.h"
29#include "linklist.h"
30#include "prefix.h"
31#include "if.h"
32#include "table.h"
33#include "stream.h"
34#include "table.h"
35#include "log.h"
36
37#include "ospfd/ospfd.h"
38#include "ospfd/ospf_interface.h"
39#include "ospfd/ospf_ism.h"
40#include "ospfd/ospf_asbr.h"
41#include "ospfd/ospf_lsa.h"
42#include "ospfd/ospf_lsdb.h"
43#include "ospfd/ospf_neighbor.h"
44#include "ospfd/ospf_nsm.h"
45#include "ospfd/ospf_network.h"
46#include "ospfd/ospf_packet.h"
47#include "ospfd/ospf_dump.h"
48#include "ospfd/ospf_flood.h"
49#include "ospfd/ospf_abr.h"
vincent5e4914c2005-09-29 16:34:30 +000050#include "ospfd/ospf_snmp.h"
paul2d598362003-01-17 23:48:42 +000051
Paul Jakmad1b1cd82006-07-04 13:50:44 +000052static void nsm_clear_adj (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +000053
54/* OSPF NSM Timer functions. */
paul4dadc292005-05-06 21:37:42 +000055static int
paul2d598362003-01-17 23:48:42 +000056ospf_inactivity_timer (struct thread *thread)
57{
58 struct ospf_neighbor *nbr;
59
60 nbr = THREAD_ARG (thread);
61 nbr->t_inactivity = NULL;
62
63 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
64 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)",
65 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
66
67 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer);
68
69 return 0;
70}
71
paul4dadc292005-05-06 21:37:42 +000072static int
paul2d598362003-01-17 23:48:42 +000073ospf_db_desc_timer (struct thread *thread)
74{
75 struct ospf_interface *oi;
76 struct ospf_neighbor *nbr;
77
78 nbr = THREAD_ARG (thread);
79 nbr->t_db_desc = NULL;
80
81 oi = nbr->oi;
82
83 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
ajs2a42e282004-12-08 18:43:03 +000084 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
paul2d598362003-01-17 23:48:42 +000085 IF_NAME (nbr->oi), inet_ntoa (nbr->src));
86
87 /* resent last send DD packet. */
88 assert (nbr->last_send);
89 ospf_db_desc_resend (nbr);
90
91 /* DD Retransmit timer set. */
92 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
93
94 return 0;
95}
96
Paul Jakma1f2c2742006-07-10 07:45:13 +000097/* Hook function called after ospf NSM event is occured.
98 *
99 * Set/clear any timers whose condition is implicit to the neighbour
100 * state. There may be other timers which are set/unset according to other
101 * state.
102 *
103 * We rely on this function to properly clear timers in lower states,
104 * particularly before deleting a neighbour.
105 */
paul4dadc292005-05-06 21:37:42 +0000106static void
paul2d598362003-01-17 23:48:42 +0000107nsm_timer_set (struct ospf_neighbor *nbr)
108{
109 switch (nbr->state)
110 {
Paul Jakma1f2c2742006-07-10 07:45:13 +0000111 case NSM_Deleted:
paul2d598362003-01-17 23:48:42 +0000112 case NSM_Down:
Paul Jakmae55dd532006-07-04 13:46:14 +0000113 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
Paul Jakma1f2c2742006-07-10 07:45:13 +0000114 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
paul2d598362003-01-17 23:48:42 +0000115 case NSM_Attempt:
paul2d598362003-01-17 23:48:42 +0000116 case NSM_Init:
paul2d598362003-01-17 23:48:42 +0000117 case NSM_TwoWay:
118 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
119 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
Paul Jakmae55dd532006-07-04 13:46:14 +0000120 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
paul2d598362003-01-17 23:48:42 +0000121 break;
122 case NSM_ExStart:
123 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
124 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
Paul Jakmae55dd532006-07-04 13:46:14 +0000125 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
paul2d598362003-01-17 23:48:42 +0000126 break;
127 case NSM_Exchange:
128 OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
129 if (!IS_SET_DD_MS (nbr->dd_flags))
130 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
131 break;
132 case NSM_Loading:
paul2d598362003-01-17 23:48:42 +0000133 case NSM_Full:
paul2d598362003-01-17 23:48:42 +0000134 default:
135 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
136 break;
137 }
138}
139
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000140/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
141 * the given neighbour
142 */
143static int
144nsm_should_adj (struct ospf_neighbor *nbr)
145{
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000146 struct ospf_interface *oi = nbr->oi;
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000147
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000148 /* These network types must always form adjacencies. */
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000149 if (oi->type == OSPF_IFTYPE_POINTOPOINT
150 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000151 || oi->type == OSPF_IFTYPE_VIRTUALLINK
152 /* Router itself is the DRouter or the BDRouter. */
153 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
154 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))
155 /* Neighboring Router is the DRouter or the BDRouter. */
156 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000157 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
158 return 1;
159
160 return 0;
161}
paul2d598362003-01-17 23:48:42 +0000162
163/* OSPF NSM functions. */
paul4dadc292005-05-06 21:37:42 +0000164static int
paul2d598362003-01-17 23:48:42 +0000165nsm_hello_received (struct ospf_neighbor *nbr)
166{
167 /* Start or Restart Inactivity Timer. */
168 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
169
170 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
171 nbr->v_inactivity);
172
173 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
174 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
175
176 return 0;
177}
178
paul4dadc292005-05-06 21:37:42 +0000179static int
paul2d598362003-01-17 23:48:42 +0000180nsm_start (struct ospf_neighbor *nbr)
181{
paul2d598362003-01-17 23:48:42 +0000182 if (nbr->nbr_nbma)
183 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
184
185 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
186
187 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
188 nbr->v_inactivity);
189
190 return 0;
191}
192
paul4dadc292005-05-06 21:37:42 +0000193static int
paul2d598362003-01-17 23:48:42 +0000194nsm_twoway_received (struct ospf_neighbor *nbr)
195{
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000196 return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay);
paul2d598362003-01-17 23:48:42 +0000197}
198
199int
200ospf_db_summary_count (struct ospf_neighbor *nbr)
201{
202 return ospf_lsdb_count_all (&nbr->db_sum);
203}
204
205int
206ospf_db_summary_isempty (struct ospf_neighbor *nbr)
207{
208 return ospf_lsdb_isempty (&nbr->db_sum);
209}
210
paul4dadc292005-05-06 21:37:42 +0000211static int
paul68980082003-03-25 05:07:42 +0000212ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
paul2d598362003-01-17 23:48:42 +0000213{
paul09e4efd2003-01-18 00:12:02 +0000214#ifdef HAVE_OPAQUE_LSA
215 switch (lsa->data->type)
216 {
217 case OSPF_OPAQUE_LINK_LSA:
218 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
219 if (lsa->oi != nbr->oi)
220 return 0;
221 break;
222 case OSPF_OPAQUE_AREA_LSA:
223 /*
224 * It is assured by the caller function "nsm_negotiation_done()"
225 * that every given LSA belongs to the same area with "nbr".
226 */
227 break;
228 case OSPF_OPAQUE_AS_LSA:
229 default:
230 break;
231 }
232#endif /* HAVE_OPAQUE_LSA */
233
paul2d598362003-01-17 23:48:42 +0000234 /* Stay away from any Local Translated Type-7 LSAs */
235 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
236 return 0;
paul2d598362003-01-17 23:48:42 +0000237
238 if (IS_LSA_MAXAGE (lsa))
239 ospf_ls_retransmit_add (nbr, lsa);
240 else
241 ospf_lsdb_add (&nbr->db_sum, lsa);
242
243 return 0;
244}
245
246void
247ospf_db_summary_clear (struct ospf_neighbor *nbr)
248{
249 struct ospf_lsdb *lsdb;
250 int i;
251
252 lsdb = &nbr->db_sum;
253 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
254 {
255 struct route_table *table = lsdb->type[i].db;
256 struct route_node *rn;
257
258 for (rn = route_top (table); rn; rn = route_next (rn))
259 if (rn->info)
260 ospf_lsdb_delete (&nbr->db_sum, rn->info);
261 }
262}
263
264
265
paul2d598362003-01-17 23:48:42 +0000266/* The area link state database consists of the router-LSAs,
267 network-LSAs and summary-LSAs contained in the area structure,
paul68980082003-03-25 05:07:42 +0000268 along with the AS-external-LSAs contained in the global structure.
269 AS-external-LSAs are omitted from a virtual neighbor's Database
paul2d598362003-01-17 23:48:42 +0000270 summary list. AS-external-LSAs are omitted from the Database
271 summary list if the area has been configured as a stub. */
paul4dadc292005-05-06 21:37:42 +0000272static int
paul2d598362003-01-17 23:48:42 +0000273nsm_negotiation_done (struct ospf_neighbor *nbr)
274{
paul68980082003-03-25 05:07:42 +0000275 struct ospf_area *area = nbr->oi->area;
276 struct ospf_lsa *lsa;
277 struct route_node *rn;
paul2d598362003-01-17 23:48:42 +0000278
paul68980082003-03-25 05:07:42 +0000279 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
280 ospf_db_summary_add (nbr, lsa);
281 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
282 ospf_db_summary_add (nbr, lsa);
283 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
284 ospf_db_summary_add (nbr, lsa);
285 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
286 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000287
paul2d598362003-01-17 23:48:42 +0000288#ifdef HAVE_OPAQUE_LSA
289 /* Process only if the neighbor is opaque capable. */
290 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
291 {
paul68980082003-03-25 05:07:42 +0000292 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
293 ospf_db_summary_add (nbr, lsa);
294 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
295 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000296 }
297#endif /* HAVE_OPAQUE_LSA */
298
hassof4833e92005-06-20 20:42:26 +0000299 if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
300 {
301 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
302 ospf_db_summary_add (nbr, lsa);
303 }
304
paul68980082003-03-25 05:07:42 +0000305 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
306 && area->external_routing == OSPF_AREA_DEFAULT)
307 LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
308 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000309
310#ifdef HAVE_OPAQUE_LSA
paul68980082003-03-25 05:07:42 +0000311 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
312 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
313 && area->external_routing == OSPF_AREA_DEFAULT))
314 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
315 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000316#endif /* HAVE_OPAQUE_LSA */
317
paul2d598362003-01-17 23:48:42 +0000318 return 0;
319}
320
paul4dadc292005-05-06 21:37:42 +0000321static int
paul2d598362003-01-17 23:48:42 +0000322nsm_exchange_done (struct ospf_neighbor *nbr)
323{
paul2d598362003-01-17 23:48:42 +0000324 if (ospf_ls_request_isempty (nbr))
325 return NSM_Full;
326
paul2d598362003-01-17 23:48:42 +0000327 /* Send Link State Request. */
328 ospf_ls_req_send (nbr);
329
330 return NSM_Loading;
331}
332
paul4dadc292005-05-06 21:37:42 +0000333static int
paul2d598362003-01-17 23:48:42 +0000334nsm_adj_ok (struct ospf_neighbor *nbr)
335{
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000336 int next_state = nbr->state;
337 int adj = nsm_should_adj (nbr);
paul2d598362003-01-17 23:48:42 +0000338
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000339 if (nbr->state == NSM_TwoWay && adj == 1)
paul2d598362003-01-17 23:48:42 +0000340 next_state = NSM_ExStart;
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000341 else if (nbr->state >= NSM_ExStart && adj == 0)
paul2d598362003-01-17 23:48:42 +0000342 next_state = NSM_TwoWay;
343
344 return next_state;
345}
346
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000347/* Clear adjacency related state for a neighbour, intended where nbr
348 * transitions from > ExStart (i.e. a Full or forming adjacency)
349 * to <= ExStart.
350 */
351static void
352nsm_clear_adj (struct ospf_neighbor *nbr)
paul2d598362003-01-17 23:48:42 +0000353{
354 /* Clear Database Summary list. */
355 if (!ospf_db_summary_isempty (nbr))
356 ospf_db_summary_clear (nbr);
357
358 /* Clear Link State Request list. */
359 if (!ospf_ls_request_isempty (nbr))
360 ospf_ls_request_delete_all (nbr);
361
362 /* Clear Link State Retransmission list. */
363 if (!ospf_ls_retransmit_isempty (nbr))
364 ospf_ls_retransmit_clear (nbr);
paul2d598362003-01-17 23:48:42 +0000365
366#ifdef HAVE_OPAQUE_LSA
367 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
368 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
369#endif /* HAVE_OPAQUE_LSA */
370}
371
paul4dadc292005-05-06 21:37:42 +0000372static int
paul2d598362003-01-17 23:48:42 +0000373nsm_kill_nbr (struct ospf_neighbor *nbr)
374{
Paul Jakma478aab92006-04-03 21:25:32 +0000375 /* killing nbr_self is invalid */
Paul Jakma478aab92006-04-03 21:25:32 +0000376 if (nbr == nbr->oi->nbr_self)
Paul Jakma1f2c2742006-07-10 07:45:13 +0000377 {
378 assert (nbr != nbr->oi->nbr_self);
379 return 0;
380 }
Paul Jakma478aab92006-04-03 21:25:32 +0000381
paul2d598362003-01-17 23:48:42 +0000382 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
383 {
384 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
385
386 nbr_nbma->nbr = NULL;
387 nbr_nbma->state_change = nbr->state_change;
388
389 nbr->nbr_nbma = NULL;
390
391 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
392 nbr_nbma->v_poll);
393
394 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000395 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
paul2d598362003-01-17 23:48:42 +0000396 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
397 }
398
paul2d598362003-01-17 23:48:42 +0000399 return 0;
400}
401
paul2d598362003-01-17 23:48:42 +0000402/* Neighbor State Machine */
403struct {
paul4dadc292005-05-06 21:37:42 +0000404 int (*func) (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +0000405 int next_state;
406} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
407{
408 {
409 /* DependUpon: dummy state. */
Paul Jakma539e1522006-07-11 17:49:22 +0000410 { NULL, NSM_DependUpon }, /* NoEvent */
411 { NULL, NSM_DependUpon }, /* HelloReceived */
412 { NULL, NSM_DependUpon }, /* Start */
413 { NULL, NSM_DependUpon }, /* 2-WayReceived */
414 { NULL, NSM_DependUpon }, /* NegotiationDone */
415 { NULL, NSM_DependUpon }, /* ExchangeDone */
416 { NULL, NSM_DependUpon }, /* BadLSReq */
417 { NULL, NSM_DependUpon }, /* LoadingDone */
418 { NULL, NSM_DependUpon }, /* AdjOK? */
419 { NULL, NSM_DependUpon }, /* SeqNumberMismatch */
420 { NULL, NSM_DependUpon }, /* 1-WayReceived */
421 { NULL, NSM_DependUpon }, /* KillNbr */
422 { NULL, NSM_DependUpon }, /* InactivityTimer */
423 { NULL, NSM_DependUpon }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000424 },
425 {
Paul Jakma1f2c2742006-07-10 07:45:13 +0000426 /* Deleted: dummy state. */
Paul Jakma539e1522006-07-11 17:49:22 +0000427 { NULL, NSM_Deleted }, /* NoEvent */
428 { NULL, NSM_Deleted }, /* HelloReceived */
429 { NULL, NSM_Deleted }, /* Start */
430 { NULL, NSM_Deleted }, /* 2-WayReceived */
431 { NULL, NSM_Deleted }, /* NegotiationDone */
432 { NULL, NSM_Deleted }, /* ExchangeDone */
433 { NULL, NSM_Deleted }, /* BadLSReq */
434 { NULL, NSM_Deleted }, /* LoadingDone */
435 { NULL, NSM_Deleted }, /* AdjOK? */
436 { NULL, NSM_Deleted }, /* SeqNumberMismatch */
437 { NULL, NSM_Deleted }, /* 1-WayReceived */
438 { NULL, NSM_Deleted }, /* KillNbr */
439 { NULL, NSM_Deleted }, /* InactivityTimer */
440 { NULL, NSM_Deleted }, /* LLDown */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000441 },
442 {
paul2d598362003-01-17 23:48:42 +0000443 /* Down: */
Paul Jakma539e1522006-07-11 17:49:22 +0000444 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000445 { nsm_hello_received, NSM_Init }, /* HelloReceived */
446 { nsm_start, NSM_Attempt }, /* Start */
Paul Jakma539e1522006-07-11 17:49:22 +0000447 { NULL, NSM_Down }, /* 2-WayReceived */
448 { NULL, NSM_Down }, /* NegotiationDone */
449 { NULL, NSM_Down }, /* ExchangeDone */
450 { NULL, NSM_Down }, /* BadLSReq */
451 { NULL, NSM_Down }, /* LoadingDone */
452 { NULL, NSM_Down }, /* AdjOK? */
453 { NULL, NSM_Down }, /* SeqNumberMismatch */
454 { NULL, NSM_Down }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000455 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000456 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
457 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000458 },
459 {
460 /* Attempt: */
Paul Jakma539e1522006-07-11 17:49:22 +0000461 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000462 { nsm_hello_received, NSM_Init }, /* HelloReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000463 { NULL, NSM_Attempt }, /* Start */
464 { NULL, NSM_Attempt }, /* 2-WayReceived */
465 { NULL, NSM_Attempt }, /* NegotiationDone */
466 { NULL, NSM_Attempt }, /* ExchangeDone */
467 { NULL, NSM_Attempt }, /* BadLSReq */
468 { NULL, NSM_Attempt }, /* LoadingDone */
469 { NULL, NSM_Attempt }, /* AdjOK? */
470 { NULL, NSM_Attempt }, /* SeqNumberMismatch */
471 { NULL, NSM_Attempt }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000472 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000473 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
474 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000475 },
476 {
477 /* Init: */
Paul Jakma539e1522006-07-11 17:49:22 +0000478 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000479 { nsm_hello_received, NSM_Init }, /* HelloReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000480 { NULL, NSM_Init }, /* Start */
paul2d598362003-01-17 23:48:42 +0000481 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000482 { NULL, NSM_Init }, /* NegotiationDone */
483 { NULL, NSM_Init }, /* ExchangeDone */
484 { NULL, NSM_Init }, /* BadLSReq */
485 { NULL, NSM_Init }, /* LoadingDone */
486 { NULL, NSM_Init }, /* AdjOK? */
487 { NULL, NSM_Init }, /* SeqNumberMismatch */
488 { NULL, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000489 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000490 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
491 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000492 },
493 {
494 /* 2-Way: */
Paul Jakma539e1522006-07-11 17:49:22 +0000495 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000496 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000497 { NULL, NSM_TwoWay }, /* Start */
498 { NULL, NSM_TwoWay }, /* 2-WayReceived */
499 { NULL, NSM_TwoWay }, /* NegotiationDone */
500 { NULL, NSM_TwoWay }, /* ExchangeDone */
501 { NULL, NSM_TwoWay }, /* BadLSReq */
502 { NULL, NSM_TwoWay }, /* LoadingDone */
paul2d598362003-01-17 23:48:42 +0000503 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
Paul Jakma539e1522006-07-11 17:49:22 +0000504 { NULL, NSM_TwoWay }, /* SeqNumberMismatch */
505 { NULL, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000506 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000507 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
508 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000509 },
510 {
511 /* ExStart: */
Paul Jakma539e1522006-07-11 17:49:22 +0000512 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000513 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000514 { NULL, NSM_ExStart }, /* Start */
515 { NULL, NSM_ExStart }, /* 2-WayReceived */
paul2d598362003-01-17 23:48:42 +0000516 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
Paul Jakma539e1522006-07-11 17:49:22 +0000517 { NULL, NSM_ExStart }, /* ExchangeDone */
518 { NULL, NSM_ExStart }, /* BadLSReq */
519 { NULL, NSM_ExStart }, /* LoadingDone */
paul2d598362003-01-17 23:48:42 +0000520 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
Paul Jakma539e1522006-07-11 17:49:22 +0000521 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
522 { NULL, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000523 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000524 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
525 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000526 },
527 {
528 /* Exchange: */
Paul Jakma539e1522006-07-11 17:49:22 +0000529 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000530 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000531 { NULL, NSM_Exchange }, /* Start */
532 { NULL, NSM_Exchange }, /* 2-WayReceived */
533 { NULL, NSM_Exchange }, /* NegotiationDone */
paul2d598362003-01-17 23:48:42 +0000534 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
Paul Jakma539e1522006-07-11 17:49:22 +0000535 { NULL, NSM_ExStart }, /* BadLSReq */
536 { NULL, NSM_Exchange }, /* LoadingDone */
paul2d598362003-01-17 23:48:42 +0000537 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
Paul Jakma539e1522006-07-11 17:49:22 +0000538 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
539 { NULL, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000540 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000541 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
542 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000543 },
544 {
545 /* Loading: */
Paul Jakma539e1522006-07-11 17:49:22 +0000546 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000547 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000548 { NULL, NSM_Loading }, /* Start */
549 { NULL, NSM_Loading }, /* 2-WayReceived */
550 { NULL, NSM_Loading }, /* NegotiationDone */
551 { NULL, NSM_Loading }, /* ExchangeDone */
552 { NULL, NSM_ExStart }, /* BadLSReq */
553 { NULL, NSM_Full }, /* LoadingDone */
paul2d598362003-01-17 23:48:42 +0000554 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
Paul Jakma539e1522006-07-11 17:49:22 +0000555 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
556 { NULL, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000557 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000558 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
559 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000560 },
561 { /* Full: */
Paul Jakma539e1522006-07-11 17:49:22 +0000562 { NULL, NSM_DependUpon }, /* NoEvent */
paul2d598362003-01-17 23:48:42 +0000563 { nsm_hello_received, NSM_Full }, /* HelloReceived */
Paul Jakma539e1522006-07-11 17:49:22 +0000564 { NULL, NSM_Full }, /* Start */
565 { NULL, NSM_Full }, /* 2-WayReceived */
566 { NULL, NSM_Full }, /* NegotiationDone */
567 { NULL, NSM_Full }, /* ExchangeDone */
568 { NULL, NSM_ExStart }, /* BadLSReq */
569 { NULL, NSM_Full }, /* LoadingDone */
paul2d598362003-01-17 23:48:42 +0000570 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
Paul Jakma539e1522006-07-11 17:49:22 +0000571 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
572 { NULL, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000573 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
Paul Jakma539e1522006-07-11 17:49:22 +0000574 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
575 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000576 },
577};
578
Paul Jakma30a22312008-08-15 14:05:22 +0100579static const char *ospf_nsm_event_str[] =
paul2d598362003-01-17 23:48:42 +0000580{
581 "NoEvent",
582 "HelloReceived",
583 "Start",
584 "2-WayReceived",
585 "NegotiationDone",
586 "ExchangeDone",
587 "BadLSReq",
588 "LoadingDone",
589 "AdjOK?",
590 "SeqNumberMismatch",
591 "1-WayReceived",
592 "KillNbr",
593 "InactivityTimer",
594 "LLDown",
595};
596
Paul Jakma3d63f382006-07-11 17:52:53 +0000597static void
598nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event)
599{
600 /* Logging change of status. */
601 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
602 zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)",
603 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
604 LOOKUP (ospf_nsm_state_msg, nbr->state),
605 LOOKUP (ospf_nsm_state_msg, next_state),
606 ospf_nsm_event_str [event]);
607
608 /* Optionally notify about adjacency changes */
609 if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
610 (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
611 (next_state == NSM_Full) || (next_state < nbr->state)))
612 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)",
613 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
614 LOOKUP (ospf_nsm_state_msg, nbr->state),
615 LOOKUP (ospf_nsm_state_msg, next_state),
616 ospf_nsm_event_str [event]);
617
Paul Jakma3fed4162006-07-25 20:44:12 +0000618 /* Advance in NSM */
619 if (next_state > nbr->state)
Paul Jakma2518efd2006-08-27 06:49:29 +0000620 nbr->ts_last_progress = recent_relative_time ();
Paul Jakma3fed4162006-07-25 20:44:12 +0000621 else /* regression in NSM */
622 {
Paul Jakma2518efd2006-08-27 06:49:29 +0000623 nbr->ts_last_regress = recent_relative_time ();
Paul Jakma3fed4162006-07-25 20:44:12 +0000624 nbr->last_regress_str = ospf_nsm_event_str [event];
625 }
Paul Jakma90c33172006-07-11 17:57:25 +0000626
Paul Jakma3d63f382006-07-11 17:52:53 +0000627#ifdef HAVE_SNMP
628 /* Terminal state or regression */
629 if ((next_state == NSM_Full)
630 || (next_state == NSM_TwoWay)
631 || (next_state < nbr->state))
632 {
633 /* ospfVirtNbrStateChange */
634 if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK)
635 ospfTrapVirtNbrStateChange(nbr);
636 /* ospfNbrStateChange trap */
637 else
638 /* To/From FULL, only managed by DR */
639 if (((next_state != NSM_Full) && (nbr->state != NSM_Full))
640 || (nbr->oi->state == ISM_DR))
641 ospfTrapNbrStateChange(nbr);
642 }
643#endif
644}
645
paul2d598362003-01-17 23:48:42 +0000646void
647nsm_change_state (struct ospf_neighbor *nbr, int state)
648{
paul68980082003-03-25 05:07:42 +0000649 struct ospf_interface *oi = nbr->oi;
paul2d598362003-01-17 23:48:42 +0000650 struct ospf_area *vl_area = NULL;
651 u_char old_state;
652 int x;
653 int force = 1;
654
paul2d598362003-01-17 23:48:42 +0000655 /* Preserve old status. */
656 old_state = nbr->state;
657
658 /* Change to new status. */
659 nbr->state = state;
660
661 /* Statistics. */
662 nbr->state_change++;
663
paul2d598362003-01-17 23:48:42 +0000664 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul68980082003-03-25 05:07:42 +0000665 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
Andrew J. Schorrd7e60dd2006-06-29 20:20:52 +0000666
paul2d598362003-01-17 23:48:42 +0000667 /* One of the neighboring routers changes to/from the FULL state. */
668 if ((old_state != NSM_Full && state == NSM_Full) ||
669 (old_state == NSM_Full && state != NSM_Full))
ajs3aa8d5f2004-12-11 18:00:06 +0000670 {
paul2d598362003-01-17 23:48:42 +0000671 if (state == NSM_Full)
672 {
673 oi->full_nbrs++;
674 oi->area->full_nbrs++;
675
paul68980082003-03-25 05:07:42 +0000676 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000677
678 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
679 if (++vl_area->full_vls == 1)
paul68980082003-03-25 05:07:42 +0000680 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000681
682 /* kevinm: refresh any redistributions */
paul68980082003-03-25 05:07:42 +0000683 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
684 {
685 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
686 continue;
687 ospf_external_lsa_refresh_type (oi->ospf, x, force);
688 }
Daniel Ng9fd49582008-08-13 20:37:52 +0100689 /* XXX: Clearly some thing is wrong with refresh of external LSAs
690 * this added to hack around defaults not refreshing after a timer
691 * jump.
692 */
693 ospf_external_lsa_refresh_default (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000694 }
695 else
696 {
697 oi->full_nbrs--;
698 oi->area->full_nbrs--;
699
paul68980082003-03-25 05:07:42 +0000700 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000701
702 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
703 if (vl_area->full_vls > 0)
704 if (--vl_area->full_vls == 0)
paul68980082003-03-25 05:07:42 +0000705 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000706 }
707
ajs3aa8d5f2004-12-11 18:00:06 +0000708 zlog_info ("nsm_change_state(%s, %s -> %s): "
709 "scheduling new router-LSA origination",
710 inet_ntoa (nbr->router_id),
711 LOOKUP(ospf_nsm_state_msg, old_state),
712 LOOKUP(ospf_nsm_state_msg, state));
paul2d598362003-01-17 23:48:42 +0000713
714 ospf_router_lsa_timer_add (oi->area);
715
716 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
717 {
718 struct ospf_area *vl_area =
paul68980082003-03-25 05:07:42 +0000719 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000720
721 if (vl_area)
722 ospf_router_lsa_timer_add (vl_area);
723 }
724
725 /* Originate network-LSA. */
726 if (oi->state == ISM_DR)
727 {
728 if (oi->network_lsa_self && oi->full_nbrs == 0)
729 {
730 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
Paul Jakma1fe6ed32006-07-26 09:37:26 +0000731 ospf_lsa_unlock (&oi->network_lsa_self);
paul2d598362003-01-17 23:48:42 +0000732 oi->network_lsa_self = NULL;
733 OSPF_TIMER_OFF (oi->t_network_lsa_self);
734 }
735 else
736 ospf_network_lsa_timer_add (oi);
737 }
738 }
739
740#ifdef HAVE_OPAQUE_LSA
741 ospf_opaque_nsm_change (nbr, old_state);
742#endif /* HAVE_OPAQUE_LSA */
743
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000744 /* State changes from > ExStart to <= ExStart should clear any Exchange
745 * or Full/LSA Update related lists and state.
746 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000747 */
Paul Jakma539e1522006-07-11 17:49:22 +0000748 if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000749 nsm_clear_adj (nbr);
750
paul2d598362003-01-17 23:48:42 +0000751 /* Start DD exchange protocol */
752 if (state == NSM_ExStart)
753 {
754 if (nbr->dd_seqnum == 0)
Paul Jakma2518efd2006-08-27 06:49:29 +0000755 nbr->dd_seqnum = quagga_time (NULL);
paul2d598362003-01-17 23:48:42 +0000756 else
757 nbr->dd_seqnum++;
758
759 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
760 ospf_db_desc_send (nbr);
761 }
762
763 /* clear cryptographic sequence number */
764 if (state == NSM_Down)
765 nbr->crypt_seqnum = 0;
766
767 /* Generete NeighborChange ISM event. */
paul2d598362003-01-17 23:48:42 +0000768 switch (oi->state) {
769 case ISM_DROther:
770 case ISM_Backup:
771 case ISM_DR:
772 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
773 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
774 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
775 break;
776 default:
777 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
778 break;
779 }
paul2d598362003-01-17 23:48:42 +0000780
781 /* Performance hack. Send hello immideately when some neighbor enter
782 Init state. This whay we decrease neighbor discovery time. Gleb.*/
783 if (state == NSM_Init)
784 {
785 OSPF_ISM_TIMER_OFF (oi->t_hello);
paulf9ad9372005-10-21 00:45:17 +0000786 OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1);
paul2d598362003-01-17 23:48:42 +0000787 }
788
789 /* Preserve old status? */
790}
791
792/* Execute NSM event process. */
793int
794ospf_nsm_event (struct thread *thread)
795{
796 int event;
797 int next_state;
798 struct ospf_neighbor *nbr;
799 struct in_addr router_id;
paul2d598362003-01-17 23:48:42 +0000800
801 nbr = THREAD_ARG (thread);
802 event = THREAD_VAL (thread);
803 router_id = nbr->router_id;
804
Paul Jakma3d63f382006-07-11 17:52:53 +0000805 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
806 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi),
807 inet_ntoa (nbr->router_id),
808 LOOKUP (ospf_nsm_state_msg, nbr->state),
809 ospf_nsm_event_str [event]);
810
Paul Jakma539e1522006-07-11 17:49:22 +0000811 next_state = NSM [nbr->state][event].next_state;
paul2d598362003-01-17 23:48:42 +0000812
Paul Jakma539e1522006-07-11 17:49:22 +0000813 /* Call function. */
814 if (NSM [nbr->state][event].func != NULL)
Paul Jakmaba0beb42006-07-04 13:44:19 +0000815 {
Paul Jakma539e1522006-07-11 17:49:22 +0000816 int func_state = (*(NSM [nbr->state][event].func))(nbr);
Paul Jakmaba0beb42006-07-04 13:44:19 +0000817
Paul Jakma539e1522006-07-11 17:49:22 +0000818 if (NSM [nbr->state][event].next_state == NSM_DependUpon)
819 next_state = func_state;
820 else if (func_state)
821 {
822 /* There's a mismatch between the FSM tables and what an FSM
823 * action/state-change function returned. State changes which
824 * do not have conditional/DependUpon next-states should not
825 * try set next_state.
826 */
827 zlog_warn ("NSM[%s:%s]: %s (%s): "
828 "Warning: action tried to change next_state to %s",
829 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
830 LOOKUP (ospf_nsm_state_msg, nbr->state),
831 ospf_nsm_event_str [event],
832 LOOKUP (ospf_nsm_state_msg, func_state));
833 }
Paul Jakmaba0beb42006-07-04 13:44:19 +0000834 }
paul2d598362003-01-17 23:48:42 +0000835
Paul Jakma539e1522006-07-11 17:49:22 +0000836 assert (next_state != NSM_DependUpon);
837
paul2d598362003-01-17 23:48:42 +0000838 /* If state is changed. */
839 if (next_state != nbr->state)
Paul Jakma3d63f382006-07-11 17:52:53 +0000840 {
841 nsm_notice_state_change (nbr, next_state, event);
842 nsm_change_state (nbr, next_state);
843 }
paul2d598362003-01-17 23:48:42 +0000844
845 /* Make sure timer is set. */
846 nsm_timer_set (nbr);
847
Paul Jakma1f2c2742006-07-10 07:45:13 +0000848 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
849 * is deleted.
850 *
851 * Rather than encode knowledge here of which events lead to NBR
852 * delete, we take our cue from the NSM table, via the dummy
853 * 'Deleted' neighbour state.
854 */
855 if (nbr->state == NSM_Deleted)
856 ospf_nbr_delete (nbr);
857
paul2d598362003-01-17 23:48:42 +0000858 return 0;
859}
860
861/* Check loading state. */
862void
863ospf_check_nbr_loading (struct ospf_neighbor *nbr)
864{
865 if (nbr->state == NSM_Loading)
866 {
867 if (ospf_ls_request_isempty (nbr))
868 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
869 else if (nbr->ls_req_last == NULL)
870 ospf_ls_req_event (nbr);
871 }
872}