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
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_snmp.h"
52 #include "ospfd/ospf_bfd.h"
54 static void nsm_clear_adj (struct ospf_neighbor
*);
56 /* OSPF NSM Timer functions. */
58 ospf_inactivity_timer (struct thread
*thread
)
60 struct ospf_neighbor
*nbr
;
62 nbr
= THREAD_ARG (thread
);
63 nbr
->t_inactivity
= NULL
;
65 if (IS_DEBUG_OSPF (nsm
, NSM_TIMERS
))
66 zlog (NULL
, LOG_DEBUG
, "NSM[%s:%s]: Timer (Inactivity timer expire)",
67 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
));
69 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_InactivityTimer
);
75 ospf_db_desc_timer (struct thread
*thread
)
77 struct ospf_neighbor
*nbr
;
79 nbr
= THREAD_ARG (thread
);
80 nbr
->t_db_desc
= NULL
;
82 if (IS_DEBUG_OSPF (nsm
, NSM_TIMERS
))
83 zlog (NULL
, LOG_DEBUG
, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
84 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->src
));
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
);
96 /* Hook function called after ospf NSM event is occured.
98 * Set/clear any timers whose condition is implicit to the neighbour
99 * state. There may be other timers which are set/unset according to other
102 * We rely on this function to properly clear timers in lower states,
103 * particularly before deleting a neighbour.
106 nsm_timer_set (struct ospf_neighbor
*nbr
)
112 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
113 OSPF_NSM_TIMER_OFF (nbr
->t_hello_reply
);
117 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
118 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
119 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
122 OSPF_NSM_TIMER_ON (nbr
->t_db_desc
, ospf_db_desc_timer
, nbr
->v_db_desc
);
123 OSPF_NSM_TIMER_OFF (nbr
->t_ls_upd
);
124 OSPF_NSM_TIMER_OFF (nbr
->t_ls_req
);
127 OSPF_NSM_TIMER_ON (nbr
->t_ls_upd
, ospf_ls_upd_timer
, nbr
->v_ls_upd
);
128 if (!IS_SET_DD_MS (nbr
->dd_flags
))
129 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
134 OSPF_NSM_TIMER_OFF (nbr
->t_db_desc
);
139 /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
140 * the given neighbour
143 nsm_should_adj (struct ospf_neighbor
*nbr
)
145 struct ospf_interface
*oi
= nbr
->oi
;
147 /* These network types must always form adjacencies. */
148 if (oi
->type
== OSPF_IFTYPE_POINTOPOINT
149 || oi
->type
== OSPF_IFTYPE_POINTOMULTIPOINT
150 || oi
->type
== OSPF_IFTYPE_VIRTUALLINK
151 /* Router itself is the DRouter or the BDRouter. */
152 || IPV4_ADDR_SAME (&oi
->address
->u
.prefix4
, &DR (oi
))
153 || IPV4_ADDR_SAME (&oi
->address
->u
.prefix4
, &BDR (oi
))
154 /* Neighboring Router is the DRouter or the BDRouter. */
155 || IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &DR (oi
))
156 || IPV4_ADDR_SAME (&nbr
->address
.u
.prefix4
, &BDR (oi
)))
162 /* OSPF NSM functions. */
164 nsm_packet_received (struct ospf_neighbor
*nbr
)
166 /* Start or Restart Inactivity Timer. */
167 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
169 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
172 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
)
173 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
175 /* Send proactive ARP requests */
176 if (nbr
->state
< NSM_Exchange
)
177 ospf_proactively_arp (nbr
);
183 nsm_start (struct ospf_neighbor
*nbr
)
186 OSPF_POLL_TIMER_OFF (nbr
->nbr_nbma
->t_poll
);
188 OSPF_NSM_TIMER_OFF (nbr
->t_inactivity
);
190 OSPF_NSM_TIMER_ON (nbr
->t_inactivity
, ospf_inactivity_timer
,
193 /* Send proactive ARP requests */
194 ospf_proactively_arp (nbr
);
200 nsm_twoway_received (struct ospf_neighbor
*nbr
)
202 int adj
= nsm_should_adj (nbr
);
204 /* Send proactive ARP requests */
206 ospf_proactively_arp (nbr
);
208 return (adj
? NSM_ExStart
: NSM_TwoWay
);
212 ospf_db_summary_count (struct ospf_neighbor
*nbr
)
214 return ospf_lsdb_count_all (&nbr
->db_sum
);
218 ospf_db_summary_isempty (struct ospf_neighbor
*nbr
)
220 return ospf_lsdb_isempty (&nbr
->db_sum
);
224 ospf_db_summary_add (struct ospf_neighbor
*nbr
, struct ospf_lsa
*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
:
244 /* Stay away from any Local Translated Type-7 LSAs */
245 if (CHECK_FLAG (lsa
->flags
, OSPF_LSA_LOCAL_XLT
))
248 if (IS_LSA_MAXAGE (lsa
))
249 ospf_ls_retransmit_add (nbr
, lsa
);
251 ospf_lsdb_add (&nbr
->db_sum
, lsa
);
257 ospf_db_summary_clear (struct ospf_neighbor
*nbr
)
259 struct ospf_lsdb
*lsdb
;
263 for (i
= OSPF_MIN_LSA
; i
< OSPF_MAX_LSA
; i
++)
265 struct route_table
*table
= lsdb
->type
[i
].db
;
266 struct route_node
*rn
;
268 for (rn
= route_top (table
); rn
; rn
= route_next (rn
))
270 ospf_lsdb_delete (&nbr
->db_sum
, rn
->info
);
276 /* The area link state database consists of the router-LSAs,
277 network-LSAs and summary-LSAs contained in the area structure,
278 along with the AS-external-LSAs contained in the global structure.
279 AS-external-LSAs are omitted from a virtual neighbor's Database
280 summary list. AS-external-LSAs are omitted from the Database
281 summary list if the area has been configured as a stub. */
283 nsm_negotiation_done (struct ospf_neighbor
*nbr
)
285 struct ospf_area
*area
= nbr
->oi
->area
;
286 struct ospf_lsa
*lsa
;
287 struct route_node
*rn
;
289 /* Send proactive ARP requests */
290 ospf_proactively_arp (nbr
);
292 LSDB_LOOP (ROUTER_LSDB (area
), rn
, lsa
)
293 ospf_db_summary_add (nbr
, lsa
);
294 LSDB_LOOP (NETWORK_LSDB (area
), rn
, lsa
)
295 ospf_db_summary_add (nbr
, lsa
);
296 LSDB_LOOP (SUMMARY_LSDB (area
), rn
, lsa
)
297 ospf_db_summary_add (nbr
, lsa
);
298 LSDB_LOOP (ASBR_SUMMARY_LSDB (area
), rn
, lsa
)
299 ospf_db_summary_add (nbr
, lsa
);
301 /* Process only if the neighbor is opaque capable. */
302 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
304 LSDB_LOOP (OPAQUE_LINK_LSDB (area
), rn
, lsa
)
305 ospf_db_summary_add (nbr
, lsa
);
306 LSDB_LOOP (OPAQUE_AREA_LSDB (area
), rn
, lsa
)
307 ospf_db_summary_add (nbr
, lsa
);
310 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_NP
))
312 LSDB_LOOP (NSSA_LSDB (area
), rn
, lsa
)
313 ospf_db_summary_add (nbr
, lsa
);
316 if (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
317 && area
->external_routing
== OSPF_AREA_DEFAULT
)
318 LSDB_LOOP (EXTERNAL_LSDB (nbr
->oi
->ospf
), rn
, lsa
)
319 ospf_db_summary_add (nbr
, lsa
);
321 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
)
322 && (nbr
->oi
->type
!= OSPF_IFTYPE_VIRTUALLINK
323 && area
->external_routing
== OSPF_AREA_DEFAULT
))
324 LSDB_LOOP (OPAQUE_AS_LSDB (nbr
->oi
->ospf
), rn
, lsa
)
325 ospf_db_summary_add (nbr
, lsa
);
331 nsm_exchange_done (struct ospf_neighbor
*nbr
)
333 if (ospf_ls_request_isempty (nbr
))
336 /* Send Link State Request. */
337 if (nbr
->t_ls_req
== NULL
)
338 ospf_ls_req_send (nbr
);
344 nsm_adj_ok (struct ospf_neighbor
*nbr
)
346 int next_state
= nbr
->state
;
347 int adj
= nsm_should_adj (nbr
);
349 if (nbr
->state
== NSM_TwoWay
&& adj
== 1)
351 next_state
= NSM_ExStart
;
353 /* Send proactive ARP requests */
354 ospf_proactively_arp (nbr
);
356 else if (nbr
->state
>= NSM_ExStart
&& adj
== 0)
357 next_state
= NSM_TwoWay
;
362 /* Clear adjacency related state for a neighbour, intended where nbr
363 * transitions from > ExStart (i.e. a Full or forming adjacency)
367 nsm_clear_adj (struct ospf_neighbor
*nbr
)
369 /* Clear Database Summary list. */
370 if (!ospf_db_summary_isempty (nbr
))
371 ospf_db_summary_clear (nbr
);
373 /* Clear Link State Request list. */
374 if (!ospf_ls_request_isempty (nbr
))
375 ospf_ls_request_delete_all (nbr
);
377 /* Clear Link State Retransmission list. */
378 if (!ospf_ls_retransmit_isempty (nbr
))
379 ospf_ls_retransmit_clear (nbr
);
381 if (CHECK_FLAG (nbr
->options
, OSPF_OPTION_O
))
382 UNSET_FLAG (nbr
->options
, OSPF_OPTION_O
);
386 nsm_kill_nbr (struct ospf_neighbor
*nbr
)
388 /* killing nbr_self is invalid */
389 if (nbr
== nbr
->oi
->nbr_self
)
391 assert (nbr
!= nbr
->oi
->nbr_self
);
395 if (nbr
->oi
->type
== OSPF_IFTYPE_NBMA
&& nbr
->nbr_nbma
!= NULL
)
397 struct ospf_nbr_nbma
*nbr_nbma
= nbr
->nbr_nbma
;
399 nbr_nbma
->nbr
= NULL
;
400 nbr_nbma
->state_change
= nbr
->state_change
;
402 nbr
->nbr_nbma
= NULL
;
404 OSPF_POLL_TIMER_ON (nbr_nbma
->t_poll
, ospf_poll_timer
,
407 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
408 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
409 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->address
.u
.prefix4
));
415 /* Neighbor State Machine */
417 int (*func
) (struct ospf_neighbor
*);
419 } 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 */
575 { NULL
, NSM_DependUpon
}, /* NoEvent */
576 { nsm_packet_received
, NSM_Full
}, /* PacketReceived */
577 { NULL
, NSM_Full
}, /* Start */
578 { NULL
, NSM_Full
}, /* 2-WayReceived */
579 { NULL
, NSM_Full
}, /* NegotiationDone */
580 { NULL
, NSM_Full
}, /* ExchangeDone */
581 { NULL
, NSM_ExStart
}, /* BadLSReq */
582 { NULL
, NSM_Full
}, /* LoadingDone */
583 { nsm_adj_ok
, NSM_DependUpon
}, /* AdjOK? */
584 { NULL
, NSM_ExStart
}, /* SeqNumberMismatch */
585 { NULL
, NSM_Init
}, /* 1-WayReceived */
586 { nsm_kill_nbr
, NSM_Deleted
}, /* KillNbr */
587 { nsm_kill_nbr
, NSM_Deleted
}, /* InactivityTimer */
588 { nsm_kill_nbr
, NSM_Deleted
}, /* LLDown */
592 static const char *ospf_nsm_event_str
[] =
611 nsm_notice_state_change (struct ospf_neighbor
*nbr
, int next_state
, int event
)
613 /* Logging change of status. */
614 if (IS_DEBUG_OSPF (nsm
, NSM_STATUS
))
615 zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)",
616 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
),
617 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
618 LOOKUP (ospf_nsm_state_msg
, next_state
),
619 ospf_nsm_event_str
[event
]);
621 /* Optionally notify about adjacency changes */
622 if (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_CHANGES
) &&
623 (CHECK_FLAG(nbr
->oi
->ospf
->config
, OSPF_LOG_ADJACENCY_DETAIL
) ||
624 (next_state
== NSM_Full
) || (next_state
< nbr
->state
)))
625 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)",
626 inet_ntoa (nbr
->router_id
), IF_NAME (nbr
->oi
),
627 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
628 LOOKUP (ospf_nsm_state_msg
, next_state
),
629 ospf_nsm_event_str
[event
]);
632 if (next_state
> nbr
->state
)
633 nbr
->ts_last_progress
= recent_relative_time ();
634 else /* regression in NSM */
636 nbr
->ts_last_regress
= recent_relative_time ();
637 nbr
->last_regress_str
= ospf_nsm_event_str
[event
];
643 nsm_change_state (struct ospf_neighbor
*nbr
, int state
)
645 struct ospf_interface
*oi
= nbr
->oi
;
646 struct ospf_area
*vl_area
= NULL
;
651 /* Preserve old status. */
652 old_state
= nbr
->state
;
654 /* Change to new status. */
660 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
661 vl_area
= ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
663 /* Generate NeighborChange ISM event.
665 * In response to NeighborChange, DR election is rerun. The information
666 * from the election process is required by the router-lsa construction.
668 * Therefore, trigger the event prior to refreshing the LSAs. */
673 if ((old_state
< NSM_TwoWay
&& state
>= NSM_TwoWay
) ||
674 (old_state
>= NSM_TwoWay
&& state
< NSM_TwoWay
))
675 OSPF_ISM_EVENT_EXECUTE (oi
, ISM_NeighborChange
);
678 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
682 /* One of the neighboring routers changes to/from the FULL state. */
683 if ((old_state
!= NSM_Full
&& state
== NSM_Full
) ||
684 (old_state
== NSM_Full
&& state
!= NSM_Full
))
686 if (state
== NSM_Full
)
689 oi
->area
->full_nbrs
++;
691 ospf_check_abr_status (oi
->ospf
);
693 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
694 if (++vl_area
->full_vls
== 1)
695 ospf_schedule_abr_task (oi
->ospf
);
697 /* kevinm: refresh any redistributions */
698 for (x
= ZEBRA_ROUTE_SYSTEM
; x
< ZEBRA_ROUTE_MAX
; x
++)
700 struct list
*red_list
;
701 struct listnode
*node
;
702 struct ospf_redist
*red
;
704 if (x
== ZEBRA_ROUTE_OSPF6
)
707 red_list
= oi
->ospf
->redist
[x
];
711 for (ALL_LIST_ELEMENTS_RO(red_list
, node
, red
))
712 ospf_external_lsa_refresh_type (oi
->ospf
, x
, red
->instance
, force
);
714 /* XXX: Clearly some thing is wrong with refresh of external LSAs
715 * this added to hack around defaults not refreshing after a timer
718 ospf_external_lsa_refresh_default (oi
->ospf
);
723 oi
->area
->full_nbrs
--;
725 ospf_check_abr_status (oi
->ospf
);
727 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
&& vl_area
)
728 if (vl_area
->full_vls
> 0)
729 if (--vl_area
->full_vls
== 0)
730 ospf_schedule_abr_task (oi
->ospf
);
733 zlog_info ("nsm_change_state(%s, %s -> %s): "
734 "scheduling new router-LSA origination",
735 inet_ntoa (nbr
->router_id
),
736 LOOKUP(ospf_nsm_state_msg
, old_state
),
737 LOOKUP(ospf_nsm_state_msg
, state
));
739 ospf_router_lsa_update_area (oi
->area
);
741 if (oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
743 struct ospf_area
*vl_area
=
744 ospf_area_lookup_by_area_id (oi
->ospf
, oi
->vl_data
->vl_area_id
);
747 ospf_router_lsa_update_area (vl_area
);
750 /* Originate network-LSA. */
751 if (oi
->state
== ISM_DR
)
753 if (oi
->network_lsa_self
&& oi
->full_nbrs
== 0)
755 ospf_lsa_flush_area (oi
->network_lsa_self
, oi
->area
);
756 ospf_lsa_unlock (&oi
->network_lsa_self
);
757 oi
->network_lsa_self
= NULL
;
760 ospf_network_lsa_update (oi
);
764 ospf_opaque_nsm_change (nbr
, old_state
);
766 /* State changes from > ExStart to <= ExStart should clear any Exchange
767 * or Full/LSA Update related lists and state.
768 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
770 if ((old_state
> NSM_ExStart
) && (state
<= NSM_ExStart
))
773 /* Start DD exchange protocol */
774 if (state
== NSM_ExStart
)
776 if (nbr
->dd_seqnum
== 0)
777 nbr
->dd_seqnum
= (uint32_t)random ();
781 nbr
->dd_flags
= OSPF_DD_FLAG_I
|OSPF_DD_FLAG_M
|OSPF_DD_FLAG_MS
;
782 ospf_db_desc_send (nbr
);
785 /* clear cryptographic sequence number */
786 if (state
== NSM_Down
)
787 nbr
->crypt_seqnum
= 0;
789 ospf_bfd_trigger_event(nbr
, old_state
, state
);
791 /* Preserve old status? */
794 /* Execute NSM event process. */
796 ospf_nsm_event (struct thread
*thread
)
800 struct ospf_neighbor
*nbr
;
802 nbr
= THREAD_ARG (thread
);
803 event
= THREAD_VAL (thread
);
805 if (IS_DEBUG_OSPF (nsm
, NSM_EVENTS
))
806 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr
->oi
),
807 inet_ntoa (nbr
->router_id
),
808 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
809 ospf_nsm_event_str
[event
]);
811 next_state
= NSM
[nbr
->state
][event
].next_state
;
814 if (NSM
[nbr
->state
][event
].func
!= NULL
)
816 int func_state
= (*(NSM
[nbr
->state
][event
].func
))(nbr
);
818 if (NSM
[nbr
->state
][event
].next_state
== NSM_DependUpon
)
819 next_state
= func_state
;
822 /* There's a mismatch between the FSM tables and what an FSM
823 * action/state-change function returned. State changes which
824 * do not have conditional/DependUpon next-states should not
825 * try set next_state.
827 zlog_warn ("NSM[%s:%s]: %s (%s): "
828 "Warning: action tried to change next_state to %s",
829 IF_NAME (nbr
->oi
), inet_ntoa (nbr
->router_id
),
830 LOOKUP (ospf_nsm_state_msg
, nbr
->state
),
831 ospf_nsm_event_str
[event
],
832 LOOKUP (ospf_nsm_state_msg
, func_state
));
836 assert (next_state
!= NSM_DependUpon
);
838 /* If state is changed. */
839 if (next_state
!= nbr
->state
)
841 nsm_notice_state_change (nbr
, next_state
, event
);
843 int send_trap_virt
= 0;
845 /* Terminal state or regression */
846 if ((next_state
== NSM_Full
)
847 || (next_state
== NSM_TwoWay
)
848 || (next_state
< nbr
->state
))
850 /* ospfVirtNbrStateChange */
851 if (nbr
->oi
->type
== OSPF_IFTYPE_VIRTUALLINK
)
853 /* ospfNbrStateChange trap */
855 /* To/From FULL, only managed by DR */
856 if (((next_state
!= NSM_Full
) && (nbr
->state
!= NSM_Full
))
857 || (nbr
->oi
->state
== ISM_DR
))
861 nsm_change_state (nbr
, next_state
);
864 if (send_trap_virt
) {
865 ospfTrapVirtNbrStateChange(nbr
);
866 } else if (send_trap
) {
867 ospfTrapNbrStateChange(nbr
);
872 /* Make sure timer is set. */
875 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
878 * Rather than encode knowledge here of which events lead to NBR
879 * delete, we take our cue from the NSM table, via the dummy
880 * 'Deleted' neighbour state.
882 if (nbr
->state
== NSM_Deleted
)
883 ospf_nbr_delete (nbr
);
888 /* Check loading state. */
890 ospf_check_nbr_loading (struct ospf_neighbor
*nbr
)
892 if (nbr
->state
== NSM_Loading
)
894 if (ospf_ls_request_isempty (nbr
))
895 OSPF_NSM_EVENT_SCHEDULE (nbr
, NSM_LoadingDone
);
896 else if (nbr
->ls_req_last
== NULL
)
897 ospf_ls_req_event (nbr
);