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"
51 #include "ospfd/ospf_bfd.h"
53 static void nsm_clear_adj (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_neighbor
*nbr
;
78 nbr
= THREAD_ARG (thread
);
79 nbr
->t_db_desc
= NULL
;
81 if (IS_DEBUG_OSPF (nsm
, NSM_TIMERS
))
82 zlog (NULL
, LOG_DEBUG
, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
83 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->src
));
85 /* resent last send DD packet. */
86 assert (nbr
->last_send
);
87 ospf_db_desc_resend (nbr
);
89 /* DD Retransmit timer set. */
90 OSPF_NSM_TIMER_ON (nbr
->t_db_desc
, ospf_db_desc_timer
, nbr
->v_db_desc
);
95 /* Hook function called after ospf NSM event is occured.
97 * Set/clear any timers whose condition is implicit to the neighbour
98 * state. There may be other timers which are set/unset according to other
101 * We rely on this function to properly clear timers in lower states,
102 * particularly before deleting a neighbour.
105 nsm_timer_set (struct ospf_neighbor
*nbr
)
111 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
112 OSPF_NSM_TIMER_OFF (nbr
->t_hello_reply
);
116 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
117 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
118 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
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 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
126 OSPF_NSM_TIMER_ON (nbr
->t_ls_upd
, ospf_ls_upd_timer
, nbr
->v_ls_upd
);
127 if (!IS_SET_DD_MS (nbr
->dd_flags
))
128 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
133 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
138 /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
139 * the given neighbour
142 nsm_should_adj (struct ospf_neighbor
*nbr
)
144 struct ospf_interface
*oi
= nbr
->oi
;
146 /* These network types must always form adjacencies. */
147 if (oi
->type
== OSPF_IFTYPE_POINTOPOINT
148 || oi
->type
== OSPF_IFTYPE_POINTOMULTIPOINT
149 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
150 /* Router itself is the DRouter or the BDRouter. */
151 || IPV4_ADDR_SAME (&oi
->address
->u
.prefix4
, &DR (oi
))
152 || IPV4_ADDR_SAME (&oi
->address
->u
.prefix4
, &BDR (oi
))
153 /* Neighboring Router is the DRouter or the BDRouter. */
154 || IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &DR (oi
))
155 || IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &BDR (oi
)))
161 /* OSPF NSM functions. */
163 nsm_packet_received (struct ospf_neighbor
*nbr
)
165 /* Start or Restart Inactivity Timer. */
166 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
168 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
171 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
)
172 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
174 /* Send proactive ARP requests */
175 if (nbr
->state
< NSM_Exchange
)
176 ospf_proactively_arp (nbr
);
182 nsm_start (struct ospf_neighbor
*nbr
)
185 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
187 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
189 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
192 /* Send proactive ARP requests */
193 ospf_proactively_arp (nbr
);
199 nsm_twoway_received (struct ospf_neighbor
*nbr
)
201 int adj
= nsm_should_adj (nbr
);
203 /* Send proactive ARP requests */
205 ospf_proactively_arp (nbr
);
207 return (adj
? NSM_ExStart
: NSM_TwoWay
);
211 ospf_db_summary_count (struct ospf_neighbor
*nbr
)
213 return ospf_lsdb_count_all (&nbr
->db_sum
);
217 ospf_db_summary_isempty (struct ospf_neighbor
*nbr
)
219 return ospf_lsdb_isempty (&nbr
->db_sum
);
223 ospf_db_summary_add (struct ospf_neighbor
*nbr
, struct ospf_lsa
*lsa
)
225 #ifdef HAVE_OPAQUE_LSA
226 switch (lsa
->data
->type
)
228 case OSPF_OPAQUE_LINK_LSA
:
229 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
230 if (nbr
->oi
&& ospf_if_exists (lsa
->oi
) != nbr
->oi
)
233 case OSPF_OPAQUE_AREA_LSA
:
235 * It is assured by the caller function "nsm_negotiation_done()"
236 * that every given LSA belongs to the same area with "nbr".
239 case OSPF_OPAQUE_AS_LSA
:
243 #endif /* HAVE_OPAQUE_LSA */
245 /* Stay away from any Local Translated Type-7 LSAs */
246 if (CHECK_FLAG (lsa
->flags
, OSPF_LSA_LOCAL_XLT
))
249 if (IS_LSA_MAXAGE (lsa
))
250 ospf_ls_retransmit_add (nbr
, lsa
);
252 ospf_lsdb_add (&nbr
->db_sum
, lsa
);
258 ospf_db_summary_clear (struct ospf_neighbor
*nbr
)
260 struct ospf_lsdb
*lsdb
;
264 for (i
= OSPF_MIN_LSA
; i
< OSPF_MAX_LSA
; i
++)
266 struct route_table
*table
= lsdb
->type
[i
].db
;
267 struct route_node
*rn
;
269 for (rn
= route_top (table
); rn
; rn
= route_next (rn
))
271 ospf_lsdb_delete (&nbr
->db_sum
, rn
->info
);
277 /* The area link state database consists of the router-LSAs,
278 network-LSAs and summary-LSAs contained in the area structure,
279 along with the AS-external-LSAs contained in the global structure.
280 AS-external-LSAs are omitted from a virtual neighbor's Database
281 summary list. AS-external-LSAs are omitted from the Database
282 summary list if the area has been configured as a stub. */
284 nsm_negotiation_done (struct ospf_neighbor
*nbr
)
286 struct ospf_area
*area
= nbr
->oi
->area
;
287 struct ospf_lsa
*lsa
;
288 struct route_node
*rn
;
290 /* Send proactive ARP requests */
291 ospf_proactively_arp (nbr
);
293 LSDB_LOOP (ROUTER_LSDB (area
), rn
, lsa
)
294 ospf_db_summary_add (nbr
, lsa
);
295 LSDB_LOOP (NETWORK_LSDB (area
), rn
, lsa
)
296 ospf_db_summary_add (nbr
, lsa
);
297 LSDB_LOOP (SUMMARY_LSDB (area
), rn
, lsa
)
298 ospf_db_summary_add (nbr
, lsa
);
299 LSDB_LOOP (ASBR_SUMMARY_LSDB (area
), rn
, lsa
)
300 ospf_db_summary_add (nbr
, lsa
);
302 #ifdef HAVE_OPAQUE_LSA
303 /* Process only if the neighbor is opaque capable. */
304 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
306 LSDB_LOOP (OPAQUE_LINK_LSDB (area
), rn
, lsa
)
307 ospf_db_summary_add (nbr
, lsa
);
308 LSDB_LOOP (OPAQUE_AREA_LSDB (area
), rn
, lsa
)
309 ospf_db_summary_add (nbr
, lsa
);
311 #endif /* HAVE_OPAQUE_LSA */
313 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_NP
))
315 LSDB_LOOP (NSSA_LSDB (area
), rn
, lsa
)
316 ospf_db_summary_add (nbr
, lsa
);
319 if (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
320 && area
->external_routing
== OSPF_AREA_DEFAULT
)
321 LSDB_LOOP (EXTERNAL_LSDB (nbr
->oi
->ospf
), rn
, lsa
)
322 ospf_db_summary_add (nbr
, lsa
);
324 #ifdef HAVE_OPAQUE_LSA
325 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
)
326 && (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
327 && area
->external_routing
== OSPF_AREA_DEFAULT
))
328 LSDB_LOOP (OPAQUE_AS_LSDB (nbr
->oi
->ospf
), rn
, lsa
)
329 ospf_db_summary_add (nbr
, lsa
);
330 #endif /* HAVE_OPAQUE_LSA */
336 nsm_exchange_done (struct ospf_neighbor
*nbr
)
338 if (ospf_ls_request_isempty (nbr
))
341 /* Send Link State Request. */
342 if (nbr
->t_ls_req
== NULL
)
343 ospf_ls_req_send (nbr
);
349 nsm_adj_ok (struct ospf_neighbor
*nbr
)
351 int next_state
= nbr
->state
;
352 int adj
= nsm_should_adj (nbr
);
354 if (nbr
->state
== NSM_TwoWay
&& adj
== 1)
356 next_state
= NSM_ExStart
;
358 /* Send proactive ARP requests */
359 ospf_proactively_arp (nbr
);
361 else if (nbr
->state
>= NSM_ExStart
&& adj
== 0)
362 next_state
= NSM_TwoWay
;
367 /* Clear adjacency related state for a neighbour, intended where nbr
368 * transitions from > ExStart (i.e. a Full or forming adjacency)
372 nsm_clear_adj (struct ospf_neighbor
*nbr
)
374 /* Clear Database Summary list. */
375 if (!ospf_db_summary_isempty (nbr
))
376 ospf_db_summary_clear (nbr
);
378 /* Clear Link State Request list. */
379 if (!ospf_ls_request_isempty (nbr
))
380 ospf_ls_request_delete_all (nbr
);
382 /* Clear Link State Retransmission list. */
383 if (!ospf_ls_retransmit_isempty (nbr
))
384 ospf_ls_retransmit_clear (nbr
);
386 #ifdef HAVE_OPAQUE_LSA
387 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
388 UNSET_FLAG (nbr
->options
, OSPF_OPTION_O
);
389 #endif /* HAVE_OPAQUE_LSA */
393 nsm_kill_nbr (struct ospf_neighbor
*nbr
)
395 /* killing nbr_self is invalid */
396 if (nbr
== nbr
->oi
->nbr_self
)
398 assert (nbr
!= nbr
->oi
->nbr_self
);
402 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
!= NULL
)
404 struct ospf_nbr_nbma
*nbr_nbma
= nbr
->nbr_nbma
;
406 nbr_nbma
->nbr
= NULL
;
407 nbr_nbma
->state_change
= nbr
->state_change
;
409 nbr
->nbr_nbma
= NULL
;
411 OSPF_POLL_TIMER_ON (nbr_nbma
->t_poll
, ospf_poll_timer
,
414 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
415 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
416 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->address
.u
.prefix4
));
422 /* Neighbor State Machine */
424 int (*func
) (struct ospf_neighbor
*);
426 } NSM
[OSPF_NSM_STATE_MAX
][OSPF_NSM_EVENT_MAX
] =
429 /* DependUpon: dummy state. */
430 { NULL
, NSM_DependUpon
}, /* NoEvent */
431 { NULL
, NSM_DependUpon
}, /* PacketReceived */
432 { NULL
, NSM_DependUpon
}, /* Start */
433 { NULL
, NSM_DependUpon
}, /* 2-WayReceived */
434 { NULL
, NSM_DependUpon
}, /* NegotiationDone */
435 { NULL
, NSM_DependUpon
}, /* ExchangeDone */
436 { NULL
, NSM_DependUpon
}, /* BadLSReq */
437 { NULL
, NSM_DependUpon
}, /* LoadingDone */
438 { NULL
, NSM_DependUpon
}, /* AdjOK? */
439 { NULL
, NSM_DependUpon
}, /* SeqNumberMismatch */
440 { NULL
, NSM_DependUpon
}, /* 1-WayReceived */
441 { NULL
, NSM_DependUpon
}, /* KillNbr */
442 { NULL
, NSM_DependUpon
}, /* InactivityTimer */
443 { NULL
, NSM_DependUpon
}, /* LLDown */
446 /* Deleted: dummy state. */
447 { NULL
, NSM_Deleted
}, /* NoEvent */
448 { NULL
, NSM_Deleted
}, /* PacketReceived */
449 { NULL
, NSM_Deleted
}, /* Start */
450 { NULL
, NSM_Deleted
}, /* 2-WayReceived */
451 { NULL
, NSM_Deleted
}, /* NegotiationDone */
452 { NULL
, NSM_Deleted
}, /* ExchangeDone */
453 { NULL
, NSM_Deleted
}, /* BadLSReq */
454 { NULL
, NSM_Deleted
}, /* LoadingDone */
455 { NULL
, NSM_Deleted
}, /* AdjOK? */
456 { NULL
, NSM_Deleted
}, /* SeqNumberMismatch */
457 { NULL
, NSM_Deleted
}, /* 1-WayReceived */
458 { NULL
, NSM_Deleted
}, /* KillNbr */
459 { NULL
, NSM_Deleted
}, /* InactivityTimer */
460 { NULL
, NSM_Deleted
}, /* LLDown */
464 { NULL
, NSM_DependUpon
}, /* NoEvent */
465 { nsm_packet_received
, NSM_Init
}, /* PacketReceived */
466 { nsm_start
, NSM_Attempt
}, /* Start */
467 { NULL
, NSM_Down
}, /* 2-WayReceived */
468 { NULL
, NSM_Down
}, /* NegotiationDone */
469 { NULL
, NSM_Down
}, /* ExchangeDone */
470 { NULL
, NSM_Down
}, /* BadLSReq */
471 { NULL
, NSM_Down
}, /* LoadingDone */
472 { NULL
, NSM_Down
}, /* AdjOK? */
473 { NULL
, NSM_Down
}, /* SeqNumberMismatch */
474 { NULL
, NSM_Down
}, /* 1-WayReceived */
475 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
476 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
477 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
481 { NULL
, NSM_DependUpon
}, /* NoEvent */
482 { nsm_packet_received
, NSM_Init
}, /* PacketReceived */
483 { NULL
, NSM_Attempt
}, /* Start */
484 { NULL
, NSM_Attempt
}, /* 2-WayReceived */
485 { NULL
, NSM_Attempt
}, /* NegotiationDone */
486 { NULL
, NSM_Attempt
}, /* ExchangeDone */
487 { NULL
, NSM_Attempt
}, /* BadLSReq */
488 { NULL
, NSM_Attempt
}, /* LoadingDone */
489 { NULL
, NSM_Attempt
}, /* AdjOK? */
490 { NULL
, NSM_Attempt
}, /* SeqNumberMismatch */
491 { NULL
, NSM_Attempt
}, /* 1-WayReceived */
492 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
493 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
494 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
498 { NULL
, NSM_DependUpon
}, /* NoEvent */
499 { nsm_packet_received
, NSM_Init
}, /* PacketReceived */
500 { NULL
, NSM_Init
}, /* Start */
501 { nsm_twoway_received
, NSM_DependUpon
}, /* 2-WayReceived */
502 { NULL
, NSM_Init
}, /* NegotiationDone */
503 { NULL
, NSM_Init
}, /* ExchangeDone */
504 { NULL
, NSM_Init
}, /* BadLSReq */
505 { NULL
, NSM_Init
}, /* LoadingDone */
506 { NULL
, NSM_Init
}, /* AdjOK? */
507 { NULL
, NSM_Init
}, /* SeqNumberMismatch */
508 { NULL
, NSM_Init
}, /* 1-WayReceived */
509 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
510 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
511 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
515 { NULL
, NSM_DependUpon
}, /* NoEvent */
516 { nsm_packet_received
, NSM_TwoWay
}, /* HelloReceived */
517 { NULL
, NSM_TwoWay
}, /* Start */
518 { NULL
, NSM_TwoWay
}, /* 2-WayReceived */
519 { NULL
, NSM_TwoWay
}, /* NegotiationDone */
520 { NULL
, NSM_TwoWay
}, /* ExchangeDone */
521 { NULL
, NSM_TwoWay
}, /* BadLSReq */
522 { NULL
, NSM_TwoWay
}, /* LoadingDone */
523 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
524 { NULL
, NSM_TwoWay
}, /* SeqNumberMismatch */
525 { NULL
, NSM_Init
}, /* 1-WayReceived */
526 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
527 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
528 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
532 { NULL
, NSM_DependUpon
}, /* NoEvent */
533 { nsm_packet_received
, NSM_ExStart
}, /* PacaketReceived */
534 { NULL
, NSM_ExStart
}, /* Start */
535 { NULL
, NSM_ExStart
}, /* 2-WayReceived */
536 { nsm_negotiation_done
, NSM_Exchange
}, /* NegotiationDone */
537 { NULL
, NSM_ExStart
}, /* ExchangeDone */
538 { NULL
, NSM_ExStart
}, /* BadLSReq */
539 { NULL
, NSM_ExStart
}, /* LoadingDone */
540 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
541 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
542 { NULL
, NSM_Init
}, /* 1-WayReceived */
543 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
544 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
545 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
549 { NULL
, NSM_DependUpon
}, /* NoEvent */
550 { nsm_packet_received
, NSM_Exchange
}, /* PacketReceived */
551 { NULL
, NSM_Exchange
}, /* Start */
552 { NULL
, NSM_Exchange
}, /* 2-WayReceived */
553 { NULL
, NSM_Exchange
}, /* NegotiationDone */
554 { nsm_exchange_done
, NSM_DependUpon
}, /* ExchangeDone */
555 { NULL
, NSM_ExStart
}, /* BadLSReq */
556 { NULL
, NSM_Exchange
}, /* LoadingDone */
557 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
558 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
559 { NULL
, NSM_Init
}, /* 1-WayReceived */
560 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
561 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
562 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
566 { NULL
, NSM_DependUpon
}, /* NoEvent */
567 { nsm_packet_received
, NSM_Loading
}, /* PacketReceived */
568 { NULL
, NSM_Loading
}, /* Start */
569 { NULL
, NSM_Loading
}, /* 2-WayReceived */
570 { NULL
, NSM_Loading
}, /* NegotiationDone */
571 { NULL
, NSM_Loading
}, /* ExchangeDone */
572 { NULL
, NSM_ExStart
}, /* BadLSReq */
573 { NULL
, NSM_Full
}, /* LoadingDone */
574 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
575 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
576 { NULL
, NSM_Init
}, /* 1-WayReceived */
577 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
578 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
579 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
582 { NULL
, NSM_DependUpon
}, /* NoEvent */
583 { nsm_packet_received
, NSM_Full
}, /* PacketReceived */
584 { NULL
, NSM_Full
}, /* Start */
585 { NULL
, NSM_Full
}, /* 2-WayReceived */
586 { NULL
, NSM_Full
}, /* NegotiationDone */
587 { NULL
, NSM_Full
}, /* ExchangeDone */
588 { NULL
, NSM_ExStart
}, /* BadLSReq */
589 { NULL
, NSM_Full
}, /* LoadingDone */
590 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
591 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
592 { NULL
, NSM_Init
}, /* 1-WayReceived */
593 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
594 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
595 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
599 static const char *ospf_nsm_event_str
[] =
618 nsm_notice_state_change (struct ospf_neighbor
*nbr
, int next_state
, int event
)
620 /* Logging change of status. */
621 if (IS_DEBUG_OSPF (nsm
, NSM_STATUS
))
622 zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)",
623 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
),
624 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
625 LOOKUP (ospf_nsm_state_msg
, next_state
),
626 ospf_nsm_event_str
[event
]);
628 /* Optionally notify about adjacency changes */
629 if (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_CHANGES
) &&
630 (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
) ||
631 (next_state
== NSM_Full
) || (next_state
< nbr
->state
)))
632 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)",
633 inet_ntoa (nbr
->router_id
), IF_NAME (nbr
->oi
),
634 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
635 LOOKUP (ospf_nsm_state_msg
, next_state
),
636 ospf_nsm_event_str
[event
]);
639 if (next_state
> nbr
->state
)
640 nbr
->ts_last_progress
= recent_relative_time ();
641 else /* regression in NSM */
643 nbr
->ts_last_regress
= recent_relative_time ();
644 nbr
->last_regress_str
= ospf_nsm_event_str
[event
];
650 nsm_change_state (struct ospf_neighbor
*nbr
, int state
)
652 struct ospf_interface
*oi
= nbr
->oi
;
653 struct ospf_area
*vl_area
= NULL
;
658 /* Preserve old status. */
659 old_state
= nbr
->state
;
661 /* Change to new status. */
667 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
668 vl_area
= ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
670 /* Generate NeighborChange ISM event.
672 * In response to NeighborChange, DR election is rerun. The information
673 * from the election process is required by the router-lsa construction.
675 * Therefore, trigger the event prior to refreshing the LSAs. */
680 if ((old_state
< NSM_TwoWay
&& state
>= NSM_TwoWay
) ||
681 (old_state
>= NSM_TwoWay
&& state
< NSM_TwoWay
))
682 OSPF_ISM_EVENT_EXECUTE (oi
, ISM_NeighborChange
);
685 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
689 /* One of the neighboring routers changes to/from the FULL state. */
690 if ((old_state
!= NSM_Full
&& state
== NSM_Full
) ||
691 (old_state
== NSM_Full
&& state
!= NSM_Full
))
693 if (state
== NSM_Full
)
696 oi
->area
->full_nbrs
++;
698 ospf_check_abr_status (oi
->ospf
);
700 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
701 if (++vl_area
->full_vls
== 1)
702 ospf_schedule_abr_task (oi
->ospf
);
704 /* kevinm: refresh any redistributions */
705 for (x
= ZEBRA_ROUTE_SYSTEM
; x
< ZEBRA_ROUTE_MAX
; x
++)
707 struct list
*red_list
;
708 struct listnode
*node
;
709 struct ospf_redist
*red
;
711 if (x
== ZEBRA_ROUTE_OSPF6
)
714 red_list
= oi
->ospf
->redist
[x
];
718 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
719 ospf_external_lsa_refresh_type (oi
->ospf
, x
, red
->instance
, force
);
721 /* XXX: Clearly some thing is wrong with refresh of external LSAs
722 * this added to hack around defaults not refreshing after a timer
725 ospf_external_lsa_refresh_default (oi
->ospf
);
730 oi
->area
->full_nbrs
--;
732 ospf_check_abr_status (oi
->ospf
);
734 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
735 if (vl_area
->full_vls
> 0)
736 if (--vl_area
->full_vls
== 0)
737 ospf_schedule_abr_task (oi
->ospf
);
740 zlog_info ("nsm_change_state(%s, %s -> %s): "
741 "scheduling new router-LSA origination",
742 inet_ntoa (nbr
->router_id
),
743 LOOKUP(ospf_nsm_state_msg
, old_state
),
744 LOOKUP(ospf_nsm_state_msg
, state
));
746 ospf_router_lsa_update_area (oi
->area
);
748 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
750 struct ospf_area
*vl_area
=
751 ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
754 ospf_router_lsa_update_area (vl_area
);
757 /* Originate network-LSA. */
758 if (oi
->state
== ISM_DR
)
760 if (oi
->network_lsa_self
&& oi
->full_nbrs
== 0)
762 ospf_lsa_flush_area (oi
->network_lsa_self
, oi
->area
);
763 ospf_lsa_unlock (&oi
->network_lsa_self
);
764 oi
->network_lsa_self
= NULL
;
767 ospf_network_lsa_update (oi
);
771 #ifdef HAVE_OPAQUE_LSA
772 ospf_opaque_nsm_change (nbr
, old_state
);
773 #endif /* HAVE_OPAQUE_LSA */
775 /* State changes from > ExStart to <= ExStart should clear any Exchange
776 * or Full/LSA Update related lists and state.
777 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
779 if ((old_state
> NSM_ExStart
) && (state
<= NSM_ExStart
))
782 /* Start DD exchange protocol */
783 if (state
== NSM_ExStart
)
785 if (nbr
->dd_seqnum
== 0)
786 nbr
->dd_seqnum
= quagga_time (NULL
);
790 nbr
->dd_flags
= OSPF_DD_FLAG_I
|OSPF_DD_FLAG_M
|OSPF_DD_FLAG_MS
;
791 ospf_db_desc_send (nbr
);
794 /* clear cryptographic sequence number */
795 if (state
== NSM_Down
)
796 nbr
->crypt_seqnum
= 0;
798 ospf_bfd_trigger_event(nbr
, old_state
, state
);
800 /* Preserve old status? */
803 /* Execute NSM event process. */
805 ospf_nsm_event (struct thread
*thread
)
809 struct ospf_neighbor
*nbr
;
811 nbr
= THREAD_ARG (thread
);
812 event
= THREAD_VAL (thread
);
814 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
815 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr
->oi
),
816 inet_ntoa (nbr
->router_id
),
817 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
818 ospf_nsm_event_str
[event
]);
820 next_state
= NSM
[nbr
->state
][event
].next_state
;
823 if (NSM
[nbr
->state
][event
].func
!= NULL
)
825 int func_state
= (*(NSM
[nbr
->state
][event
].func
))(nbr
);
827 if (NSM
[nbr
->state
][event
].next_state
== NSM_DependUpon
)
828 next_state
= func_state
;
831 /* There's a mismatch between the FSM tables and what an FSM
832 * action/state-change function returned. State changes which
833 * do not have conditional/DependUpon next-states should not
834 * try set next_state.
836 zlog_warn ("NSM[%s:%s]: %s (%s): "
837 "Warning: action tried to change next_state to %s",
838 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
),
839 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
840 ospf_nsm_event_str
[event
],
841 LOOKUP (ospf_nsm_state_msg
, func_state
));
845 assert (next_state
!= NSM_DependUpon
);
847 /* If state is changed. */
848 if (next_state
!= nbr
->state
)
850 nsm_notice_state_change (nbr
, next_state
, event
);
852 int send_trap_virt
= 0;
854 /* Terminal state or regression */
855 if ((next_state
== NSM_Full
)
856 || (next_state
== NSM_TwoWay
)
857 || (next_state
< nbr
->state
))
859 /* ospfVirtNbrStateChange */
860 if (nbr
->oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
862 /* ospfNbrStateChange trap */
864 /* To/From FULL, only managed by DR */
865 if (((next_state
!= NSM_Full
) && (nbr
->state
!= NSM_Full
))
866 || (nbr
->oi
->state
== ISM_DR
))
870 nsm_change_state (nbr
, next_state
);
873 if (send_trap_virt
) {
874 ospfTrapVirtNbrStateChange(nbr
);
875 } else if (send_trap
) {
876 ospfTrapNbrStateChange(nbr
);
881 /* Make sure timer is set. */
884 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
887 * Rather than encode knowledge here of which events lead to NBR
888 * delete, we take our cue from the NSM table, via the dummy
889 * 'Deleted' neighbour state.
891 if (nbr
->state
== NSM_Deleted
)
892 ospf_nbr_delete (nbr
);
897 /* Check loading state. */
899 ospf_check_nbr_loading (struct ospf_neighbor
*nbr
)
901 if (nbr
->state
== NSM_Loading
)
903 if (ospf_ls_request_isempty (nbr
))
904 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_LoadingDone
);
905 else if (nbr
->ls_req_last
== NULL
)
906 ospf_ls_req_event (nbr
);