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 along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
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_bfd.h"
52 DEFINE_HOOK(ospf_nsm_change
,
53 (struct ospf_neighbor
*on
, int state
, int oldstate
),
54 (on
, state
, oldstate
))
56 static void nsm_clear_adj (struct ospf_neighbor
*);
58 /* OSPF NSM Timer functions. */
60 ospf_inactivity_timer (struct thread
*thread
)
62 struct ospf_neighbor
*nbr
;
64 nbr
= THREAD_ARG (thread
);
65 nbr
->t_inactivity
= NULL
;
67 if (IS_DEBUG_OSPF (nsm
, NSM_TIMERS
))
68 zlog_debug("NSM[%s:%s]: Timer (Inactivity timer expire)",
69 IF_NAME(nbr
->oi
), inet_ntoa(nbr
->router_id
));
71 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_InactivityTimer
);
77 ospf_db_desc_timer (struct thread
*thread
)
79 struct ospf_neighbor
*nbr
;
81 nbr
= THREAD_ARG (thread
);
82 nbr
->t_db_desc
= NULL
;
84 if (IS_DEBUG_OSPF (nsm
, NSM_TIMERS
))
85 zlog_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.
100 * Set/clear any timers whose condition is implicit to the neighbour
101 * state. There may be other timers which are set/unset according to other
104 * We rely on this function to properly clear timers in lower states,
105 * particularly before deleting a neighbour.
108 nsm_timer_set (struct ospf_neighbor
*nbr
)
114 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
115 OSPF_NSM_TIMER_OFF (nbr
->t_hello_reply
);
119 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
120 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
121 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
124 OSPF_NSM_TIMER_ON (nbr
->t_db_desc
, ospf_db_desc_timer
, nbr
->v_db_desc
);
125 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
126 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
129 OSPF_NSM_TIMER_ON (nbr
->t_ls_upd
, ospf_ls_upd_timer
, nbr
->v_ls_upd
);
130 if (!IS_SET_DD_MS (nbr
->dd_flags
))
131 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
136 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
141 /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
142 * the given neighbour
145 nsm_should_adj (struct ospf_neighbor
*nbr
)
147 struct ospf_interface
*oi
= nbr
->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
153 /* Router itself is the DRouter or the BDRouter. */
154 || IPV4_ADDR_SAME (&oi
->address
->u
.prefix4
, &DR (oi
))
155 || IPV4_ADDR_SAME (&oi
->address
->u
.prefix4
, &BDR (oi
))
156 /* Neighboring Router is the DRouter or the BDRouter. */
157 || IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &DR (oi
))
158 || IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &BDR (oi
)))
164 /* OSPF NSM functions. */
166 nsm_packet_received (struct ospf_neighbor
*nbr
)
168 /* Start or Restart Inactivity Timer. */
169 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
171 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
174 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
)
175 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
177 /* Send proactive ARP requests */
178 if (nbr
->state
< NSM_Exchange
)
179 ospf_proactively_arp (nbr
);
185 nsm_start (struct ospf_neighbor
*nbr
)
188 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
190 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
192 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
195 /* Send proactive ARP requests */
196 ospf_proactively_arp (nbr
);
202 nsm_twoway_received (struct ospf_neighbor
*nbr
)
204 int adj
= nsm_should_adj (nbr
);
206 /* Send proactive ARP requests */
208 ospf_proactively_arp (nbr
);
210 return (adj
? NSM_ExStart
: NSM_TwoWay
);
214 ospf_db_summary_count (struct ospf_neighbor
*nbr
)
216 return ospf_lsdb_count_all (&nbr
->db_sum
);
220 ospf_db_summary_isempty (struct ospf_neighbor
*nbr
)
222 return ospf_lsdb_isempty (&nbr
->db_sum
);
226 ospf_db_summary_add (struct ospf_neighbor
*nbr
, struct ospf_lsa
*lsa
)
228 switch (lsa
->data
->type
)
230 case OSPF_OPAQUE_LINK_LSA
:
231 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
232 if (nbr
->oi
&& ospf_if_exists (lsa
->oi
) != nbr
->oi
)
235 case OSPF_OPAQUE_AREA_LSA
:
237 * It is assured by the caller function "nsm_negotiation_done()"
238 * that every given LSA belongs to the same area with "nbr".
241 case OSPF_OPAQUE_AS_LSA
:
246 /* Stay away from any Local Translated Type-7 LSAs */
247 if (CHECK_FLAG (lsa
->flags
, OSPF_LSA_LOCAL_XLT
))
250 if (IS_LSA_MAXAGE (lsa
))
251 ospf_ls_retransmit_add (nbr
, lsa
);
253 ospf_lsdb_add (&nbr
->db_sum
, lsa
);
259 ospf_db_summary_clear (struct ospf_neighbor
*nbr
)
261 struct ospf_lsdb
*lsdb
;
265 for (i
= OSPF_MIN_LSA
; i
< OSPF_MAX_LSA
; i
++)
267 struct route_table
*table
= lsdb
->type
[i
].db
;
268 struct route_node
*rn
;
270 for (rn
= route_top (table
); rn
; rn
= route_next (rn
))
272 ospf_lsdb_delete (&nbr
->db_sum
, rn
->info
);
278 /* The area link state database consists of the router-LSAs,
279 network-LSAs and summary-LSAs contained in the area structure,
280 along with the AS-external-LSAs contained in the global structure.
281 AS-external-LSAs are omitted from a virtual neighbor's Database
282 summary list. AS-external-LSAs are omitted from the Database
283 summary list if the area has been configured as a stub. */
285 nsm_negotiation_done (struct ospf_neighbor
*nbr
)
287 struct ospf_area
*area
= nbr
->oi
->area
;
288 struct ospf_lsa
*lsa
;
289 struct route_node
*rn
;
291 /* Send proactive ARP requests */
292 ospf_proactively_arp (nbr
);
294 LSDB_LOOP (ROUTER_LSDB (area
), rn
, lsa
)
295 ospf_db_summary_add (nbr
, lsa
);
296 LSDB_LOOP (NETWORK_LSDB (area
), rn
, lsa
)
297 ospf_db_summary_add (nbr
, lsa
);
298 LSDB_LOOP (SUMMARY_LSDB (area
), rn
, lsa
)
299 ospf_db_summary_add (nbr
, lsa
);
300 LSDB_LOOP (ASBR_SUMMARY_LSDB (area
), rn
, lsa
)
301 ospf_db_summary_add (nbr
, 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
);
312 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_NP
))
314 LSDB_LOOP (NSSA_LSDB (area
), rn
, lsa
)
315 ospf_db_summary_add (nbr
, lsa
);
318 if (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
319 && area
->external_routing
== OSPF_AREA_DEFAULT
)
320 LSDB_LOOP (EXTERNAL_LSDB (nbr
->oi
->ospf
), rn
, lsa
)
321 ospf_db_summary_add (nbr
, lsa
);
323 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
)
324 && (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
325 && area
->external_routing
== OSPF_AREA_DEFAULT
))
326 LSDB_LOOP (OPAQUE_AS_LSDB (nbr
->oi
->ospf
), rn
, lsa
)
327 ospf_db_summary_add (nbr
, lsa
);
333 nsm_exchange_done (struct ospf_neighbor
*nbr
)
335 if (ospf_ls_request_isempty (nbr
))
338 /* Send Link State Request. */
339 if (nbr
->t_ls_req
== NULL
)
340 ospf_ls_req_send (nbr
);
346 nsm_adj_ok (struct ospf_neighbor
*nbr
)
348 int next_state
= nbr
->state
;
349 int adj
= nsm_should_adj (nbr
);
351 if (nbr
->state
== NSM_TwoWay
&& adj
== 1)
353 next_state
= NSM_ExStart
;
355 /* Send proactive ARP requests */
356 ospf_proactively_arp (nbr
);
358 else if (nbr
->state
>= NSM_ExStart
&& adj
== 0)
359 next_state
= NSM_TwoWay
;
364 /* Clear adjacency related state for a neighbour, intended where nbr
365 * transitions from > ExStart (i.e. a Full or forming adjacency)
369 nsm_clear_adj (struct ospf_neighbor
*nbr
)
371 /* Clear Database Summary list. */
372 if (!ospf_db_summary_isempty (nbr
))
373 ospf_db_summary_clear (nbr
);
375 /* Clear Link State Request list. */
376 if (!ospf_ls_request_isempty (nbr
))
377 ospf_ls_request_delete_all (nbr
);
379 /* Clear Link State Retransmission list. */
380 if (!ospf_ls_retransmit_isempty (nbr
))
381 ospf_ls_retransmit_clear (nbr
);
383 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
384 UNSET_FLAG (nbr
->options
, OSPF_OPTION_O
);
388 nsm_kill_nbr (struct ospf_neighbor
*nbr
)
390 /* killing nbr_self is invalid */
391 if (nbr
== nbr
->oi
->nbr_self
)
393 assert (nbr
!= nbr
->oi
->nbr_self
);
397 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
!= NULL
)
399 struct ospf_nbr_nbma
*nbr_nbma
= nbr
->nbr_nbma
;
401 nbr_nbma
->nbr
= NULL
;
402 nbr_nbma
->state_change
= nbr
->state_change
;
404 nbr
->nbr_nbma
= NULL
;
406 OSPF_POLL_TIMER_ON (nbr_nbma
->t_poll
, ospf_poll_timer
,
409 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
410 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
411 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->address
.u
.prefix4
));
417 /* Neighbor State Machine */
419 int (*func
) (struct ospf_neighbor
*);
421 } NSM
[OSPF_NSM_STATE_MAX
][OSPF_NSM_EVENT_MAX
] =
424 /* DependUpon: dummy state. */
425 { NULL
, NSM_DependUpon
}, /* NoEvent */
426 { NULL
, NSM_DependUpon
}, /* PacketReceived */
427 { NULL
, NSM_DependUpon
}, /* Start */
428 { NULL
, NSM_DependUpon
}, /* 2-WayReceived */
429 { NULL
, NSM_DependUpon
}, /* NegotiationDone */
430 { NULL
, NSM_DependUpon
}, /* ExchangeDone */
431 { NULL
, NSM_DependUpon
}, /* BadLSReq */
432 { NULL
, NSM_DependUpon
}, /* LoadingDone */
433 { NULL
, NSM_DependUpon
}, /* AdjOK? */
434 { NULL
, NSM_DependUpon
}, /* SeqNumberMismatch */
435 { NULL
, NSM_DependUpon
}, /* 1-WayReceived */
436 { NULL
, NSM_DependUpon
}, /* KillNbr */
437 { NULL
, NSM_DependUpon
}, /* InactivityTimer */
438 { NULL
, NSM_DependUpon
}, /* LLDown */
441 /* Deleted: dummy state. */
442 { NULL
, NSM_Deleted
}, /* NoEvent */
443 { NULL
, NSM_Deleted
}, /* PacketReceived */
444 { NULL
, NSM_Deleted
}, /* Start */
445 { NULL
, NSM_Deleted
}, /* 2-WayReceived */
446 { NULL
, NSM_Deleted
}, /* NegotiationDone */
447 { NULL
, NSM_Deleted
}, /* ExchangeDone */
448 { NULL
, NSM_Deleted
}, /* BadLSReq */
449 { NULL
, NSM_Deleted
}, /* LoadingDone */
450 { NULL
, NSM_Deleted
}, /* AdjOK? */
451 { NULL
, NSM_Deleted
}, /* SeqNumberMismatch */
452 { NULL
, NSM_Deleted
}, /* 1-WayReceived */
453 { NULL
, NSM_Deleted
}, /* KillNbr */
454 { NULL
, NSM_Deleted
}, /* InactivityTimer */
455 { NULL
, NSM_Deleted
}, /* LLDown */
459 { NULL
, NSM_DependUpon
}, /* NoEvent */
460 { nsm_packet_received
, NSM_Init
}, /* PacketReceived */
461 { nsm_start
, NSM_Attempt
}, /* Start */
462 { NULL
, NSM_Down
}, /* 2-WayReceived */
463 { NULL
, NSM_Down
}, /* NegotiationDone */
464 { NULL
, NSM_Down
}, /* ExchangeDone */
465 { NULL
, NSM_Down
}, /* BadLSReq */
466 { NULL
, NSM_Down
}, /* LoadingDone */
467 { NULL
, NSM_Down
}, /* AdjOK? */
468 { NULL
, NSM_Down
}, /* SeqNumberMismatch */
469 { NULL
, NSM_Down
}, /* 1-WayReceived */
470 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
471 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
472 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
476 { NULL
, NSM_DependUpon
}, /* NoEvent */
477 { nsm_packet_received
, NSM_Init
}, /* PacketReceived */
478 { NULL
, NSM_Attempt
}, /* Start */
479 { NULL
, NSM_Attempt
}, /* 2-WayReceived */
480 { NULL
, NSM_Attempt
}, /* NegotiationDone */
481 { NULL
, NSM_Attempt
}, /* ExchangeDone */
482 { NULL
, NSM_Attempt
}, /* BadLSReq */
483 { NULL
, NSM_Attempt
}, /* LoadingDone */
484 { NULL
, NSM_Attempt
}, /* AdjOK? */
485 { NULL
, NSM_Attempt
}, /* SeqNumberMismatch */
486 { NULL
, NSM_Attempt
}, /* 1-WayReceived */
487 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
488 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
489 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
493 { NULL
, NSM_DependUpon
}, /* NoEvent */
494 { nsm_packet_received
, NSM_Init
}, /* PacketReceived */
495 { NULL
, NSM_Init
}, /* Start */
496 { nsm_twoway_received
, NSM_DependUpon
}, /* 2-WayReceived */
497 { NULL
, NSM_Init
}, /* NegotiationDone */
498 { NULL
, NSM_Init
}, /* ExchangeDone */
499 { NULL
, NSM_Init
}, /* BadLSReq */
500 { NULL
, NSM_Init
}, /* LoadingDone */
501 { NULL
, NSM_Init
}, /* AdjOK? */
502 { NULL
, NSM_Init
}, /* SeqNumberMismatch */
503 { NULL
, NSM_Init
}, /* 1-WayReceived */
504 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
505 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
506 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
510 { NULL
, NSM_DependUpon
}, /* NoEvent */
511 { nsm_packet_received
, NSM_TwoWay
}, /* HelloReceived */
512 { NULL
, NSM_TwoWay
}, /* Start */
513 { NULL
, NSM_TwoWay
}, /* 2-WayReceived */
514 { NULL
, NSM_TwoWay
}, /* NegotiationDone */
515 { NULL
, NSM_TwoWay
}, /* ExchangeDone */
516 { NULL
, NSM_TwoWay
}, /* BadLSReq */
517 { NULL
, NSM_TwoWay
}, /* LoadingDone */
518 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
519 { NULL
, NSM_TwoWay
}, /* SeqNumberMismatch */
520 { NULL
, NSM_Init
}, /* 1-WayReceived */
521 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
522 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
523 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
527 { NULL
, NSM_DependUpon
}, /* NoEvent */
528 { nsm_packet_received
, NSM_ExStart
}, /* PacaketReceived */
529 { NULL
, NSM_ExStart
}, /* Start */
530 { NULL
, NSM_ExStart
}, /* 2-WayReceived */
531 { nsm_negotiation_done
, NSM_Exchange
}, /* NegotiationDone */
532 { NULL
, NSM_ExStart
}, /* ExchangeDone */
533 { NULL
, NSM_ExStart
}, /* BadLSReq */
534 { NULL
, NSM_ExStart
}, /* LoadingDone */
535 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
536 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
537 { NULL
, NSM_Init
}, /* 1-WayReceived */
538 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
539 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
540 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
544 { NULL
, NSM_DependUpon
}, /* NoEvent */
545 { nsm_packet_received
, NSM_Exchange
}, /* PacketReceived */
546 { NULL
, NSM_Exchange
}, /* Start */
547 { NULL
, NSM_Exchange
}, /* 2-WayReceived */
548 { NULL
, NSM_Exchange
}, /* NegotiationDone */
549 { nsm_exchange_done
, NSM_DependUpon
}, /* ExchangeDone */
550 { NULL
, NSM_ExStart
}, /* BadLSReq */
551 { NULL
, NSM_Exchange
}, /* LoadingDone */
552 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
553 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
554 { NULL
, NSM_Init
}, /* 1-WayReceived */
555 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
556 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
557 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
561 { NULL
, NSM_DependUpon
}, /* NoEvent */
562 { nsm_packet_received
, NSM_Loading
}, /* PacketReceived */
563 { NULL
, NSM_Loading
}, /* Start */
564 { NULL
, NSM_Loading
}, /* 2-WayReceived */
565 { NULL
, NSM_Loading
}, /* NegotiationDone */
566 { NULL
, NSM_Loading
}, /* ExchangeDone */
567 { NULL
, NSM_ExStart
}, /* BadLSReq */
568 { NULL
, NSM_Full
}, /* LoadingDone */
569 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
570 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
571 { NULL
, NSM_Init
}, /* 1-WayReceived */
572 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
573 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
574 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
577 { NULL
, NSM_DependUpon
}, /* NoEvent */
578 { nsm_packet_received
, NSM_Full
}, /* PacketReceived */
579 { NULL
, NSM_Full
}, /* Start */
580 { NULL
, NSM_Full
}, /* 2-WayReceived */
581 { NULL
, NSM_Full
}, /* NegotiationDone */
582 { NULL
, NSM_Full
}, /* ExchangeDone */
583 { NULL
, NSM_ExStart
}, /* BadLSReq */
584 { NULL
, NSM_Full
}, /* LoadingDone */
585 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
586 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
587 { NULL
, NSM_Init
}, /* 1-WayReceived */
588 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
589 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
590 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
594 static const char *ospf_nsm_event_str
[] =
613 nsm_notice_state_change (struct ospf_neighbor
*nbr
, int next_state
, int event
)
615 /* Logging change of status. */
616 if (IS_DEBUG_OSPF (nsm
, NSM_STATUS
))
617 zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)",
618 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
),
619 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
620 LOOKUP (ospf_nsm_state_msg
, next_state
),
621 ospf_nsm_event_str
[event
]);
623 /* Optionally notify about adjacency changes */
624 if (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_CHANGES
) &&
625 (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
) ||
626 (next_state
== NSM_Full
) || (next_state
< nbr
->state
)))
627 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)",
628 inet_ntoa (nbr
->router_id
), IF_NAME (nbr
->oi
),
629 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
630 LOOKUP (ospf_nsm_state_msg
, next_state
),
631 ospf_nsm_event_str
[event
]);
634 if (next_state
> nbr
->state
)
635 monotime(&nbr
->ts_last_progress
);
636 else /* regression in NSM */
638 monotime(&nbr
->ts_last_regress
);
639 nbr
->last_regress_str
= ospf_nsm_event_str
[event
];
645 nsm_change_state (struct ospf_neighbor
*nbr
, int state
)
647 struct ospf_interface
*oi
= nbr
->oi
;
648 struct ospf_area
*vl_area
= NULL
;
653 /* Preserve old status. */
654 old_state
= nbr
->state
;
656 /* Change to new status. */
662 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
663 vl_area
= ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
665 /* Generate NeighborChange ISM event.
667 * In response to NeighborChange, DR election is rerun. The information
668 * from the election process is required by the router-lsa construction.
670 * Therefore, trigger the event prior to refreshing the LSAs. */
675 if ((old_state
< NSM_TwoWay
&& state
>= NSM_TwoWay
) ||
676 (old_state
>= NSM_TwoWay
&& state
< NSM_TwoWay
))
677 OSPF_ISM_EVENT_EXECUTE (oi
, ISM_NeighborChange
);
680 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
684 /* One of the neighboring routers changes to/from the FULL state. */
685 if ((old_state
!= NSM_Full
&& state
== NSM_Full
) ||
686 (old_state
== NSM_Full
&& state
!= NSM_Full
))
688 if (state
== NSM_Full
)
691 oi
->area
->full_nbrs
++;
693 ospf_check_abr_status (oi
->ospf
);
695 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
696 if (++vl_area
->full_vls
== 1)
697 ospf_schedule_abr_task (oi
->ospf
);
699 /* kevinm: refresh any redistributions */
700 for (x
= ZEBRA_ROUTE_SYSTEM
; x
< ZEBRA_ROUTE_MAX
; x
++)
702 struct list
*red_list
;
703 struct listnode
*node
;
704 struct ospf_redist
*red
;
706 if (x
== ZEBRA_ROUTE_OSPF6
)
709 red_list
= oi
->ospf
->redist
[x
];
713 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
714 ospf_external_lsa_refresh_type (oi
->ospf
, x
, red
->instance
, force
);
716 /* XXX: Clearly some thing is wrong with refresh of external LSAs
717 * this added to hack around defaults not refreshing after a timer
720 ospf_external_lsa_refresh_default (oi
->ospf
);
725 oi
->area
->full_nbrs
--;
727 ospf_check_abr_status (oi
->ospf
);
729 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
730 if (vl_area
->full_vls
> 0)
731 if (--vl_area
->full_vls
== 0)
732 ospf_schedule_abr_task (oi
->ospf
);
735 zlog_info ("nsm_change_state(%s, %s -> %s): "
736 "scheduling new router-LSA origination",
737 inet_ntoa (nbr
->router_id
),
738 LOOKUP(ospf_nsm_state_msg
, old_state
),
739 LOOKUP(ospf_nsm_state_msg
, state
));
741 ospf_router_lsa_update_area (oi
->area
);
743 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
745 struct ospf_area
*vl_area
=
746 ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
749 ospf_router_lsa_update_area (vl_area
);
752 /* Originate network-LSA. */
753 if (oi
->state
== ISM_DR
)
755 if (oi
->network_lsa_self
&& oi
->full_nbrs
== 0)
757 ospf_lsa_flush_area (oi
->network_lsa_self
, oi
->area
);
758 ospf_lsa_unlock (&oi
->network_lsa_self
);
759 oi
->network_lsa_self
= NULL
;
762 ospf_network_lsa_update (oi
);
766 ospf_opaque_nsm_change (nbr
, old_state
);
768 /* State changes from > ExStart to <= ExStart should clear any Exchange
769 * or Full/LSA Update related lists and state.
770 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
772 if ((old_state
> NSM_ExStart
) && (state
<= NSM_ExStart
))
775 /* Start DD exchange protocol */
776 if (state
== NSM_ExStart
)
778 if (nbr
->dd_seqnum
== 0)
779 nbr
->dd_seqnum
= (uint32_t)random ();
783 nbr
->dd_flags
= OSPF_DD_FLAG_I
|OSPF_DD_FLAG_M
|OSPF_DD_FLAG_MS
;
784 ospf_db_desc_send (nbr
);
787 /* clear cryptographic sequence number */
788 if (state
== NSM_Down
)
789 nbr
->crypt_seqnum
= 0;
791 ospf_bfd_trigger_event(nbr
, old_state
, state
);
793 /* Preserve old status? */
796 /* Execute NSM event process. */
798 ospf_nsm_event (struct thread
*thread
)
802 struct ospf_neighbor
*nbr
;
804 nbr
= THREAD_ARG (thread
);
805 event
= THREAD_VAL (thread
);
807 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
808 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr
->oi
),
809 inet_ntoa (nbr
->router_id
),
810 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
811 ospf_nsm_event_str
[event
]);
813 next_state
= NSM
[nbr
->state
][event
].next_state
;
816 if (NSM
[nbr
->state
][event
].func
!= NULL
)
818 int func_state
= (*(NSM
[nbr
->state
][event
].func
))(nbr
);
820 if (NSM
[nbr
->state
][event
].next_state
== NSM_DependUpon
)
821 next_state
= func_state
;
824 /* There's a mismatch between the FSM tables and what an FSM
825 * action/state-change function returned. State changes which
826 * do not have conditional/DependUpon next-states should not
827 * try set next_state.
829 zlog_warn ("NSM[%s:%s]: %s (%s): "
830 "Warning: action tried to change next_state to %s",
831 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
),
832 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
833 ospf_nsm_event_str
[event
],
834 LOOKUP (ospf_nsm_state_msg
, func_state
));
838 assert (next_state
!= NSM_DependUpon
);
840 /* If state is changed. */
841 if (next_state
!= nbr
->state
)
843 int old_state
= nbr
->state
;
845 nsm_notice_state_change (nbr
, next_state
, event
);
846 nsm_change_state (nbr
, next_state
);
848 hook_call(ospf_nsm_change
, nbr
, next_state
, old_state
);
851 /* Make sure timer is set. */
854 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
857 * Rather than encode knowledge here of which events lead to NBR
858 * delete, we take our cue from the NSM table, via the dummy
859 * 'Deleted' neighbour state.
861 if (nbr
->state
== NSM_Deleted
)
862 ospf_nbr_delete (nbr
);
867 /* Check loading state. */
869 ospf_check_nbr_loading (struct ospf_neighbor
*nbr
)
871 if (nbr
->state
== NSM_Loading
)
873 if (ospf_ls_request_isempty (nbr
))
874 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_LoadingDone
);
875 else if (nbr
->ls_req_last
== NULL
)
876 ospf_ls_req_event (nbr
);