blob: 149ff7cbd5cce3eef052cd5a6f37758aeb930c83 [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:
128 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
129 break;
130 case NSM_Full:
131 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
132 break;
133 default:
134 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
135 break;
136 }
137}
138
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000139/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
140 * the given neighbour
141 */
142static int
143nsm_should_adj (struct ospf_neighbor *nbr)
144{
145 struct ospf_interface *oi;
146
147 oi = nbr->oi;
148
149 /* These network types must always form adjacencies. */
150 if (oi->type == OSPF_IFTYPE_POINTOPOINT
151 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
152 || oi->type == OSPF_IFTYPE_VIRTUALLINK)
153 return 1;
154
155 /* Router itself is the DRouter or the BDRouter. */
156 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
157 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
158 return 1;
159
160 /* Neighboring Router is the DRouter or the BDRouter. */
161 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
162 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
163 return 1;
164
165 return 0;
166}
paul2d598362003-01-17 23:48:42 +0000167
168/* OSPF NSM functions. */
paul4dadc292005-05-06 21:37:42 +0000169static int
paul2d598362003-01-17 23:48:42 +0000170nsm_ignore (struct ospf_neighbor *nbr)
171{
172 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000173 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: nsm_ignore called",
paul2d598362003-01-17 23:48:42 +0000174 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
175
176 return 0;
177}
178
paul4dadc292005-05-06 21:37:42 +0000179static int
paul2d598362003-01-17 23:48:42 +0000180nsm_hello_received (struct ospf_neighbor *nbr)
181{
182 /* Start or Restart Inactivity Timer. */
183 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
184
185 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
186 nbr->v_inactivity);
187
188 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
189 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
190
191 return 0;
192}
193
paul4dadc292005-05-06 21:37:42 +0000194static int
paul2d598362003-01-17 23:48:42 +0000195nsm_start (struct ospf_neighbor *nbr)
196{
197
198 nsm_reset_nbr (nbr);
199
200 if (nbr->nbr_nbma)
201 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
202
203 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
204
205 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
206 nbr->v_inactivity);
207
208 return 0;
209}
210
paul4dadc292005-05-06 21:37:42 +0000211static int
paul2d598362003-01-17 23:48:42 +0000212nsm_twoway_received (struct ospf_neighbor *nbr)
213{
paul2d598362003-01-17 23:48:42 +0000214 int next_state = NSM_TwoWay;
215
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000216 if (nsm_should_adj (nbr))
paul2d598362003-01-17 23:48:42 +0000217 next_state = NSM_ExStart;
218
219 return next_state;
220}
221
222int
223ospf_db_summary_count (struct ospf_neighbor *nbr)
224{
225 return ospf_lsdb_count_all (&nbr->db_sum);
226}
227
228int
229ospf_db_summary_isempty (struct ospf_neighbor *nbr)
230{
231 return ospf_lsdb_isempty (&nbr->db_sum);
232}
233
paul4dadc292005-05-06 21:37:42 +0000234static int
paul68980082003-03-25 05:07:42 +0000235ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
paul2d598362003-01-17 23:48:42 +0000236{
paul09e4efd2003-01-18 00:12:02 +0000237#ifdef HAVE_OPAQUE_LSA
238 switch (lsa->data->type)
239 {
240 case OSPF_OPAQUE_LINK_LSA:
241 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
242 if (lsa->oi != nbr->oi)
243 return 0;
244 break;
245 case OSPF_OPAQUE_AREA_LSA:
246 /*
247 * It is assured by the caller function "nsm_negotiation_done()"
248 * that every given LSA belongs to the same area with "nbr".
249 */
250 break;
251 case OSPF_OPAQUE_AS_LSA:
252 default:
253 break;
254 }
255#endif /* HAVE_OPAQUE_LSA */
256
paul2d598362003-01-17 23:48:42 +0000257 /* Stay away from any Local Translated Type-7 LSAs */
258 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
259 return 0;
paul2d598362003-01-17 23:48:42 +0000260
261 if (IS_LSA_MAXAGE (lsa))
262 ospf_ls_retransmit_add (nbr, lsa);
263 else
264 ospf_lsdb_add (&nbr->db_sum, lsa);
265
266 return 0;
267}
268
269void
270ospf_db_summary_clear (struct ospf_neighbor *nbr)
271{
272 struct ospf_lsdb *lsdb;
273 int i;
274
275 lsdb = &nbr->db_sum;
276 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
277 {
278 struct route_table *table = lsdb->type[i].db;
279 struct route_node *rn;
280
281 for (rn = route_top (table); rn; rn = route_next (rn))
282 if (rn->info)
283 ospf_lsdb_delete (&nbr->db_sum, rn->info);
284 }
285}
286
287
288
paul2d598362003-01-17 23:48:42 +0000289/* The area link state database consists of the router-LSAs,
290 network-LSAs and summary-LSAs contained in the area structure,
paul68980082003-03-25 05:07:42 +0000291 along with the AS-external-LSAs contained in the global structure.
292 AS-external-LSAs are omitted from a virtual neighbor's Database
paul2d598362003-01-17 23:48:42 +0000293 summary list. AS-external-LSAs are omitted from the Database
294 summary list if the area has been configured as a stub. */
paul4dadc292005-05-06 21:37:42 +0000295static int
paul2d598362003-01-17 23:48:42 +0000296nsm_negotiation_done (struct ospf_neighbor *nbr)
297{
paul68980082003-03-25 05:07:42 +0000298 struct ospf_area *area = nbr->oi->area;
299 struct ospf_lsa *lsa;
300 struct route_node *rn;
paul2d598362003-01-17 23:48:42 +0000301
paul68980082003-03-25 05:07:42 +0000302 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
303 ospf_db_summary_add (nbr, lsa);
304 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
305 ospf_db_summary_add (nbr, lsa);
306 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
307 ospf_db_summary_add (nbr, lsa);
308 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
309 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000310
paul2d598362003-01-17 23:48:42 +0000311#ifdef HAVE_OPAQUE_LSA
312 /* Process only if the neighbor is opaque capable. */
313 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
314 {
paul68980082003-03-25 05:07:42 +0000315 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
316 ospf_db_summary_add (nbr, lsa);
317 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
318 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000319 }
320#endif /* HAVE_OPAQUE_LSA */
321
hassof4833e92005-06-20 20:42:26 +0000322 if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
323 {
324 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
325 ospf_db_summary_add (nbr, lsa);
326 }
327
paul68980082003-03-25 05:07:42 +0000328 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
329 && area->external_routing == OSPF_AREA_DEFAULT)
330 LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
331 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000332
333#ifdef HAVE_OPAQUE_LSA
paul68980082003-03-25 05:07:42 +0000334 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
335 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
336 && area->external_routing == OSPF_AREA_DEFAULT))
337 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
338 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000339#endif /* HAVE_OPAQUE_LSA */
340
paul2d598362003-01-17 23:48:42 +0000341 return 0;
342}
343
paul4dadc292005-05-06 21:37:42 +0000344static int
paul2d598362003-01-17 23:48:42 +0000345nsm_exchange_done (struct ospf_neighbor *nbr)
346{
paul2d598362003-01-17 23:48:42 +0000347 if (ospf_ls_request_isempty (nbr))
348 return NSM_Full;
349
350 /* Cancel dd retransmit timer. */
351 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
352
353 /* Send Link State Request. */
354 ospf_ls_req_send (nbr);
355
356 return NSM_Loading;
357}
358
paul4dadc292005-05-06 21:37:42 +0000359static int
paul2d598362003-01-17 23:48:42 +0000360nsm_bad_ls_req (struct ospf_neighbor *nbr)
361{
362 /* Clear neighbor. */
363 nsm_reset_nbr (nbr);
364
365 return 0;
366}
367
paul4dadc292005-05-06 21:37:42 +0000368static int
paul2d598362003-01-17 23:48:42 +0000369nsm_adj_ok (struct ospf_neighbor *nbr)
370{
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000371 int next_state = nbr->state;
372 int adj = nsm_should_adj (nbr);
paul2d598362003-01-17 23:48:42 +0000373
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000374 if (nbr->state == NSM_TwoWay && adj == 1)
paul2d598362003-01-17 23:48:42 +0000375 next_state = NSM_ExStart;
Paul Jakmad7b0fb62006-07-04 13:35:24 +0000376 else if (nbr->state >= NSM_ExStart && adj == 0)
paul2d598362003-01-17 23:48:42 +0000377 next_state = NSM_TwoWay;
378
379 return next_state;
380}
381
paul4dadc292005-05-06 21:37:42 +0000382static int
paul2d598362003-01-17 23:48:42 +0000383nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
384{
385 /* Clear neighbor. */
386 nsm_reset_nbr (nbr);
387
388 return 0;
389}
390
paul4dadc292005-05-06 21:37:42 +0000391static int
paul2d598362003-01-17 23:48:42 +0000392nsm_oneway_received (struct ospf_neighbor *nbr)
393{
394 /* Clear neighbor. */
395 nsm_reset_nbr (nbr);
396
397 return 0;
398}
399
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000400/* Clear adjacency related state for a neighbour, intended where nbr
401 * transitions from > ExStart (i.e. a Full or forming adjacency)
402 * to <= ExStart.
403 */
404static void
405nsm_clear_adj (struct ospf_neighbor *nbr)
paul2d598362003-01-17 23:48:42 +0000406{
407 /* Clear Database Summary list. */
408 if (!ospf_db_summary_isempty (nbr))
409 ospf_db_summary_clear (nbr);
410
411 /* Clear Link State Request list. */
412 if (!ospf_ls_request_isempty (nbr))
413 ospf_ls_request_delete_all (nbr);
414
415 /* Clear Link State Retransmission list. */
416 if (!ospf_ls_retransmit_isempty (nbr))
417 ospf_ls_retransmit_clear (nbr);
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000418}
419
420static void
421nsm_reset_nbr (struct ospf_neighbor *nbr)
422{
423 nsm_clear_adj (nbr);
paul2d598362003-01-17 23:48:42 +0000424
425 /* Cancel thread. */
426 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
427 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
428 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
429 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
430
431#ifdef HAVE_OPAQUE_LSA
432 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
433 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
434#endif /* HAVE_OPAQUE_LSA */
435}
436
paul4dadc292005-05-06 21:37:42 +0000437static int
paul2d598362003-01-17 23:48:42 +0000438nsm_kill_nbr (struct ospf_neighbor *nbr)
439{
440 /* call it here because we cannot call it from ospf_nsm_event */
441 nsm_change_state (nbr, NSM_Down);
442
Paul Jakma478aab92006-04-03 21:25:32 +0000443 /* killing nbr_self is invalid */
444 assert (nbr != nbr->oi->nbr_self);
445 if (nbr == nbr->oi->nbr_self)
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000446 return 0;
Paul Jakma478aab92006-04-03 21:25:32 +0000447
paul2d598362003-01-17 23:48:42 +0000448 /* Reset neighbor. */
449 nsm_reset_nbr (nbr);
450
451 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
452 {
453 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
454
455 nbr_nbma->nbr = NULL;
456 nbr_nbma->state_change = nbr->state_change;
457
458 nbr->nbr_nbma = NULL;
459
460 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
461 nbr_nbma->v_poll);
462
463 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000464 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
paul2d598362003-01-17 23:48:42 +0000465 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
466 }
467
468 /* Delete neighbor from interface. */
469 ospf_nbr_delete (nbr);
470
471 return 0;
472}
473
paul4dadc292005-05-06 21:37:42 +0000474static int
paul2d598362003-01-17 23:48:42 +0000475nsm_inactivity_timer (struct ospf_neighbor *nbr)
476{
477 /* Kill neighbor. */
478 nsm_kill_nbr (nbr);
479
480 return 0;
481}
482
paul4dadc292005-05-06 21:37:42 +0000483static int
paul2d598362003-01-17 23:48:42 +0000484nsm_ll_down (struct ospf_neighbor *nbr)
485{
486 /* Reset neighbor. */
487 /*nsm_reset_nbr (nbr);*/
488
489 /* Kill neighbor. */
490 nsm_kill_nbr (nbr);
491
492 return 0;
493}
494
495/* Neighbor State Machine */
496struct {
paul4dadc292005-05-06 21:37:42 +0000497 int (*func) (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +0000498 int next_state;
499} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
500{
501 {
502 /* DependUpon: dummy state. */
503 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
504 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */
505 { nsm_ignore, NSM_DependUpon }, /* Start */
506 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */
507 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */
508 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */
509 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */
510 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */
511 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */
512 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */
513 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */
514 { nsm_ignore, NSM_DependUpon }, /* KillNbr */
515 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */
516 { nsm_ignore, NSM_DependUpon }, /* LLDown */
517 },
518 {
519 /* Down: */
520 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
521 { nsm_hello_received, NSM_Init }, /* HelloReceived */
522 { nsm_start, NSM_Attempt }, /* Start */
523 { nsm_ignore, NSM_Down }, /* 2-WayReceived */
524 { nsm_ignore, NSM_Down }, /* NegotiationDone */
525 { nsm_ignore, NSM_Down }, /* ExchangeDone */
526 { nsm_ignore, NSM_Down }, /* BadLSReq */
527 { nsm_ignore, NSM_Down }, /* LoadingDone */
528 { nsm_ignore, NSM_Down }, /* AdjOK? */
529 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */
530 { nsm_ignore, NSM_Down }, /* 1-WayReceived */
531 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
532 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
533 { nsm_ll_down, NSM_Down }, /* LLDown */
534 },
535 {
536 /* Attempt: */
537 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
538 { nsm_hello_received, NSM_Init }, /* HelloReceived */
539 { nsm_ignore, NSM_Attempt }, /* Start */
540 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */
541 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */
542 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */
543 { nsm_ignore, NSM_Attempt }, /* BadLSReq */
544 { nsm_ignore, NSM_Attempt }, /* LoadingDone */
545 { nsm_ignore, NSM_Attempt }, /* AdjOK? */
546 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */
547 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */
548 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
549 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
550 { nsm_ll_down, NSM_Down }, /* LLDown */
551 },
552 {
553 /* Init: */
554 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
555 { nsm_hello_received, NSM_Init }, /* HelloReceived */
556 { nsm_ignore, NSM_Init }, /* Start */
557 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
558 { nsm_ignore, NSM_Init }, /* NegotiationDone */
559 { nsm_ignore, NSM_Init }, /* ExchangeDone */
560 { nsm_ignore, NSM_Init }, /* BadLSReq */
561 { nsm_ignore, NSM_Init }, /* LoadingDone */
562 { nsm_ignore, NSM_Init }, /* AdjOK? */
563 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */
564 { nsm_ignore, NSM_Init }, /* 1-WayReceived */
565 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
566 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
567 { nsm_ll_down, NSM_Down }, /* LLDown */
568 },
569 {
570 /* 2-Way: */
571 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
572 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
573 { nsm_ignore, NSM_TwoWay }, /* Start */
574 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */
575 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */
576 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */
577 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */
578 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */
579 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
580 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */
581 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
582 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
583 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
584 { nsm_ll_down, NSM_Down }, /* LLDown */
585 },
586 {
587 /* ExStart: */
588 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
589 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
590 { nsm_ignore, NSM_ExStart }, /* Start */
591 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */
592 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
593 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */
594 { nsm_ignore, NSM_ExStart }, /* BadLSReq */
595 { nsm_ignore, NSM_ExStart }, /* LoadingDone */
596 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
597 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */
598 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
599 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
600 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
601 { nsm_ll_down, NSM_Down }, /* LLDown */
602 },
603 {
604 /* Exchange: */
605 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
606 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
607 { nsm_ignore, NSM_Exchange }, /* Start */
608 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */
609 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */
610 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
611 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
612 { nsm_ignore, NSM_Exchange }, /* LoadingDone */
613 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
614 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
615 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
616 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
617 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
618 { nsm_ll_down, NSM_Down }, /* LLDown */
619 },
620 {
621 /* Loading: */
622 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
623 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
624 { nsm_ignore, NSM_Loading }, /* Start */
625 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */
626 { nsm_ignore, NSM_Loading }, /* NegotiationDone */
627 { nsm_ignore, NSM_Loading }, /* ExchangeDone */
628 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
629 { nsm_ignore, NSM_Full }, /* LoadingDone */
630 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
631 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
632 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
633 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
634 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
635 { nsm_ll_down, NSM_Down }, /* LLDown */
636 },
637 { /* Full: */
638 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
639 { nsm_hello_received, NSM_Full }, /* HelloReceived */
640 { nsm_ignore, NSM_Full }, /* Start */
641 { nsm_ignore, NSM_Full }, /* 2-WayReceived */
642 { nsm_ignore, NSM_Full }, /* NegotiationDone */
643 { nsm_ignore, NSM_Full }, /* ExchangeDone */
644 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
645 { nsm_ignore, NSM_Full }, /* LoadingDone */
646 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
647 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
648 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
649 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
650 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
651 { nsm_ll_down, NSM_Down }, /* LLDown */
652 },
653};
654
hassoeb1ce602004-10-08 08:17:22 +0000655const static char *ospf_nsm_event_str[] =
paul2d598362003-01-17 23:48:42 +0000656{
657 "NoEvent",
658 "HelloReceived",
659 "Start",
660 "2-WayReceived",
661 "NegotiationDone",
662 "ExchangeDone",
663 "BadLSReq",
664 "LoadingDone",
665 "AdjOK?",
666 "SeqNumberMismatch",
667 "1-WayReceived",
668 "KillNbr",
669 "InactivityTimer",
670 "LLDown",
671};
672
673void
674nsm_change_state (struct ospf_neighbor *nbr, int state)
675{
paul68980082003-03-25 05:07:42 +0000676 struct ospf_interface *oi = nbr->oi;
paul2d598362003-01-17 23:48:42 +0000677 struct ospf_area *vl_area = NULL;
678 u_char old_state;
679 int x;
680 int force = 1;
681
682 /* Logging change of status. */
683 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
ajs2a42e282004-12-08 18:43:03 +0000684 zlog_debug ("NSM[%s:%s]: State change %s -> %s",
paul2d598362003-01-17 23:48:42 +0000685 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
686 LOOKUP (ospf_nsm_state_msg, nbr->state),
687 LOOKUP (ospf_nsm_state_msg, state));
688
689 /* Preserve old status. */
690 old_state = nbr->state;
691
692 /* Change to new status. */
693 nbr->state = state;
694
695 /* Statistics. */
696 nbr->state_change++;
697
paul2d598362003-01-17 23:48:42 +0000698 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul68980082003-03-25 05:07:42 +0000699 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
Andrew J. Schorrd7e60dd2006-06-29 20:20:52 +0000700
701 /* Optionally notify about adjacency changes */
702 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
703 (old_state != state) &&
704 (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
705 (state == NSM_Full) || (state < old_state)))
706 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s",
707 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
708 LOOKUP (ospf_nsm_state_msg, old_state),
709 LOOKUP (ospf_nsm_state_msg, state));
710
vincent5e4914c2005-09-29 16:34:30 +0000711#ifdef HAVE_SNMP
712 /* Terminal state or regression */
713 if ((state == NSM_Full) || (state == NSM_TwoWay) || (state < old_state))
714 {
715 /* ospfVirtNbrStateChange */
716 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
717 ospfTrapVirtNbrStateChange(nbr);
718 /* ospfNbrStateChange trap */
719 else
720 /* To/From FULL, only managed by DR */
721 if (((state != NSM_Full) && (old_state != NSM_Full)) ||
722 (oi->state == ISM_DR))
723 ospfTrapNbrStateChange(nbr);
724 }
725#endif
726
paul2d598362003-01-17 23:48:42 +0000727 /* One of the neighboring routers changes to/from the FULL state. */
728 if ((old_state != NSM_Full && state == NSM_Full) ||
729 (old_state == NSM_Full && state != NSM_Full))
ajs3aa8d5f2004-12-11 18:00:06 +0000730 {
paul2d598362003-01-17 23:48:42 +0000731 if (state == NSM_Full)
732 {
733 oi->full_nbrs++;
734 oi->area->full_nbrs++;
735
paul68980082003-03-25 05:07:42 +0000736 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000737
738 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
739 if (++vl_area->full_vls == 1)
paul68980082003-03-25 05:07:42 +0000740 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000741
742 /* kevinm: refresh any redistributions */
paul68980082003-03-25 05:07:42 +0000743 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
744 {
745 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
746 continue;
747 ospf_external_lsa_refresh_type (oi->ospf, x, force);
748 }
paul2d598362003-01-17 23:48:42 +0000749 }
750 else
751 {
752 oi->full_nbrs--;
753 oi->area->full_nbrs--;
754
paul68980082003-03-25 05:07:42 +0000755 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000756
757 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
758 if (vl_area->full_vls > 0)
759 if (--vl_area->full_vls == 0)
paul68980082003-03-25 05:07:42 +0000760 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000761 }
762
ajs3aa8d5f2004-12-11 18:00:06 +0000763 zlog_info ("nsm_change_state(%s, %s -> %s): "
764 "scheduling new router-LSA origination",
765 inet_ntoa (nbr->router_id),
766 LOOKUP(ospf_nsm_state_msg, old_state),
767 LOOKUP(ospf_nsm_state_msg, state));
paul2d598362003-01-17 23:48:42 +0000768
769 ospf_router_lsa_timer_add (oi->area);
770
771 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
772 {
773 struct ospf_area *vl_area =
paul68980082003-03-25 05:07:42 +0000774 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000775
776 if (vl_area)
777 ospf_router_lsa_timer_add (vl_area);
778 }
779
780 /* Originate network-LSA. */
781 if (oi->state == ISM_DR)
782 {
783 if (oi->network_lsa_self && oi->full_nbrs == 0)
784 {
785 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
786 ospf_lsa_unlock (oi->network_lsa_self);
787 oi->network_lsa_self = NULL;
788 OSPF_TIMER_OFF (oi->t_network_lsa_self);
789 }
790 else
791 ospf_network_lsa_timer_add (oi);
792 }
793 }
794
795#ifdef HAVE_OPAQUE_LSA
796 ospf_opaque_nsm_change (nbr, old_state);
797#endif /* HAVE_OPAQUE_LSA */
798
Paul Jakmad1b1cd82006-07-04 13:50:44 +0000799 /* State changes from > ExStart to <= ExStart should clear any Exchange
800 * or Full/LSA Update related lists and state.
801 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
802 *
803 * Note that transitions from > ExStart to < 2-Way (e.g. due to
804 * KillNbr or 1-Way) must and will do the same, but via
805 * nsm_reset_nbr.
806 */
807 if (old_state > NSM_ExStart
808 && (state == NSM_ExStart || state == NSM_TwoWay))
809 nsm_clear_adj (nbr);
810
paul2d598362003-01-17 23:48:42 +0000811 /* Start DD exchange protocol */
812 if (state == NSM_ExStart)
813 {
814 if (nbr->dd_seqnum == 0)
815 nbr->dd_seqnum = time (NULL);
816 else
817 nbr->dd_seqnum++;
818
819 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
820 ospf_db_desc_send (nbr);
821 }
822
823 /* clear cryptographic sequence number */
824 if (state == NSM_Down)
825 nbr->crypt_seqnum = 0;
826
827 /* Generete NeighborChange ISM event. */
paul2d598362003-01-17 23:48:42 +0000828 switch (oi->state) {
829 case ISM_DROther:
830 case ISM_Backup:
831 case ISM_DR:
832 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
833 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
834 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
835 break;
836 default:
837 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
838 break;
839 }
paul2d598362003-01-17 23:48:42 +0000840
841 /* Performance hack. Send hello immideately when some neighbor enter
842 Init state. This whay we decrease neighbor discovery time. Gleb.*/
843 if (state == NSM_Init)
844 {
845 OSPF_ISM_TIMER_OFF (oi->t_hello);
paulf9ad9372005-10-21 00:45:17 +0000846 OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1);
paul2d598362003-01-17 23:48:42 +0000847 }
848
849 /* Preserve old status? */
850}
851
852/* Execute NSM event process. */
853int
854ospf_nsm_event (struct thread *thread)
855{
856 int event;
857 int next_state;
858 struct ospf_neighbor *nbr;
859 struct in_addr router_id;
860 int old_state;
861 struct ospf_interface *oi;
862
863 nbr = THREAD_ARG (thread);
864 event = THREAD_VAL (thread);
865 router_id = nbr->router_id;
866
867 old_state = nbr->state;
868 oi = nbr->oi ;
869
870 /* Call function. */
871 next_state = (*(NSM [nbr->state][event].func))(nbr);
872
873 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
874 deleted. */
875 if (event == NSM_KillNbr || event == NSM_InactivityTimer)
876 {
877 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000878 zlog_debug ("NSM[%s:%s]: neighbor deleted",
paul2d598362003-01-17 23:48:42 +0000879 IF_NAME (oi), inet_ntoa (router_id));
880
881 /* Timers are canceled in ospf_nbr_free, moreover we cannot call
882 nsm_timer_set here because nbr is freed already!!!*/
883 /*nsm_timer_set (nbr);*/
884
885 return 0;
886 }
887
888 if (! next_state)
889 next_state = NSM [nbr->state][event].next_state;
Paul Jakmaba0beb42006-07-04 13:44:19 +0000890 else if (NSM [nbr->state][event].next_state != NSM_DependUpon)
891 {
892 /* There's a mismatch between the FSM tables and what an FSM
893 * action/state-change function returned. State changes which
894 * do not have conditional/DependUpon next-states should not
895 * try set next_state.
896 */
897 zlog_warn ("NSM[%s:%s]: %s (%s): "
898 "Warning: action tried to change next_state to %s",
899 IF_NAME (oi), inet_ntoa (nbr->router_id),
900 LOOKUP (ospf_nsm_state_msg, nbr->state),
901 ospf_nsm_event_str [event],
902 LOOKUP (ospf_nsm_state_msg, next_state));
903
904 next_state = NSM [nbr->state][event].next_state;
905 }
paul2d598362003-01-17 23:48:42 +0000906
907 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000908 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
paul2d598362003-01-17 23:48:42 +0000909 inet_ntoa (nbr->router_id),
910 LOOKUP (ospf_nsm_state_msg, nbr->state),
911 ospf_nsm_event_str [event]);
912
913 /* If state is changed. */
914 if (next_state != nbr->state)
915 nsm_change_state (nbr, next_state);
916
917 /* Make sure timer is set. */
918 nsm_timer_set (nbr);
919
920 return 0;
921}
922
923/* Check loading state. */
924void
925ospf_check_nbr_loading (struct ospf_neighbor *nbr)
926{
927 if (nbr->state == NSM_Loading)
928 {
929 if (ospf_ls_request_isempty (nbr))
930 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
931 else if (nbr->ls_req_last == NULL)
932 ospf_ls_req_event (nbr);
933 }
934}