2 * OSPF version 2 Neighbor State Machine
3 * From RFC2328 [OSPF Version 2]
4 * Copyright (C) 1999, 2000 Toshiaki Takada
6 * This file is part of GNU Zebra.
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
37 #include "ospfd/ospfd.h"
38 #include "ospfd/ospf_interface.h"
39 #include "ospfd/ospf_ism.h"
40 #include "ospfd/ospf_asbr.h"
41 #include "ospfd/ospf_lsa.h"
42 #include "ospfd/ospf_lsdb.h"
43 #include "ospfd/ospf_neighbor.h"
44 #include "ospfd/ospf_nsm.h"
45 #include "ospfd/ospf_network.h"
46 #include "ospfd/ospf_packet.h"
47 #include "ospfd/ospf_dump.h"
48 #include "ospfd/ospf_flood.h"
49 #include "ospfd/ospf_abr.h"
50 #include "ospfd/ospf_snmp.h"
52 static void nsm_clear_adj (struct ospf_neighbor *);
54 /* OSPF NSM Timer functions. */
56 ospf_inactivity_timer (struct thread *thread)
58 struct ospf_neighbor *nbr;
60 nbr = THREAD_ARG (thread);
61 nbr->t_inactivity = NULL;
63 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
64 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)",
65 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
67 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer);
73 ospf_db_desc_timer (struct thread *thread)
75 struct ospf_neighbor *nbr;
77 nbr = THREAD_ARG (thread);
78 nbr->t_db_desc = NULL;
80 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
81 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
82 IF_NAME (nbr->oi), inet_ntoa (nbr->src));
84 /* resent last send DD packet. */
85 assert (nbr->last_send);
86 ospf_db_desc_resend (nbr);
88 /* DD Retransmit timer set. */
89 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 occured.
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.
104 nsm_timer_set (struct ospf_neighbor *nbr)
110 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
111 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
115 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
116 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
117 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
120 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
121 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
122 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
125 OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
126 if (!IS_SET_DD_MS (nbr->dd_flags))
127 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
132 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
137 /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
138 * the given neighbour
141 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. */
162 nsm_packet_received (struct ospf_neighbor *nbr)
164 /* Start or Restart Inactivity Timer. */
165 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
167 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
170 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
171 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
177 nsm_start (struct ospf_neighbor *nbr)
180 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
182 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
184 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
191 nsm_twoway_received (struct ospf_neighbor *nbr)
193 return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay);
197 ospf_db_summary_count (struct ospf_neighbor *nbr)
199 return ospf_lsdb_count_all (&nbr->db_sum);
203 ospf_db_summary_isempty (struct ospf_neighbor *nbr)
205 return ospf_lsdb_isempty (&nbr->db_sum);
209 ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
211 switch (lsa->data->type)
213 case OSPF_OPAQUE_LINK_LSA:
214 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
215 if (nbr->oi && ospf_if_exists (lsa->oi) != nbr->oi)
218 case OSPF_OPAQUE_AREA_LSA:
220 * It is assured by the caller function "nsm_negotiation_done()"
221 * that every given LSA belongs to the same area with "nbr".
224 case OSPF_OPAQUE_AS_LSA:
229 /* Stay away from any Local Translated Type-7 LSAs */
230 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
233 if (IS_LSA_MAXAGE (lsa))
234 ospf_ls_retransmit_add (nbr, lsa);
236 ospf_lsdb_add (&nbr->db_sum, lsa);
242 ospf_db_summary_clear (struct ospf_neighbor *nbr)
244 struct ospf_lsdb *lsdb;
248 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
250 struct route_table *table = lsdb->type[i].db;
251 struct route_node *rn;
253 for (rn = route_top (table); rn; rn = route_next (rn))
255 ospf_lsdb_delete (&nbr->db_sum, rn->info);
261 /* The area link state database consists of the router-LSAs,
262 network-LSAs and summary-LSAs contained in the area structure,
263 along with the AS-external-LSAs contained in the global structure.
264 AS-external-LSAs are omitted from a virtual neighbor's Database
265 summary list. AS-external-LSAs are omitted from the Database
266 summary list if the area has been configured as a stub. */
268 nsm_negotiation_done (struct ospf_neighbor *nbr)
270 struct ospf_area *area = nbr->oi->area;
271 struct ospf_lsa *lsa;
272 struct route_node *rn;
274 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
275 ospf_db_summary_add (nbr, lsa);
276 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
277 ospf_db_summary_add (nbr, lsa);
278 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
279 ospf_db_summary_add (nbr, lsa);
280 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
281 ospf_db_summary_add (nbr, lsa);
283 /* Process only if the neighbor is opaque capable. */
284 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
286 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
287 ospf_db_summary_add (nbr, lsa);
288 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
289 ospf_db_summary_add (nbr, lsa);
292 if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
294 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
295 ospf_db_summary_add (nbr, lsa);
298 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
299 && area->external_routing == OSPF_AREA_DEFAULT)
300 LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
301 ospf_db_summary_add (nbr, lsa);
303 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
304 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
305 && area->external_routing == OSPF_AREA_DEFAULT))
306 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
307 ospf_db_summary_add (nbr, lsa);
309 /* Send Link State Request. */
310 if (nbr->t_ls_req == NULL)
311 ospf_ls_req_send (nbr);
317 nsm_exchange_done (struct ospf_neighbor *nbr)
319 if (ospf_ls_request_isempty (nbr))
322 if (nbr->t_ls_req == NULL)
323 ospf_ls_req_send (nbr);
329 nsm_adj_ok (struct ospf_neighbor *nbr)
331 int next_state = nbr->state;
332 int adj = nsm_should_adj (nbr);
334 if (nbr->state == NSM_TwoWay && adj == 1)
335 next_state = NSM_ExStart;
336 else if (nbr->state >= NSM_ExStart && adj == 0)
337 next_state = NSM_TwoWay;
342 /* Clear adjacency related state for a neighbour, intended where nbr
343 * transitions from > ExStart (i.e. a Full or forming adjacency)
347 nsm_clear_adj (struct ospf_neighbor *nbr)
349 /* Clear Database Summary list. */
350 if (!ospf_db_summary_isempty (nbr))
351 ospf_db_summary_clear (nbr);
353 /* Clear Link State Request list. */
354 if (!ospf_ls_request_isempty (nbr))
355 ospf_ls_request_delete_all (nbr);
357 /* Clear Link State Retransmission list. */
358 if (!ospf_ls_retransmit_isempty (nbr))
359 ospf_ls_retransmit_clear (nbr);
361 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
362 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
366 nsm_kill_nbr (struct ospf_neighbor *nbr)
368 /* killing nbr_self is invalid */
369 if (nbr == nbr->oi->nbr_self)
371 assert (nbr != nbr->oi->nbr_self);
375 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
377 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
379 nbr_nbma->nbr = NULL;
380 nbr_nbma->state_change = nbr->state_change;
382 nbr->nbr_nbma = NULL;
384 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
387 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
388 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
389 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
395 /* Neighbor State Machine */
397 int (*func) (struct ospf_neighbor *);
399 } NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
402 /* DependUpon: dummy state. */
403 { NULL, NSM_DependUpon }, /* NoEvent */
404 { NULL, NSM_DependUpon }, /* PacketReceived */
405 { NULL, NSM_DependUpon }, /* Start */
406 { NULL, NSM_DependUpon }, /* 2-WayReceived */
407 { NULL, NSM_DependUpon }, /* NegotiationDone */
408 { NULL, NSM_DependUpon }, /* ExchangeDone */
409 { NULL, NSM_DependUpon }, /* BadLSReq */
410 { NULL, NSM_DependUpon }, /* LoadingDone */
411 { NULL, NSM_DependUpon }, /* AdjOK? */
412 { NULL, NSM_DependUpon }, /* SeqNumberMismatch */
413 { NULL, NSM_DependUpon }, /* 1-WayReceived */
414 { NULL, NSM_DependUpon }, /* KillNbr */
415 { NULL, NSM_DependUpon }, /* InactivityTimer */
416 { NULL, NSM_DependUpon }, /* LLDown */
419 /* Deleted: dummy state. */
420 { NULL, NSM_Deleted }, /* NoEvent */
421 { NULL, NSM_Deleted }, /* PacketReceived */
422 { NULL, NSM_Deleted }, /* Start */
423 { NULL, NSM_Deleted }, /* 2-WayReceived */
424 { NULL, NSM_Deleted }, /* NegotiationDone */
425 { NULL, NSM_Deleted }, /* ExchangeDone */
426 { NULL, NSM_Deleted }, /* BadLSReq */
427 { NULL, NSM_Deleted }, /* LoadingDone */
428 { NULL, NSM_Deleted }, /* AdjOK? */
429 { NULL, NSM_Deleted }, /* SeqNumberMismatch */
430 { NULL, NSM_Deleted }, /* 1-WayReceived */
431 { NULL, NSM_Deleted }, /* KillNbr */
432 { NULL, NSM_Deleted }, /* InactivityTimer */
433 { NULL, NSM_Deleted }, /* LLDown */
437 { NULL, NSM_DependUpon }, /* NoEvent */
438 { nsm_packet_received, NSM_Init }, /* PacketReceived */
439 { nsm_start, NSM_Attempt }, /* Start */
440 { NULL, NSM_Down }, /* 2-WayReceived */
441 { NULL, NSM_Down }, /* NegotiationDone */
442 { NULL, NSM_Down }, /* ExchangeDone */
443 { NULL, NSM_Down }, /* BadLSReq */
444 { NULL, NSM_Down }, /* LoadingDone */
445 { NULL, NSM_Down }, /* AdjOK? */
446 { NULL, NSM_Down }, /* SeqNumberMismatch */
447 { NULL, NSM_Down }, /* 1-WayReceived */
448 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
449 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
450 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
454 { NULL, NSM_DependUpon }, /* NoEvent */
455 { nsm_packet_received, NSM_Init }, /* PacketReceived */
456 { NULL, NSM_Attempt }, /* Start */
457 { NULL, NSM_Attempt }, /* 2-WayReceived */
458 { NULL, NSM_Attempt }, /* NegotiationDone */
459 { NULL, NSM_Attempt }, /* ExchangeDone */
460 { NULL, NSM_Attempt }, /* BadLSReq */
461 { NULL, NSM_Attempt }, /* LoadingDone */
462 { NULL, NSM_Attempt }, /* AdjOK? */
463 { NULL, NSM_Attempt }, /* SeqNumberMismatch */
464 { NULL, NSM_Attempt }, /* 1-WayReceived */
465 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
466 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
467 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
471 { NULL, NSM_DependUpon }, /* NoEvent */
472 { nsm_packet_received, NSM_Init }, /* PacketReceived */
473 { NULL, NSM_Init }, /* Start */
474 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
475 { NULL, NSM_Init }, /* NegotiationDone */
476 { NULL, NSM_Init }, /* ExchangeDone */
477 { NULL, NSM_Init }, /* BadLSReq */
478 { NULL, NSM_Init }, /* LoadingDone */
479 { NULL, NSM_Init }, /* AdjOK? */
480 { NULL, NSM_Init }, /* SeqNumberMismatch */
481 { NULL, NSM_Init }, /* 1-WayReceived */
482 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
483 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
484 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
488 { NULL, NSM_DependUpon }, /* NoEvent */
489 { nsm_packet_received, NSM_TwoWay }, /* HelloReceived */
490 { NULL, NSM_TwoWay }, /* Start */
491 { NULL, NSM_TwoWay }, /* 2-WayReceived */
492 { NULL, NSM_TwoWay }, /* NegotiationDone */
493 { NULL, NSM_TwoWay }, /* ExchangeDone */
494 { NULL, NSM_TwoWay }, /* BadLSReq */
495 { NULL, NSM_TwoWay }, /* LoadingDone */
496 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
497 { NULL, NSM_TwoWay }, /* SeqNumberMismatch */
498 { NULL, NSM_Init }, /* 1-WayReceived */
499 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
500 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
501 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
505 { NULL, NSM_DependUpon }, /* NoEvent */
506 { nsm_packet_received, NSM_ExStart }, /* PacaketReceived */
507 { NULL, NSM_ExStart }, /* Start */
508 { NULL, NSM_ExStart }, /* 2-WayReceived */
509 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
510 { NULL, NSM_ExStart }, /* ExchangeDone */
511 { NULL, NSM_ExStart }, /* BadLSReq */
512 { NULL, NSM_ExStart }, /* LoadingDone */
513 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
514 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
515 { NULL, NSM_Init }, /* 1-WayReceived */
516 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
517 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
518 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
522 { NULL, NSM_DependUpon }, /* NoEvent */
523 { nsm_packet_received, NSM_Exchange }, /* PacketReceived */
524 { NULL, NSM_Exchange }, /* Start */
525 { NULL, NSM_Exchange }, /* 2-WayReceived */
526 { NULL, NSM_Exchange }, /* NegotiationDone */
527 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
528 { NULL, NSM_ExStart }, /* BadLSReq */
529 { NULL, NSM_Exchange }, /* LoadingDone */
530 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
531 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
532 { NULL, NSM_Init }, /* 1-WayReceived */
533 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
534 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
535 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
539 { NULL, NSM_DependUpon }, /* NoEvent */
540 { nsm_packet_received, NSM_Loading }, /* PacketReceived */
541 { NULL, NSM_Loading }, /* Start */
542 { NULL, NSM_Loading }, /* 2-WayReceived */
543 { NULL, NSM_Loading }, /* NegotiationDone */
544 { NULL, NSM_Loading }, /* ExchangeDone */
545 { NULL, NSM_ExStart }, /* BadLSReq */
546 { NULL, NSM_Full }, /* LoadingDone */
547 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
548 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
549 { NULL, NSM_Init }, /* 1-WayReceived */
550 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
551 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
552 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
555 { NULL, NSM_DependUpon }, /* NoEvent */
556 { nsm_packet_received, NSM_Full }, /* PacketReceived */
557 { NULL, NSM_Full }, /* Start */
558 { NULL, NSM_Full }, /* 2-WayReceived */
559 { NULL, NSM_Full }, /* NegotiationDone */
560 { NULL, NSM_Full }, /* ExchangeDone */
561 { NULL, NSM_ExStart }, /* BadLSReq */
562 { NULL, NSM_Full }, /* LoadingDone */
563 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
564 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
565 { NULL, NSM_Init }, /* 1-WayReceived */
566 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
567 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
568 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
572 static const char *ospf_nsm_event_str[] =
591 nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event)
593 /* Logging change of status. */
594 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
595 zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)",
596 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
597 LOOKUP (ospf_nsm_state_msg, nbr->state),
598 LOOKUP (ospf_nsm_state_msg, next_state),
599 ospf_nsm_event_str [event]);
601 /* Optionally notify about adjacency changes */
602 if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
603 (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
604 (next_state == NSM_Full) || (next_state < nbr->state)))
605 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)",
606 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
607 LOOKUP (ospf_nsm_state_msg, nbr->state),
608 LOOKUP (ospf_nsm_state_msg, next_state),
609 ospf_nsm_event_str [event]);
612 if (next_state > nbr->state)
613 nbr->ts_last_progress = recent_relative_time ();
614 else /* regression in NSM */
616 nbr->ts_last_regress = recent_relative_time ();
617 nbr->last_regress_str = ospf_nsm_event_str [event];
623 nsm_change_state (struct ospf_neighbor *nbr, int state)
625 struct ospf_interface *oi = nbr->oi;
626 struct ospf_area *vl_area = NULL;
631 /* Preserve old status. */
632 old_state = nbr->state;
634 /* Change to new status. */
640 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
641 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
643 /* Generate NeighborChange ISM event.
645 * In response to NeighborChange, DR election is rerun. The information
646 * from the election process is required by the router-lsa construction.
648 * Therefore, trigger the event prior to refreshing the LSAs. */
653 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
654 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
655 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
658 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
662 /* One of the neighboring routers changes to/from the FULL state. */
663 if ((old_state != NSM_Full && state == NSM_Full) ||
664 (old_state == NSM_Full && state != NSM_Full))
666 if (state == NSM_Full)
669 oi->area->full_nbrs++;
671 ospf_check_abr_status (oi->ospf);
673 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
674 if (++vl_area->full_vls == 1)
675 ospf_schedule_abr_task (oi->ospf);
677 /* kevinm: refresh any redistributions */
678 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
680 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
682 ospf_external_lsa_refresh_type (oi->ospf, x, force);
684 /* XXX: Clearly some thing is wrong with refresh of external LSAs
685 * this added to hack around defaults not refreshing after a timer
688 ospf_external_lsa_refresh_default (oi->ospf);
693 oi->area->full_nbrs--;
695 ospf_check_abr_status (oi->ospf);
697 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
698 if (vl_area->full_vls > 0)
699 if (--vl_area->full_vls == 0)
700 ospf_schedule_abr_task (oi->ospf);
703 zlog_info ("nsm_change_state(%s, %s -> %s): "
704 "scheduling new router-LSA origination",
705 inet_ntoa (nbr->router_id),
706 LOOKUP(ospf_nsm_state_msg, old_state),
707 LOOKUP(ospf_nsm_state_msg, state));
709 ospf_router_lsa_update_area (oi->area);
711 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
713 struct ospf_area *vl_area =
714 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
717 ospf_router_lsa_update_area (vl_area);
720 /* Originate network-LSA. */
721 if (oi->state == ISM_DR)
723 if (oi->network_lsa_self && oi->full_nbrs == 0)
725 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
726 ospf_lsa_unlock (&oi->network_lsa_self);
727 oi->network_lsa_self = NULL;
730 ospf_network_lsa_update (oi);
734 ospf_opaque_nsm_change (nbr, old_state);
736 /* State changes from > ExStart to <= ExStart should clear any Exchange
737 * or Full/LSA Update related lists and state.
738 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
740 if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
743 /* Start DD exchange protocol */
744 if (state == NSM_ExStart)
746 if (nbr->dd_seqnum == 0)
747 nbr->dd_seqnum = quagga_time (NULL);
751 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
752 ospf_db_desc_send (nbr);
755 /* clear cryptographic sequence number */
756 if (state == NSM_Down)
757 nbr->crypt_seqnum = 0;
759 /* Preserve old status? */
762 /* Execute NSM event process. */
764 ospf_nsm_event (struct thread *thread)
768 struct ospf_neighbor *nbr;
770 nbr = THREAD_ARG (thread);
771 event = THREAD_VAL (thread);
773 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
774 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi),
775 inet_ntoa (nbr->router_id),
776 LOOKUP (ospf_nsm_state_msg, nbr->state),
777 ospf_nsm_event_str [event]);
779 next_state = NSM [nbr->state][event].next_state;
782 if (NSM [nbr->state][event].func != NULL)
784 int func_state = (*(NSM [nbr->state][event].func))(nbr);
786 if (NSM [nbr->state][event].next_state == NSM_DependUpon)
787 next_state = func_state;
790 /* There's a mismatch between the FSM tables and what an FSM
791 * action/state-change function returned. State changes which
792 * do not have conditional/DependUpon next-states should not
793 * try set next_state.
795 zlog_warn ("NSM[%s:%s]: %s (%s): "
796 "Warning: action tried to change next_state to %s",
797 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
798 LOOKUP (ospf_nsm_state_msg, nbr->state),
799 ospf_nsm_event_str [event],
800 LOOKUP (ospf_nsm_state_msg, func_state));
804 assert (next_state != NSM_DependUpon);
806 /* If state is changed. */
807 if (next_state != nbr->state)
809 nsm_notice_state_change (nbr, next_state, event);
811 int send_trap_virt = 0;
813 /* Terminal state or regression */
814 if ((next_state == NSM_Full)
815 || (next_state == NSM_TwoWay)
816 || (next_state < nbr->state))
818 /* ospfVirtNbrStateChange */
819 if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK)
821 /* ospfNbrStateChange trap */
823 /* To/From FULL, only managed by DR */
824 if (((next_state != NSM_Full) && (nbr->state != NSM_Full))
825 || (nbr->oi->state == ISM_DR))
829 nsm_change_state (nbr, next_state);
832 if (send_trap_virt) {
833 ospfTrapVirtNbrStateChange(nbr);
834 } else if (send_trap) {
835 ospfTrapNbrStateChange(nbr);
840 /* Make sure timer is set. */
843 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
846 * Rather than encode knowledge here of which events lead to NBR
847 * delete, we take our cue from the NSM table, via the dummy
848 * 'Deleted' neighbour state.
850 if (nbr->state == NSM_Deleted)
851 ospf_nbr_delete (nbr);
856 /* Check loading state. */
858 ospf_check_nbr_loading (struct ospf_neighbor *nbr)
860 if (nbr->state == NSM_Loading)
862 if (ospf_ls_request_isempty (nbr))
863 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
864 else if (nbr->ls_req_last == NULL)
865 ospf_ls_req_event (nbr);