2 * OSPF version 2 Neighbor State Machine
3 * From RFC2328 [OSPF Version 2]
4 * Copyright (C) 1999, 2000 Toshiaki Takada
6 * This file is part of GNU Zebra.
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
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.
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
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 #include "ospfd/ospf_snmp.h"
52 void nsm_reset_nbr (struct ospf_neighbor
*);
55 /* OSPF NSM Timer functions. */
57 ospf_inactivity_timer (struct thread
*thread
)
59 struct ospf_neighbor
*nbr
;
61 nbr
= THREAD_ARG (thread
);
62 nbr
->t_inactivity
= NULL
;
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
));
68 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_InactivityTimer
);
74 ospf_db_desc_timer (struct thread
*thread
)
76 struct ospf_interface
*oi
;
77 struct ospf_neighbor
*nbr
;
79 nbr
= THREAD_ARG (thread
);
80 nbr
->t_db_desc
= NULL
;
84 if (IS_DEBUG_OSPF (nsm
, NSM_TIMERS
))
85 zlog (NULL
, LOG_DEBUG
, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
86 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->src
));
88 /* resent last send DD packet. */
89 assert (nbr
->last_send
);
90 ospf_db_desc_resend (nbr
);
92 /* DD Retransmit timer set. */
93 OSPF_NSM_TIMER_ON (nbr
->t_db_desc
, ospf_db_desc_timer
, nbr
->v_db_desc
);
98 /* Hook function called after ospf NSM event is occured. */
101 nsm_timer_set (struct ospf_neighbor
*nbr
)
106 /* This is here for documentation purposes, don't actually get here
107 * as Down neighbours are deleted typically, see nsm_kill_nbr
109 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
113 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
114 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
115 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
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
);
120 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
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
);
128 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
131 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
134 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
139 /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
140 * the given neighbour
143 nsm_should_adj (struct ospf_neighbor
*nbr
)
145 struct ospf_interface
*oi
;
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
)
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
)))
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
)))
168 /* OSPF NSM functions. */
170 nsm_ignore (struct ospf_neighbor
*nbr
)
172 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
173 zlog (NULL
, LOG_DEBUG
, "NSM[%s:%s]: nsm_ignore called",
174 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
));
180 nsm_hello_received (struct ospf_neighbor
*nbr
)
182 /* Start or Restart Inactivity Timer. */
183 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
185 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
188 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
)
189 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
195 nsm_start (struct ospf_neighbor
*nbr
)
201 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
203 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
205 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
212 nsm_twoway_received (struct ospf_neighbor
*nbr
)
214 int next_state
= NSM_TwoWay
;
216 if (nsm_should_adj (nbr
))
217 next_state
= NSM_ExStart
;
223 ospf_db_summary_count (struct ospf_neighbor
*nbr
)
225 return ospf_lsdb_count_all (&nbr
->db_sum
);
229 ospf_db_summary_isempty (struct ospf_neighbor
*nbr
)
231 return ospf_lsdb_isempty (&nbr
->db_sum
);
235 ospf_db_summary_add (struct ospf_neighbor
*nbr
, struct ospf_lsa
*lsa
)
237 #ifdef HAVE_OPAQUE_LSA
238 switch (lsa
->data
->type
)
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
)
245 case OSPF_OPAQUE_AREA_LSA
:
247 * It is assured by the caller function "nsm_negotiation_done()"
248 * that every given LSA belongs to the same area with "nbr".
251 case OSPF_OPAQUE_AS_LSA
:
255 #endif /* HAVE_OPAQUE_LSA */
257 /* Stay away from any Local Translated Type-7 LSAs */
258 if (CHECK_FLAG (lsa
->flags
, OSPF_LSA_LOCAL_XLT
))
261 if (IS_LSA_MAXAGE (lsa
))
262 ospf_ls_retransmit_add (nbr
, lsa
);
264 ospf_lsdb_add (&nbr
->db_sum
, lsa
);
270 ospf_db_summary_clear (struct ospf_neighbor
*nbr
)
272 struct ospf_lsdb
*lsdb
;
276 for (i
= OSPF_MIN_LSA
; i
< OSPF_MAX_LSA
; i
++)
278 struct route_table
*table
= lsdb
->type
[i
].db
;
279 struct route_node
*rn
;
281 for (rn
= route_top (table
); rn
; rn
= route_next (rn
))
283 ospf_lsdb_delete (&nbr
->db_sum
, rn
->info
);
289 /* The area link state database consists of the router-LSAs,
290 network-LSAs and summary-LSAs contained in the area structure,
291 along with the AS-external-LSAs contained in the global structure.
292 AS-external-LSAs are omitted from a virtual neighbor's Database
293 summary list. AS-external-LSAs are omitted from the Database
294 summary list if the area has been configured as a stub. */
296 nsm_negotiation_done (struct ospf_neighbor
*nbr
)
298 struct ospf_area
*area
= nbr
->oi
->area
;
299 struct ospf_lsa
*lsa
;
300 struct route_node
*rn
;
302 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
);
311 #ifdef HAVE_OPAQUE_LSA
312 /* Process only if the neighbor is opaque capable. */
313 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
315 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
);
320 #endif /* HAVE_OPAQUE_LSA */
322 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_NP
))
324 LSDB_LOOP (NSSA_LSDB (area
), rn
, lsa
)
325 ospf_db_summary_add (nbr
, lsa
);
328 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
);
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 LSDB_LOOP (OPAQUE_AS_LSDB (nbr
->oi
->ospf
), rn
, lsa
)
338 ospf_db_summary_add (nbr
, lsa
);
339 #endif /* HAVE_OPAQUE_LSA */
345 nsm_exchange_done (struct ospf_neighbor
*nbr
)
347 if (ospf_ls_request_isempty (nbr
))
350 /* Cancel dd retransmit timer. */
351 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
353 /* Send Link State Request. */
354 ospf_ls_req_send (nbr
);
360 nsm_bad_ls_req (struct ospf_neighbor
*nbr
)
362 /* Clear neighbor. */
369 nsm_adj_ok (struct ospf_neighbor
*nbr
)
371 int next_state
= nbr
->state
;
372 int adj
= nsm_should_adj (nbr
);
374 if (nbr
->state
== NSM_TwoWay
&& adj
== 1)
375 next_state
= NSM_ExStart
;
376 else if (nbr
->state
>= NSM_ExStart
&& adj
== 0)
377 next_state
= NSM_TwoWay
;
383 nsm_seq_number_mismatch (struct ospf_neighbor
*nbr
)
385 /* Clear neighbor. */
392 nsm_oneway_received (struct ospf_neighbor
*nbr
)
394 /* Clear neighbor. */
401 nsm_reset_nbr (struct ospf_neighbor
*nbr
)
403 /* Clear Database Summary list. */
404 if (!ospf_db_summary_isempty (nbr
))
405 ospf_db_summary_clear (nbr
);
407 /* Clear Link State Request list. */
408 if (!ospf_ls_request_isempty (nbr
))
409 ospf_ls_request_delete_all (nbr
);
411 /* Clear Link State Retransmission list. */
412 if (!ospf_ls_retransmit_isempty (nbr
))
413 ospf_ls_retransmit_clear (nbr
);
416 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
417 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
418 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
419 OSPF_NSM_TIMER_OFF (nbr
->t_hello_reply
);
421 #ifdef HAVE_OPAQUE_LSA
422 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
423 UNSET_FLAG (nbr
->options
, OSPF_OPTION_O
);
424 #endif /* HAVE_OPAQUE_LSA */
428 nsm_kill_nbr (struct ospf_neighbor
*nbr
)
430 /* call it here because we cannot call it from ospf_nsm_event */
431 nsm_change_state (nbr
, NSM_Down
);
433 /* killing nbr_self is invalid */
434 assert (nbr
!= nbr
->oi
->nbr_self
);
435 if (nbr
== nbr
->oi
->nbr_self
)
438 /* Reset neighbor. */
441 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
!= NULL
)
443 struct ospf_nbr_nbma
*nbr_nbma
= nbr
->nbr_nbma
;
445 nbr_nbma
->nbr
= NULL
;
446 nbr_nbma
->state_change
= nbr
->state_change
;
448 nbr
->nbr_nbma
= NULL
;
450 OSPF_POLL_TIMER_ON (nbr_nbma
->t_poll
, ospf_poll_timer
,
453 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
454 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
455 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->address
.u
.prefix4
));
458 /* Delete neighbor from interface. */
459 ospf_nbr_delete (nbr
);
465 nsm_inactivity_timer (struct ospf_neighbor
*nbr
)
474 nsm_ll_down (struct ospf_neighbor
*nbr
)
476 /* Reset neighbor. */
477 /*nsm_reset_nbr (nbr);*/
485 /* Neighbor State Machine */
487 int (*func
) (struct ospf_neighbor
*);
489 } NSM
[OSPF_NSM_STATE_MAX
][OSPF_NSM_EVENT_MAX
] =
492 /* DependUpon: dummy state. */
493 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
494 { nsm_ignore
, NSM_DependUpon
}, /* HelloReceived */
495 { nsm_ignore
, NSM_DependUpon
}, /* Start */
496 { nsm_ignore
, NSM_DependUpon
}, /* 2-WayReceived */
497 { nsm_ignore
, NSM_DependUpon
}, /* NegotiationDone */
498 { nsm_ignore
, NSM_DependUpon
}, /* ExchangeDone */
499 { nsm_ignore
, NSM_DependUpon
}, /* BadLSReq */
500 { nsm_ignore
, NSM_DependUpon
}, /* LoadingDone */
501 { nsm_ignore
, NSM_DependUpon
}, /* AdjOK? */
502 { nsm_ignore
, NSM_DependUpon
}, /* SeqNumberMismatch */
503 { nsm_ignore
, NSM_DependUpon
}, /* 1-WayReceived */
504 { nsm_ignore
, NSM_DependUpon
}, /* KillNbr */
505 { nsm_ignore
, NSM_DependUpon
}, /* InactivityTimer */
506 { nsm_ignore
, NSM_DependUpon
}, /* LLDown */
510 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
511 { nsm_hello_received
, NSM_Init
}, /* HelloReceived */
512 { nsm_start
, NSM_Attempt
}, /* Start */
513 { nsm_ignore
, NSM_Down
}, /* 2-WayReceived */
514 { nsm_ignore
, NSM_Down
}, /* NegotiationDone */
515 { nsm_ignore
, NSM_Down
}, /* ExchangeDone */
516 { nsm_ignore
, NSM_Down
}, /* BadLSReq */
517 { nsm_ignore
, NSM_Down
}, /* LoadingDone */
518 { nsm_ignore
, NSM_Down
}, /* AdjOK? */
519 { nsm_ignore
, NSM_Down
}, /* SeqNumberMismatch */
520 { nsm_ignore
, NSM_Down
}, /* 1-WayReceived */
521 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
522 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
523 { nsm_ll_down
, NSM_Down
}, /* LLDown */
527 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
528 { nsm_hello_received
, NSM_Init
}, /* HelloReceived */
529 { nsm_ignore
, NSM_Attempt
}, /* Start */
530 { nsm_ignore
, NSM_Attempt
}, /* 2-WayReceived */
531 { nsm_ignore
, NSM_Attempt
}, /* NegotiationDone */
532 { nsm_ignore
, NSM_Attempt
}, /* ExchangeDone */
533 { nsm_ignore
, NSM_Attempt
}, /* BadLSReq */
534 { nsm_ignore
, NSM_Attempt
}, /* LoadingDone */
535 { nsm_ignore
, NSM_Attempt
}, /* AdjOK? */
536 { nsm_ignore
, NSM_Attempt
}, /* SeqNumberMismatch */
537 { nsm_ignore
, NSM_Attempt
}, /* 1-WayReceived */
538 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
539 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
540 { nsm_ll_down
, NSM_Down
}, /* LLDown */
544 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
545 { nsm_hello_received
, NSM_Init
}, /* HelloReceived */
546 { nsm_ignore
, NSM_Init
}, /* Start */
547 { nsm_twoway_received
, NSM_DependUpon
}, /* 2-WayReceived */
548 { nsm_ignore
, NSM_Init
}, /* NegotiationDone */
549 { nsm_ignore
, NSM_Init
}, /* ExchangeDone */
550 { nsm_ignore
, NSM_Init
}, /* BadLSReq */
551 { nsm_ignore
, NSM_Init
}, /* LoadingDone */
552 { nsm_ignore
, NSM_Init
}, /* AdjOK? */
553 { nsm_ignore
, NSM_Init
}, /* SeqNumberMismatch */
554 { nsm_ignore
, NSM_Init
}, /* 1-WayReceived */
555 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
556 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
557 { nsm_ll_down
, NSM_Down
}, /* LLDown */
561 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
562 { nsm_hello_received
, NSM_TwoWay
}, /* HelloReceived */
563 { nsm_ignore
, NSM_TwoWay
}, /* Start */
564 { nsm_ignore
, NSM_TwoWay
}, /* 2-WayReceived */
565 { nsm_ignore
, NSM_TwoWay
}, /* NegotiationDone */
566 { nsm_ignore
, NSM_TwoWay
}, /* ExchangeDone */
567 { nsm_ignore
, NSM_TwoWay
}, /* BadLSReq */
568 { nsm_ignore
, NSM_TwoWay
}, /* LoadingDone */
569 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
570 { nsm_ignore
, NSM_TwoWay
}, /* SeqNumberMismatch */
571 { nsm_oneway_received
, NSM_Init
}, /* 1-WayReceived */
572 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
573 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
574 { nsm_ll_down
, NSM_Down
}, /* LLDown */
578 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
579 { nsm_hello_received
, NSM_ExStart
}, /* HelloReceived */
580 { nsm_ignore
, NSM_ExStart
}, /* Start */
581 { nsm_ignore
, NSM_ExStart
}, /* 2-WayReceived */
582 { nsm_negotiation_done
, NSM_Exchange
}, /* NegotiationDone */
583 { nsm_ignore
, NSM_ExStart
}, /* ExchangeDone */
584 { nsm_ignore
, NSM_ExStart
}, /* BadLSReq */
585 { nsm_ignore
, NSM_ExStart
}, /* LoadingDone */
586 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
587 { nsm_ignore
, NSM_ExStart
}, /* SeqNumberMismatch */
588 { nsm_oneway_received
, NSM_Init
}, /* 1-WayReceived */
589 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
590 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
591 { nsm_ll_down
, NSM_Down
}, /* LLDown */
595 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
596 { nsm_hello_received
, NSM_Exchange
}, /* HelloReceived */
597 { nsm_ignore
, NSM_Exchange
}, /* Start */
598 { nsm_ignore
, NSM_Exchange
}, /* 2-WayReceived */
599 { nsm_ignore
, NSM_Exchange
}, /* NegotiationDone */
600 { nsm_exchange_done
, NSM_DependUpon
}, /* ExchangeDone */
601 { nsm_bad_ls_req
, NSM_ExStart
}, /* BadLSReq */
602 { nsm_ignore
, NSM_Exchange
}, /* LoadingDone */
603 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
604 { nsm_seq_number_mismatch
, NSM_ExStart
}, /* SeqNumberMismatch */
605 { nsm_oneway_received
, NSM_Init
}, /* 1-WayReceived */
606 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
607 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
608 { nsm_ll_down
, NSM_Down
}, /* LLDown */
612 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
613 { nsm_hello_received
, NSM_Loading
}, /* HelloReceived */
614 { nsm_ignore
, NSM_Loading
}, /* Start */
615 { nsm_ignore
, NSM_Loading
}, /* 2-WayReceived */
616 { nsm_ignore
, NSM_Loading
}, /* NegotiationDone */
617 { nsm_ignore
, NSM_Loading
}, /* ExchangeDone */
618 { nsm_bad_ls_req
, NSM_ExStart
}, /* BadLSReq */
619 { nsm_ignore
, NSM_Full
}, /* LoadingDone */
620 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
621 { nsm_seq_number_mismatch
, NSM_ExStart
}, /* SeqNumberMismatch */
622 { nsm_oneway_received
, NSM_Init
}, /* 1-WayReceived */
623 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
624 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
625 { nsm_ll_down
, NSM_Down
}, /* LLDown */
628 { nsm_ignore
, NSM_DependUpon
}, /* NoEvent */
629 { nsm_hello_received
, NSM_Full
}, /* HelloReceived */
630 { nsm_ignore
, NSM_Full
}, /* Start */
631 { nsm_ignore
, NSM_Full
}, /* 2-WayReceived */
632 { nsm_ignore
, NSM_Full
}, /* NegotiationDone */
633 { nsm_ignore
, NSM_Full
}, /* ExchangeDone */
634 { nsm_bad_ls_req
, NSM_ExStart
}, /* BadLSReq */
635 { nsm_ignore
, NSM_Full
}, /* LoadingDone */
636 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
637 { nsm_seq_number_mismatch
, NSM_ExStart
}, /* SeqNumberMismatch */
638 { nsm_oneway_received
, NSM_Init
}, /* 1-WayReceived */
639 { nsm_kill_nbr
, NSM_Down
}, /* KillNbr */
640 { nsm_inactivity_timer
, NSM_Down
}, /* InactivityTimer */
641 { nsm_ll_down
, NSM_Down
}, /* LLDown */
645 const static char *ospf_nsm_event_str
[] =
664 nsm_change_state (struct ospf_neighbor
*nbr
, int state
)
666 struct ospf_interface
*oi
= nbr
->oi
;
667 struct ospf_area
*vl_area
= NULL
;
672 /* Logging change of status. */
673 if (IS_DEBUG_OSPF (nsm
, NSM_STATUS
))
674 zlog_debug ("NSM[%s:%s]: State change %s -> %s",
675 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
),
676 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
677 LOOKUP (ospf_nsm_state_msg
, state
));
679 /* Preserve old status. */
680 old_state
= nbr
->state
;
682 /* Change to new status. */
688 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
689 vl_area
= ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
691 /* Optionally notify about adjacency changes */
692 if (CHECK_FLAG(oi
->ospf
->config
, OSPF_LOG_ADJACENCY_CHANGES
) &&
693 (old_state
!= state
) &&
694 (CHECK_FLAG(oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
) ||
695 (state
== NSM_Full
) || (state
< old_state
)))
696 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s",
697 inet_ntoa (nbr
->router_id
), IF_NAME (nbr
->oi
),
698 LOOKUP (ospf_nsm_state_msg
, old_state
),
699 LOOKUP (ospf_nsm_state_msg
, state
));
702 /* Terminal state or regression */
703 if ((state
== NSM_Full
) || (state
== NSM_TwoWay
) || (state
< old_state
))
705 /* ospfVirtNbrStateChange */
706 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
707 ospfTrapVirtNbrStateChange(nbr
);
708 /* ospfNbrStateChange trap */
710 /* To/From FULL, only managed by DR */
711 if (((state
!= NSM_Full
) && (old_state
!= NSM_Full
)) ||
712 (oi
->state
== ISM_DR
))
713 ospfTrapNbrStateChange(nbr
);
717 /* One of the neighboring routers changes to/from the FULL state. */
718 if ((old_state
!= NSM_Full
&& state
== NSM_Full
) ||
719 (old_state
== NSM_Full
&& state
!= NSM_Full
))
721 if (state
== NSM_Full
)
724 oi
->area
->full_nbrs
++;
726 ospf_check_abr_status (oi
->ospf
);
728 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
729 if (++vl_area
->full_vls
== 1)
730 ospf_schedule_abr_task (oi
->ospf
);
732 /* kevinm: refresh any redistributions */
733 for (x
= ZEBRA_ROUTE_SYSTEM
; x
< ZEBRA_ROUTE_MAX
; x
++)
735 if (x
== ZEBRA_ROUTE_OSPF
|| x
== ZEBRA_ROUTE_OSPF6
)
737 ospf_external_lsa_refresh_type (oi
->ospf
, x
, force
);
743 oi
->area
->full_nbrs
--;
745 ospf_check_abr_status (oi
->ospf
);
747 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
748 if (vl_area
->full_vls
> 0)
749 if (--vl_area
->full_vls
== 0)
750 ospf_schedule_abr_task (oi
->ospf
);
752 /* clear neighbor retransmit list */
753 if (!ospf_ls_retransmit_isempty (nbr
))
754 ospf_ls_retransmit_clear (nbr
);
757 zlog_info ("nsm_change_state(%s, %s -> %s): "
758 "scheduling new router-LSA origination",
759 inet_ntoa (nbr
->router_id
),
760 LOOKUP(ospf_nsm_state_msg
, old_state
),
761 LOOKUP(ospf_nsm_state_msg
, state
));
763 ospf_router_lsa_timer_add (oi
->area
);
765 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
767 struct ospf_area
*vl_area
=
768 ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
771 ospf_router_lsa_timer_add (vl_area
);
774 /* Originate network-LSA. */
775 if (oi
->state
== ISM_DR
)
777 if (oi
->network_lsa_self
&& oi
->full_nbrs
== 0)
779 ospf_lsa_flush_area (oi
->network_lsa_self
, oi
->area
);
780 ospf_lsa_unlock (oi
->network_lsa_self
);
781 oi
->network_lsa_self
= NULL
;
782 OSPF_TIMER_OFF (oi
->t_network_lsa_self
);
785 ospf_network_lsa_timer_add (oi
);
789 #ifdef HAVE_OPAQUE_LSA
790 ospf_opaque_nsm_change (nbr
, old_state
);
791 #endif /* HAVE_OPAQUE_LSA */
793 /* Start DD exchange protocol */
794 if (state
== NSM_ExStart
)
796 if (nbr
->dd_seqnum
== 0)
797 nbr
->dd_seqnum
= time (NULL
);
801 nbr
->dd_flags
= OSPF_DD_FLAG_I
|OSPF_DD_FLAG_M
|OSPF_DD_FLAG_MS
;
802 ospf_db_desc_send (nbr
);
805 /* clear cryptographic sequence number */
806 if (state
== NSM_Down
)
807 nbr
->crypt_seqnum
= 0;
809 /* Generete NeighborChange ISM event. */
810 #ifdef BUGGY_ISM_TRANSITION
811 if ((old_state
< NSM_TwoWay
&& state
>= NSM_TwoWay
) ||
812 (old_state
>= NSM_TwoWay
&& state
< NSM_TwoWay
))
813 OSPF_ISM_EVENT_EXECUTE (oi
, ISM_NeighborChange
);
814 #else /* BUGGY_ISM_TRANSITION */
819 if ((old_state
< NSM_TwoWay
&& state
>= NSM_TwoWay
) ||
820 (old_state
>= NSM_TwoWay
&& state
< NSM_TwoWay
))
821 OSPF_ISM_EVENT_EXECUTE (oi
, ISM_NeighborChange
);
824 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
827 #endif /* BUGGY_ISM_TRANSITION */
829 /* Performance hack. Send hello immideately when some neighbor enter
830 Init state. This whay we decrease neighbor discovery time. Gleb.*/
831 if (state
== NSM_Init
)
833 OSPF_ISM_TIMER_OFF (oi
->t_hello
);
834 OSPF_ISM_TIMER_MSEC_ON (oi
->t_hello
, ospf_hello_timer
, 1);
837 /* Preserve old status? */
840 /* Execute NSM event process. */
842 ospf_nsm_event (struct thread
*thread
)
846 struct ospf_neighbor
*nbr
;
847 struct in_addr router_id
;
849 struct ospf_interface
*oi
;
851 nbr
= THREAD_ARG (thread
);
852 event
= THREAD_VAL (thread
);
853 router_id
= nbr
->router_id
;
855 old_state
= nbr
->state
;
859 next_state
= (*(NSM
[nbr
->state
][event
].func
))(nbr
);
861 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
863 if (event
== NSM_KillNbr
|| event
== NSM_InactivityTimer
)
865 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
866 zlog_debug ("NSM[%s:%s]: neighbor deleted",
867 IF_NAME (oi
), inet_ntoa (router_id
));
869 /* Timers are canceled in ospf_nbr_free, moreover we cannot call
870 nsm_timer_set here because nbr is freed already!!!*/
871 /*nsm_timer_set (nbr);*/
877 next_state
= NSM
[nbr
->state
][event
].next_state
;
878 else if (NSM
[nbr
->state
][event
].next_state
!= NSM_DependUpon
)
880 /* There's a mismatch between the FSM tables and what an FSM
881 * action/state-change function returned. State changes which
882 * do not have conditional/DependUpon next-states should not
883 * try set next_state.
885 zlog_warn ("NSM[%s:%s]: %s (%s): "
886 "Warning: action tried to change next_state to %s",
887 IF_NAME (oi
), inet_ntoa (nbr
->router_id
),
888 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
889 ospf_nsm_event_str
[event
],
890 LOOKUP (ospf_nsm_state_msg
, next_state
));
892 next_state
= NSM
[nbr
->state
][event
].next_state
;
895 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
896 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (oi
),
897 inet_ntoa (nbr
->router_id
),
898 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
899 ospf_nsm_event_str
[event
]);
901 /* If state is changed. */
902 if (next_state
!= nbr
->state
)
903 nsm_change_state (nbr
, next_state
);
905 /* Make sure timer is set. */
911 /* Check loading state. */
913 ospf_check_nbr_loading (struct ospf_neighbor
*nbr
)
915 if (nbr
->state
== NSM_Loading
)
917 if (ospf_ls_request_isempty (nbr
))
918 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_LoadingDone
);
919 else if (nbr
->ls_req_last
== NULL
)
920 ospf_ls_req_event (nbr
);