blob: 57303570b7b56ce0d0a80faf4725f56c96ac11c1 [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. */
55int
56ospf_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
72int
73ospf_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))
84 zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
85 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
99void
100nsm_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. */
143int
144nsm_ignore (struct ospf_neighbor *nbr)
145{
146 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
147 zlog (NULL, LOG_INFO, "NSM[%s:%s]: nsm_ignore called",
148 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
149
150 return 0;
151}
152
153int
154nsm_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
168int
169nsm_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
185int
186nsm_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
224int
225ospf_db_summary_add (struct ospf_lsa *lsa, void *v, int i)
226{
227 struct ospf_neighbor *nbr = (struct ospf_neighbor *) v;
228
229 if (lsa == NULL)
230 return 0;
231
paul09e4efd2003-01-18 00:12:02 +0000232#ifdef HAVE_OPAQUE_LSA
233 switch (lsa->data->type)
234 {
235 case OSPF_OPAQUE_LINK_LSA:
236 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
237 if (lsa->oi != nbr->oi)
238 return 0;
239 break;
240 case OSPF_OPAQUE_AREA_LSA:
241 /*
242 * It is assured by the caller function "nsm_negotiation_done()"
243 * that every given LSA belongs to the same area with "nbr".
244 */
245 break;
246 case OSPF_OPAQUE_AS_LSA:
247 default:
248 break;
249 }
250#endif /* HAVE_OPAQUE_LSA */
251
paul2d598362003-01-17 23:48:42 +0000252#ifdef HAVE_NSSA
253 /* Stay away from any Local Translated Type-7 LSAs */
254 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
255 return 0;
256#endif /* HAVE_NSSA */
257
258 if (IS_LSA_MAXAGE (lsa))
259 ospf_ls_retransmit_add (nbr, lsa);
260 else
261 ospf_lsdb_add (&nbr->db_sum, lsa);
262
263 return 0;
264}
265
266void
267ospf_db_summary_clear (struct ospf_neighbor *nbr)
268{
269 struct ospf_lsdb *lsdb;
270 int i;
271
272 lsdb = &nbr->db_sum;
273 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
274 {
275 struct route_table *table = lsdb->type[i].db;
276 struct route_node *rn;
277
278 for (rn = route_top (table); rn; rn = route_next (rn))
279 if (rn->info)
280 ospf_lsdb_delete (&nbr->db_sum, rn->info);
281 }
282}
283
284
285
286#ifdef HAVE_OPAQUE_LSA
287/* The area link state database consists of the router-LSAs,
288 network-LSAs, summary-LSAs, and type-9/10 opaque-LSAs contained
289 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
290 in the area structure, along with the AS-external and type-11
291 ^^^^^^^^^^^
292 opaque LSAs contained in the global structure.
293 ^^^^^^
294 AS-external and type-11 opaque LSAs are omitted from a virtual
295 ^^^^^^^^^^^^^^^^^^
296 neighbor's Database summary list. AS-external and type-11 opaque
297 ^^^^^^^^^^^^^^^^^^
298 LSAs are omitted from the Database summary list if the area has
299 been configured as a stub. */
300#else /* HAVE_OPAQUE_LSA */
301/* The area link state database consists of the router-LSAs,
302 network-LSAs and summary-LSAs contained in the area structure,
303 along with the AS-external- LSAs contained in the global structure.
304 AS- external-LSAs are omitted from a virtual neighbor's Database
305 summary list. AS-external-LSAs are omitted from the Database
306 summary list if the area has been configured as a stub. */
307#endif /* HAVE_OPAQUE_LSA */
308int
309nsm_negotiation_done (struct ospf_neighbor *nbr)
310{
311 struct ospf_area *area;
312
313 area = nbr->oi->area;
314
315 foreach_lsa (ROUTER_LSDB (area), nbr, 0, ospf_db_summary_add);
316 foreach_lsa (NETWORK_LSDB (area), nbr, 0, ospf_db_summary_add);
317 foreach_lsa (SUMMARY_LSDB (area), nbr, 0, ospf_db_summary_add);
318 foreach_lsa (ASBR_SUMMARY_LSDB (area), nbr, 0, ospf_db_summary_add);
319
320#ifdef HAVE_OPAQUE_LSA
321 /* Process only if the neighbor is opaque capable. */
322 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
323 {
324 foreach_lsa (OPAQUE_LINK_LSDB (area), nbr, 0, ospf_db_summary_add);
325 foreach_lsa (OPAQUE_AREA_LSDB (area), nbr, 0, ospf_db_summary_add);
326 }
327#endif /* HAVE_OPAQUE_LSA */
328
329 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK &&
330 area->external_routing == OSPF_AREA_DEFAULT)
331 foreach_lsa (EXTERNAL_LSDB (ospf_top), nbr, 0, ospf_db_summary_add);
332
333#ifdef HAVE_OPAQUE_LSA
334 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) &&
335 (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK &&
336 area->external_routing == OSPF_AREA_DEFAULT))
337 foreach_lsa (OPAQUE_AS_LSDB (ospf_top),
338 nbr, 0, ospf_db_summary_add);
339#endif /* HAVE_OPAQUE_LSA */
340
341 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
342
343 return 0;
344}
345
346int
347nsm_exchange_done (struct ospf_neighbor *nbr)
348{
349 struct ospf_interface *oi;
350
351 oi = nbr->oi;
352
353 if (ospf_ls_request_isempty (nbr))
354 return NSM_Full;
355
356 /* Cancel dd retransmit timer. */
357 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
358
359 /* Send Link State Request. */
360 ospf_ls_req_send (nbr);
361
362 return NSM_Loading;
363}
364
365int
366nsm_bad_ls_req (struct ospf_neighbor *nbr)
367{
368 /* Clear neighbor. */
369 nsm_reset_nbr (nbr);
370
371 return 0;
372}
373
374int
375nsm_adj_ok (struct ospf_neighbor *nbr)
376{
377 struct ospf_interface *oi;
378 int next_state;
379 int flag = 0;
380
381 oi = nbr->oi;
382 next_state = nbr->state;
383
384 /* These netowork types must be adjacency. */
385 if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
386 oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
387 oi->type == OSPF_IFTYPE_VIRTUALLINK)
388 flag = 1;
389
390 /* Router itself is the DRouter or the BDRouter. */
391 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) ||
392 IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
393 flag = 1;
394
395 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi)) ||
396 IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
397 flag = 1;
398
399 if (nbr->state == NSM_TwoWay && flag == 1)
400 next_state = NSM_ExStart;
401 else if (nbr->state >= NSM_ExStart && flag == 0)
402 next_state = NSM_TwoWay;
403
404 return next_state;
405}
406
407int
408nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
409{
410 /* Clear neighbor. */
411 nsm_reset_nbr (nbr);
412
413 return 0;
414}
415
416int
417nsm_oneway_received (struct ospf_neighbor *nbr)
418{
419 /* Clear neighbor. */
420 nsm_reset_nbr (nbr);
421
422 return 0;
423}
424
425void
426nsm_reset_nbr (struct ospf_neighbor *nbr)
427{
428 /* Clear Database Summary list. */
429 if (!ospf_db_summary_isempty (nbr))
430 ospf_db_summary_clear (nbr);
431
432 /* Clear Link State Request list. */
433 if (!ospf_ls_request_isempty (nbr))
434 ospf_ls_request_delete_all (nbr);
435
436 /* Clear Link State Retransmission list. */
437 if (!ospf_ls_retransmit_isempty (nbr))
438 ospf_ls_retransmit_clear (nbr);
439
440 /* Cancel thread. */
441 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
442 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
443 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
444 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
445
446#ifdef HAVE_OPAQUE_LSA
447 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
448 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
449#endif /* HAVE_OPAQUE_LSA */
450}
451
452int
453nsm_kill_nbr (struct ospf_neighbor *nbr)
454{
455 /* call it here because we cannot call it from ospf_nsm_event */
456 nsm_change_state (nbr, NSM_Down);
457
458 /* Reset neighbor. */
459 nsm_reset_nbr (nbr);
460
461 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
462 {
463 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
464
465 nbr_nbma->nbr = NULL;
466 nbr_nbma->state_change = nbr->state_change;
467
468 nbr->nbr_nbma = NULL;
469
470 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
471 nbr_nbma->v_poll);
472
473 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
474 zlog_info ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
475 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
476 }
477
478 /* Delete neighbor from interface. */
479 ospf_nbr_delete (nbr);
480
481 return 0;
482}
483
484int
485nsm_inactivity_timer (struct ospf_neighbor *nbr)
486{
487 /* Kill neighbor. */
488 nsm_kill_nbr (nbr);
489
490 return 0;
491}
492
493int
494nsm_ll_down (struct ospf_neighbor *nbr)
495{
496 /* Reset neighbor. */
497 /*nsm_reset_nbr (nbr);*/
498
499 /* Kill neighbor. */
500 nsm_kill_nbr (nbr);
501
502 return 0;
503}
504
505/* Neighbor State Machine */
506struct {
507 int (*func) ();
508 int next_state;
509} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
510{
511 {
512 /* DependUpon: dummy state. */
513 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
514 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */
515 { nsm_ignore, NSM_DependUpon }, /* Start */
516 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */
517 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */
518 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */
519 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */
520 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */
521 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */
522 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */
523 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */
524 { nsm_ignore, NSM_DependUpon }, /* KillNbr */
525 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */
526 { nsm_ignore, NSM_DependUpon }, /* LLDown */
527 },
528 {
529 /* Down: */
530 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
531 { nsm_hello_received, NSM_Init }, /* HelloReceived */
532 { nsm_start, NSM_Attempt }, /* Start */
533 { nsm_ignore, NSM_Down }, /* 2-WayReceived */
534 { nsm_ignore, NSM_Down }, /* NegotiationDone */
535 { nsm_ignore, NSM_Down }, /* ExchangeDone */
536 { nsm_ignore, NSM_Down }, /* BadLSReq */
537 { nsm_ignore, NSM_Down }, /* LoadingDone */
538 { nsm_ignore, NSM_Down }, /* AdjOK? */
539 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */
540 { nsm_ignore, NSM_Down }, /* 1-WayReceived */
541 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
542 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
543 { nsm_ll_down, NSM_Down }, /* LLDown */
544 },
545 {
546 /* Attempt: */
547 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
548 { nsm_hello_received, NSM_Init }, /* HelloReceived */
549 { nsm_ignore, NSM_Attempt }, /* Start */
550 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */
551 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */
552 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */
553 { nsm_ignore, NSM_Attempt }, /* BadLSReq */
554 { nsm_ignore, NSM_Attempt }, /* LoadingDone */
555 { nsm_ignore, NSM_Attempt }, /* AdjOK? */
556 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */
557 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */
558 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
559 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
560 { nsm_ll_down, NSM_Down }, /* LLDown */
561 },
562 {
563 /* Init: */
564 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
565 { nsm_hello_received, NSM_Init }, /* HelloReceived */
566 { nsm_ignore, NSM_Init }, /* Start */
567 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
568 { nsm_ignore, NSM_Init }, /* NegotiationDone */
569 { nsm_ignore, NSM_Init }, /* ExchangeDone */
570 { nsm_ignore, NSM_Init }, /* BadLSReq */
571 { nsm_ignore, NSM_Init }, /* LoadingDone */
572 { nsm_ignore, NSM_Init }, /* AdjOK? */
573 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */
574 { nsm_ignore, NSM_Init }, /* 1-WayReceived */
575 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
576 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
577 { nsm_ll_down, NSM_Down }, /* LLDown */
578 },
579 {
580 /* 2-Way: */
581 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
582 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
583 { nsm_ignore, NSM_TwoWay }, /* Start */
584 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */
585 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */
586 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */
587 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */
588 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */
589 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
590 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */
591 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
592 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
593 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
594 { nsm_ll_down, NSM_Down }, /* LLDown */
595 },
596 {
597 /* ExStart: */
598 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
599 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
600 { nsm_ignore, NSM_ExStart }, /* Start */
601 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */
602 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
603 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */
604 { nsm_ignore, NSM_ExStart }, /* BadLSReq */
605 { nsm_ignore, NSM_ExStart }, /* LoadingDone */
606 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
607 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */
608 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
609 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
610 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
611 { nsm_ll_down, NSM_Down }, /* LLDown */
612 },
613 {
614 /* Exchange: */
615 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
616 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
617 { nsm_ignore, NSM_Exchange }, /* Start */
618 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */
619 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */
620 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
621 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
622 { nsm_ignore, NSM_Exchange }, /* LoadingDone */
623 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
624 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
625 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
626 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
627 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
628 { nsm_ll_down, NSM_Down }, /* LLDown */
629 },
630 {
631 /* Loading: */
632 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
633 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
634 { nsm_ignore, NSM_Loading }, /* Start */
635 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */
636 { nsm_ignore, NSM_Loading }, /* NegotiationDone */
637 { nsm_ignore, NSM_Loading }, /* 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 { /* Full: */
648 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
649 { nsm_hello_received, NSM_Full }, /* HelloReceived */
650 { nsm_ignore, NSM_Full }, /* Start */
651 { nsm_ignore, NSM_Full }, /* 2-WayReceived */
652 { nsm_ignore, NSM_Full }, /* NegotiationDone */
653 { nsm_ignore, NSM_Full }, /* ExchangeDone */
654 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
655 { nsm_ignore, NSM_Full }, /* LoadingDone */
656 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
657 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
658 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
659 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
660 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
661 { nsm_ll_down, NSM_Down }, /* LLDown */
662 },
663};
664
665static char *ospf_nsm_event_str[] =
666{
667 "NoEvent",
668 "HelloReceived",
669 "Start",
670 "2-WayReceived",
671 "NegotiationDone",
672 "ExchangeDone",
673 "BadLSReq",
674 "LoadingDone",
675 "AdjOK?",
676 "SeqNumberMismatch",
677 "1-WayReceived",
678 "KillNbr",
679 "InactivityTimer",
680 "LLDown",
681};
682
683void
684nsm_change_state (struct ospf_neighbor *nbr, int state)
685{
686 struct ospf_interface *oi;
687 struct ospf_area *vl_area = NULL;
688 u_char old_state;
689 int x;
690 int force = 1;
691
692 /* Logging change of status. */
693 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
694 zlog_info ("NSM[%s:%s]: State change %s -> %s",
695 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
696 LOOKUP (ospf_nsm_state_msg, nbr->state),
697 LOOKUP (ospf_nsm_state_msg, state));
698
699 /* Preserve old status. */
700 old_state = nbr->state;
701
702 /* Change to new status. */
703 nbr->state = state;
704
705 /* Statistics. */
706 nbr->state_change++;
707
708 oi = nbr->oi;
709
710 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
711 vl_area = ospf_area_lookup_by_area_id (oi->vl_data->vl_area_id);
712
713 /* One of the neighboring routers changes to/from the FULL state. */
714 if ((old_state != NSM_Full && state == NSM_Full) ||
715 (old_state == NSM_Full && state != NSM_Full))
716 {
717 if (state == NSM_Full)
718 {
719 oi->full_nbrs++;
720 oi->area->full_nbrs++;
721
722 ospf_check_abr_status ();
723
724 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
725 if (++vl_area->full_vls == 1)
726 ospf_schedule_abr_task ();
727
728 /* kevinm: refresh any redistributions */
729 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++) {
730 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
731 continue;
732 ospf_external_lsa_refresh_type(x, force);
733 }
734
735 }
736 else
737 {
738 oi->full_nbrs--;
739 oi->area->full_nbrs--;
740
741 ospf_check_abr_status ();
742
743 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
744 if (vl_area->full_vls > 0)
745 if (--vl_area->full_vls == 0)
746 ospf_schedule_abr_task ();
747
748 /* clear neighbor retransmit list */
749 if (!ospf_ls_retransmit_isempty (nbr))
750 ospf_ls_retransmit_clear (nbr);
751 }
752
753 zlog_info ("nsm_change_state(): "
754 "scheduling new router-LSA origination");
755
756 ospf_router_lsa_timer_add (oi->area);
757
758 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
759 {
760 struct ospf_area *vl_area =
761 ospf_area_lookup_by_area_id (oi->vl_data->vl_area_id);
762
763 if (vl_area)
764 ospf_router_lsa_timer_add (vl_area);
765 }
766
767 /* Originate network-LSA. */
768 if (oi->state == ISM_DR)
769 {
770 if (oi->network_lsa_self && oi->full_nbrs == 0)
771 {
772 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
773 ospf_lsa_unlock (oi->network_lsa_self);
774 oi->network_lsa_self = NULL;
775 OSPF_TIMER_OFF (oi->t_network_lsa_self);
776 }
777 else
778 ospf_network_lsa_timer_add (oi);
779 }
780 }
781
782#ifdef HAVE_OPAQUE_LSA
783 ospf_opaque_nsm_change (nbr, old_state);
784#endif /* HAVE_OPAQUE_LSA */
785
786 /* Start DD exchange protocol */
787 if (state == NSM_ExStart)
788 {
789 if (nbr->dd_seqnum == 0)
790 nbr->dd_seqnum = time (NULL);
791 else
792 nbr->dd_seqnum++;
793
794 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
795 ospf_db_desc_send (nbr);
796 }
797
798 /* clear cryptographic sequence number */
799 if (state == NSM_Down)
800 nbr->crypt_seqnum = 0;
801
802 /* Generete NeighborChange ISM event. */
803#ifdef BUGGY_ISM_TRANSITION
804 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
805 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
806 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
807#else /* BUGGY_ISM_TRANSITION */
808 switch (oi->state) {
809 case ISM_DROther:
810 case ISM_Backup:
811 case ISM_DR:
812 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
813 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
814 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
815 break;
816 default:
817 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
818 break;
819 }
820#endif /* BUGGY_ISM_TRANSITION */
821
822 /* Performance hack. Send hello immideately when some neighbor enter
823 Init state. This whay we decrease neighbor discovery time. Gleb.*/
824 if (state == NSM_Init)
825 {
826 OSPF_ISM_TIMER_OFF (oi->t_hello);
827 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1);
828 }
829
830 /* Preserve old status? */
831}
832
833/* Execute NSM event process. */
834int
835ospf_nsm_event (struct thread *thread)
836{
837 int event;
838 int next_state;
839 struct ospf_neighbor *nbr;
840 struct in_addr router_id;
841 int old_state;
842 struct ospf_interface *oi;
843
844 nbr = THREAD_ARG (thread);
845 event = THREAD_VAL (thread);
846 router_id = nbr->router_id;
847
848 old_state = nbr->state;
849 oi = nbr->oi ;
850
851 /* Call function. */
852 next_state = (*(NSM [nbr->state][event].func))(nbr);
853
854 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
855 deleted. */
856 if (event == NSM_KillNbr || event == NSM_InactivityTimer)
857 {
858 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
859 zlog_info ("NSM[%s:%s]: neighbor deleted",
860 IF_NAME (oi), inet_ntoa (router_id));
861
862 /* Timers are canceled in ospf_nbr_free, moreover we cannot call
863 nsm_timer_set here because nbr is freed already!!!*/
864 /*nsm_timer_set (nbr);*/
865
866 return 0;
867 }
868
869 if (! next_state)
870 next_state = NSM [nbr->state][event].next_state;
871
872 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
873 zlog_info ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
874 inet_ntoa (nbr->router_id),
875 LOOKUP (ospf_nsm_state_msg, nbr->state),
876 ospf_nsm_event_str [event]);
877
878 /* If state is changed. */
879 if (next_state != nbr->state)
880 nsm_change_state (nbr, next_state);
881
882 /* Make sure timer is set. */
883 nsm_timer_set (nbr);
884
885 return 0;
886}
887
888/* Check loading state. */
889void
890ospf_check_nbr_loading (struct ospf_neighbor *nbr)
891{
892 if (nbr->state == NSM_Loading)
893 {
894 if (ospf_ls_request_isempty (nbr))
895 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
896 else if (nbr->ls_req_last == NULL)
897 ospf_ls_req_event (nbr);
898 }
899}