1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * OSPF version 2 Neighbor State Machine
4 * From RFC2328 [OSPF Version 2]
5 * Copyright (C) 1999, 2000 Toshiaki Takada
23 #include "ospfd/ospfd.h"
24 #include "ospfd/ospf_interface.h"
25 #include "ospfd/ospf_ism.h"
26 #include "ospfd/ospf_asbr.h"
27 #include "ospfd/ospf_lsa.h"
28 #include "ospfd/ospf_lsdb.h"
29 #include "ospfd/ospf_neighbor.h"
30 #include "ospfd/ospf_nsm.h"
31 #include "ospfd/ospf_network.h"
32 #include "ospfd/ospf_packet.h"
33 #include "ospfd/ospf_dump.h"
34 #include "ospfd/ospf_flood.h"
35 #include "ospfd/ospf_abr.h"
36 #include "ospfd/ospf_bfd.h"
37 #include "ospfd/ospf_gr.h"
38 #include "ospfd/ospf_errors.h"
40 DEFINE_HOOK(ospf_nsm_change
,
41 (struct ospf_neighbor
* on
, int state
, int oldstate
),
42 (on
, state
, oldstate
));
44 static void nsm_clear_adj(struct ospf_neighbor
*);
46 /* OSPF NSM Timer functions. */
47 static void ospf_inactivity_timer(struct event
*thread
)
49 struct ospf_neighbor
*nbr
;
51 nbr
= EVENT_ARG(thread
);
52 nbr
->t_inactivity
= NULL
;
54 if (IS_DEBUG_OSPF(nsm
, NSM_TIMERS
))
55 zlog_debug("NSM[%s:%pI4:%s]: Timer (Inactivity timer expire)",
56 IF_NAME(nbr
->oi
), &nbr
->router_id
,
57 ospf_get_name(nbr
->oi
->ospf
));
59 /* Dont trigger NSM_InactivityTimer event , if the current
60 * router acting as HELPER for this neighbour.
62 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
63 OSPF_NSM_EVENT_SCHEDULE(nbr
, NSM_InactivityTimer
);
67 "%s, Acting as HELPER for this neighbour, So restart the dead timer",
69 OSPF_NSM_TIMER_ON(nbr
->t_inactivity
, ospf_inactivity_timer
,
74 static void ospf_db_desc_timer(struct event
*thread
)
76 struct ospf_neighbor
*nbr
;
78 nbr
= EVENT_ARG(thread
);
79 nbr
->t_db_desc
= NULL
;
81 if (IS_DEBUG_OSPF(nsm
, NSM_TIMERS
))
82 zlog_debug("NSM[%s:%pI4:%s]: Timer (DD Retransmit timer expire)",
83 IF_NAME(nbr
->oi
), &nbr
->src
,
84 ospf_get_name(nbr
->oi
->ospf
));
86 /* resent last send DD packet. */
87 assert(nbr
->last_send
);
88 ospf_db_desc_resend(nbr
);
90 /* DD Retransmit timer set. */
91 OSPF_NSM_TIMER_ON(nbr
->t_db_desc
, ospf_db_desc_timer
, nbr
->v_db_desc
);
94 /* Hook function called after ospf NSM event is occurred.
96 * Set/clear any timers whose condition is implicit to the neighbour
97 * state. There may be other timers which are set/unset according to other
100 * We rely on this function to properly clear timers in lower states,
101 * particularly before deleting a neighbour.
103 static void nsm_timer_set(struct ospf_neighbor
*nbr
)
105 switch (nbr
->state
) {
108 EVENT_OFF(nbr
->t_inactivity
);
109 EVENT_OFF(nbr
->t_hello_reply
);
114 EVENT_OFF(nbr
->t_db_desc
);
115 EVENT_OFF(nbr
->t_ls_upd
);
116 EVENT_OFF(nbr
->t_ls_req
);
119 OSPF_NSM_TIMER_ON(nbr
->t_db_desc
, ospf_db_desc_timer
,
121 EVENT_OFF(nbr
->t_ls_upd
);
122 EVENT_OFF(nbr
->t_ls_req
);
125 OSPF_NSM_TIMER_ON(nbr
->t_ls_upd
, ospf_ls_upd_timer
,
127 if (!IS_SET_DD_MS(nbr
->dd_flags
))
128 EVENT_OFF(nbr
->t_db_desc
);
133 EVENT_OFF(nbr
->t_db_desc
);
138 /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
139 * the given neighbour
141 int nsm_should_adj(struct ospf_neighbor
*nbr
)
143 struct ospf_interface
*oi
= nbr
->oi
;
145 /* These network types must always form adjacencies. */
146 if (oi
->type
== OSPF_IFTYPE_POINTOPOINT
147 || oi
->type
== OSPF_IFTYPE_POINTOMULTIPOINT
148 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
149 /* Router itself is the DRouter or the BDRouter. */
150 || IPV4_ADDR_SAME(&oi
->address
->u
.prefix4
, &DR(oi
))
151 || IPV4_ADDR_SAME(&oi
->address
->u
.prefix4
, &BDR(oi
))
152 /* Neighboring Router is the DRouter or the BDRouter. */
153 || IPV4_ADDR_SAME(&nbr
->address
.u
.prefix4
, &DR(oi
))
154 || IPV4_ADDR_SAME(&nbr
->address
.u
.prefix4
, &BDR(oi
)))
160 /* OSPF NSM functions. */
161 static int nsm_hello_received(struct ospf_neighbor
*nbr
)
163 /* Start or Restart Inactivity Timer. */
164 EVENT_OFF(nbr
->t_inactivity
);
166 OSPF_NSM_TIMER_ON(nbr
->t_inactivity
, ospf_inactivity_timer
,
169 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
)
170 EVENT_OFF(nbr
->nbr_nbma
->t_poll
);
172 /* Send proactive ARP requests */
173 if (nbr
->state
< NSM_Exchange
)
174 ospf_proactively_arp(nbr
);
179 static int nsm_start(struct ospf_neighbor
*nbr
)
182 EVENT_OFF(nbr
->nbr_nbma
->t_poll
);
184 EVENT_OFF(nbr
->t_inactivity
);
186 OSPF_NSM_TIMER_ON(nbr
->t_inactivity
, ospf_inactivity_timer
,
189 /* Send proactive ARP requests */
190 ospf_proactively_arp(nbr
);
195 static int nsm_twoway_received(struct ospf_neighbor
*nbr
)
197 int adj
= nsm_should_adj(nbr
);
199 /* Send proactive ARP requests */
201 ospf_proactively_arp(nbr
);
203 return (adj
? NSM_ExStart
: NSM_TwoWay
);
206 int ospf_db_summary_count(struct ospf_neighbor
*nbr
)
208 return ospf_lsdb_count_all(&nbr
->db_sum
);
211 int ospf_db_summary_isempty(struct ospf_neighbor
*nbr
)
213 return ospf_lsdb_isempty(&nbr
->db_sum
);
216 static int ospf_db_summary_add(struct ospf_neighbor
*nbr
, struct ospf_lsa
*lsa
)
218 switch (lsa
->data
->type
) {
219 case OSPF_OPAQUE_LINK_LSA
:
220 /* Exclude type-9 LSAs that does not have the same "oi" with
222 if (ospf_if_exists(lsa
->oi
) != nbr
->oi
)
225 case OSPF_OPAQUE_AREA_LSA
:
227 * It is assured by the caller function "nsm_negotiation_done()"
228 * that every given LSA belongs to the same area with "nbr".
231 case OSPF_OPAQUE_AS_LSA
:
236 /* Stay away from any Local Translated Type-7 LSAs */
237 if (CHECK_FLAG(lsa
->flags
, OSPF_LSA_LOCAL_XLT
))
240 if (IS_LSA_MAXAGE(lsa
))
241 ospf_ls_retransmit_add(nbr
, lsa
);
243 ospf_lsdb_add(&nbr
->db_sum
, lsa
);
248 void ospf_db_summary_clear(struct ospf_neighbor
*nbr
)
250 struct ospf_lsdb
*lsdb
;
254 for (i
= OSPF_MIN_LSA
; i
< OSPF_MAX_LSA
; i
++) {
255 struct route_table
*table
= lsdb
->type
[i
].db
;
256 struct route_node
*rn
;
258 for (rn
= route_top(table
); rn
; rn
= route_next(rn
))
260 ospf_lsdb_delete(&nbr
->db_sum
, rn
->info
);
265 /* The area link state database consists of the router-LSAs,
266 network-LSAs and summary-LSAs contained in the area structure,
267 along with the AS-external-LSAs contained in the global structure.
268 AS-external-LSAs are omitted from a virtual neighbor's Database
269 summary list. AS-external-LSAs are omitted from the Database
270 summary list if the area has been configured as a stub. */
271 static int nsm_negotiation_done(struct ospf_neighbor
*nbr
)
273 struct ospf_area
*area
= nbr
->oi
->area
;
274 struct ospf_lsa
*lsa
;
275 struct route_node
*rn
;
277 /* Send proactive ARP requests */
278 ospf_proactively_arp(nbr
);
280 LSDB_LOOP (ROUTER_LSDB(area
), rn
, lsa
)
281 ospf_db_summary_add(nbr
, lsa
);
282 LSDB_LOOP (NETWORK_LSDB(area
), rn
, lsa
)
283 ospf_db_summary_add(nbr
, lsa
);
284 LSDB_LOOP (SUMMARY_LSDB(area
), rn
, lsa
)
285 ospf_db_summary_add(nbr
, lsa
);
287 /* Process only if the neighbor is opaque capable. */
288 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
)) {
289 LSDB_LOOP (OPAQUE_LINK_LSDB(area
), rn
, lsa
)
290 ospf_db_summary_add(nbr
, lsa
);
291 LSDB_LOOP (OPAQUE_AREA_LSDB(area
), rn
, lsa
)
292 ospf_db_summary_add(nbr
, lsa
);
295 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_NP
)) {
296 LSDB_LOOP (NSSA_LSDB(area
), rn
, lsa
)
297 ospf_db_summary_add(nbr
, lsa
);
300 /* For Stub/NSSA area, we should not send Type-4 and Type-5 LSAs */
301 if (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
302 && area
->external_routing
== OSPF_AREA_DEFAULT
) {
303 LSDB_LOOP (ASBR_SUMMARY_LSDB(area
), rn
, lsa
)
304 ospf_db_summary_add(nbr
, lsa
);
305 LSDB_LOOP (EXTERNAL_LSDB(nbr
->oi
->ospf
), rn
, lsa
)
306 ospf_db_summary_add(nbr
, lsa
);
309 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
)
310 && (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
311 && area
->external_routing
== OSPF_AREA_DEFAULT
))
312 LSDB_LOOP (OPAQUE_AS_LSDB(nbr
->oi
->ospf
), rn
, lsa
)
313 ospf_db_summary_add(nbr
, lsa
);
318 static int nsm_exchange_done(struct ospf_neighbor
*nbr
)
320 if (ospf_ls_request_isempty(nbr
))
323 /* Send Link State Request. */
324 if (nbr
->t_ls_req
== NULL
)
325 ospf_ls_req_send(nbr
);
330 static int nsm_adj_ok(struct ospf_neighbor
*nbr
)
332 int next_state
= nbr
->state
;
333 int adj
= nsm_should_adj(nbr
);
335 if (nbr
->state
== NSM_TwoWay
&& adj
== 1) {
336 next_state
= NSM_ExStart
;
338 /* Send proactive ARP requests */
339 ospf_proactively_arp(nbr
);
340 } else if (nbr
->state
>= NSM_ExStart
&& adj
== 0)
341 next_state
= NSM_TwoWay
;
346 /* Clear adjacency related state for a neighbour, intended where nbr
347 * transitions from > ExStart (i.e. a Full or forming adjacency)
350 static void nsm_clear_adj(struct ospf_neighbor
*nbr
)
352 /* Clear Database Summary list. */
353 if (!ospf_db_summary_isempty(nbr
))
354 ospf_db_summary_clear(nbr
);
356 /* Clear Link State Request list. */
357 if (!ospf_ls_request_isempty(nbr
))
358 ospf_ls_request_delete_all(nbr
);
360 /* Clear Link State Retransmission list. */
361 if (!ospf_ls_retransmit_isempty(nbr
))
362 ospf_ls_retransmit_clear(nbr
);
364 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
))
365 UNSET_FLAG(nbr
->options
, OSPF_OPTION_O
);
368 static int nsm_kill_nbr(struct ospf_neighbor
*nbr
)
370 struct ospf_interface
*oi
= nbr
->oi
;
371 struct ospf_neighbor
*on
;
372 struct route_node
*rn
;
374 /* killing nbr_self is invalid */
375 if (nbr
== nbr
->oi
->nbr_self
) {
376 assert(nbr
!= nbr
->oi
->nbr_self
);
380 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
!= NULL
) {
381 struct ospf_nbr_nbma
*nbr_nbma
= nbr
->nbr_nbma
;
383 nbr_nbma
->nbr
= NULL
;
384 nbr_nbma
->state_change
= nbr
->state_change
;
386 nbr
->nbr_nbma
= NULL
;
388 OSPF_POLL_TIMER_ON(nbr_nbma
->t_poll
, ospf_poll_timer
,
391 if (IS_DEBUG_OSPF(nsm
, NSM_EVENTS
))
393 "NSM[%s:%pI4:%s]: Down (PollIntervalTimer scheduled)",
395 &nbr
->address
.u
.prefix4
,
396 ospf_get_name(nbr
->oi
->ospf
));
400 * Do we have any neighbors that are also operating
403 for (rn
= route_top(oi
->nbrs
); rn
; rn
= route_next(rn
)) {
409 if (on
== nbr
|| on
== oi
->nbr_self
)
413 * on is in some state where we might be
414 * sending packets on this interface
416 if (on
->state
> NSM_Down
) {
417 route_unlock_node(rn
);
422 * If we get here we know that this interface
423 * has no neighbors in a state where we could
424 * be sending packets. Let's flush anything
427 ospf_interface_fifo_flush(oi
);
431 /* Neighbor State Machine */
433 int (*func
)(struct ospf_neighbor
*);
435 } NSM
[OSPF_NSM_STATE_MAX
][OSPF_NSM_EVENT_MAX
] = {
437 /* DependUpon: dummy state. */
438 {NULL
, NSM_DependUpon
}, /* NoEvent */
439 {NULL
, NSM_DependUpon
}, /* HelloReceived */
440 {NULL
, NSM_DependUpon
}, /* Start */
441 {NULL
, NSM_DependUpon
}, /* 2-WayReceived */
442 {NULL
, NSM_DependUpon
}, /* NegotiationDone */
443 {NULL
, NSM_DependUpon
}, /* ExchangeDone */
444 {NULL
, NSM_DependUpon
}, /* BadLSReq */
445 {NULL
, NSM_DependUpon
}, /* LoadingDone */
446 {NULL
, NSM_DependUpon
}, /* AdjOK? */
447 {NULL
, NSM_DependUpon
}, /* SeqNumberMismatch */
448 {NULL
, NSM_DependUpon
}, /* 1-WayReceived */
449 {NULL
, NSM_DependUpon
}, /* KillNbr */
450 {NULL
, NSM_DependUpon
}, /* InactivityTimer */
451 {NULL
, NSM_DependUpon
}, /* LLDown */
454 /* Deleted: dummy state. */
455 {NULL
, NSM_Deleted
}, /* NoEvent */
456 {NULL
, NSM_Deleted
}, /* HelloReceived */
457 {NULL
, NSM_Deleted
}, /* Start */
458 {NULL
, NSM_Deleted
}, /* 2-WayReceived */
459 {NULL
, NSM_Deleted
}, /* NegotiationDone */
460 {NULL
, NSM_Deleted
}, /* ExchangeDone */
461 {NULL
, NSM_Deleted
}, /* BadLSReq */
462 {NULL
, NSM_Deleted
}, /* LoadingDone */
463 {NULL
, NSM_Deleted
}, /* AdjOK? */
464 {NULL
, NSM_Deleted
}, /* SeqNumberMismatch */
465 {NULL
, NSM_Deleted
}, /* 1-WayReceived */
466 {NULL
, NSM_Deleted
}, /* KillNbr */
467 {NULL
, NSM_Deleted
}, /* InactivityTimer */
468 {NULL
, NSM_Deleted
}, /* LLDown */
472 {NULL
, NSM_DependUpon
}, /* NoEvent */
473 {nsm_hello_received
, NSM_Init
}, /* HelloReceived */
474 {nsm_start
, NSM_Attempt
}, /* Start */
475 {NULL
, NSM_Down
}, /* 2-WayReceived */
476 {NULL
, NSM_Down
}, /* NegotiationDone */
477 {NULL
, NSM_Down
}, /* ExchangeDone */
478 {NULL
, NSM_Down
}, /* BadLSReq */
479 {NULL
, NSM_Down
}, /* LoadingDone */
480 {NULL
, NSM_Down
}, /* AdjOK? */
481 {NULL
, NSM_Down
}, /* SeqNumberMismatch */
482 {NULL
, NSM_Down
}, /* 1-WayReceived */
483 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
484 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
485 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
489 {NULL
, NSM_DependUpon
}, /* NoEvent */
490 {nsm_hello_received
, NSM_Init
}, /* HelloReceived */
491 {NULL
, NSM_Attempt
}, /* Start */
492 {NULL
, NSM_Attempt
}, /* 2-WayReceived */
493 {NULL
, NSM_Attempt
}, /* NegotiationDone */
494 {NULL
, NSM_Attempt
}, /* ExchangeDone */
495 {NULL
, NSM_Attempt
}, /* BadLSReq */
496 {NULL
, NSM_Attempt
}, /* LoadingDone */
497 {NULL
, NSM_Attempt
}, /* AdjOK? */
498 {NULL
, NSM_Attempt
}, /* SeqNumberMismatch */
499 {NULL
, NSM_Attempt
}, /* 1-WayReceived */
500 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
501 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
502 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
506 {NULL
, NSM_DependUpon
}, /* NoEvent */
507 {nsm_hello_received
, NSM_Init
}, /* HelloReceived */
508 {NULL
, NSM_Init
}, /* Start */
509 {nsm_twoway_received
, NSM_DependUpon
}, /* 2-WayReceived */
510 {NULL
, NSM_Init
}, /* NegotiationDone */
511 {NULL
, NSM_Init
}, /* ExchangeDone */
512 {NULL
, NSM_Init
}, /* BadLSReq */
513 {NULL
, NSM_Init
}, /* LoadingDone */
514 {NULL
, NSM_Init
}, /* AdjOK? */
515 {NULL
, NSM_Init
}, /* SeqNumberMismatch */
516 {NULL
, NSM_Init
}, /* 1-WayReceived */
517 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
518 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
519 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
523 {NULL
, NSM_DependUpon
}, /* NoEvent */
524 {nsm_hello_received
, NSM_TwoWay
}, /* HelloReceived */
525 {NULL
, NSM_TwoWay
}, /* Start */
526 {NULL
, NSM_TwoWay
}, /* 2-WayReceived */
527 {NULL
, NSM_TwoWay
}, /* NegotiationDone */
528 {NULL
, NSM_TwoWay
}, /* ExchangeDone */
529 {NULL
, NSM_TwoWay
}, /* BadLSReq */
530 {NULL
, NSM_TwoWay
}, /* LoadingDone */
531 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
532 {NULL
, NSM_TwoWay
}, /* SeqNumberMismatch */
533 {NULL
, NSM_Init
}, /* 1-WayReceived */
534 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
535 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
536 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
540 {NULL
, NSM_DependUpon
}, /* NoEvent */
541 {nsm_hello_received
, NSM_ExStart
}, /* HelloReceived */
542 {NULL
, NSM_ExStart
}, /* Start */
543 {NULL
, NSM_ExStart
}, /* 2-WayReceived */
544 {nsm_negotiation_done
, NSM_Exchange
}, /* NegotiationDone */
545 {NULL
, NSM_ExStart
}, /* ExchangeDone */
546 {NULL
, NSM_ExStart
}, /* BadLSReq */
547 {NULL
, NSM_ExStart
}, /* LoadingDone */
548 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
549 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
550 {NULL
, NSM_Init
}, /* 1-WayReceived */
551 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
552 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
553 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
557 {NULL
, NSM_DependUpon
}, /* NoEvent */
558 {nsm_hello_received
, NSM_Exchange
}, /* HelloReceived */
559 {NULL
, NSM_Exchange
}, /* Start */
560 {NULL
, NSM_Exchange
}, /* 2-WayReceived */
561 {NULL
, NSM_Exchange
}, /* NegotiationDone */
562 {nsm_exchange_done
, NSM_DependUpon
}, /* ExchangeDone */
563 {NULL
, NSM_ExStart
}, /* BadLSReq */
564 {NULL
, NSM_Exchange
}, /* LoadingDone */
565 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
566 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
567 {NULL
, NSM_Init
}, /* 1-WayReceived */
568 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
569 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
570 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
574 {NULL
, NSM_DependUpon
}, /* NoEvent */
575 {nsm_hello_received
, NSM_Loading
}, /* HelloReceived */
576 {NULL
, NSM_Loading
}, /* Start */
577 {NULL
, NSM_Loading
}, /* 2-WayReceived */
578 {NULL
, NSM_Loading
}, /* NegotiationDone */
579 {NULL
, NSM_Loading
}, /* ExchangeDone */
580 {NULL
, NSM_ExStart
}, /* BadLSReq */
581 {NULL
, NSM_Full
}, /* LoadingDone */
582 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
583 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
584 {NULL
, NSM_Init
}, /* 1-WayReceived */
585 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
586 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
587 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
591 {NULL
, NSM_DependUpon
}, /* NoEvent */
592 {nsm_hello_received
, NSM_Full
}, /* HelloReceived */
593 {NULL
, NSM_Full
}, /* Start */
594 {NULL
, NSM_Full
}, /* 2-WayReceived */
595 {NULL
, NSM_Full
}, /* NegotiationDone */
596 {NULL
, NSM_Full
}, /* ExchangeDone */
597 {NULL
, NSM_ExStart
}, /* BadLSReq */
598 {NULL
, NSM_Full
}, /* LoadingDone */
599 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
600 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
601 {NULL
, NSM_Init
}, /* 1-WayReceived */
602 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
603 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
604 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
608 static const char *const ospf_nsm_event_str
[] = {
609 "NoEvent", "HelloReceived", "Start",
610 "2-WayReceived", "NegotiationDone", "ExchangeDone",
611 "BadLSReq", "LoadingDone", "AdjOK?",
612 "SeqNumberMismatch", "1-WayReceived", "KillNbr",
613 "InactivityTimer", "LLDown",
616 static void nsm_notice_state_change(struct ospf_neighbor
*nbr
, int next_state
,
619 /* Logging change of status. */
620 if (IS_DEBUG_OSPF(nsm
, NSM_STATUS
))
621 zlog_debug("NSM[%s:%pI4:%s]: State change %s -> %s (%s)",
622 IF_NAME(nbr
->oi
), &nbr
->router_id
,
623 ospf_get_name(nbr
->oi
->ospf
),
624 lookup_msg(ospf_nsm_state_msg
, nbr
->state
, NULL
),
625 lookup_msg(ospf_nsm_state_msg
, next_state
, NULL
),
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
)))
633 "AdjChg: Nbr %pI4, NbrIP %pI4 (%s) on %s: %s -> %s (%s)",
634 &nbr
->router_id
, &nbr
->src
,
635 ospf_get_name(nbr
->oi
->ospf
), IF_NAME(nbr
->oi
),
636 lookup_msg(ospf_nsm_state_msg
, nbr
->state
, NULL
),
637 lookup_msg(ospf_nsm_state_msg
, next_state
, NULL
),
638 ospf_nsm_event_str
[event
]);
641 if (next_state
> nbr
->state
)
642 monotime(&nbr
->ts_last_progress
);
643 else /* regression in NSM */
645 monotime(&nbr
->ts_last_regress
);
646 nbr
->last_regress_str
= ospf_nsm_event_str
[event
];
650 static void nsm_change_state(struct ospf_neighbor
*nbr
, int state
)
652 struct ospf_interface
*oi
= nbr
->oi
;
653 struct ospf_area
*vl_area
= NULL
;
656 /* Preserve old status. */
657 old_state
= nbr
->state
;
659 /* Change to new status. */
665 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
666 vl_area
= ospf_area_lookup_by_area_id(oi
->ospf
,
667 oi
->vl_data
->vl_area_id
);
669 /* Generate NeighborChange ISM event.
671 * In response to NeighborChange, DR election is rerun. The information
672 * from the election process is required by the router-lsa construction.
674 * Therefore, trigger the event prior to refreshing the LSAs. */
679 if ((old_state
< NSM_TwoWay
&& state
>= NSM_TwoWay
)
680 || (old_state
>= NSM_TwoWay
&& state
< NSM_TwoWay
))
681 OSPF_ISM_EVENT_EXECUTE(oi
, ISM_NeighborChange
);
684 /* 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
)) {
692 if (state
== NSM_Full
) {
694 oi
->area
->full_nbrs
++;
696 ospf_check_abr_status(oi
->ospf
);
698 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
699 if (++vl_area
->full_vls
== 1)
700 ospf_schedule_abr_task(oi
->ospf
);
703 oi
->area
->full_nbrs
--;
705 ospf_check_abr_status(oi
->ospf
);
707 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
708 if (vl_area
->full_vls
> 0)
709 if (--vl_area
->full_vls
== 0)
710 ospf_schedule_abr_task(
714 if (CHECK_FLAG(oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
))
716 "%s:[%pI4:%s], %s -> %s): scheduling new router-LSA origination",
717 __func__
, &nbr
->router_id
,
718 ospf_get_name(oi
->ospf
),
719 lookup_msg(ospf_nsm_state_msg
, old_state
, NULL
),
720 lookup_msg(ospf_nsm_state_msg
, state
, NULL
));
722 /* Dont originate router LSA if the current
723 * router is acting as a HELPER for this neighbour.
725 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
726 ospf_router_lsa_update_area(oi
->area
);
728 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
) {
729 vl_area
= ospf_area_lookup_by_area_id(
730 oi
->ospf
, oi
->vl_data
->vl_area_id
);
733 ospf_router_lsa_update_area(vl_area
);
736 /* Dont originate/flush network LSA if the current
737 * router is acting as a HELPER for this neighbour.
739 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
)) {
740 /* Originate network-LSA. */
741 if (oi
->state
== ISM_DR
) {
742 if (oi
->network_lsa_self
743 && oi
->full_nbrs
== 0) {
745 oi
->network_lsa_self
, oi
->area
);
746 ospf_lsa_unlock(&oi
->network_lsa_self
);
747 oi
->network_lsa_self
= NULL
;
749 ospf_network_lsa_update(oi
);
753 if (state
== NSM_Full
&& oi
->ospf
->gr_info
.restart_in_progress
)
754 ospf_gr_check_adjs(oi
->ospf
);
757 ospf_opaque_nsm_change(nbr
, old_state
);
759 /* State changes from > ExStart to <= ExStart should clear any Exchange
760 * or Full/LSA Update related lists and state.
761 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
763 if ((old_state
> NSM_ExStart
) && (state
<= NSM_ExStart
))
766 /* Start DD exchange protocol */
767 if (state
== NSM_ExStart
) {
768 if (nbr
->dd_seqnum
== 0)
769 nbr
->dd_seqnum
= (uint32_t)frr_weak_random();
774 OSPF_DD_FLAG_I
| OSPF_DD_FLAG_M
| OSPF_DD_FLAG_MS
;
775 if (CHECK_FLAG(oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
))
777 "%s: Initializing [DD]: %pI4 with seqnum:%x , flags:%x",
778 ospf_get_name(oi
->ospf
), &nbr
->router_id
,
779 nbr
->dd_seqnum
, nbr
->dd_flags
);
780 ospf_db_desc_send(nbr
);
783 /* clear cryptographic sequence number */
784 if (state
== NSM_Down
)
785 nbr
->crypt_seqnum
= 0;
787 if (nbr
->bfd_session
)
788 ospf_bfd_trigger_event(nbr
, old_state
, state
);
790 /* Preserve old status? */
793 /* Execute NSM event process. */
794 void ospf_nsm_event(struct event
*thread
)
798 struct ospf_neighbor
*nbr
;
800 nbr
= EVENT_ARG(thread
);
801 event
= EVENT_VAL(thread
);
803 if (IS_DEBUG_OSPF(nsm
, NSM_EVENTS
))
804 zlog_debug("NSM[%s:%pI4:%s]: %s (%s)", IF_NAME(nbr
->oi
),
806 ospf_get_name(nbr
->oi
->ospf
),
807 lookup_msg(ospf_nsm_state_msg
, nbr
->state
, NULL
),
808 ospf_nsm_event_str
[event
]);
810 next_state
= NSM
[nbr
->state
][event
].next_state
;
813 if (NSM
[nbr
->state
][event
].func
!= NULL
) {
814 int func_state
= (*(NSM
[nbr
->state
][event
].func
))(nbr
);
816 if (NSM
[nbr
->state
][event
].next_state
== NSM_DependUpon
)
817 next_state
= func_state
;
818 else if (func_state
) {
819 /* There's a mismatch between the FSM tables and what an
821 * action/state-change function returned. State changes
823 * do not have conditional/DependUpon next-states should
825 * try set next_state.
828 EC_OSPF_FSM_INVALID_STATE
,
829 "NSM[%s:%pI4:%s]: %s (%s): Warning: action tried to change next_state to %s",
830 IF_NAME(nbr
->oi
), &nbr
->router_id
,
831 ospf_get_name(nbr
->oi
->ospf
),
832 lookup_msg(ospf_nsm_state_msg
, nbr
->state
,
834 ospf_nsm_event_str
[event
],
835 lookup_msg(ospf_nsm_state_msg
, func_state
,
840 assert(next_state
!= NSM_DependUpon
);
842 /* If state is changed. */
843 if (next_state
!= nbr
->state
) {
844 int old_state
= nbr
->state
;
846 nsm_notice_state_change(nbr
, next_state
, event
);
847 nsm_change_state(nbr
, next_state
);
849 hook_call(ospf_nsm_change
, nbr
, next_state
, old_state
);
852 /* Make sure timer is set. */
855 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
858 * Rather than encode knowledge here of which events lead to NBR
859 * delete, we take our cue from the NSM table, via the dummy
860 * 'Deleted' neighbour state.
862 if (nbr
->state
== NSM_Deleted
)
863 ospf_nbr_delete(nbr
);
866 /* Check loading state. */
867 void ospf_check_nbr_loading(struct ospf_neighbor
*nbr
)
869 if (nbr
->state
== NSM_Loading
) {
870 if (ospf_ls_request_isempty(nbr
))
871 OSPF_NSM_EVENT_SCHEDULE(nbr
, NSM_LoadingDone
);
872 else if (nbr
->ls_req_last
== NULL
)
873 ospf_ls_req_event(nbr
);