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
38 #include "ospfd/ospfd.h"
39 #include "ospfd/ospf_interface.h"
40 #include "ospfd/ospf_ism.h"
41 #include "ospfd/ospf_asbr.h"
42 #include "ospfd/ospf_lsa.h"
43 #include "ospfd/ospf_lsdb.h"
44 #include "ospfd/ospf_neighbor.h"
45 #include "ospfd/ospf_nsm.h"
46 #include "ospfd/ospf_network.h"
47 #include "ospfd/ospf_packet.h"
48 #include "ospfd/ospf_dump.h"
49 #include "ospfd/ospf_flood.h"
50 #include "ospfd/ospf_abr.h"
51 #include "ospfd/ospf_bfd.h"
52 #include "ospfd/ospf_gr.h"
53 #include "ospfd/ospf_errors.h"
55 DEFINE_HOOK(ospf_nsm_change
,
56 (struct ospf_neighbor
* on
, int state
, int oldstate
),
57 (on
, state
, oldstate
));
59 static void nsm_clear_adj(struct ospf_neighbor
*);
61 /* OSPF NSM Timer functions. */
62 static int ospf_inactivity_timer(struct thread
*thread
)
64 struct ospf_neighbor
*nbr
;
66 nbr
= THREAD_ARG(thread
);
67 nbr
->t_inactivity
= NULL
;
69 if (IS_DEBUG_OSPF(nsm
, NSM_TIMERS
))
70 zlog_debug("NSM[%s:%pI4:%s]: Timer (Inactivity timer expire)",
71 IF_NAME(nbr
->oi
), &nbr
->router_id
,
72 ospf_get_name(nbr
->oi
->ospf
));
74 /* Dont trigger NSM_InactivityTimer event , if the current
75 * router acting as HELPER for this neighbour.
77 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
78 OSPF_NSM_EVENT_SCHEDULE(nbr
, NSM_InactivityTimer
);
79 else if (IS_DEBUG_OSPF_GR
) {
81 "%s, Acting as HELPER for this neighbour, So restart the dead timer",
83 OSPF_NSM_TIMER_ON(nbr
->t_inactivity
, ospf_inactivity_timer
,
90 static int ospf_db_desc_timer(struct thread
*thread
)
92 struct ospf_neighbor
*nbr
;
94 nbr
= THREAD_ARG(thread
);
95 nbr
->t_db_desc
= NULL
;
97 if (IS_DEBUG_OSPF(nsm
, NSM_TIMERS
))
98 zlog_debug("NSM[%s:%pI4:%s]: Timer (DD Retransmit timer expire)",
99 IF_NAME(nbr
->oi
), &nbr
->src
,
100 ospf_get_name(nbr
->oi
->ospf
));
102 /* resent last send DD packet. */
103 assert(nbr
->last_send
);
104 ospf_db_desc_resend(nbr
);
106 /* DD Retransmit timer set. */
107 OSPF_NSM_TIMER_ON(nbr
->t_db_desc
, ospf_db_desc_timer
, nbr
->v_db_desc
);
112 /* Hook function called after ospf NSM event is occurred.
114 * Set/clear any timers whose condition is implicit to the neighbour
115 * state. There may be other timers which are set/unset according to other
118 * We rely on this function to properly clear timers in lower states,
119 * particularly before deleting a neighbour.
121 static void nsm_timer_set(struct ospf_neighbor
*nbr
)
123 switch (nbr
->state
) {
126 OSPF_NSM_TIMER_OFF(nbr
->t_inactivity
);
127 OSPF_NSM_TIMER_OFF(nbr
->t_hello_reply
);
132 OSPF_NSM_TIMER_OFF(nbr
->t_db_desc
);
133 OSPF_NSM_TIMER_OFF(nbr
->t_ls_upd
);
134 OSPF_NSM_TIMER_OFF(nbr
->t_ls_req
);
137 OSPF_NSM_TIMER_ON(nbr
->t_db_desc
, ospf_db_desc_timer
,
139 OSPF_NSM_TIMER_OFF(nbr
->t_ls_upd
);
140 OSPF_NSM_TIMER_OFF(nbr
->t_ls_req
);
143 OSPF_NSM_TIMER_ON(nbr
->t_ls_upd
, ospf_ls_upd_timer
,
145 if (!IS_SET_DD_MS(nbr
->dd_flags
))
146 OSPF_NSM_TIMER_OFF(nbr
->t_db_desc
);
151 OSPF_NSM_TIMER_OFF(nbr
->t_db_desc
);
156 /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
157 * the given neighbour
159 int nsm_should_adj(struct ospf_neighbor
*nbr
)
161 struct ospf_interface
*oi
= nbr
->oi
;
163 /* These network types must always form adjacencies. */
164 if (oi
->type
== OSPF_IFTYPE_POINTOPOINT
165 || oi
->type
== OSPF_IFTYPE_POINTOMULTIPOINT
166 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
167 /* Router itself is the DRouter or the BDRouter. */
168 || IPV4_ADDR_SAME(&oi
->address
->u
.prefix4
, &DR(oi
))
169 || IPV4_ADDR_SAME(&oi
->address
->u
.prefix4
, &BDR(oi
))
170 /* Neighboring Router is the DRouter or the BDRouter. */
171 || IPV4_ADDR_SAME(&nbr
->address
.u
.prefix4
, &DR(oi
))
172 || IPV4_ADDR_SAME(&nbr
->address
.u
.prefix4
, &BDR(oi
)))
178 /* OSPF NSM functions. */
179 static int nsm_packet_received(struct ospf_neighbor
*nbr
)
181 /* Start or Restart Inactivity Timer. */
182 OSPF_NSM_TIMER_OFF(nbr
->t_inactivity
);
184 OSPF_NSM_TIMER_ON(nbr
->t_inactivity
, ospf_inactivity_timer
,
187 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
)
188 OSPF_POLL_TIMER_OFF(nbr
->nbr_nbma
->t_poll
);
190 /* Send proactive ARP requests */
191 if (nbr
->state
< NSM_Exchange
)
192 ospf_proactively_arp(nbr
);
197 static int nsm_start(struct ospf_neighbor
*nbr
)
200 OSPF_POLL_TIMER_OFF(nbr
->nbr_nbma
->t_poll
);
202 OSPF_NSM_TIMER_OFF(nbr
->t_inactivity
);
204 OSPF_NSM_TIMER_ON(nbr
->t_inactivity
, ospf_inactivity_timer
,
207 /* Send proactive ARP requests */
208 ospf_proactively_arp(nbr
);
213 static int nsm_twoway_received(struct ospf_neighbor
*nbr
)
215 int adj
= nsm_should_adj(nbr
);
217 /* Send proactive ARP requests */
219 ospf_proactively_arp(nbr
);
221 return (adj
? NSM_ExStart
: NSM_TwoWay
);
224 int ospf_db_summary_count(struct ospf_neighbor
*nbr
)
226 return ospf_lsdb_count_all(&nbr
->db_sum
);
229 int ospf_db_summary_isempty(struct ospf_neighbor
*nbr
)
231 return ospf_lsdb_isempty(&nbr
->db_sum
);
234 static int ospf_db_summary_add(struct ospf_neighbor
*nbr
, struct ospf_lsa
*lsa
)
236 switch (lsa
->data
->type
) {
237 case OSPF_OPAQUE_LINK_LSA
:
238 /* Exclude type-9 LSAs that does not have the same "oi" with
240 if (ospf_if_exists(lsa
->oi
) != nbr
->oi
)
243 case OSPF_OPAQUE_AREA_LSA
:
245 * It is assured by the caller function "nsm_negotiation_done()"
246 * that every given LSA belongs to the same area with "nbr".
249 case OSPF_OPAQUE_AS_LSA
:
254 /* Stay away from any Local Translated Type-7 LSAs */
255 if (CHECK_FLAG(lsa
->flags
, OSPF_LSA_LOCAL_XLT
))
258 if (IS_LSA_MAXAGE(lsa
))
259 ospf_ls_retransmit_add(nbr
, lsa
);
261 ospf_lsdb_add(&nbr
->db_sum
, lsa
);
266 void ospf_db_summary_clear(struct ospf_neighbor
*nbr
)
268 struct ospf_lsdb
*lsdb
;
272 for (i
= OSPF_MIN_LSA
; i
< OSPF_MAX_LSA
; i
++) {
273 struct route_table
*table
= lsdb
->type
[i
].db
;
274 struct route_node
*rn
;
276 for (rn
= route_top(table
); rn
; rn
= route_next(rn
))
278 ospf_lsdb_delete(&nbr
->db_sum
, rn
->info
);
283 /* The area link state database consists of the router-LSAs,
284 network-LSAs and summary-LSAs contained in the area structure,
285 along with the AS-external-LSAs contained in the global structure.
286 AS-external-LSAs are omitted from a virtual neighbor's Database
287 summary list. AS-external-LSAs are omitted from the Database
288 summary list if the area has been configured as a stub. */
289 static int nsm_negotiation_done(struct ospf_neighbor
*nbr
)
291 struct ospf_area
*area
= nbr
->oi
->area
;
292 struct ospf_lsa
*lsa
;
293 struct route_node
*rn
;
295 /* Send proactive ARP requests */
296 ospf_proactively_arp(nbr
);
298 LSDB_LOOP (ROUTER_LSDB(area
), rn
, lsa
)
299 ospf_db_summary_add(nbr
, lsa
);
300 LSDB_LOOP (NETWORK_LSDB(area
), rn
, lsa
)
301 ospf_db_summary_add(nbr
, lsa
);
302 LSDB_LOOP (SUMMARY_LSDB(area
), rn
, lsa
)
303 ospf_db_summary_add(nbr
, lsa
);
305 /* Process only if the neighbor is opaque capable. */
306 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
)) {
307 LSDB_LOOP (OPAQUE_LINK_LSDB(area
), rn
, lsa
)
308 ospf_db_summary_add(nbr
, lsa
);
309 LSDB_LOOP (OPAQUE_AREA_LSDB(area
), rn
, lsa
)
310 ospf_db_summary_add(nbr
, lsa
);
313 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_NP
)) {
314 LSDB_LOOP (NSSA_LSDB(area
), rn
, lsa
)
315 ospf_db_summary_add(nbr
, lsa
);
318 /* For Stub/NSSA area, we should not send Type-4 and Type-5 LSAs */
319 if (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
320 && area
->external_routing
== OSPF_AREA_DEFAULT
) {
321 LSDB_LOOP (ASBR_SUMMARY_LSDB(area
), rn
, lsa
)
322 ospf_db_summary_add(nbr
, lsa
);
323 LSDB_LOOP (EXTERNAL_LSDB(nbr
->oi
->ospf
), rn
, lsa
)
324 ospf_db_summary_add(nbr
, lsa
);
327 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
)
328 && (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
329 && area
->external_routing
== OSPF_AREA_DEFAULT
))
330 LSDB_LOOP (OPAQUE_AS_LSDB(nbr
->oi
->ospf
), rn
, lsa
)
331 ospf_db_summary_add(nbr
, lsa
);
336 static int 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
);
348 static int nsm_adj_ok(struct ospf_neighbor
*nbr
)
350 int next_state
= nbr
->state
;
351 int adj
= nsm_should_adj(nbr
);
353 if (nbr
->state
== NSM_TwoWay
&& adj
== 1) {
354 next_state
= NSM_ExStart
;
356 /* Send proactive ARP requests */
357 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)
368 static void nsm_clear_adj(struct ospf_neighbor
*nbr
)
370 /* Clear Database Summary list. */
371 if (!ospf_db_summary_isempty(nbr
))
372 ospf_db_summary_clear(nbr
);
374 /* Clear Link State Request list. */
375 if (!ospf_ls_request_isempty(nbr
))
376 ospf_ls_request_delete_all(nbr
);
378 /* Clear Link State Retransmission list. */
379 if (!ospf_ls_retransmit_isempty(nbr
))
380 ospf_ls_retransmit_clear(nbr
);
382 if (CHECK_FLAG(nbr
->options
, OSPF_OPTION_O
))
383 UNSET_FLAG(nbr
->options
, OSPF_OPTION_O
);
386 static int nsm_kill_nbr(struct ospf_neighbor
*nbr
)
388 /* killing nbr_self is invalid */
389 if (nbr
== nbr
->oi
->nbr_self
) {
390 assert(nbr
!= nbr
->oi
->nbr_self
);
394 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
!= NULL
) {
395 struct ospf_nbr_nbma
*nbr_nbma
= nbr
->nbr_nbma
;
397 nbr_nbma
->nbr
= NULL
;
398 nbr_nbma
->state_change
= nbr
->state_change
;
400 nbr
->nbr_nbma
= NULL
;
402 OSPF_POLL_TIMER_ON(nbr_nbma
->t_poll
, ospf_poll_timer
,
405 if (IS_DEBUG_OSPF(nsm
, NSM_EVENTS
))
407 "NSM[%s:%pI4:%s]: Down (PollIntervalTimer scheduled)",
409 &nbr
->address
.u
.prefix4
,
410 ospf_get_name(nbr
->oi
->ospf
));
416 /* Neighbor State Machine */
418 int (*func
)(struct ospf_neighbor
*);
420 } NSM
[OSPF_NSM_STATE_MAX
][OSPF_NSM_EVENT_MAX
] = {
422 /* DependUpon: dummy state. */
423 {NULL
, NSM_DependUpon
}, /* NoEvent */
424 {NULL
, NSM_DependUpon
}, /* PacketReceived */
425 {NULL
, NSM_DependUpon
}, /* Start */
426 {NULL
, NSM_DependUpon
}, /* 2-WayReceived */
427 {NULL
, NSM_DependUpon
}, /* NegotiationDone */
428 {NULL
, NSM_DependUpon
}, /* ExchangeDone */
429 {NULL
, NSM_DependUpon
}, /* BadLSReq */
430 {NULL
, NSM_DependUpon
}, /* LoadingDone */
431 {NULL
, NSM_DependUpon
}, /* AdjOK? */
432 {NULL
, NSM_DependUpon
}, /* SeqNumberMismatch */
433 {NULL
, NSM_DependUpon
}, /* 1-WayReceived */
434 {NULL
, NSM_DependUpon
}, /* KillNbr */
435 {NULL
, NSM_DependUpon
}, /* InactivityTimer */
436 {NULL
, NSM_DependUpon
}, /* LLDown */
439 /* Deleted: dummy state. */
440 {NULL
, NSM_Deleted
}, /* NoEvent */
441 {NULL
, NSM_Deleted
}, /* PacketReceived */
442 {NULL
, NSM_Deleted
}, /* Start */
443 {NULL
, NSM_Deleted
}, /* 2-WayReceived */
444 {NULL
, NSM_Deleted
}, /* NegotiationDone */
445 {NULL
, NSM_Deleted
}, /* ExchangeDone */
446 {NULL
, NSM_Deleted
}, /* BadLSReq */
447 {NULL
, NSM_Deleted
}, /* LoadingDone */
448 {NULL
, NSM_Deleted
}, /* AdjOK? */
449 {NULL
, NSM_Deleted
}, /* SeqNumberMismatch */
450 {NULL
, NSM_Deleted
}, /* 1-WayReceived */
451 {NULL
, NSM_Deleted
}, /* KillNbr */
452 {NULL
, NSM_Deleted
}, /* InactivityTimer */
453 {NULL
, NSM_Deleted
}, /* LLDown */
457 {NULL
, NSM_DependUpon
}, /* NoEvent */
458 {nsm_packet_received
, NSM_Init
}, /* PacketReceived */
459 {nsm_start
, NSM_Attempt
}, /* Start */
460 {NULL
, NSM_Down
}, /* 2-WayReceived */
461 {NULL
, NSM_Down
}, /* NegotiationDone */
462 {NULL
, NSM_Down
}, /* ExchangeDone */
463 {NULL
, NSM_Down
}, /* BadLSReq */
464 {NULL
, NSM_Down
}, /* LoadingDone */
465 {NULL
, NSM_Down
}, /* AdjOK? */
466 {NULL
, NSM_Down
}, /* SeqNumberMismatch */
467 {NULL
, NSM_Down
}, /* 1-WayReceived */
468 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
469 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
470 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
474 {NULL
, NSM_DependUpon
}, /* NoEvent */
475 {nsm_packet_received
, NSM_Init
}, /* PacketReceived */
476 {NULL
, NSM_Attempt
}, /* Start */
477 {NULL
, NSM_Attempt
}, /* 2-WayReceived */
478 {NULL
, NSM_Attempt
}, /* NegotiationDone */
479 {NULL
, NSM_Attempt
}, /* ExchangeDone */
480 {NULL
, NSM_Attempt
}, /* BadLSReq */
481 {NULL
, NSM_Attempt
}, /* LoadingDone */
482 {NULL
, NSM_Attempt
}, /* AdjOK? */
483 {NULL
, NSM_Attempt
}, /* SeqNumberMismatch */
484 {NULL
, NSM_Attempt
}, /* 1-WayReceived */
485 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
486 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
487 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
491 {NULL
, NSM_DependUpon
}, /* NoEvent */
492 {nsm_packet_received
, NSM_Init
}, /* PacketReceived */
493 {NULL
, NSM_Init
}, /* Start */
494 {nsm_twoway_received
, NSM_DependUpon
}, /* 2-WayReceived */
495 {NULL
, NSM_Init
}, /* NegotiationDone */
496 {NULL
, NSM_Init
}, /* ExchangeDone */
497 {NULL
, NSM_Init
}, /* BadLSReq */
498 {NULL
, NSM_Init
}, /* LoadingDone */
499 {NULL
, NSM_Init
}, /* AdjOK? */
500 {NULL
, NSM_Init
}, /* SeqNumberMismatch */
501 {NULL
, NSM_Init
}, /* 1-WayReceived */
502 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
503 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
504 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
508 {NULL
, NSM_DependUpon
}, /* NoEvent */
509 {nsm_packet_received
, NSM_TwoWay
}, /* HelloReceived */
510 {NULL
, NSM_TwoWay
}, /* Start */
511 {NULL
, NSM_TwoWay
}, /* 2-WayReceived */
512 {NULL
, NSM_TwoWay
}, /* NegotiationDone */
513 {NULL
, NSM_TwoWay
}, /* ExchangeDone */
514 {NULL
, NSM_TwoWay
}, /* BadLSReq */
515 {NULL
, NSM_TwoWay
}, /* LoadingDone */
516 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
517 {NULL
, NSM_TwoWay
}, /* SeqNumberMismatch */
518 {NULL
, NSM_Init
}, /* 1-WayReceived */
519 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
520 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
521 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
525 {NULL
, NSM_DependUpon
}, /* NoEvent */
526 {nsm_packet_received
, NSM_ExStart
}, /* PacaketReceived */
527 {NULL
, NSM_ExStart
}, /* Start */
528 {NULL
, NSM_ExStart
}, /* 2-WayReceived */
529 {nsm_negotiation_done
, NSM_Exchange
}, /* NegotiationDone */
530 {NULL
, NSM_ExStart
}, /* ExchangeDone */
531 {NULL
, NSM_ExStart
}, /* BadLSReq */
532 {NULL
, NSM_ExStart
}, /* LoadingDone */
533 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
534 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
535 {NULL
, NSM_Init
}, /* 1-WayReceived */
536 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
537 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
538 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
542 {NULL
, NSM_DependUpon
}, /* NoEvent */
543 {nsm_packet_received
, NSM_Exchange
}, /* PacketReceived */
544 {NULL
, NSM_Exchange
}, /* Start */
545 {NULL
, NSM_Exchange
}, /* 2-WayReceived */
546 {NULL
, NSM_Exchange
}, /* NegotiationDone */
547 {nsm_exchange_done
, NSM_DependUpon
}, /* ExchangeDone */
548 {NULL
, NSM_ExStart
}, /* BadLSReq */
549 {NULL
, NSM_Exchange
}, /* LoadingDone */
550 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
551 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
552 {NULL
, NSM_Init
}, /* 1-WayReceived */
553 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
554 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
555 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
559 {NULL
, NSM_DependUpon
}, /* NoEvent */
560 {nsm_packet_received
, NSM_Loading
}, /* PacketReceived */
561 {NULL
, NSM_Loading
}, /* Start */
562 {NULL
, NSM_Loading
}, /* 2-WayReceived */
563 {NULL
, NSM_Loading
}, /* NegotiationDone */
564 {NULL
, NSM_Loading
}, /* ExchangeDone */
565 {NULL
, NSM_ExStart
}, /* BadLSReq */
566 {NULL
, NSM_Full
}, /* LoadingDone */
567 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
568 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
569 {NULL
, NSM_Init
}, /* 1-WayReceived */
570 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
571 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
572 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
576 {NULL
, NSM_DependUpon
}, /* NoEvent */
577 {nsm_packet_received
, NSM_Full
}, /* PacketReceived */
578 {NULL
, NSM_Full
}, /* Start */
579 {NULL
, NSM_Full
}, /* 2-WayReceived */
580 {NULL
, NSM_Full
}, /* NegotiationDone */
581 {NULL
, NSM_Full
}, /* ExchangeDone */
582 {NULL
, NSM_ExStart
}, /* BadLSReq */
583 {NULL
, NSM_Full
}, /* LoadingDone */
584 {nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
585 {NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
586 {NULL
, NSM_Init
}, /* 1-WayReceived */
587 {nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
588 {nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
589 {nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
593 static const char *const ospf_nsm_event_str
[] = {
594 "NoEvent", "PacketReceived", "Start",
595 "2-WayReceived", "NegotiationDone", "ExchangeDone",
596 "BadLSReq", "LoadingDone", "AdjOK?",
597 "SeqNumberMismatch", "1-WayReceived", "KillNbr",
598 "InactivityTimer", "LLDown",
601 static void nsm_notice_state_change(struct ospf_neighbor
*nbr
, int next_state
,
604 /* Logging change of status. */
605 if (IS_DEBUG_OSPF(nsm
, NSM_STATUS
))
606 zlog_debug("NSM[%s:%pI4:%s]: State change %s -> %s (%s)",
607 IF_NAME(nbr
->oi
), &nbr
->router_id
,
608 ospf_get_name(nbr
->oi
->ospf
),
609 lookup_msg(ospf_nsm_state_msg
, nbr
->state
, NULL
),
610 lookup_msg(ospf_nsm_state_msg
, next_state
, NULL
),
611 ospf_nsm_event_str
[event
]);
613 /* Optionally notify about adjacency changes */
614 if (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_CHANGES
)
615 && (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
)
616 || (next_state
== NSM_Full
) || (next_state
< nbr
->state
)))
617 zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
619 ospf_get_name(nbr
->oi
->ospf
), IF_NAME(nbr
->oi
),
620 lookup_msg(ospf_nsm_state_msg
, nbr
->state
, NULL
),
621 lookup_msg(ospf_nsm_state_msg
, next_state
, NULL
),
622 ospf_nsm_event_str
[event
]);
625 if (next_state
> nbr
->state
)
626 monotime(&nbr
->ts_last_progress
);
627 else /* regression in NSM */
629 monotime(&nbr
->ts_last_regress
);
630 nbr
->last_regress_str
= ospf_nsm_event_str
[event
];
634 static void nsm_change_state(struct ospf_neighbor
*nbr
, int state
)
636 struct ospf_interface
*oi
= nbr
->oi
;
637 struct ospf_area
*vl_area
= NULL
;
640 /* Preserve old status. */
641 old_state
= nbr
->state
;
643 /* Change to new status. */
649 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
650 vl_area
= ospf_area_lookup_by_area_id(oi
->ospf
,
651 oi
->vl_data
->vl_area_id
);
653 /* Generate NeighborChange ISM event.
655 * In response to NeighborChange, DR election is rerun. The information
656 * from the election process is required by the router-lsa construction.
658 * Therefore, trigger the event prior to refreshing the LSAs. */
663 if ((old_state
< NSM_TwoWay
&& state
>= NSM_TwoWay
)
664 || (old_state
>= NSM_TwoWay
&& state
< NSM_TwoWay
))
665 OSPF_ISM_EVENT_EXECUTE(oi
, ISM_NeighborChange
);
668 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc.
673 /* One of the neighboring routers changes to/from the FULL state. */
674 if ((old_state
!= NSM_Full
&& state
== NSM_Full
)
675 || (old_state
== NSM_Full
&& state
!= NSM_Full
)) {
676 if (state
== NSM_Full
) {
678 oi
->area
->full_nbrs
++;
680 ospf_check_abr_status(oi
->ospf
);
682 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
683 if (++vl_area
->full_vls
== 1)
684 ospf_schedule_abr_task(oi
->ospf
);
687 oi
->area
->full_nbrs
--;
689 ospf_check_abr_status(oi
->ospf
);
691 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
692 if (vl_area
->full_vls
> 0)
693 if (--vl_area
->full_vls
== 0)
694 ospf_schedule_abr_task(
698 if (CHECK_FLAG(oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
))
700 "%s:[%pI4:%s], %s -> %s): scheduling new router-LSA origination",
701 __func__
, &nbr
->router_id
,
702 ospf_get_name(oi
->ospf
),
703 lookup_msg(ospf_nsm_state_msg
, old_state
, NULL
),
704 lookup_msg(ospf_nsm_state_msg
, state
, NULL
));
706 /* Dont originate router LSA if the current
707 * router is acting as a HELPER for this neighbour.
709 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
))
710 ospf_router_lsa_update_area(oi
->area
);
712 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
) {
713 vl_area
= ospf_area_lookup_by_area_id(
714 oi
->ospf
, oi
->vl_data
->vl_area_id
);
717 ospf_router_lsa_update_area(vl_area
);
720 /* Dont originate/flush network LSA if the current
721 * router is acting as a HELPER for this neighbour.
723 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr
)) {
724 /* Originate network-LSA. */
725 if (oi
->state
== ISM_DR
) {
726 if (oi
->network_lsa_self
727 && oi
->full_nbrs
== 0) {
729 oi
->network_lsa_self
, oi
->area
);
730 ospf_lsa_unlock(&oi
->network_lsa_self
);
731 oi
->network_lsa_self
= NULL
;
733 ospf_network_lsa_update(oi
);
737 if (state
== NSM_Full
&& oi
->ospf
->gr_info
.restart_in_progress
)
738 ospf_gr_check_adjs(oi
->ospf
);
741 ospf_opaque_nsm_change(nbr
, old_state
);
743 /* State changes from > ExStart to <= ExStart should clear any Exchange
744 * or Full/LSA Update related lists and state.
745 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
747 if ((old_state
> NSM_ExStart
) && (state
<= NSM_ExStart
))
750 /* Start DD exchange protocol */
751 if (state
== NSM_ExStart
) {
752 if (nbr
->dd_seqnum
== 0)
753 nbr
->dd_seqnum
= (uint32_t)frr_weak_random();
758 OSPF_DD_FLAG_I
| OSPF_DD_FLAG_M
| OSPF_DD_FLAG_MS
;
759 if (CHECK_FLAG(oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
))
761 "%s: Initializing [DD]: %pI4 with seqnum:%x , flags:%x",
762 (oi
->ospf
->name
) ? oi
->ospf
->name
764 &nbr
->router_id
, nbr
->dd_seqnum
,
766 ospf_db_desc_send(nbr
);
769 /* clear cryptographic sequence number */
770 if (state
== NSM_Down
)
771 nbr
->crypt_seqnum
= 0;
773 if (nbr
->bfd_session
)
774 ospf_bfd_trigger_event(nbr
, old_state
, state
);
776 /* Preserve old status? */
779 /* Execute NSM event process. */
780 int ospf_nsm_event(struct thread
*thread
)
784 struct ospf_neighbor
*nbr
;
786 nbr
= THREAD_ARG(thread
);
787 event
= THREAD_VAL(thread
);
789 if (IS_DEBUG_OSPF(nsm
, NSM_EVENTS
))
790 zlog_debug("NSM[%s:%pI4:%s]: %s (%s)", IF_NAME(nbr
->oi
),
792 ospf_get_name(nbr
->oi
->ospf
),
793 lookup_msg(ospf_nsm_state_msg
, nbr
->state
, NULL
),
794 ospf_nsm_event_str
[event
]);
796 next_state
= NSM
[nbr
->state
][event
].next_state
;
799 if (NSM
[nbr
->state
][event
].func
!= NULL
) {
800 int func_state
= (*(NSM
[nbr
->state
][event
].func
))(nbr
);
802 if (NSM
[nbr
->state
][event
].next_state
== NSM_DependUpon
)
803 next_state
= func_state
;
804 else if (func_state
) {
805 /* There's a mismatch between the FSM tables and what an
807 * action/state-change function returned. State changes
809 * do not have conditional/DependUpon next-states should
811 * try set next_state.
814 EC_OSPF_FSM_INVALID_STATE
,
815 "NSM[%s:%pI4:%s]: %s (%s): Warning: action tried to change next_state to %s",
816 IF_NAME(nbr
->oi
), &nbr
->router_id
,
817 ospf_get_name(nbr
->oi
->ospf
),
818 lookup_msg(ospf_nsm_state_msg
, nbr
->state
,
820 ospf_nsm_event_str
[event
],
821 lookup_msg(ospf_nsm_state_msg
, func_state
,
826 assert(next_state
!= NSM_DependUpon
);
828 /* If state is changed. */
829 if (next_state
!= nbr
->state
) {
830 int old_state
= nbr
->state
;
832 nsm_notice_state_change(nbr
, next_state
, event
);
833 nsm_change_state(nbr
, next_state
);
835 hook_call(ospf_nsm_change
, nbr
, next_state
, old_state
);
838 /* Make sure timer is set. */
841 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
844 * Rather than encode knowledge here of which events lead to NBR
845 * delete, we take our cue from the NSM table, via the dummy
846 * 'Deleted' neighbour state.
848 if (nbr
->state
== NSM_Deleted
)
849 ospf_nbr_delete(nbr
);
854 /* Check loading state. */
855 void ospf_check_nbr_loading(struct ospf_neighbor
*nbr
)
857 if (nbr
->state
== NSM_Loading
) {
858 if (ospf_ls_request_isempty(nbr
))
859 OSPF_NSM_EVENT_SCHEDULE(nbr
, NSM_LoadingDone
);
860 else if (nbr
->ls_req_last
== NULL
)
861 ospf_ls_req_event(nbr
);