blob: 11da503e46dd338b1d0e3c2d8bc2bbfdcf9d856b [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
98/* Hook function called after ospf NSM event is occured. */
99
paul4dadc292005-05-06 21:37:42 +0000100static void
paul2d598362003-01-17 23:48:42 +0000101nsm_timer_set (struct ospf_neighbor *nbr)
102{
103 switch (nbr->state)
104 {
105 case NSM_Down:
Paul Jakmae55dd532006-07-04 13:46:14 +0000106 /* This is here for documentation purposes, don't actually get here
107 * as Down neighbours are deleted typically, see nsm_kill_nbr
108 */
109 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
paul2d598362003-01-17 23:48:42 +0000110 case NSM_Attempt:
paul2d598362003-01-17 23:48:42 +0000111 case NSM_Init:
paul2d598362003-01-17 23:48:42 +0000112 case NSM_TwoWay:
113 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
114 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
Paul Jakmae55dd532006-07-04 13:46:14 +0000115 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
paul2d598362003-01-17 23:48:42 +0000116 break;
117 case NSM_ExStart:
118 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_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_Exchange:
123 OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
124 if (!IS_SET_DD_MS (nbr->dd_flags))
125 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
126 break;
127 case NSM_Loading:
paul2d598362003-01-17 23:48:42 +0000128 case NSM_Full:
paul2d598362003-01-17 23:48:42 +0000129 default:
130 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
131 break;
132 }
133}
134
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000135/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
136 * the given neighbour
137 */
138static int
139nsm_should_adj (struct ospf_neighbor *nbr)
140{
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000141 struct ospf_interface *oi = nbr->oi;
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000142
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000143 /* These network types must always form adjacencies. */
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000144 if (oi->type == OSPF_IFTYPE_POINTOPOINT
145 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000146 || oi->type == OSPF_IFTYPE_VIRTUALLINK
147 /* Router itself is the DRouter or the BDRouter. */
148 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
149 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))
150 /* Neighboring Router is the DRouter or the BDRouter. */
151 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000152 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
153 return 1;
154
155 return 0;
156}
paul2d598362003-01-17 23:48:42 +0000157
158/* OSPF NSM functions. */
paul4dadc292005-05-06 21:37:42 +0000159static int
paul2d598362003-01-17 23:48:42 +0000160nsm_ignore (struct ospf_neighbor *nbr)
161{
162 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000163 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: nsm_ignore called",
paul2d598362003-01-17 23:48:42 +0000164 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
165
166 return 0;
167}
168
paul4dadc292005-05-06 21:37:42 +0000169static int
paul2d598362003-01-17 23:48:42 +0000170nsm_hello_received (struct ospf_neighbor *nbr)
171{
172 /* Start or Restart Inactivity Timer. */
173 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
174
175 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
176 nbr->v_inactivity);
177
178 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
179 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
180
181 return 0;
182}
183
paul4dadc292005-05-06 21:37:42 +0000184static int
paul2d598362003-01-17 23:48:42 +0000185nsm_start (struct ospf_neighbor *nbr)
186{
187
188 nsm_reset_nbr (nbr);
189
190 if (nbr->nbr_nbma)
191 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
192
193 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
194
195 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
196 nbr->v_inactivity);
197
198 return 0;
199}
200
paul4dadc292005-05-06 21:37:42 +0000201static int
paul2d598362003-01-17 23:48:42 +0000202nsm_twoway_received (struct ospf_neighbor *nbr)
203{
Paul Jakmaf7a76ab2006-07-04 13:57:49 +0000204 return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay);
paul2d598362003-01-17 23:48:42 +0000205}
206
207int
208ospf_db_summary_count (struct ospf_neighbor *nbr)
209{
210 return ospf_lsdb_count_all (&nbr->db_sum);
211}
212
213int
214ospf_db_summary_isempty (struct ospf_neighbor *nbr)
215{
216 return ospf_lsdb_isempty (&nbr->db_sum);
217}
218
paul4dadc292005-05-06 21:37:42 +0000219static int
paul68980082003-03-25 05:07:42 +0000220ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
paul2d598362003-01-17 23:48:42 +0000221{
paul09e4efd2003-01-18 00:12:02 +0000222#ifdef HAVE_OPAQUE_LSA
223 switch (lsa->data->type)
224 {
225 case OSPF_OPAQUE_LINK_LSA:
226 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
227 if (lsa->oi != nbr->oi)
228 return 0;
229 break;
230 case OSPF_OPAQUE_AREA_LSA:
231 /*
232 * It is assured by the caller function "nsm_negotiation_done()"
233 * that every given LSA belongs to the same area with "nbr".
234 */
235 break;
236 case OSPF_OPAQUE_AS_LSA:
237 default:
238 break;
239 }
240#endif /* HAVE_OPAQUE_LSA */
241
paul2d598362003-01-17 23:48:42 +0000242 /* Stay away from any Local Translated Type-7 LSAs */
243 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
244 return 0;
paul2d598362003-01-17 23:48:42 +0000245
246 if (IS_LSA_MAXAGE (lsa))
247 ospf_ls_retransmit_add (nbr, lsa);
248 else
249 ospf_lsdb_add (&nbr->db_sum, lsa);
250
251 return 0;
252}
253
254void
255ospf_db_summary_clear (struct ospf_neighbor *nbr)
256{
257 struct ospf_lsdb *lsdb;
258 int i;
259
260 lsdb = &nbr->db_sum;
261 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
262 {
263 struct route_table *table = lsdb->type[i].db;
264 struct route_node *rn;
265
266 for (rn = route_top (table); rn; rn = route_next (rn))
267 if (rn->info)
268 ospf_lsdb_delete (&nbr->db_sum, rn->info);
269 }
270}
271
272
273
paul2d598362003-01-17 23:48:42 +0000274/* The area link state database consists of the router-LSAs,
275 network-LSAs and summary-LSAs contained in the area structure,
paul68980082003-03-25 05:07:42 +0000276 along with the AS-external-LSAs contained in the global structure.
277 AS-external-LSAs are omitted from a virtual neighbor's Database
paul2d598362003-01-17 23:48:42 +0000278 summary list. AS-external-LSAs are omitted from the Database
279 summary list if the area has been configured as a stub. */
paul4dadc292005-05-06 21:37:42 +0000280static int
paul2d598362003-01-17 23:48:42 +0000281nsm_negotiation_done (struct ospf_neighbor *nbr)
282{
paul68980082003-03-25 05:07:42 +0000283 struct ospf_area *area = nbr->oi->area;
284 struct ospf_lsa *lsa;
285 struct route_node *rn;
paul2d598362003-01-17 23:48:42 +0000286
paul68980082003-03-25 05:07:42 +0000287 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
288 ospf_db_summary_add (nbr, lsa);
289 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
290 ospf_db_summary_add (nbr, lsa);
291 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
292 ospf_db_summary_add (nbr, lsa);
293 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
294 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000295
paul2d598362003-01-17 23:48:42 +0000296#ifdef HAVE_OPAQUE_LSA
297 /* Process only if the neighbor is opaque capable. */
298 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
299 {
paul68980082003-03-25 05:07:42 +0000300 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
301 ospf_db_summary_add (nbr, lsa);
302 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
303 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000304 }
305#endif /* HAVE_OPAQUE_LSA */
306
hassof4833e92005-06-20 20:42:26 +0000307 if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
308 {
309 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
310 ospf_db_summary_add (nbr, lsa);
311 }
312
paul68980082003-03-25 05:07:42 +0000313 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
314 && area->external_routing == OSPF_AREA_DEFAULT)
315 LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
316 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000317
318#ifdef HAVE_OPAQUE_LSA
paul68980082003-03-25 05:07:42 +0000319 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
320 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
321 && area->external_routing == OSPF_AREA_DEFAULT))
322 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
323 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000324#endif /* HAVE_OPAQUE_LSA */
325
paul2d598362003-01-17 23:48:42 +0000326 return 0;
327}
328
paul4dadc292005-05-06 21:37:42 +0000329static int
paul2d598362003-01-17 23:48:42 +0000330nsm_exchange_done (struct ospf_neighbor *nbr)
331{
paul2d598362003-01-17 23:48:42 +0000332 if (ospf_ls_request_isempty (nbr))
333 return NSM_Full;
334
335 /* Cancel dd retransmit timer. */
336 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
337
338 /* Send Link State Request. */
339 ospf_ls_req_send (nbr);
340
341 return NSM_Loading;
342}
343
paul4dadc292005-05-06 21:37:42 +0000344static int
paul2d598362003-01-17 23:48:42 +0000345nsm_bad_ls_req (struct ospf_neighbor *nbr)
346{
347 /* Clear neighbor. */
348 nsm_reset_nbr (nbr);
349
350 return 0;
351}
352
paul4dadc292005-05-06 21:37:42 +0000353static int
paul2d598362003-01-17 23:48:42 +0000354nsm_adj_ok (struct ospf_neighbor *nbr)
355{
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000356 int next_state = nbr->state;
357 int adj = nsm_should_adj (nbr);
paul2d598362003-01-17 23:48:42 +0000358
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000359 if (nbr->state == NSM_TwoWay && adj == 1)
paul2d598362003-01-17 23:48:42 +0000360 next_state = NSM_ExStart;
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000361 else if (nbr->state >= NSM_ExStart && adj == 0)
paul2d598362003-01-17 23:48:42 +0000362 next_state = NSM_TwoWay;
363
364 return next_state;
365}
366
paul4dadc292005-05-06 21:37:42 +0000367static int
paul2d598362003-01-17 23:48:42 +0000368nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
369{
370 /* Clear neighbor. */
371 nsm_reset_nbr (nbr);
372
373 return 0;
374}
375
paul4dadc292005-05-06 21:37:42 +0000376static int
paul2d598362003-01-17 23:48:42 +0000377nsm_oneway_received (struct ospf_neighbor *nbr)
378{
379 /* Clear neighbor. */
380 nsm_reset_nbr (nbr);
381
382 return 0;
383}
384
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000385/* Clear adjacency related state for a neighbour, intended where nbr
386 * transitions from > ExStart (i.e. a Full or forming adjacency)
387 * to <= ExStart.
388 */
389static void
390nsm_clear_adj (struct ospf_neighbor *nbr)
paul2d598362003-01-17 23:48:42 +0000391{
392 /* Clear Database Summary list. */
393 if (!ospf_db_summary_isempty (nbr))
394 ospf_db_summary_clear (nbr);
395
396 /* Clear Link State Request list. */
397 if (!ospf_ls_request_isempty (nbr))
398 ospf_ls_request_delete_all (nbr);
399
400 /* Clear Link State Retransmission list. */
401 if (!ospf_ls_retransmit_isempty (nbr))
402 ospf_ls_retransmit_clear (nbr);
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000403}
404
405static void
406nsm_reset_nbr (struct ospf_neighbor *nbr)
407{
408 nsm_clear_adj (nbr);
paul2d598362003-01-17 23:48:42 +0000409
410 /* Cancel thread. */
411 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
412 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
413 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
414 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
415
416#ifdef HAVE_OPAQUE_LSA
417 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
418 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
419#endif /* HAVE_OPAQUE_LSA */
420}
421
paul4dadc292005-05-06 21:37:42 +0000422static int
paul2d598362003-01-17 23:48:42 +0000423nsm_kill_nbr (struct ospf_neighbor *nbr)
424{
425 /* call it here because we cannot call it from ospf_nsm_event */
426 nsm_change_state (nbr, NSM_Down);
427
Paul Jakma478aab92006-04-03 21:25:32 +0000428 /* killing nbr_self is invalid */
429 assert (nbr != nbr->oi->nbr_self);
430 if (nbr == nbr->oi->nbr_self)
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000431 return 0;
Paul Jakma478aab92006-04-03 21:25:32 +0000432
paul2d598362003-01-17 23:48:42 +0000433 /* Reset neighbor. */
434 nsm_reset_nbr (nbr);
435
436 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
437 {
438 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
439
440 nbr_nbma->nbr = NULL;
441 nbr_nbma->state_change = nbr->state_change;
442
443 nbr->nbr_nbma = NULL;
444
445 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
446 nbr_nbma->v_poll);
447
448 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000449 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
paul2d598362003-01-17 23:48:42 +0000450 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
451 }
452
453 /* Delete neighbor from interface. */
454 ospf_nbr_delete (nbr);
455
456 return 0;
457}
458
paul4dadc292005-05-06 21:37:42 +0000459static int
paul2d598362003-01-17 23:48:42 +0000460nsm_inactivity_timer (struct ospf_neighbor *nbr)
461{
462 /* Kill neighbor. */
463 nsm_kill_nbr (nbr);
464
465 return 0;
466}
467
paul4dadc292005-05-06 21:37:42 +0000468static int
paul2d598362003-01-17 23:48:42 +0000469nsm_ll_down (struct ospf_neighbor *nbr)
470{
471 /* Reset neighbor. */
472 /*nsm_reset_nbr (nbr);*/
473
474 /* Kill neighbor. */
475 nsm_kill_nbr (nbr);
476
477 return 0;
478}
479
480/* Neighbor State Machine */
481struct {
paul4dadc292005-05-06 21:37:42 +0000482 int (*func) (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +0000483 int next_state;
484} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
485{
486 {
487 /* DependUpon: dummy state. */
488 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
489 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */
490 { nsm_ignore, NSM_DependUpon }, /* Start */
491 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */
492 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */
493 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */
494 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */
495 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */
496 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */
497 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */
498 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */
499 { nsm_ignore, NSM_DependUpon }, /* KillNbr */
500 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */
501 { nsm_ignore, NSM_DependUpon }, /* LLDown */
502 },
503 {
504 /* Down: */
505 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
506 { nsm_hello_received, NSM_Init }, /* HelloReceived */
507 { nsm_start, NSM_Attempt }, /* Start */
508 { nsm_ignore, NSM_Down }, /* 2-WayReceived */
509 { nsm_ignore, NSM_Down }, /* NegotiationDone */
510 { nsm_ignore, NSM_Down }, /* ExchangeDone */
511 { nsm_ignore, NSM_Down }, /* BadLSReq */
512 { nsm_ignore, NSM_Down }, /* LoadingDone */
513 { nsm_ignore, NSM_Down }, /* AdjOK? */
514 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */
515 { nsm_ignore, NSM_Down }, /* 1-WayReceived */
516 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
517 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
518 { nsm_ll_down, NSM_Down }, /* LLDown */
519 },
520 {
521 /* Attempt: */
522 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
523 { nsm_hello_received, NSM_Init }, /* HelloReceived */
524 { nsm_ignore, NSM_Attempt }, /* Start */
525 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */
526 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */
527 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */
528 { nsm_ignore, NSM_Attempt }, /* BadLSReq */
529 { nsm_ignore, NSM_Attempt }, /* LoadingDone */
530 { nsm_ignore, NSM_Attempt }, /* AdjOK? */
531 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */
532 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */
533 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
534 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
535 { nsm_ll_down, NSM_Down }, /* LLDown */
536 },
537 {
538 /* Init: */
539 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
540 { nsm_hello_received, NSM_Init }, /* HelloReceived */
541 { nsm_ignore, NSM_Init }, /* Start */
542 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
543 { nsm_ignore, NSM_Init }, /* NegotiationDone */
544 { nsm_ignore, NSM_Init }, /* ExchangeDone */
545 { nsm_ignore, NSM_Init }, /* BadLSReq */
546 { nsm_ignore, NSM_Init }, /* LoadingDone */
547 { nsm_ignore, NSM_Init }, /* AdjOK? */
548 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */
549 { nsm_ignore, NSM_Init }, /* 1-WayReceived */
550 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
551 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
552 { nsm_ll_down, NSM_Down }, /* LLDown */
553 },
554 {
555 /* 2-Way: */
556 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
557 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
558 { nsm_ignore, NSM_TwoWay }, /* Start */
559 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */
560 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */
561 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */
562 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */
563 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */
564 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
565 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */
566 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
567 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
568 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
569 { nsm_ll_down, NSM_Down }, /* LLDown */
570 },
571 {
572 /* ExStart: */
573 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
574 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
575 { nsm_ignore, NSM_ExStart }, /* Start */
576 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */
577 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
578 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */
579 { nsm_ignore, NSM_ExStart }, /* BadLSReq */
580 { nsm_ignore, NSM_ExStart }, /* LoadingDone */
581 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
582 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */
583 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
584 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
585 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
586 { nsm_ll_down, NSM_Down }, /* LLDown */
587 },
588 {
589 /* Exchange: */
590 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
591 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
592 { nsm_ignore, NSM_Exchange }, /* Start */
593 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */
594 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */
595 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
596 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
597 { nsm_ignore, NSM_Exchange }, /* LoadingDone */
598 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
599 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
600 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
601 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
602 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
603 { nsm_ll_down, NSM_Down }, /* LLDown */
604 },
605 {
606 /* Loading: */
607 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
608 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
609 { nsm_ignore, NSM_Loading }, /* Start */
610 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */
611 { nsm_ignore, NSM_Loading }, /* NegotiationDone */
612 { nsm_ignore, NSM_Loading }, /* ExchangeDone */
613 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
614 { nsm_ignore, NSM_Full }, /* LoadingDone */
615 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
616 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
617 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
618 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
619 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
620 { nsm_ll_down, NSM_Down }, /* LLDown */
621 },
622 { /* Full: */
623 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
624 { nsm_hello_received, NSM_Full }, /* HelloReceived */
625 { nsm_ignore, NSM_Full }, /* Start */
626 { nsm_ignore, NSM_Full }, /* 2-WayReceived */
627 { nsm_ignore, NSM_Full }, /* NegotiationDone */
628 { nsm_ignore, NSM_Full }, /* ExchangeDone */
629 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
630 { nsm_ignore, NSM_Full }, /* LoadingDone */
631 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
632 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
633 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
634 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
635 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
636 { nsm_ll_down, NSM_Down }, /* LLDown */
637 },
638};
639
hassoeb1ce602004-10-08 08:17:22 +0000640const static char *ospf_nsm_event_str[] =
paul2d598362003-01-17 23:48:42 +0000641{
642 "NoEvent",
643 "HelloReceived",
644 "Start",
645 "2-WayReceived",
646 "NegotiationDone",
647 "ExchangeDone",
648 "BadLSReq",
649 "LoadingDone",
650 "AdjOK?",
651 "SeqNumberMismatch",
652 "1-WayReceived",
653 "KillNbr",
654 "InactivityTimer",
655 "LLDown",
656};
657
658void
659nsm_change_state (struct ospf_neighbor *nbr, int state)
660{
paul68980082003-03-25 05:07:42 +0000661 struct ospf_interface *oi = nbr->oi;
paul2d598362003-01-17 23:48:42 +0000662 struct ospf_area *vl_area = NULL;
663 u_char old_state;
664 int x;
665 int force = 1;
666
667 /* Logging change of status. */
668 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
ajs2a42e282004-12-08 18:43:03 +0000669 zlog_debug ("NSM[%s:%s]: State change %s -> %s",
paul2d598362003-01-17 23:48:42 +0000670 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
671 LOOKUP (ospf_nsm_state_msg, nbr->state),
672 LOOKUP (ospf_nsm_state_msg, state));
673
674 /* Preserve old status. */
675 old_state = nbr->state;
676
677 /* Change to new status. */
678 nbr->state = state;
679
680 /* Statistics. */
681 nbr->state_change++;
682
paul2d598362003-01-17 23:48:42 +0000683 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul68980082003-03-25 05:07:42 +0000684 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
Andrew J. Schorrd7e60dd2006-06-29 20:20:52 +0000685
686 /* Optionally notify about adjacency changes */
687 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
688 (old_state != state) &&
689 (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
690 (state == NSM_Full) || (state < old_state)))
691 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s",
692 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
693 LOOKUP (ospf_nsm_state_msg, old_state),
694 LOOKUP (ospf_nsm_state_msg, state));
695
vincent5e4914c2005-09-29 16:34:30 +0000696#ifdef HAVE_SNMP
697 /* Terminal state or regression */
698 if ((state == NSM_Full) || (state == NSM_TwoWay) || (state < old_state))
699 {
700 /* ospfVirtNbrStateChange */
701 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
702 ospfTrapVirtNbrStateChange(nbr);
703 /* ospfNbrStateChange trap */
704 else
705 /* To/From FULL, only managed by DR */
706 if (((state != NSM_Full) && (old_state != NSM_Full)) ||
707 (oi->state == ISM_DR))
708 ospfTrapNbrStateChange(nbr);
709 }
710#endif
711
paul2d598362003-01-17 23:48:42 +0000712 /* One of the neighboring routers changes to/from the FULL state. */
713 if ((old_state != NSM_Full && state == NSM_Full) ||
714 (old_state == NSM_Full && state != NSM_Full))
ajs3aa8d5f2004-12-11 18:00:06 +0000715 {
paul2d598362003-01-17 23:48:42 +0000716 if (state == NSM_Full)
717 {
718 oi->full_nbrs++;
719 oi->area->full_nbrs++;
720
paul68980082003-03-25 05:07:42 +0000721 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000722
723 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
724 if (++vl_area->full_vls == 1)
paul68980082003-03-25 05:07:42 +0000725 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000726
727 /* kevinm: refresh any redistributions */
paul68980082003-03-25 05:07:42 +0000728 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
729 {
730 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
731 continue;
732 ospf_external_lsa_refresh_type (oi->ospf, x, force);
733 }
paul2d598362003-01-17 23:48:42 +0000734 }
735 else
736 {
737 oi->full_nbrs--;
738 oi->area->full_nbrs--;
739
paul68980082003-03-25 05:07:42 +0000740 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000741
742 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
743 if (vl_area->full_vls > 0)
744 if (--vl_area->full_vls == 0)
paul68980082003-03-25 05:07:42 +0000745 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000746 }
747
ajs3aa8d5f2004-12-11 18:00:06 +0000748 zlog_info ("nsm_change_state(%s, %s -> %s): "
749 "scheduling new router-LSA origination",
750 inet_ntoa (nbr->router_id),
751 LOOKUP(ospf_nsm_state_msg, old_state),
752 LOOKUP(ospf_nsm_state_msg, state));
paul2d598362003-01-17 23:48:42 +0000753
754 ospf_router_lsa_timer_add (oi->area);
755
756 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
757 {
758 struct ospf_area *vl_area =
paul68980082003-03-25 05:07:42 +0000759 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000760
761 if (vl_area)
762 ospf_router_lsa_timer_add (vl_area);
763 }
764
765 /* Originate network-LSA. */
766 if (oi->state == ISM_DR)
767 {
768 if (oi->network_lsa_self && oi->full_nbrs == 0)
769 {
770 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
771 ospf_lsa_unlock (oi->network_lsa_self);
772 oi->network_lsa_self = NULL;
773 OSPF_TIMER_OFF (oi->t_network_lsa_self);
774 }
775 else
776 ospf_network_lsa_timer_add (oi);
777 }
778 }
779
780#ifdef HAVE_OPAQUE_LSA
781 ospf_opaque_nsm_change (nbr, old_state);
782#endif /* HAVE_OPAQUE_LSA */
783
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000784 /* State changes from > ExStart to <= ExStart should clear any Exchange
785 * or Full/LSA Update related lists and state.
786 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
787 *
788 * Note that transitions from > ExStart to < 2-Way (e.g. due to
789 * KillNbr or 1-Way) must and will do the same, but via
790 * nsm_reset_nbr.
791 */
792 if (old_state > NSM_ExStart
793 && (state == NSM_ExStart || state == NSM_TwoWay))
794 nsm_clear_adj (nbr);
795
paul2d598362003-01-17 23:48:42 +0000796 /* Start DD exchange protocol */
797 if (state == NSM_ExStart)
798 {
799 if (nbr->dd_seqnum == 0)
800 nbr->dd_seqnum = time (NULL);
801 else
802 nbr->dd_seqnum++;
803
804 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
805 ospf_db_desc_send (nbr);
806 }
807
808 /* clear cryptographic sequence number */
809 if (state == NSM_Down)
810 nbr->crypt_seqnum = 0;
811
812 /* Generete NeighborChange ISM event. */
paul2d598362003-01-17 23:48:42 +0000813 switch (oi->state) {
814 case ISM_DROther:
815 case ISM_Backup:
816 case ISM_DR:
817 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
818 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
819 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
820 break;
821 default:
822 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
823 break;
824 }
paul2d598362003-01-17 23:48:42 +0000825
826 /* Performance hack. Send hello immideately when some neighbor enter
827 Init state. This whay we decrease neighbor discovery time. Gleb.*/
828 if (state == NSM_Init)
829 {
830 OSPF_ISM_TIMER_OFF (oi->t_hello);
paulf9ad9372005-10-21 00:45:17 +0000831 OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1);
paul2d598362003-01-17 23:48:42 +0000832 }
833
834 /* Preserve old status? */
835}
836
837/* Execute NSM event process. */
838int
839ospf_nsm_event (struct thread *thread)
840{
841 int event;
842 int next_state;
843 struct ospf_neighbor *nbr;
844 struct in_addr router_id;
845 int old_state;
846 struct ospf_interface *oi;
847
848 nbr = THREAD_ARG (thread);
849 event = THREAD_VAL (thread);
850 router_id = nbr->router_id;
851
852 old_state = nbr->state;
853 oi = nbr->oi ;
854
855 /* Call function. */
856 next_state = (*(NSM [nbr->state][event].func))(nbr);
857
858 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
859 deleted. */
860 if (event == NSM_KillNbr || event == NSM_InactivityTimer)
861 {
862 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000863 zlog_debug ("NSM[%s:%s]: neighbor deleted",
paul2d598362003-01-17 23:48:42 +0000864 IF_NAME (oi), inet_ntoa (router_id));
865
866 /* Timers are canceled in ospf_nbr_free, moreover we cannot call
867 nsm_timer_set here because nbr is freed already!!!*/
868 /*nsm_timer_set (nbr);*/
869
870 return 0;
871 }
872
873 if (! next_state)
874 next_state = NSM [nbr->state][event].next_state;
Paul Jakmaba0beb42006-07-04 13:44:19 +0000875 else if (NSM [nbr->state][event].next_state != NSM_DependUpon)
876 {
877 /* There's a mismatch between the FSM tables and what an FSM
878 * action/state-change function returned. State changes which
879 * do not have conditional/DependUpon next-states should not
880 * try set next_state.
881 */
882 zlog_warn ("NSM[%s:%s]: %s (%s): "
883 "Warning: action tried to change next_state to %s",
884 IF_NAME (oi), inet_ntoa (nbr->router_id),
885 LOOKUP (ospf_nsm_state_msg, nbr->state),
886 ospf_nsm_event_str [event],
887 LOOKUP (ospf_nsm_state_msg, next_state));
888
889 next_state = NSM [nbr->state][event].next_state;
890 }
paul2d598362003-01-17 23:48:42 +0000891
892 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000893 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
paul2d598362003-01-17 23:48:42 +0000894 inet_ntoa (nbr->router_id),
895 LOOKUP (ospf_nsm_state_msg, nbr->state),
896 ospf_nsm_event_str [event]);
897
898 /* If state is changed. */
899 if (next_state != nbr->state)
900 nsm_change_state (nbr, next_state);
901
902 /* Make sure timer is set. */
903 nsm_timer_set (nbr);
904
905 return 0;
906}
907
908/* Check loading state. */
909void
910ospf_check_nbr_loading (struct ospf_neighbor *nbr)
911{
912 if (nbr->state == NSM_Loading)
913 {
914 if (ospf_ls_request_isempty (nbr))
915 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
916 else if (nbr->ls_req_last == NULL)
917 ospf_ls_req_event (nbr);
918 }
919}