blob: 2af4fc187c34af49ffe6b1006d083a41fb3d1bd4 [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"
50
51void nsm_reset_nbr (struct ospf_neighbor *);
52
53
54/* OSPF NSM Timer functions. */
paul4dadc292005-05-06 21:37:42 +000055static int
paul2d598362003-01-17 23:48:42 +000056ospf_inactivity_timer (struct thread *thread)
57{
58 struct ospf_neighbor *nbr;
59
60 nbr = THREAD_ARG (thread);
61 nbr->t_inactivity = NULL;
62
63 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
64 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)",
65 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
66
67 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer);
68
69 return 0;
70}
71
paul4dadc292005-05-06 21:37:42 +000072static int
paul2d598362003-01-17 23:48:42 +000073ospf_db_desc_timer (struct thread *thread)
74{
75 struct ospf_interface *oi;
76 struct ospf_neighbor *nbr;
77
78 nbr = THREAD_ARG (thread);
79 nbr->t_db_desc = NULL;
80
81 oi = nbr->oi;
82
83 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
ajs2a42e282004-12-08 18:43:03 +000084 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
paul2d598362003-01-17 23:48:42 +000085 IF_NAME (nbr->oi), inet_ntoa (nbr->src));
86
87 /* resent last send DD packet. */
88 assert (nbr->last_send);
89 ospf_db_desc_resend (nbr);
90
91 /* DD Retransmit timer set. */
92 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
93
94 return 0;
95}
96
97/* Hook function called after ospf NSM event is occured. */
98
paul4dadc292005-05-06 21:37:42 +000099static void
paul2d598362003-01-17 23:48:42 +0000100nsm_timer_set (struct ospf_neighbor *nbr)
101{
102 switch (nbr->state)
103 {
104 case NSM_Down:
105 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
106 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
107 break;
108 case NSM_Attempt:
109 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
110 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
111 break;
112 case NSM_Init:
113 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
114 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
115 break;
116 case NSM_TwoWay:
117 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
118 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
119 break;
120 case NSM_ExStart:
121 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
122 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
123 break;
124 case NSM_Exchange:
125 OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
126 if (!IS_SET_DD_MS (nbr->dd_flags))
127 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
128 break;
129 case NSM_Loading:
130 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
131 break;
132 case NSM_Full:
133 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
134 break;
135 default:
136 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
137 break;
138 }
139}
140
141
142/* OSPF NSM functions. */
paul4dadc292005-05-06 21:37:42 +0000143static int
paul2d598362003-01-17 23:48:42 +0000144nsm_ignore (struct ospf_neighbor *nbr)
145{
146 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000147 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: nsm_ignore called",
paul2d598362003-01-17 23:48:42 +0000148 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
149
150 return 0;
151}
152
paul4dadc292005-05-06 21:37:42 +0000153static int
paul2d598362003-01-17 23:48:42 +0000154nsm_hello_received (struct ospf_neighbor *nbr)
155{
156 /* Start or Restart Inactivity Timer. */
157 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
158
159 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
160 nbr->v_inactivity);
161
162 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
163 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
164
165 return 0;
166}
167
paul4dadc292005-05-06 21:37:42 +0000168static int
paul2d598362003-01-17 23:48:42 +0000169nsm_start (struct ospf_neighbor *nbr)
170{
171
172 nsm_reset_nbr (nbr);
173
174 if (nbr->nbr_nbma)
175 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
176
177 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
178
179 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
180 nbr->v_inactivity);
181
182 return 0;
183}
184
paul4dadc292005-05-06 21:37:42 +0000185static int
paul2d598362003-01-17 23:48:42 +0000186nsm_twoway_received (struct ospf_neighbor *nbr)
187{
188 struct ospf_interface *oi;
189 int next_state = NSM_TwoWay;
190
191 oi = nbr->oi;
192
193 /* These netowork types must be adjacency. */
194 if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
195 oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
196 oi->type == OSPF_IFTYPE_VIRTUALLINK)
197 next_state = NSM_ExStart;
198
199 /* Router itself is the DRouter or the BDRouter. */
200 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) ||
201 IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
202 next_state = NSM_ExStart;
203
204 /* Neighboring Router is the DRouter or the BDRouter. */
205 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router) ||
206 IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router))
207 next_state = NSM_ExStart;
208
209 return next_state;
210}
211
212int
213ospf_db_summary_count (struct ospf_neighbor *nbr)
214{
215 return ospf_lsdb_count_all (&nbr->db_sum);
216}
217
218int
219ospf_db_summary_isempty (struct ospf_neighbor *nbr)
220{
221 return ospf_lsdb_isempty (&nbr->db_sum);
222}
223
paul4dadc292005-05-06 21:37:42 +0000224static int
paul68980082003-03-25 05:07:42 +0000225ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
paul2d598362003-01-17 23:48:42 +0000226{
paul09e4efd2003-01-18 00:12:02 +0000227#ifdef HAVE_OPAQUE_LSA
228 switch (lsa->data->type)
229 {
230 case OSPF_OPAQUE_LINK_LSA:
231 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
232 if (lsa->oi != nbr->oi)
233 return 0;
234 break;
235 case OSPF_OPAQUE_AREA_LSA:
236 /*
237 * It is assured by the caller function "nsm_negotiation_done()"
238 * that every given LSA belongs to the same area with "nbr".
239 */
240 break;
241 case OSPF_OPAQUE_AS_LSA:
242 default:
243 break;
244 }
245#endif /* HAVE_OPAQUE_LSA */
246
paul2d598362003-01-17 23:48:42 +0000247 /* Stay away from any Local Translated Type-7 LSAs */
248 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
249 return 0;
paul2d598362003-01-17 23:48:42 +0000250
251 if (IS_LSA_MAXAGE (lsa))
252 ospf_ls_retransmit_add (nbr, lsa);
253 else
254 ospf_lsdb_add (&nbr->db_sum, lsa);
255
256 return 0;
257}
258
259void
260ospf_db_summary_clear (struct ospf_neighbor *nbr)
261{
262 struct ospf_lsdb *lsdb;
263 int i;
264
265 lsdb = &nbr->db_sum;
266 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
267 {
268 struct route_table *table = lsdb->type[i].db;
269 struct route_node *rn;
270
271 for (rn = route_top (table); rn; rn = route_next (rn))
272 if (rn->info)
273 ospf_lsdb_delete (&nbr->db_sum, rn->info);
274 }
275}
276
277
278
paul2d598362003-01-17 23:48:42 +0000279/* The area link state database consists of the router-LSAs,
280 network-LSAs and summary-LSAs contained in the area structure,
paul68980082003-03-25 05:07:42 +0000281 along with the AS-external-LSAs contained in the global structure.
282 AS-external-LSAs are omitted from a virtual neighbor's Database
paul2d598362003-01-17 23:48:42 +0000283 summary list. AS-external-LSAs are omitted from the Database
284 summary list if the area has been configured as a stub. */
paul4dadc292005-05-06 21:37:42 +0000285static int
paul2d598362003-01-17 23:48:42 +0000286nsm_negotiation_done (struct ospf_neighbor *nbr)
287{
paul68980082003-03-25 05:07:42 +0000288 struct ospf_area *area = nbr->oi->area;
289 struct ospf_lsa *lsa;
290 struct route_node *rn;
paul2d598362003-01-17 23:48:42 +0000291
paul68980082003-03-25 05:07:42 +0000292 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
293 ospf_db_summary_add (nbr, lsa);
294 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
295 ospf_db_summary_add (nbr, lsa);
296 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
297 ospf_db_summary_add (nbr, lsa);
298 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
299 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000300
paul2d598362003-01-17 23:48:42 +0000301#ifdef HAVE_OPAQUE_LSA
302 /* Process only if the neighbor is opaque capable. */
303 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
304 {
paul68980082003-03-25 05:07:42 +0000305 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
306 ospf_db_summary_add (nbr, lsa);
307 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
308 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000309 }
310#endif /* HAVE_OPAQUE_LSA */
311
hassof4833e92005-06-20 20:42:26 +0000312 if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
313 {
314 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
315 ospf_db_summary_add (nbr, lsa);
316 }
317
paul68980082003-03-25 05:07:42 +0000318 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
319 && area->external_routing == OSPF_AREA_DEFAULT)
320 LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
321 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000322
323#ifdef HAVE_OPAQUE_LSA
paul68980082003-03-25 05:07:42 +0000324 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
325 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
326 && area->external_routing == OSPF_AREA_DEFAULT))
327 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
328 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000329#endif /* HAVE_OPAQUE_LSA */
330
paul2d598362003-01-17 23:48:42 +0000331 return 0;
332}
333
paul4dadc292005-05-06 21:37:42 +0000334static int
paul2d598362003-01-17 23:48:42 +0000335nsm_exchange_done (struct ospf_neighbor *nbr)
336{
paul2d598362003-01-17 23:48:42 +0000337 if (ospf_ls_request_isempty (nbr))
338 return NSM_Full;
339
340 /* Cancel dd retransmit timer. */
341 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
342
343 /* Send Link State Request. */
344 ospf_ls_req_send (nbr);
345
346 return NSM_Loading;
347}
348
paul4dadc292005-05-06 21:37:42 +0000349static int
paul2d598362003-01-17 23:48:42 +0000350nsm_bad_ls_req (struct ospf_neighbor *nbr)
351{
352 /* Clear neighbor. */
353 nsm_reset_nbr (nbr);
354
355 return 0;
356}
357
paul4dadc292005-05-06 21:37:42 +0000358static int
paul2d598362003-01-17 23:48:42 +0000359nsm_adj_ok (struct ospf_neighbor *nbr)
360{
361 struct ospf_interface *oi;
362 int next_state;
363 int flag = 0;
364
365 oi = nbr->oi;
366 next_state = nbr->state;
367
368 /* These netowork types must be adjacency. */
paul68980082003-03-25 05:07:42 +0000369 if (oi->type == OSPF_IFTYPE_POINTOPOINT
370 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
371 || oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul2d598362003-01-17 23:48:42 +0000372 flag = 1;
373
374 /* Router itself is the DRouter or the BDRouter. */
paul68980082003-03-25 05:07:42 +0000375 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
376 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
paul2d598362003-01-17 23:48:42 +0000377 flag = 1;
378
paul68980082003-03-25 05:07:42 +0000379 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
380 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
paul2d598362003-01-17 23:48:42 +0000381 flag = 1;
382
383 if (nbr->state == NSM_TwoWay && flag == 1)
384 next_state = NSM_ExStart;
385 else if (nbr->state >= NSM_ExStart && flag == 0)
386 next_state = NSM_TwoWay;
387
388 return next_state;
389}
390
paul4dadc292005-05-06 21:37:42 +0000391static int
paul2d598362003-01-17 23:48:42 +0000392nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
393{
394 /* Clear neighbor. */
395 nsm_reset_nbr (nbr);
396
397 return 0;
398}
399
paul4dadc292005-05-06 21:37:42 +0000400static int
paul2d598362003-01-17 23:48:42 +0000401nsm_oneway_received (struct ospf_neighbor *nbr)
402{
403 /* Clear neighbor. */
404 nsm_reset_nbr (nbr);
405
406 return 0;
407}
408
409void
410nsm_reset_nbr (struct ospf_neighbor *nbr)
411{
412 /* Clear Database Summary list. */
413 if (!ospf_db_summary_isempty (nbr))
414 ospf_db_summary_clear (nbr);
415
416 /* Clear Link State Request list. */
417 if (!ospf_ls_request_isempty (nbr))
418 ospf_ls_request_delete_all (nbr);
419
420 /* Clear Link State Retransmission list. */
421 if (!ospf_ls_retransmit_isempty (nbr))
422 ospf_ls_retransmit_clear (nbr);
423
424 /* Cancel thread. */
425 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
426 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
427 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
428 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
429
430#ifdef HAVE_OPAQUE_LSA
431 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
432 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
433#endif /* HAVE_OPAQUE_LSA */
434}
435
paul4dadc292005-05-06 21:37:42 +0000436static int
paul2d598362003-01-17 23:48:42 +0000437nsm_kill_nbr (struct ospf_neighbor *nbr)
438{
439 /* call it here because we cannot call it from ospf_nsm_event */
440 nsm_change_state (nbr, NSM_Down);
441
442 /* Reset neighbor. */
443 nsm_reset_nbr (nbr);
444
445 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
446 {
447 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
448
449 nbr_nbma->nbr = NULL;
450 nbr_nbma->state_change = nbr->state_change;
451
452 nbr->nbr_nbma = NULL;
453
454 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
455 nbr_nbma->v_poll);
456
457 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000458 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
paul2d598362003-01-17 23:48:42 +0000459 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
460 }
461
462 /* Delete neighbor from interface. */
463 ospf_nbr_delete (nbr);
464
465 return 0;
466}
467
paul4dadc292005-05-06 21:37:42 +0000468static int
paul2d598362003-01-17 23:48:42 +0000469nsm_inactivity_timer (struct ospf_neighbor *nbr)
470{
471 /* Kill neighbor. */
472 nsm_kill_nbr (nbr);
473
474 return 0;
475}
476
paul4dadc292005-05-06 21:37:42 +0000477static int
paul2d598362003-01-17 23:48:42 +0000478nsm_ll_down (struct ospf_neighbor *nbr)
479{
480 /* Reset neighbor. */
481 /*nsm_reset_nbr (nbr);*/
482
483 /* Kill neighbor. */
484 nsm_kill_nbr (nbr);
485
486 return 0;
487}
488
489/* Neighbor State Machine */
490struct {
paul4dadc292005-05-06 21:37:42 +0000491 int (*func) (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +0000492 int next_state;
493} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
494{
495 {
496 /* DependUpon: dummy state. */
497 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
498 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */
499 { nsm_ignore, NSM_DependUpon }, /* Start */
500 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */
501 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */
502 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */
503 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */
504 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */
505 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */
506 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */
507 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */
508 { nsm_ignore, NSM_DependUpon }, /* KillNbr */
509 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */
510 { nsm_ignore, NSM_DependUpon }, /* LLDown */
511 },
512 {
513 /* Down: */
514 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
515 { nsm_hello_received, NSM_Init }, /* HelloReceived */
516 { nsm_start, NSM_Attempt }, /* Start */
517 { nsm_ignore, NSM_Down }, /* 2-WayReceived */
518 { nsm_ignore, NSM_Down }, /* NegotiationDone */
519 { nsm_ignore, NSM_Down }, /* ExchangeDone */
520 { nsm_ignore, NSM_Down }, /* BadLSReq */
521 { nsm_ignore, NSM_Down }, /* LoadingDone */
522 { nsm_ignore, NSM_Down }, /* AdjOK? */
523 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */
524 { nsm_ignore, NSM_Down }, /* 1-WayReceived */
525 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
526 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
527 { nsm_ll_down, NSM_Down }, /* LLDown */
528 },
529 {
530 /* Attempt: */
531 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
532 { nsm_hello_received, NSM_Init }, /* HelloReceived */
533 { nsm_ignore, NSM_Attempt }, /* Start */
534 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */
535 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */
536 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */
537 { nsm_ignore, NSM_Attempt }, /* BadLSReq */
538 { nsm_ignore, NSM_Attempt }, /* LoadingDone */
539 { nsm_ignore, NSM_Attempt }, /* AdjOK? */
540 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */
541 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */
542 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
543 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
544 { nsm_ll_down, NSM_Down }, /* LLDown */
545 },
546 {
547 /* Init: */
548 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
549 { nsm_hello_received, NSM_Init }, /* HelloReceived */
550 { nsm_ignore, NSM_Init }, /* Start */
551 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
552 { nsm_ignore, NSM_Init }, /* NegotiationDone */
553 { nsm_ignore, NSM_Init }, /* ExchangeDone */
554 { nsm_ignore, NSM_Init }, /* BadLSReq */
555 { nsm_ignore, NSM_Init }, /* LoadingDone */
556 { nsm_ignore, NSM_Init }, /* AdjOK? */
557 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */
558 { nsm_ignore, NSM_Init }, /* 1-WayReceived */
559 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
560 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
561 { nsm_ll_down, NSM_Down }, /* LLDown */
562 },
563 {
564 /* 2-Way: */
565 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
566 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
567 { nsm_ignore, NSM_TwoWay }, /* Start */
568 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */
569 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */
570 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */
571 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */
572 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */
573 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
574 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */
575 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
576 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
577 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
578 { nsm_ll_down, NSM_Down }, /* LLDown */
579 },
580 {
581 /* ExStart: */
582 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
583 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
584 { nsm_ignore, NSM_ExStart }, /* Start */
585 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */
586 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
587 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */
588 { nsm_ignore, NSM_ExStart }, /* BadLSReq */
589 { nsm_ignore, NSM_ExStart }, /* LoadingDone */
590 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
591 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */
592 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
593 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
594 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
595 { nsm_ll_down, NSM_Down }, /* LLDown */
596 },
597 {
598 /* Exchange: */
599 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
600 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
601 { nsm_ignore, NSM_Exchange }, /* Start */
602 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */
603 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */
604 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
605 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
606 { nsm_ignore, NSM_Exchange }, /* LoadingDone */
607 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
608 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
609 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
610 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
611 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
612 { nsm_ll_down, NSM_Down }, /* LLDown */
613 },
614 {
615 /* Loading: */
616 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
617 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
618 { nsm_ignore, NSM_Loading }, /* Start */
619 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */
620 { nsm_ignore, NSM_Loading }, /* NegotiationDone */
621 { nsm_ignore, NSM_Loading }, /* ExchangeDone */
622 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
623 { nsm_ignore, NSM_Full }, /* LoadingDone */
624 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
625 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
626 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
627 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
628 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
629 { nsm_ll_down, NSM_Down }, /* LLDown */
630 },
631 { /* Full: */
632 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
633 { nsm_hello_received, NSM_Full }, /* HelloReceived */
634 { nsm_ignore, NSM_Full }, /* Start */
635 { nsm_ignore, NSM_Full }, /* 2-WayReceived */
636 { nsm_ignore, NSM_Full }, /* NegotiationDone */
637 { nsm_ignore, NSM_Full }, /* ExchangeDone */
638 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
639 { nsm_ignore, NSM_Full }, /* LoadingDone */
640 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
641 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
642 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
643 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
644 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
645 { nsm_ll_down, NSM_Down }, /* LLDown */
646 },
647};
648
hassoeb1ce602004-10-08 08:17:22 +0000649const static char *ospf_nsm_event_str[] =
paul2d598362003-01-17 23:48:42 +0000650{
651 "NoEvent",
652 "HelloReceived",
653 "Start",
654 "2-WayReceived",
655 "NegotiationDone",
656 "ExchangeDone",
657 "BadLSReq",
658 "LoadingDone",
659 "AdjOK?",
660 "SeqNumberMismatch",
661 "1-WayReceived",
662 "KillNbr",
663 "InactivityTimer",
664 "LLDown",
665};
666
667void
668nsm_change_state (struct ospf_neighbor *nbr, int state)
669{
paul68980082003-03-25 05:07:42 +0000670 struct ospf_interface *oi = nbr->oi;
paul2d598362003-01-17 23:48:42 +0000671 struct ospf_area *vl_area = NULL;
672 u_char old_state;
673 int x;
674 int force = 1;
675
676 /* Logging change of status. */
677 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
ajs2a42e282004-12-08 18:43:03 +0000678 zlog_debug ("NSM[%s:%s]: State change %s -> %s",
paul2d598362003-01-17 23:48:42 +0000679 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
680 LOOKUP (ospf_nsm_state_msg, nbr->state),
681 LOOKUP (ospf_nsm_state_msg, state));
682
683 /* Preserve old status. */
684 old_state = nbr->state;
685
686 /* Change to new status. */
687 nbr->state = state;
688
689 /* Statistics. */
690 nbr->state_change++;
691
paul2d598362003-01-17 23:48:42 +0000692 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul68980082003-03-25 05:07:42 +0000693 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000694
695 /* One of the neighboring routers changes to/from the FULL state. */
696 if ((old_state != NSM_Full && state == NSM_Full) ||
697 (old_state == NSM_Full && state != NSM_Full))
ajs3aa8d5f2004-12-11 18:00:06 +0000698 {
paul2d598362003-01-17 23:48:42 +0000699 if (state == NSM_Full)
700 {
701 oi->full_nbrs++;
702 oi->area->full_nbrs++;
703
paul68980082003-03-25 05:07:42 +0000704 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000705
706 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
707 if (++vl_area->full_vls == 1)
paul68980082003-03-25 05:07:42 +0000708 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000709
710 /* kevinm: refresh any redistributions */
paul68980082003-03-25 05:07:42 +0000711 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
712 {
713 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
714 continue;
715 ospf_external_lsa_refresh_type (oi->ospf, x, force);
716 }
paul2d598362003-01-17 23:48:42 +0000717 }
718 else
719 {
720 oi->full_nbrs--;
721 oi->area->full_nbrs--;
722
paul68980082003-03-25 05:07:42 +0000723 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000724
725 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
726 if (vl_area->full_vls > 0)
727 if (--vl_area->full_vls == 0)
paul68980082003-03-25 05:07:42 +0000728 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000729
730 /* clear neighbor retransmit list */
731 if (!ospf_ls_retransmit_isempty (nbr))
732 ospf_ls_retransmit_clear (nbr);
733 }
734
ajs3aa8d5f2004-12-11 18:00:06 +0000735 zlog_info ("nsm_change_state(%s, %s -> %s): "
736 "scheduling new router-LSA origination",
737 inet_ntoa (nbr->router_id),
738 LOOKUP(ospf_nsm_state_msg, old_state),
739 LOOKUP(ospf_nsm_state_msg, state));
paul2d598362003-01-17 23:48:42 +0000740
741 ospf_router_lsa_timer_add (oi->area);
742
743 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
744 {
745 struct ospf_area *vl_area =
paul68980082003-03-25 05:07:42 +0000746 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000747
748 if (vl_area)
749 ospf_router_lsa_timer_add (vl_area);
750 }
751
752 /* Originate network-LSA. */
753 if (oi->state == ISM_DR)
754 {
755 if (oi->network_lsa_self && oi->full_nbrs == 0)
756 {
757 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
758 ospf_lsa_unlock (oi->network_lsa_self);
759 oi->network_lsa_self = NULL;
760 OSPF_TIMER_OFF (oi->t_network_lsa_self);
761 }
762 else
763 ospf_network_lsa_timer_add (oi);
764 }
765 }
766
767#ifdef HAVE_OPAQUE_LSA
768 ospf_opaque_nsm_change (nbr, old_state);
769#endif /* HAVE_OPAQUE_LSA */
770
771 /* Start DD exchange protocol */
772 if (state == NSM_ExStart)
773 {
774 if (nbr->dd_seqnum == 0)
775 nbr->dd_seqnum = time (NULL);
776 else
777 nbr->dd_seqnum++;
778
779 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
780 ospf_db_desc_send (nbr);
781 }
782
783 /* clear cryptographic sequence number */
784 if (state == NSM_Down)
785 nbr->crypt_seqnum = 0;
786
787 /* Generete NeighborChange ISM event. */
788#ifdef BUGGY_ISM_TRANSITION
789 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
790 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
791 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
792#else /* BUGGY_ISM_TRANSITION */
793 switch (oi->state) {
794 case ISM_DROther:
795 case ISM_Backup:
796 case ISM_DR:
797 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
798 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
799 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
800 break;
801 default:
802 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
803 break;
804 }
805#endif /* BUGGY_ISM_TRANSITION */
806
807 /* Performance hack. Send hello immideately when some neighbor enter
808 Init state. This whay we decrease neighbor discovery time. Gleb.*/
809 if (state == NSM_Init)
810 {
811 OSPF_ISM_TIMER_OFF (oi->t_hello);
812 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1);
813 }
814
815 /* Preserve old status? */
816}
817
818/* Execute NSM event process. */
819int
820ospf_nsm_event (struct thread *thread)
821{
822 int event;
823 int next_state;
824 struct ospf_neighbor *nbr;
825 struct in_addr router_id;
826 int old_state;
827 struct ospf_interface *oi;
828
829 nbr = THREAD_ARG (thread);
830 event = THREAD_VAL (thread);
831 router_id = nbr->router_id;
832
833 old_state = nbr->state;
834 oi = nbr->oi ;
835
836 /* Call function. */
837 next_state = (*(NSM [nbr->state][event].func))(nbr);
838
839 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
840 deleted. */
841 if (event == NSM_KillNbr || event == NSM_InactivityTimer)
842 {
843 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000844 zlog_debug ("NSM[%s:%s]: neighbor deleted",
paul2d598362003-01-17 23:48:42 +0000845 IF_NAME (oi), inet_ntoa (router_id));
846
847 /* Timers are canceled in ospf_nbr_free, moreover we cannot call
848 nsm_timer_set here because nbr is freed already!!!*/
849 /*nsm_timer_set (nbr);*/
850
851 return 0;
852 }
853
854 if (! next_state)
855 next_state = NSM [nbr->state][event].next_state;
856
857 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000858 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
paul2d598362003-01-17 23:48:42 +0000859 inet_ntoa (nbr->router_id),
860 LOOKUP (ospf_nsm_state_msg, nbr->state),
861 ospf_nsm_event_str [event]);
862
863 /* If state is changed. */
864 if (next_state != nbr->state)
865 nsm_change_state (nbr, next_state);
866
867 /* Make sure timer is set. */
868 nsm_timer_set (nbr);
869
870 return 0;
871}
872
873/* Check loading state. */
874void
875ospf_check_nbr_loading (struct ospf_neighbor *nbr)
876{
877 if (nbr->state == NSM_Loading)
878 {
879 if (ospf_ls_request_isempty (nbr))
880 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
881 else if (nbr->ls_req_last == NULL)
882 ospf_ls_req_event (nbr);
883 }
884}