blob: 56f818659011490d90d8bf457c83620337cfafa6 [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_reset_nbr (struct ospf_neighbor *);
53static void nsm_clear_adj (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +000054
55/* OSPF NSM Timer functions. */
paul4dadc292005-05-06 21:37:42 +000056static int
paul2d598362003-01-17 23:48:42 +000057ospf_inactivity_timer (struct thread *thread)
58{
59 struct ospf_neighbor *nbr;
60
61 nbr = THREAD_ARG (thread);
62 nbr->t_inactivity = NULL;
63
64 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
65 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)",
66 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
67
68 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer);
69
70 return 0;
71}
72
paul4dadc292005-05-06 21:37:42 +000073static int
paul2d598362003-01-17 23:48:42 +000074ospf_db_desc_timer (struct thread *thread)
75{
76 struct ospf_interface *oi;
77 struct ospf_neighbor *nbr;
78
79 nbr = THREAD_ARG (thread);
80 nbr->t_db_desc = NULL;
81
82 oi = nbr->oi;
83
84 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
ajs2a42e282004-12-08 18:43:03 +000085 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
paul2d598362003-01-17 23:48:42 +000086 IF_NAME (nbr->oi), inet_ntoa (nbr->src));
87
88 /* resent last send DD packet. */
89 assert (nbr->last_send);
90 ospf_db_desc_resend (nbr);
91
92 /* DD Retransmit timer set. */
93 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
94
95 return 0;
96}
97
Paul Jakma1f2c2742006-07-10 07:45:13 +000098/* Hook function called after ospf NSM event is occured.
99 *
100 * Set/clear any timers whose condition is implicit to the neighbour
101 * state. There may be other timers which are set/unset according to other
102 * state.
103 *
104 * We rely on this function to properly clear timers in lower states,
105 * particularly before deleting a neighbour.
106 */
paul4dadc292005-05-06 21:37:42 +0000107static void
paul2d598362003-01-17 23:48:42 +0000108nsm_timer_set (struct ospf_neighbor *nbr)
109{
110 switch (nbr->state)
111 {
Paul Jakma1f2c2742006-07-10 07:45:13 +0000112 case NSM_Deleted:
paul2d598362003-01-17 23:48:42 +0000113 case NSM_Down:
Paul Jakmae55dd532006-07-04 13:46:14 +0000114 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
Paul Jakma1f2c2742006-07-10 07:45:13 +0000115 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
paul2d598362003-01-17 23:48:42 +0000116 case NSM_Attempt:
paul2d598362003-01-17 23:48:42 +0000117 case NSM_Init:
paul2d598362003-01-17 23:48:42 +0000118 case NSM_TwoWay:
119 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
120 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
Paul Jakmae55dd532006-07-04 13:46:14 +0000121 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
paul2d598362003-01-17 23:48:42 +0000122 break;
123 case NSM_ExStart:
124 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
125 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
Paul Jakmae55dd532006-07-04 13:46:14 +0000126 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
paul2d598362003-01-17 23:48:42 +0000127 break;
128 case NSM_Exchange:
129 OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
130 if (!IS_SET_DD_MS (nbr->dd_flags))
131 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
132 break;
133 case NSM_Loading:
paul2d598362003-01-17 23:48:42 +0000134 case NSM_Full:
paul2d598362003-01-17 23:48:42 +0000135 default:
136 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
137 break;
138 }
139}
140
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000141/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
142 * the given neighbour
143 */
144static int
145nsm_should_adj (struct ospf_neighbor *nbr)
146{
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000147 struct ospf_interface *oi = nbr->oi;
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000148
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000149 /* These network types must always form adjacencies. */
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000150 if (oi->type == OSPF_IFTYPE_POINTOPOINT
151 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000152 || oi->type == OSPF_IFTYPE_VIRTUALLINK
153 /* Router itself is the DRouter or the BDRouter. */
154 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
155 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))
156 /* Neighboring Router is the DRouter or the BDRouter. */
157 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000158 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
159 return 1;
160
161 return 0;
162}
paul2d598362003-01-17 23:48:42 +0000163
164/* OSPF NSM functions. */
paul4dadc292005-05-06 21:37:42 +0000165static int
paul2d598362003-01-17 23:48:42 +0000166nsm_ignore (struct ospf_neighbor *nbr)
167{
168 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000169 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: nsm_ignore called",
paul2d598362003-01-17 23:48:42 +0000170 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
171
172 return 0;
173}
174
paul4dadc292005-05-06 21:37:42 +0000175static int
paul2d598362003-01-17 23:48:42 +0000176nsm_hello_received (struct ospf_neighbor *nbr)
177{
178 /* Start or Restart Inactivity Timer. */
179 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
180
181 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
182 nbr->v_inactivity);
183
184 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
185 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
186
187 return 0;
188}
189
paul4dadc292005-05-06 21:37:42 +0000190static int
paul2d598362003-01-17 23:48:42 +0000191nsm_start (struct ospf_neighbor *nbr)
192{
193
194 nsm_reset_nbr (nbr);
195
196 if (nbr->nbr_nbma)
197 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
198
199 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
200
201 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
202 nbr->v_inactivity);
203
204 return 0;
205}
206
paul4dadc292005-05-06 21:37:42 +0000207static int
paul2d598362003-01-17 23:48:42 +0000208nsm_twoway_received (struct ospf_neighbor *nbr)
209{
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000210 return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay);
paul2d598362003-01-17 23:48:42 +0000211}
212
213int
214ospf_db_summary_count (struct ospf_neighbor *nbr)
215{
216 return ospf_lsdb_count_all (&nbr->db_sum);
217}
218
219int
220ospf_db_summary_isempty (struct ospf_neighbor *nbr)
221{
222 return ospf_lsdb_isempty (&nbr->db_sum);
223}
224
paul4dadc292005-05-06 21:37:42 +0000225static int
paul68980082003-03-25 05:07:42 +0000226ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
paul2d598362003-01-17 23:48:42 +0000227{
paul09e4efd2003-01-18 00:12:02 +0000228#ifdef HAVE_OPAQUE_LSA
229 switch (lsa->data->type)
230 {
231 case OSPF_OPAQUE_LINK_LSA:
232 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
233 if (lsa->oi != nbr->oi)
234 return 0;
235 break;
236 case OSPF_OPAQUE_AREA_LSA:
237 /*
238 * It is assured by the caller function "nsm_negotiation_done()"
239 * that every given LSA belongs to the same area with "nbr".
240 */
241 break;
242 case OSPF_OPAQUE_AS_LSA:
243 default:
244 break;
245 }
246#endif /* HAVE_OPAQUE_LSA */
247
paul2d598362003-01-17 23:48:42 +0000248 /* Stay away from any Local Translated Type-7 LSAs */
249 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
250 return 0;
paul2d598362003-01-17 23:48:42 +0000251
252 if (IS_LSA_MAXAGE (lsa))
253 ospf_ls_retransmit_add (nbr, lsa);
254 else
255 ospf_lsdb_add (&nbr->db_sum, lsa);
256
257 return 0;
258}
259
260void
261ospf_db_summary_clear (struct ospf_neighbor *nbr)
262{
263 struct ospf_lsdb *lsdb;
264 int i;
265
266 lsdb = &nbr->db_sum;
267 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
268 {
269 struct route_table *table = lsdb->type[i].db;
270 struct route_node *rn;
271
272 for (rn = route_top (table); rn; rn = route_next (rn))
273 if (rn->info)
274 ospf_lsdb_delete (&nbr->db_sum, rn->info);
275 }
276}
277
278
279
paul2d598362003-01-17 23:48:42 +0000280/* The area link state database consists of the router-LSAs,
281 network-LSAs and summary-LSAs contained in the area structure,
paul68980082003-03-25 05:07:42 +0000282 along with the AS-external-LSAs contained in the global structure.
283 AS-external-LSAs are omitted from a virtual neighbor's Database
paul2d598362003-01-17 23:48:42 +0000284 summary list. AS-external-LSAs are omitted from the Database
285 summary list if the area has been configured as a stub. */
paul4dadc292005-05-06 21:37:42 +0000286static int
paul2d598362003-01-17 23:48:42 +0000287nsm_negotiation_done (struct ospf_neighbor *nbr)
288{
paul68980082003-03-25 05:07:42 +0000289 struct ospf_area *area = nbr->oi->area;
290 struct ospf_lsa *lsa;
291 struct route_node *rn;
paul2d598362003-01-17 23:48:42 +0000292
paul68980082003-03-25 05:07:42 +0000293 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
294 ospf_db_summary_add (nbr, lsa);
295 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
296 ospf_db_summary_add (nbr, lsa);
297 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
298 ospf_db_summary_add (nbr, lsa);
299 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
300 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000301
paul2d598362003-01-17 23:48:42 +0000302#ifdef HAVE_OPAQUE_LSA
303 /* Process only if the neighbor is opaque capable. */
304 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
305 {
paul68980082003-03-25 05:07:42 +0000306 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
307 ospf_db_summary_add (nbr, lsa);
308 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
309 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000310 }
311#endif /* HAVE_OPAQUE_LSA */
312
hassof4833e92005-06-20 20:42:26 +0000313 if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
314 {
315 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
316 ospf_db_summary_add (nbr, lsa);
317 }
318
paul68980082003-03-25 05:07:42 +0000319 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
320 && area->external_routing == OSPF_AREA_DEFAULT)
321 LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
322 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000323
324#ifdef HAVE_OPAQUE_LSA
paul68980082003-03-25 05:07:42 +0000325 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
326 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
327 && area->external_routing == OSPF_AREA_DEFAULT))
328 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
329 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000330#endif /* HAVE_OPAQUE_LSA */
331
paul2d598362003-01-17 23:48:42 +0000332 return 0;
333}
334
paul4dadc292005-05-06 21:37:42 +0000335static int
paul2d598362003-01-17 23:48:42 +0000336nsm_exchange_done (struct ospf_neighbor *nbr)
337{
paul2d598362003-01-17 23:48:42 +0000338 if (ospf_ls_request_isempty (nbr))
339 return NSM_Full;
340
paul2d598362003-01-17 23:48:42 +0000341 /* Send Link State Request. */
342 ospf_ls_req_send (nbr);
343
344 return NSM_Loading;
345}
346
paul4dadc292005-05-06 21:37:42 +0000347static int
paul2d598362003-01-17 23:48:42 +0000348nsm_bad_ls_req (struct ospf_neighbor *nbr)
349{
350 /* Clear neighbor. */
351 nsm_reset_nbr (nbr);
352
353 return 0;
354}
355
paul4dadc292005-05-06 21:37:42 +0000356static int
paul2d598362003-01-17 23:48:42 +0000357nsm_adj_ok (struct ospf_neighbor *nbr)
358{
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000359 int next_state = nbr->state;
360 int adj = nsm_should_adj (nbr);
paul2d598362003-01-17 23:48:42 +0000361
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000362 if (nbr->state == NSM_TwoWay && adj == 1)
paul2d598362003-01-17 23:48:42 +0000363 next_state = NSM_ExStart;
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000364 else if (nbr->state >= NSM_ExStart && adj == 0)
paul2d598362003-01-17 23:48:42 +0000365 next_state = NSM_TwoWay;
366
367 return next_state;
368}
369
paul4dadc292005-05-06 21:37:42 +0000370static int
paul2d598362003-01-17 23:48:42 +0000371nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
372{
373 /* Clear neighbor. */
374 nsm_reset_nbr (nbr);
375
376 return 0;
377}
378
paul4dadc292005-05-06 21:37:42 +0000379static int
paul2d598362003-01-17 23:48:42 +0000380nsm_oneway_received (struct ospf_neighbor *nbr)
381{
382 /* Clear neighbor. */
383 nsm_reset_nbr (nbr);
384
385 return 0;
386}
387
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000388/* Clear adjacency related state for a neighbour, intended where nbr
389 * transitions from > ExStart (i.e. a Full or forming adjacency)
390 * to <= ExStart.
391 */
392static void
393nsm_clear_adj (struct ospf_neighbor *nbr)
paul2d598362003-01-17 23:48:42 +0000394{
395 /* Clear Database Summary list. */
396 if (!ospf_db_summary_isempty (nbr))
397 ospf_db_summary_clear (nbr);
398
399 /* Clear Link State Request list. */
400 if (!ospf_ls_request_isempty (nbr))
401 ospf_ls_request_delete_all (nbr);
402
403 /* Clear Link State Retransmission list. */
404 if (!ospf_ls_retransmit_isempty (nbr))
405 ospf_ls_retransmit_clear (nbr);
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000406}
407
408static void
409nsm_reset_nbr (struct ospf_neighbor *nbr)
410{
411 nsm_clear_adj (nbr);
paul2d598362003-01-17 23:48:42 +0000412
413 /* Cancel thread. */
414 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
415 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
416 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
417 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
418
419#ifdef HAVE_OPAQUE_LSA
420 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
421 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
422#endif /* HAVE_OPAQUE_LSA */
423}
424
paul4dadc292005-05-06 21:37:42 +0000425static int
paul2d598362003-01-17 23:48:42 +0000426nsm_kill_nbr (struct ospf_neighbor *nbr)
427{
Paul Jakma478aab92006-04-03 21:25:32 +0000428 /* killing nbr_self is invalid */
Paul Jakma478aab92006-04-03 21:25:32 +0000429 if (nbr == nbr->oi->nbr_self)
Paul Jakma1f2c2742006-07-10 07:45:13 +0000430 {
431 assert (nbr != nbr->oi->nbr_self);
432 return 0;
433 }
Paul Jakma478aab92006-04-03 21:25:32 +0000434
paul2d598362003-01-17 23:48:42 +0000435 /* Reset neighbor. */
436 nsm_reset_nbr (nbr);
437
438 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
439 {
440 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
441
442 nbr_nbma->nbr = NULL;
443 nbr_nbma->state_change = nbr->state_change;
444
445 nbr->nbr_nbma = NULL;
446
447 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
448 nbr_nbma->v_poll);
449
450 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000451 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
paul2d598362003-01-17 23:48:42 +0000452 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
453 }
454
paul2d598362003-01-17 23:48:42 +0000455 return 0;
456}
457
paul4dadc292005-05-06 21:37:42 +0000458static int
paul2d598362003-01-17 23:48:42 +0000459nsm_inactivity_timer (struct ospf_neighbor *nbr)
460{
461 /* Kill neighbor. */
462 nsm_kill_nbr (nbr);
463
464 return 0;
465}
466
paul4dadc292005-05-06 21:37:42 +0000467static int
paul2d598362003-01-17 23:48:42 +0000468nsm_ll_down (struct ospf_neighbor *nbr)
469{
paul2d598362003-01-17 23:48:42 +0000470 /* Kill neighbor. */
471 nsm_kill_nbr (nbr);
472
473 return 0;
474}
475
476/* Neighbor State Machine */
477struct {
paul4dadc292005-05-06 21:37:42 +0000478 int (*func) (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +0000479 int next_state;
480} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
481{
482 {
483 /* DependUpon: dummy state. */
484 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
485 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */
486 { nsm_ignore, NSM_DependUpon }, /* Start */
487 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */
488 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */
489 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */
490 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */
491 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */
492 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */
493 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */
494 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */
495 { nsm_ignore, NSM_DependUpon }, /* KillNbr */
496 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */
497 { nsm_ignore, NSM_DependUpon }, /* LLDown */
498 },
499 {
Paul Jakma1f2c2742006-07-10 07:45:13 +0000500 /* Deleted: dummy state. */
501 { nsm_ignore, NSM_Deleted }, /* NoEvent */
502 { nsm_ignore, NSM_Deleted }, /* HelloReceived */
503 { nsm_ignore, NSM_Deleted }, /* Start */
504 { nsm_ignore, NSM_Deleted }, /* 2-WayReceived */
505 { nsm_ignore, NSM_Deleted }, /* NegotiationDone */
506 { nsm_ignore, NSM_Deleted }, /* ExchangeDone */
507 { nsm_ignore, NSM_Deleted }, /* BadLSReq */
508 { nsm_ignore, NSM_Deleted }, /* LoadingDone */
509 { nsm_ignore, NSM_Deleted }, /* AdjOK? */
510 { nsm_ignore, NSM_Deleted }, /* SeqNumberMismatch */
511 { nsm_ignore, NSM_Deleted }, /* 1-WayReceived */
512 { nsm_ignore, NSM_Deleted }, /* KillNbr */
513 { nsm_ignore, NSM_Deleted }, /* InactivityTimer */
514 { nsm_ignore, NSM_Deleted }, /* LLDown */
515 },
516 {
paul2d598362003-01-17 23:48:42 +0000517 /* Down: */
518 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
519 { nsm_hello_received, NSM_Init }, /* HelloReceived */
520 { nsm_start, NSM_Attempt }, /* Start */
521 { nsm_ignore, NSM_Down }, /* 2-WayReceived */
522 { nsm_ignore, NSM_Down }, /* NegotiationDone */
523 { nsm_ignore, NSM_Down }, /* ExchangeDone */
524 { nsm_ignore, NSM_Down }, /* BadLSReq */
525 { nsm_ignore, NSM_Down }, /* LoadingDone */
526 { nsm_ignore, NSM_Down }, /* AdjOK? */
527 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */
528 { nsm_ignore, NSM_Down }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000529 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
530 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
531 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000532 },
533 {
534 /* Attempt: */
535 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
536 { nsm_hello_received, NSM_Init }, /* HelloReceived */
537 { nsm_ignore, NSM_Attempt }, /* Start */
538 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */
539 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */
540 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */
541 { nsm_ignore, NSM_Attempt }, /* BadLSReq */
542 { nsm_ignore, NSM_Attempt }, /* LoadingDone */
543 { nsm_ignore, NSM_Attempt }, /* AdjOK? */
544 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */
545 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000546 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
547 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
548 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000549 },
550 {
551 /* Init: */
552 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
553 { nsm_hello_received, NSM_Init }, /* HelloReceived */
554 { nsm_ignore, NSM_Init }, /* Start */
555 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
556 { nsm_ignore, NSM_Init }, /* NegotiationDone */
557 { nsm_ignore, NSM_Init }, /* ExchangeDone */
558 { nsm_ignore, NSM_Init }, /* BadLSReq */
559 { nsm_ignore, NSM_Init }, /* LoadingDone */
560 { nsm_ignore, NSM_Init }, /* AdjOK? */
561 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */
562 { nsm_ignore, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000563 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
564 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
565 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000566 },
567 {
568 /* 2-Way: */
569 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
570 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
571 { nsm_ignore, NSM_TwoWay }, /* Start */
572 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */
573 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */
574 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */
575 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */
576 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */
577 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
578 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */
579 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000580 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
581 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
582 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000583 },
584 {
585 /* ExStart: */
586 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
587 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
588 { nsm_ignore, NSM_ExStart }, /* Start */
589 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */
590 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
591 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */
592 { nsm_ignore, NSM_ExStart }, /* BadLSReq */
593 { nsm_ignore, NSM_ExStart }, /* LoadingDone */
594 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
595 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */
596 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000597 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
598 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
599 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000600 },
601 {
602 /* Exchange: */
603 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
604 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
605 { nsm_ignore, NSM_Exchange }, /* Start */
606 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */
607 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */
608 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
609 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
610 { nsm_ignore, NSM_Exchange }, /* LoadingDone */
611 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
612 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
613 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000614 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
615 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
616 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000617 },
618 {
619 /* Loading: */
620 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
621 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
622 { nsm_ignore, NSM_Loading }, /* Start */
623 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */
624 { nsm_ignore, NSM_Loading }, /* NegotiationDone */
625 { nsm_ignore, NSM_Loading }, /* ExchangeDone */
626 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
627 { nsm_ignore, NSM_Full }, /* LoadingDone */
628 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
629 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
630 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000631 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
632 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
633 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000634 },
635 { /* Full: */
636 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
637 { nsm_hello_received, NSM_Full }, /* HelloReceived */
638 { nsm_ignore, NSM_Full }, /* Start */
639 { nsm_ignore, NSM_Full }, /* 2-WayReceived */
640 { nsm_ignore, NSM_Full }, /* NegotiationDone */
641 { nsm_ignore, NSM_Full }, /* ExchangeDone */
642 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
643 { nsm_ignore, NSM_Full }, /* LoadingDone */
644 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
645 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
646 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000647 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
648 { nsm_inactivity_timer, NSM_Deleted }, /* InactivityTimer */
649 { nsm_ll_down, NSM_Deleted }, /* LLDown */
paul2d598362003-01-17 23:48:42 +0000650 },
651};
652
hassoeb1ce602004-10-08 08:17:22 +0000653const static char *ospf_nsm_event_str[] =
paul2d598362003-01-17 23:48:42 +0000654{
655 "NoEvent",
656 "HelloReceived",
657 "Start",
658 "2-WayReceived",
659 "NegotiationDone",
660 "ExchangeDone",
661 "BadLSReq",
662 "LoadingDone",
663 "AdjOK?",
664 "SeqNumberMismatch",
665 "1-WayReceived",
666 "KillNbr",
667 "InactivityTimer",
668 "LLDown",
669};
670
671void
672nsm_change_state (struct ospf_neighbor *nbr, int state)
673{
paul68980082003-03-25 05:07:42 +0000674 struct ospf_interface *oi = nbr->oi;
paul2d598362003-01-17 23:48:42 +0000675 struct ospf_area *vl_area = NULL;
676 u_char old_state;
677 int x;
678 int force = 1;
679
680 /* Logging change of status. */
681 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
ajs2a42e282004-12-08 18:43:03 +0000682 zlog_debug ("NSM[%s:%s]: State change %s -> %s",
paul2d598362003-01-17 23:48:42 +0000683 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
684 LOOKUP (ospf_nsm_state_msg, nbr->state),
685 LOOKUP (ospf_nsm_state_msg, state));
686
687 /* Preserve old status. */
688 old_state = nbr->state;
689
690 /* Change to new status. */
691 nbr->state = state;
692
693 /* Statistics. */
694 nbr->state_change++;
695
paul2d598362003-01-17 23:48:42 +0000696 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul68980082003-03-25 05:07:42 +0000697 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
Andrew J. Schorrd7e60dd2006-06-29 20:20:52 +0000698
699 /* Optionally notify about adjacency changes */
700 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
701 (old_state != state) &&
702 (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
703 (state == NSM_Full) || (state < old_state)))
704 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s",
Paul Jakma1f2c2742006-07-10 07:45:13 +0000705 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
706 LOOKUP (ospf_nsm_state_msg, old_state),
707 LOOKUP (ospf_nsm_state_msg, state));
Andrew J. Schorrd7e60dd2006-06-29 20:20:52 +0000708
vincent5e4914c2005-09-29 16:34:30 +0000709#ifdef HAVE_SNMP
710 /* Terminal state or regression */
711 if ((state == NSM_Full) || (state == NSM_TwoWay) || (state < old_state))
712 {
713 /* ospfVirtNbrStateChange */
714 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
715 ospfTrapVirtNbrStateChange(nbr);
716 /* ospfNbrStateChange trap */
Paul Jakma1f2c2742006-07-10 07:45:13 +0000717 else
vincent5e4914c2005-09-29 16:34:30 +0000718 /* To/From FULL, only managed by DR */
719 if (((state != NSM_Full) && (old_state != NSM_Full)) ||
720 (oi->state == ISM_DR))
721 ospfTrapNbrStateChange(nbr);
722 }
723#endif
724
paul2d598362003-01-17 23:48:42 +0000725 /* One of the neighboring routers changes to/from the FULL state. */
726 if ((old_state != NSM_Full && state == NSM_Full) ||
727 (old_state == NSM_Full && state != NSM_Full))
ajs3aa8d5f2004-12-11 18:00:06 +0000728 {
paul2d598362003-01-17 23:48:42 +0000729 if (state == NSM_Full)
730 {
731 oi->full_nbrs++;
732 oi->area->full_nbrs++;
733
paul68980082003-03-25 05:07:42 +0000734 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000735
736 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
737 if (++vl_area->full_vls == 1)
paul68980082003-03-25 05:07:42 +0000738 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000739
740 /* kevinm: refresh any redistributions */
paul68980082003-03-25 05:07:42 +0000741 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
742 {
743 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
744 continue;
745 ospf_external_lsa_refresh_type (oi->ospf, x, force);
746 }
paul2d598362003-01-17 23:48:42 +0000747 }
748 else
749 {
750 oi->full_nbrs--;
751 oi->area->full_nbrs--;
752
paul68980082003-03-25 05:07:42 +0000753 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000754
755 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
756 if (vl_area->full_vls > 0)
757 if (--vl_area->full_vls == 0)
paul68980082003-03-25 05:07:42 +0000758 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000759 }
760
ajs3aa8d5f2004-12-11 18:00:06 +0000761 zlog_info ("nsm_change_state(%s, %s -> %s): "
762 "scheduling new router-LSA origination",
763 inet_ntoa (nbr->router_id),
764 LOOKUP(ospf_nsm_state_msg, old_state),
765 LOOKUP(ospf_nsm_state_msg, state));
paul2d598362003-01-17 23:48:42 +0000766
767 ospf_router_lsa_timer_add (oi->area);
768
769 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
770 {
771 struct ospf_area *vl_area =
paul68980082003-03-25 05:07:42 +0000772 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000773
774 if (vl_area)
775 ospf_router_lsa_timer_add (vl_area);
776 }
777
778 /* Originate network-LSA. */
779 if (oi->state == ISM_DR)
780 {
781 if (oi->network_lsa_self && oi->full_nbrs == 0)
782 {
783 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
784 ospf_lsa_unlock (oi->network_lsa_self);
785 oi->network_lsa_self = NULL;
786 OSPF_TIMER_OFF (oi->t_network_lsa_self);
787 }
788 else
789 ospf_network_lsa_timer_add (oi);
790 }
791 }
792
793#ifdef HAVE_OPAQUE_LSA
794 ospf_opaque_nsm_change (nbr, old_state);
795#endif /* HAVE_OPAQUE_LSA */
796
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000797 /* State changes from > ExStart to <= ExStart should clear any Exchange
798 * or Full/LSA Update related lists and state.
799 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
800 *
801 * Note that transitions from > ExStart to < 2-Way (e.g. due to
802 * KillNbr or 1-Way) must and will do the same, but via
803 * nsm_reset_nbr.
804 */
805 if (old_state > NSM_ExStart
806 && (state == NSM_ExStart || state == NSM_TwoWay))
807 nsm_clear_adj (nbr);
808
paul2d598362003-01-17 23:48:42 +0000809 /* Start DD exchange protocol */
810 if (state == NSM_ExStart)
811 {
812 if (nbr->dd_seqnum == 0)
813 nbr->dd_seqnum = time (NULL);
814 else
815 nbr->dd_seqnum++;
816
817 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
818 ospf_db_desc_send (nbr);
819 }
820
821 /* clear cryptographic sequence number */
822 if (state == NSM_Down)
823 nbr->crypt_seqnum = 0;
824
825 /* Generete NeighborChange ISM event. */
paul2d598362003-01-17 23:48:42 +0000826 switch (oi->state) {
827 case ISM_DROther:
828 case ISM_Backup:
829 case ISM_DR:
830 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
831 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
832 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
833 break;
834 default:
835 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
836 break;
837 }
paul2d598362003-01-17 23:48:42 +0000838
839 /* Performance hack. Send hello immideately when some neighbor enter
840 Init state. This whay we decrease neighbor discovery time. Gleb.*/
841 if (state == NSM_Init)
842 {
843 OSPF_ISM_TIMER_OFF (oi->t_hello);
paulf9ad9372005-10-21 00:45:17 +0000844 OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1);
paul2d598362003-01-17 23:48:42 +0000845 }
846
847 /* Preserve old status? */
848}
849
850/* Execute NSM event process. */
851int
852ospf_nsm_event (struct thread *thread)
853{
854 int event;
855 int next_state;
856 struct ospf_neighbor *nbr;
857 struct in_addr router_id;
858 int old_state;
859 struct ospf_interface *oi;
860
861 nbr = THREAD_ARG (thread);
862 event = THREAD_VAL (thread);
863 router_id = nbr->router_id;
864
865 old_state = nbr->state;
866 oi = nbr->oi ;
867
868 /* Call function. */
869 next_state = (*(NSM [nbr->state][event].func))(nbr);
870
paul2d598362003-01-17 23:48:42 +0000871 if (! next_state)
872 next_state = NSM [nbr->state][event].next_state;
Paul Jakmaba0beb42006-07-04 13:44:19 +0000873 else if (NSM [nbr->state][event].next_state != NSM_DependUpon)
874 {
875 /* There's a mismatch between the FSM tables and what an FSM
876 * action/state-change function returned. State changes which
877 * do not have conditional/DependUpon next-states should not
878 * try set next_state.
879 */
880 zlog_warn ("NSM[%s:%s]: %s (%s): "
881 "Warning: action tried to change next_state to %s",
882 IF_NAME (oi), inet_ntoa (nbr->router_id),
883 LOOKUP (ospf_nsm_state_msg, nbr->state),
884 ospf_nsm_event_str [event],
885 LOOKUP (ospf_nsm_state_msg, next_state));
886
887 next_state = NSM [nbr->state][event].next_state;
888 }
paul2d598362003-01-17 23:48:42 +0000889
890 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000891 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
paul2d598362003-01-17 23:48:42 +0000892 inet_ntoa (nbr->router_id),
893 LOOKUP (ospf_nsm_state_msg, nbr->state),
894 ospf_nsm_event_str [event]);
895
896 /* If state is changed. */
897 if (next_state != nbr->state)
898 nsm_change_state (nbr, next_state);
899
900 /* Make sure timer is set. */
901 nsm_timer_set (nbr);
902
Paul Jakma1f2c2742006-07-10 07:45:13 +0000903 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
904 * is deleted.
905 *
906 * Rather than encode knowledge here of which events lead to NBR
907 * delete, we take our cue from the NSM table, via the dummy
908 * 'Deleted' neighbour state.
909 */
910 if (nbr->state == NSM_Deleted)
911 ospf_nbr_delete (nbr);
912
paul2d598362003-01-17 23:48:42 +0000913 return 0;
914}
915
916/* Check loading state. */
917void
918ospf_check_nbr_loading (struct ospf_neighbor *nbr)
919{
920 if (nbr->state == NSM_Loading)
921 {
922 if (ospf_ls_request_isempty (nbr))
923 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
924 else if (nbr->ls_req_last == NULL)
925 ospf_ls_req_event (nbr);
926 }
927}