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"
51 void nsm_reset_nbr (struct ospf_neighbor
*);
54 /* OSPF NSM Timer functions. */
56 ospf_inactivity_timer (struct thread
*thread
)
58 struct ospf_neighbor
*nbr
;
60 nbr
= THREAD_ARG (thread
);
61 nbr
->t_inactivity
= NULL
;
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
));
67 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_InactivityTimer
);
73 ospf_db_desc_timer (struct thread
*thread
)
75 struct ospf_interface
*oi
;
76 struct ospf_neighbor
*nbr
;
78 nbr
= THREAD_ARG (thread
);
79 nbr
->t_db_desc
= NULL
;
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
));
87 /* resent last send DD packet. */
88 assert (nbr
->last_send
);
89 ospf_db_desc_resend (nbr
);
91 /* DD Retransmit timer set. */
92 OSPF_NSM_TIMER_ON (nbr
->t_db_desc
, ospf_db_desc_timer
, nbr
->v_db_desc
);
97 /* Hook function called after ospf NSM event is occured. */
100 nsm_timer_set (struct ospf_neighbor
*nbr
)
105 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
106 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
109 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
110 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
113 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
114 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
117 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
118 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
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
);
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
);
130 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
133 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
136 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
142 /* OSPF NSM functions. */
144 nsm_ignore (struct ospf_neighbor
*nbr
)
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
));
154 nsm_hello_received (struct ospf_neighbor
*nbr
)
156 /* Start or Restart Inactivity Timer. */
157 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
159 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
162 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
)
163 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
169 nsm_start (struct ospf_neighbor
*nbr
)
175 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
177 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
179 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
186 nsm_twoway_received (struct ospf_neighbor
*nbr
)
188 struct ospf_interface
*oi
;
189 int next_state
= NSM_TwoWay
;
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
;
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
;
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
;
213 ospf_db_summary_count (struct ospf_neighbor
*nbr
)
215 return ospf_lsdb_count_all (&nbr
->db_sum
);
219 ospf_db_summary_isempty (struct ospf_neighbor
*nbr
)
221 return ospf_lsdb_isempty (&nbr
->db_sum
);
225 ospf_db_summary_add (struct ospf_lsa
*lsa
, void *v
, int i
)
227 struct ospf_neighbor
*nbr
= (struct ospf_neighbor
*) v
;
232 #ifdef HAVE_OPAQUE_LSA
233 switch (lsa
->data
->type
)
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
)
240 case OSPF_OPAQUE_AREA_LSA
:
242 * It is assured by the caller function "nsm_negotiation_done()"
243 * that every given LSA belongs to the same area with "nbr".
246 case OSPF_OPAQUE_AS_LSA
:
250 #endif /* HAVE_OPAQUE_LSA */
253 /* Stay away from any Local Translated Type-7 LSAs */
254 if (CHECK_FLAG (lsa
->flags
, OSPF_LSA_LOCAL_XLT
))
256 #endif /* HAVE_NSSA */
258 if (IS_LSA_MAXAGE (lsa
))
259 ospf_ls_retransmit_add (nbr
, lsa
);
261 ospf_lsdb_add (&nbr
->db_sum
, lsa
);
267 ospf_db_summary_clear (struct ospf_neighbor
*nbr
)
269 struct ospf_lsdb
*lsdb
;
273 for (i
= OSPF_MIN_LSA
; i
< OSPF_MAX_LSA
; i
++)
275 struct route_table
*table
= lsdb
->type
[i
].db
;
276 struct route_node
*rn
;
278 for (rn
= route_top (table
); rn
; rn
= route_next (rn
))
280 ospf_lsdb_delete (&nbr
->db_sum
, rn
->info
);
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
292 opaque LSAs contained in the global structure.
294 AS-external and type-11 opaque LSAs are omitted from a virtual
296 neighbor's Database summary list. AS-external and type-11 opaque
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 */
309 nsm_negotiation_done (struct ospf_neighbor
*nbr
)
311 struct ospf_area
*area
;
313 area
= nbr
->oi
->area
;
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
);
320 #ifdef HAVE_OPAQUE_LSA
321 /* Process only if the neighbor is opaque capable. */
322 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
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
);
327 #endif /* HAVE_OPAQUE_LSA */
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
);
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 */
341 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
347 nsm_exchange_done (struct ospf_neighbor
*nbr
)
349 struct ospf_interface
*oi
;
353 if (ospf_ls_request_isempty (nbr
))
356 /* Cancel dd retransmit timer. */
357 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
359 /* Send Link State Request. */
360 ospf_ls_req_send (nbr
);
366 nsm_bad_ls_req (struct ospf_neighbor
*nbr
)
368 /* Clear neighbor. */
375 nsm_adj_ok (struct ospf_neighbor
*nbr
)
377 struct ospf_interface
*oi
;
382 next_state
= nbr
->state
;
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
)
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
)))
395 if (IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &DR (oi
)) ||
396 IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &BDR (oi
)))
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
;
408 nsm_seq_number_mismatch (struct ospf_neighbor
*nbr
)
410 /* Clear neighbor. */
417 nsm_oneway_received (struct ospf_neighbor
*nbr
)
419 /* Clear neighbor. */
426 nsm_reset_nbr (struct ospf_neighbor
*nbr
)
428 /* Clear Database Summary list. */
429 if (!ospf_db_summary_isempty (nbr
))
430 ospf_db_summary_clear (nbr
);
432 /* Clear Link State Request list. */
433 if (!ospf_ls_request_isempty (nbr
))
434 ospf_ls_request_delete_all (nbr
);
436 /* Clear Link State Retransmission list. */
437 if (!ospf_ls_retransmit_isempty (nbr
))
438 ospf_ls_retransmit_clear (nbr
);
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
);
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 */
453 nsm_kill_nbr (struct ospf_neighbor
*nbr
)
455 /* call it here because we cannot call it from ospf_nsm_event */
456 nsm_change_state (nbr
, NSM_Down
);
458 /* Reset neighbor. */
461 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
!= NULL
)
463 struct ospf_nbr_nbma
*nbr_nbma
= nbr
->nbr_nbma
;
465 nbr_nbma
->nbr
= NULL
;
466 nbr_nbma
->state_change
= nbr
->state_change
;
468 nbr
->nbr_nbma
= NULL
;
470 OSPF_POLL_TIMER_ON (nbr_nbma
->t_poll
, ospf_poll_timer
,
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
));
478 /* Delete neighbor from interface. */
479 ospf_nbr_delete (nbr
);
485 nsm_inactivity_timer (struct ospf_neighbor
*nbr
)
494 nsm_ll_down (struct ospf_neighbor
*nbr
)
496 /* Reset neighbor. */
497 /*nsm_reset_nbr (nbr);*/
505 /* Neighbor State Machine */
509 } NSM
[OSPF_NSM_STATE_MAX
][OSPF_NSM_EVENT_MAX
] =
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
665 static char *ospf_nsm_event_str
[] =
684 nsm_change_state (struct ospf_neighbor
*nbr
, int state
)
686 struct ospf_interface
*oi
;
687 struct ospf_area
*vl_area
= NULL
;
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
));
699 /* Preserve old status. */
700 old_state
= nbr
->state
;
702 /* Change to new status. */
710 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
711 vl_area
= ospf_area_lookup_by_area_id (oi
->vl_data
->vl_area_id
);
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
))
717 if (state
== NSM_Full
)
720 oi
->area
->full_nbrs
++;
722 ospf_check_abr_status ();
724 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
725 if (++vl_area
->full_vls
== 1)
726 ospf_schedule_abr_task ();
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
)
732 ospf_external_lsa_refresh_type(x
, force
);
739 oi
->area
->full_nbrs
--;
741 ospf_check_abr_status ();
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 ();
748 /* clear neighbor retransmit list */
749 if (!ospf_ls_retransmit_isempty (nbr
))
750 ospf_ls_retransmit_clear (nbr
);
753 zlog_info ("nsm_change_state(): "
754 "scheduling new router-LSA origination");
756 ospf_router_lsa_timer_add (oi
->area
);
758 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
760 struct ospf_area
*vl_area
=
761 ospf_area_lookup_by_area_id (oi
->vl_data
->vl_area_id
);
764 ospf_router_lsa_timer_add (vl_area
);
767 /* Originate network-LSA. */
768 if (oi
->state
== ISM_DR
)
770 if (oi
->network_lsa_self
&& oi
->full_nbrs
== 0)
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
);
778 ospf_network_lsa_timer_add (oi
);
782 #ifdef HAVE_OPAQUE_LSA
783 ospf_opaque_nsm_change (nbr
, old_state
);
784 #endif /* HAVE_OPAQUE_LSA */
786 /* Start DD exchange protocol */
787 if (state
== NSM_ExStart
)
789 if (nbr
->dd_seqnum
== 0)
790 nbr
->dd_seqnum
= time (NULL
);
794 nbr
->dd_flags
= OSPF_DD_FLAG_I
|OSPF_DD_FLAG_M
|OSPF_DD_FLAG_MS
;
795 ospf_db_desc_send (nbr
);
798 /* clear cryptographic sequence number */
799 if (state
== NSM_Down
)
800 nbr
->crypt_seqnum
= 0;
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 */
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
);
817 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
820 #endif /* BUGGY_ISM_TRANSITION */
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
)
826 OSPF_ISM_TIMER_OFF (oi
->t_hello
);
827 OSPF_ISM_TIMER_ON (oi
->t_hello
, ospf_hello_timer
, 1);
830 /* Preserve old status? */
833 /* Execute NSM event process. */
835 ospf_nsm_event (struct thread
*thread
)
839 struct ospf_neighbor
*nbr
;
840 struct in_addr router_id
;
842 struct ospf_interface
*oi
;
844 nbr
= THREAD_ARG (thread
);
845 event
= THREAD_VAL (thread
);
846 router_id
= nbr
->router_id
;
848 old_state
= nbr
->state
;
852 next_state
= (*(NSM
[nbr
->state
][event
].func
))(nbr
);
854 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
856 if (event
== NSM_KillNbr
|| event
== NSM_InactivityTimer
)
858 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
859 zlog_info ("NSM[%s:%s]: neighbor deleted",
860 IF_NAME (oi
), inet_ntoa (router_id
));
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);*/
870 next_state
= NSM
[nbr
->state
][event
].next_state
;
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
]);
878 /* If state is changed. */
879 if (next_state
!= nbr
->state
)
880 nsm_change_state (nbr
, next_state
);
882 /* Make sure timer is set. */
888 /* Check loading state. */
890 ospf_check_nbr_loading (struct ospf_neighbor
*nbr
)
892 if (nbr
->state
== NSM_Loading
)
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
);