]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_nsm.c
[ospfd] early-return in nsm_event missed LLDown event, fixes use after free
[mirror_frr.git] / ospfd / ospf_nsm.c
CommitLineData
2d59836a 1/*
2 * OSPF version 2 Neighbor State Machine
3 * From RFC2328 [OSPF Version 2]
4 * Copyright (C) 1999, 2000 Toshiaki Takada
5 *
6 * This file is part of GNU Zebra.
7 *
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
11 * later version.
12 *
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.
17 *
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
21 * 02111-1307, USA.
22 */
23
24#include <zebra.h>
25
26#include "thread.h"
27#include "memory.h"
28#include "hash.h"
29#include "linklist.h"
30#include "prefix.h"
31#include "if.h"
32#include "table.h"
33#include "stream.h"
34#include "table.h"
35#include "log.h"
36
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"
5e4914c3 50#include "ospfd/ospf_snmp.h"
2d59836a 51
d1b1cd8f
PJ
52static void nsm_reset_nbr (struct ospf_neighbor *);
53static void nsm_clear_adj (struct ospf_neighbor *);
2d59836a 54\f
55/* OSPF NSM Timer functions. */
4dadc291 56static int
2d59836a 57ospf_inactivity_timer (struct thread *thread)
58{
59 struct ospf_neighbor *nbr;
60
61 nbr = THREAD_ARG (thread);
62 nbr->t_inactivity = NULL;
63
64 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
65 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)",
66 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
67
68 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer);
69
70 return 0;
71}
72
4dadc291 73static int
2d59836a 74ospf_db_desc_timer (struct thread *thread)
75{
76 struct ospf_interface *oi;
77 struct ospf_neighbor *nbr;
78
79 nbr = THREAD_ARG (thread);
80 nbr->t_db_desc = NULL;
81
82 oi = nbr->oi;
83
84 if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
2a42e285 85 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
2d59836a 86 IF_NAME (nbr->oi), inet_ntoa (nbr->src));
87
88 /* resent last send DD packet. */
89 assert (nbr->last_send);
90 ospf_db_desc_resend (nbr);
91
92 /* DD Retransmit timer set. */
93 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
94
95 return 0;
96}
97
98/* Hook function called after ospf NSM event is occured. */
99
4dadc291 100static void
2d59836a 101nsm_timer_set (struct ospf_neighbor *nbr)
102{
103 switch (nbr->state)
104 {
105 case NSM_Down:
e55dd53b
PJ
106 /* This is here for documentation purposes, don't actually get here
107 * as Down neighbours are deleted typically, see nsm_kill_nbr
108 */
109 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
2d59836a 110 case NSM_Attempt:
2d59836a 111 case NSM_Init:
2d59836a 112 case NSM_TwoWay:
113 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
114 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
e55dd53b 115 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
2d59836a 116 break;
117 case NSM_ExStart:
118 OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
119 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
e55dd53b 120 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
2d59836a 121 break;
122 case NSM_Exchange:
123 OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
124 if (!IS_SET_DD_MS (nbr->dd_flags))
125 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
126 break;
127 case NSM_Loading:
2d59836a 128 case NSM_Full:
2d59836a 129 default:
130 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
131 break;
132 }
133}
134
d7b0fb62
PJ
135/* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
136 * the given neighbour
137 */
138static int
139nsm_should_adj (struct ospf_neighbor *nbr)
140{
f7a76abf 141 struct ospf_interface *oi = nbr->oi;
d7b0fb62 142
f7a76abf 143 /* These network types must always form adjacencies. */
d7b0fb62
PJ
144 if (oi->type == OSPF_IFTYPE_POINTOPOINT
145 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
f7a76abf
PJ
146 || oi->type == OSPF_IFTYPE_VIRTUALLINK
147 /* Router itself is the DRouter or the BDRouter. */
148 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
149 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))
150 /* Neighboring Router is the DRouter or the BDRouter. */
151 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
d7b0fb62
PJ
152 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
153 return 1;
154
155 return 0;
156}
2d59836a 157\f
158/* OSPF NSM functions. */
4dadc291 159static int
2d59836a 160nsm_ignore (struct ospf_neighbor *nbr)
161{
162 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
2a42e285 163 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: nsm_ignore called",
2d59836a 164 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
165
166 return 0;
167}
168
4dadc291 169static int
2d59836a 170nsm_hello_received (struct ospf_neighbor *nbr)
171{
172 /* Start or Restart Inactivity Timer. */
173 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
174
175 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
176 nbr->v_inactivity);
177
178 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
179 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
180
181 return 0;
182}
183
4dadc291 184static int
2d59836a 185nsm_start (struct ospf_neighbor *nbr)
186{
187
188 nsm_reset_nbr (nbr);
189
190 if (nbr->nbr_nbma)
191 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
192
193 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
194
195 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
196 nbr->v_inactivity);
197
198 return 0;
199}
200
4dadc291 201static int
2d59836a 202nsm_twoway_received (struct ospf_neighbor *nbr)
203{
f7a76abf 204 return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay);
2d59836a 205}
206
207int
208ospf_db_summary_count (struct ospf_neighbor *nbr)
209{
210 return ospf_lsdb_count_all (&nbr->db_sum);
211}
212
213int
214ospf_db_summary_isempty (struct ospf_neighbor *nbr)
215{
216 return ospf_lsdb_isempty (&nbr->db_sum);
217}
218
4dadc291 219static int
68980084 220ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
2d59836a 221{
09e4efdc 222#ifdef HAVE_OPAQUE_LSA
223 switch (lsa->data->type)
224 {
225 case OSPF_OPAQUE_LINK_LSA:
226 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
227 if (lsa->oi != nbr->oi)
228 return 0;
229 break;
230 case OSPF_OPAQUE_AREA_LSA:
231 /*
232 * It is assured by the caller function "nsm_negotiation_done()"
233 * that every given LSA belongs to the same area with "nbr".
234 */
235 break;
236 case OSPF_OPAQUE_AS_LSA:
237 default:
238 break;
239 }
240#endif /* HAVE_OPAQUE_LSA */
241
2d59836a 242 /* Stay away from any Local Translated Type-7 LSAs */
243 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
244 return 0;
2d59836a 245
246 if (IS_LSA_MAXAGE (lsa))
247 ospf_ls_retransmit_add (nbr, lsa);
248 else
249 ospf_lsdb_add (&nbr->db_sum, lsa);
250
251 return 0;
252}
253
254void
255ospf_db_summary_clear (struct ospf_neighbor *nbr)
256{
257 struct ospf_lsdb *lsdb;
258 int i;
259
260 lsdb = &nbr->db_sum;
261 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
262 {
263 struct route_table *table = lsdb->type[i].db;
264 struct route_node *rn;
265
266 for (rn = route_top (table); rn; rn = route_next (rn))
267 if (rn->info)
268 ospf_lsdb_delete (&nbr->db_sum, rn->info);
269 }
270}
271
272\f
273
2d59836a 274/* The area link state database consists of the router-LSAs,
275 network-LSAs and summary-LSAs contained in the area structure,
68980084 276 along with the AS-external-LSAs contained in the global structure.
277 AS-external-LSAs are omitted from a virtual neighbor's Database
2d59836a 278 summary list. AS-external-LSAs are omitted from the Database
279 summary list if the area has been configured as a stub. */
4dadc291 280static int
2d59836a 281nsm_negotiation_done (struct ospf_neighbor *nbr)
282{
68980084 283 struct ospf_area *area = nbr->oi->area;
284 struct ospf_lsa *lsa;
285 struct route_node *rn;
286
287 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
288 ospf_db_summary_add (nbr, lsa);
289 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
290 ospf_db_summary_add (nbr, lsa);
291 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
292 ospf_db_summary_add (nbr, lsa);
293 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
294 ospf_db_summary_add (nbr, lsa);
2d59836a 295
2d59836a 296#ifdef HAVE_OPAQUE_LSA
297 /* Process only if the neighbor is opaque capable. */
298 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
299 {
68980084 300 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
301 ospf_db_summary_add (nbr, lsa);
302 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
303 ospf_db_summary_add (nbr, lsa);
2d59836a 304 }
305#endif /* HAVE_OPAQUE_LSA */
306
f4833e9f 307 if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
308 {
309 LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
310 ospf_db_summary_add (nbr, lsa);
311 }
312
68980084 313 if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
314 && area->external_routing == OSPF_AREA_DEFAULT)
315 LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
316 ospf_db_summary_add (nbr, lsa);
2d59836a 317
318#ifdef HAVE_OPAQUE_LSA
68980084 319 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
320 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
321 && area->external_routing == OSPF_AREA_DEFAULT))
322 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
323 ospf_db_summary_add (nbr, lsa);
2d59836a 324#endif /* HAVE_OPAQUE_LSA */
325
2d59836a 326 return 0;
327}
328
4dadc291 329static int
2d59836a 330nsm_exchange_done (struct ospf_neighbor *nbr)
331{
2d59836a 332 if (ospf_ls_request_isempty (nbr))
333 return NSM_Full;
334
335 /* Cancel dd retransmit timer. */
336 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
337
338 /* Send Link State Request. */
339 ospf_ls_req_send (nbr);
340
341 return NSM_Loading;
342}
343
4dadc291 344static int
2d59836a 345nsm_bad_ls_req (struct ospf_neighbor *nbr)
346{
347 /* Clear neighbor. */
348 nsm_reset_nbr (nbr);
349
350 return 0;
351}
352
4dadc291 353static int
2d59836a 354nsm_adj_ok (struct ospf_neighbor *nbr)
355{
d7b0fb62
PJ
356 int next_state = nbr->state;
357 int adj = nsm_should_adj (nbr);
2d59836a 358
d7b0fb62 359 if (nbr->state == NSM_TwoWay && adj == 1)
2d59836a 360 next_state = NSM_ExStart;
d7b0fb62 361 else if (nbr->state >= NSM_ExStart && adj == 0)
2d59836a 362 next_state = NSM_TwoWay;
363
364 return next_state;
365}
366
4dadc291 367static int
2d59836a 368nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
369{
370 /* Clear neighbor. */
371 nsm_reset_nbr (nbr);
372
373 return 0;
374}
375
4dadc291 376static int
2d59836a 377nsm_oneway_received (struct ospf_neighbor *nbr)
378{
379 /* Clear neighbor. */
380 nsm_reset_nbr (nbr);
381
382 return 0;
383}
384
d1b1cd8f
PJ
385/* Clear adjacency related state for a neighbour, intended where nbr
386 * transitions from > ExStart (i.e. a Full or forming adjacency)
387 * to <= ExStart.
388 */
389static void
390nsm_clear_adj (struct ospf_neighbor *nbr)
2d59836a 391{
392 /* Clear Database Summary list. */
393 if (!ospf_db_summary_isempty (nbr))
394 ospf_db_summary_clear (nbr);
395
396 /* Clear Link State Request list. */
397 if (!ospf_ls_request_isempty (nbr))
398 ospf_ls_request_delete_all (nbr);
399
400 /* Clear Link State Retransmission list. */
401 if (!ospf_ls_retransmit_isempty (nbr))
402 ospf_ls_retransmit_clear (nbr);
d1b1cd8f
PJ
403}
404
405static void
406nsm_reset_nbr (struct ospf_neighbor *nbr)
407{
408 nsm_clear_adj (nbr);
2d59836a 409
410 /* Cancel thread. */
411 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
412 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
413 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
414 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
415
416#ifdef HAVE_OPAQUE_LSA
417 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
418 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
419#endif /* HAVE_OPAQUE_LSA */
420}
421
4dadc291 422static int
2d59836a 423nsm_kill_nbr (struct ospf_neighbor *nbr)
424{
425 /* call it here because we cannot call it from ospf_nsm_event */
426 nsm_change_state (nbr, NSM_Down);
427
478aab98
PJ
428 /* killing nbr_self is invalid */
429 assert (nbr != nbr->oi->nbr_self);
430 if (nbr == nbr->oi->nbr_self)
d1b1cd8f 431 return 0;
478aab98 432
2d59836a 433 /* Reset neighbor. */
434 nsm_reset_nbr (nbr);
435
436 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
437 {
438 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
439
440 nbr_nbma->nbr = NULL;
441 nbr_nbma->state_change = nbr->state_change;
442
443 nbr->nbr_nbma = NULL;
444
445 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
446 nbr_nbma->v_poll);
447
448 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
2a42e285 449 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
2d59836a 450 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
451 }
452
453 /* Delete neighbor from interface. */
454 ospf_nbr_delete (nbr);
455
456 return 0;
457}
458
4dadc291 459static int
2d59836a 460nsm_inactivity_timer (struct ospf_neighbor *nbr)
461{
462 /* Kill neighbor. */
463 nsm_kill_nbr (nbr);
464
465 return 0;
466}
467
4dadc291 468static int
2d59836a 469nsm_ll_down (struct ospf_neighbor *nbr)
470{
471 /* Reset neighbor. */
472 /*nsm_reset_nbr (nbr);*/
473
474 /* Kill neighbor. */
475 nsm_kill_nbr (nbr);
476
477 return 0;
478}
479
480/* Neighbor State Machine */
481struct {
4dadc291 482 int (*func) (struct ospf_neighbor *);
2d59836a 483 int next_state;
484} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
485{
486 {
487 /* DependUpon: dummy state. */
488 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
489 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */
490 { nsm_ignore, NSM_DependUpon }, /* Start */
491 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */
492 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */
493 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */
494 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */
495 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */
496 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */
497 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */
498 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */
499 { nsm_ignore, NSM_DependUpon }, /* KillNbr */
500 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */
501 { nsm_ignore, NSM_DependUpon }, /* LLDown */
502 },
503 {
504 /* Down: */
505 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
506 { nsm_hello_received, NSM_Init }, /* HelloReceived */
507 { nsm_start, NSM_Attempt }, /* Start */
508 { nsm_ignore, NSM_Down }, /* 2-WayReceived */
509 { nsm_ignore, NSM_Down }, /* NegotiationDone */
510 { nsm_ignore, NSM_Down }, /* ExchangeDone */
511 { nsm_ignore, NSM_Down }, /* BadLSReq */
512 { nsm_ignore, NSM_Down }, /* LoadingDone */
513 { nsm_ignore, NSM_Down }, /* AdjOK? */
514 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */
515 { nsm_ignore, NSM_Down }, /* 1-WayReceived */
516 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
517 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
518 { nsm_ll_down, NSM_Down }, /* LLDown */
519 },
520 {
521 /* Attempt: */
522 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
523 { nsm_hello_received, NSM_Init }, /* HelloReceived */
524 { nsm_ignore, NSM_Attempt }, /* Start */
525 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */
526 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */
527 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */
528 { nsm_ignore, NSM_Attempt }, /* BadLSReq */
529 { nsm_ignore, NSM_Attempt }, /* LoadingDone */
530 { nsm_ignore, NSM_Attempt }, /* AdjOK? */
531 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */
532 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */
533 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
534 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
535 { nsm_ll_down, NSM_Down }, /* LLDown */
536 },
537 {
538 /* Init: */
539 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
540 { nsm_hello_received, NSM_Init }, /* HelloReceived */
541 { nsm_ignore, NSM_Init }, /* Start */
542 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
543 { nsm_ignore, NSM_Init }, /* NegotiationDone */
544 { nsm_ignore, NSM_Init }, /* ExchangeDone */
545 { nsm_ignore, NSM_Init }, /* BadLSReq */
546 { nsm_ignore, NSM_Init }, /* LoadingDone */
547 { nsm_ignore, NSM_Init }, /* AdjOK? */
548 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */
549 { nsm_ignore, NSM_Init }, /* 1-WayReceived */
550 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
551 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
552 { nsm_ll_down, NSM_Down }, /* LLDown */
553 },
554 {
555 /* 2-Way: */
556 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
557 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
558 { nsm_ignore, NSM_TwoWay }, /* Start */
559 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */
560 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */
561 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */
562 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */
563 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */
564 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
565 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */
566 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
567 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
568 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
569 { nsm_ll_down, NSM_Down }, /* LLDown */
570 },
571 {
572 /* ExStart: */
573 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
574 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
575 { nsm_ignore, NSM_ExStart }, /* Start */
576 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */
577 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
578 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */
579 { nsm_ignore, NSM_ExStart }, /* BadLSReq */
580 { nsm_ignore, NSM_ExStart }, /* LoadingDone */
581 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
582 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */
583 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
584 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
585 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
586 { nsm_ll_down, NSM_Down }, /* LLDown */
587 },
588 {
589 /* Exchange: */
590 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
591 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
592 { nsm_ignore, NSM_Exchange }, /* Start */
593 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */
594 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */
595 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
596 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
597 { nsm_ignore, NSM_Exchange }, /* LoadingDone */
598 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
599 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
600 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
601 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
602 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
603 { nsm_ll_down, NSM_Down }, /* LLDown */
604 },
605 {
606 /* Loading: */
607 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
608 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
609 { nsm_ignore, NSM_Loading }, /* Start */
610 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */
611 { nsm_ignore, NSM_Loading }, /* NegotiationDone */
612 { nsm_ignore, NSM_Loading }, /* ExchangeDone */
613 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
614 { nsm_ignore, NSM_Full }, /* LoadingDone */
615 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
616 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
617 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
618 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
619 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
620 { nsm_ll_down, NSM_Down }, /* LLDown */
621 },
622 { /* Full: */
623 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
624 { nsm_hello_received, NSM_Full }, /* HelloReceived */
625 { nsm_ignore, NSM_Full }, /* Start */
626 { nsm_ignore, NSM_Full }, /* 2-WayReceived */
627 { nsm_ignore, NSM_Full }, /* NegotiationDone */
628 { nsm_ignore, NSM_Full }, /* ExchangeDone */
629 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
630 { nsm_ignore, NSM_Full }, /* LoadingDone */
631 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
632 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
633 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
634 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
635 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
636 { nsm_ll_down, NSM_Down }, /* LLDown */
637 },
638};
639
eb1ce605 640const static char *ospf_nsm_event_str[] =
2d59836a 641{
642 "NoEvent",
643 "HelloReceived",
644 "Start",
645 "2-WayReceived",
646 "NegotiationDone",
647 "ExchangeDone",
648 "BadLSReq",
649 "LoadingDone",
650 "AdjOK?",
651 "SeqNumberMismatch",
652 "1-WayReceived",
653 "KillNbr",
654 "InactivityTimer",
655 "LLDown",
656};
657
658void
659nsm_change_state (struct ospf_neighbor *nbr, int state)
660{
68980084 661 struct ospf_interface *oi = nbr->oi;
2d59836a 662 struct ospf_area *vl_area = NULL;
663 u_char old_state;
664 int x;
665 int force = 1;
666
667 /* Logging change of status. */
668 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
2a42e285 669 zlog_debug ("NSM[%s:%s]: State change %s -> %s",
2d59836a 670 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
671 LOOKUP (ospf_nsm_state_msg, nbr->state),
672 LOOKUP (ospf_nsm_state_msg, state));
673
674 /* Preserve old status. */
675 old_state = nbr->state;
676
677 /* Change to new status. */
678 nbr->state = state;
679
680 /* Statistics. */
681 nbr->state_change++;
682
2d59836a 683 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
68980084 684 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
d7e60dd7
AS
685
686 /* Optionally notify about adjacency changes */
687 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
688 (old_state != state) &&
689 (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
690 (state == NSM_Full) || (state < old_state)))
691 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s",
692 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
693 LOOKUP (ospf_nsm_state_msg, old_state),
694 LOOKUP (ospf_nsm_state_msg, state));
695
5e4914c3 696#ifdef HAVE_SNMP
697 /* Terminal state or regression */
698 if ((state == NSM_Full) || (state == NSM_TwoWay) || (state < old_state))
699 {
700 /* ospfVirtNbrStateChange */
701 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
702 ospfTrapVirtNbrStateChange(nbr);
703 /* ospfNbrStateChange trap */
704 else
705 /* To/From FULL, only managed by DR */
706 if (((state != NSM_Full) && (old_state != NSM_Full)) ||
707 (oi->state == ISM_DR))
708 ospfTrapNbrStateChange(nbr);
709 }
710#endif
711
2d59836a 712 /* One of the neighboring routers changes to/from the FULL state. */
713 if ((old_state != NSM_Full && state == NSM_Full) ||
714 (old_state == NSM_Full && state != NSM_Full))
3aa8d5f9 715 {
2d59836a 716 if (state == NSM_Full)
717 {
718 oi->full_nbrs++;
719 oi->area->full_nbrs++;
720
68980084 721 ospf_check_abr_status (oi->ospf);
2d59836a 722
723 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
724 if (++vl_area->full_vls == 1)
68980084 725 ospf_schedule_abr_task (oi->ospf);
2d59836a 726
727 /* kevinm: refresh any redistributions */
68980084 728 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
729 {
730 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
731 continue;
732 ospf_external_lsa_refresh_type (oi->ospf, x, force);
733 }
2d59836a 734 }
735 else
736 {
737 oi->full_nbrs--;
738 oi->area->full_nbrs--;
739
68980084 740 ospf_check_abr_status (oi->ospf);
2d59836a 741
742 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
743 if (vl_area->full_vls > 0)
744 if (--vl_area->full_vls == 0)
68980084 745 ospf_schedule_abr_task (oi->ospf);
2d59836a 746 }
747
3aa8d5f9 748 zlog_info ("nsm_change_state(%s, %s -> %s): "
749 "scheduling new router-LSA origination",
750 inet_ntoa (nbr->router_id),
751 LOOKUP(ospf_nsm_state_msg, old_state),
752 LOOKUP(ospf_nsm_state_msg, state));
2d59836a 753
754 ospf_router_lsa_timer_add (oi->area);
755
756 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
757 {
758 struct ospf_area *vl_area =
68980084 759 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
2d59836a 760
761 if (vl_area)
762 ospf_router_lsa_timer_add (vl_area);
763 }
764
765 /* Originate network-LSA. */
766 if (oi->state == ISM_DR)
767 {
768 if (oi->network_lsa_self && oi->full_nbrs == 0)
769 {
770 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
771 ospf_lsa_unlock (oi->network_lsa_self);
772 oi->network_lsa_self = NULL;
773 OSPF_TIMER_OFF (oi->t_network_lsa_self);
774 }
775 else
776 ospf_network_lsa_timer_add (oi);
777 }
778 }
779
780#ifdef HAVE_OPAQUE_LSA
781 ospf_opaque_nsm_change (nbr, old_state);
782#endif /* HAVE_OPAQUE_LSA */
783
d1b1cd8f
PJ
784 /* State changes from > ExStart to <= ExStart should clear any Exchange
785 * or Full/LSA Update related lists and state.
786 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
787 *
788 * Note that transitions from > ExStart to < 2-Way (e.g. due to
789 * KillNbr or 1-Way) must and will do the same, but via
790 * nsm_reset_nbr.
791 */
792 if (old_state > NSM_ExStart
793 && (state == NSM_ExStart || state == NSM_TwoWay))
794 nsm_clear_adj (nbr);
795
2d59836a 796 /* Start DD exchange protocol */
797 if (state == NSM_ExStart)
798 {
799 if (nbr->dd_seqnum == 0)
800 nbr->dd_seqnum = time (NULL);
801 else
802 nbr->dd_seqnum++;
803
804 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
805 ospf_db_desc_send (nbr);
806 }
807
808 /* clear cryptographic sequence number */
809 if (state == NSM_Down)
810 nbr->crypt_seqnum = 0;
811
812 /* Generete NeighborChange ISM event. */
2d59836a 813 switch (oi->state) {
814 case ISM_DROther:
815 case ISM_Backup:
816 case ISM_DR:
817 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
818 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
819 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
820 break;
821 default:
822 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
823 break;
824 }
2d59836a 825
826 /* Performance hack. Send hello immideately when some neighbor enter
827 Init state. This whay we decrease neighbor discovery time. Gleb.*/
828 if (state == NSM_Init)
829 {
830 OSPF_ISM_TIMER_OFF (oi->t_hello);
f9ad937f 831 OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1);
2d59836a 832 }
833
834 /* Preserve old status? */
835}
836
837/* Execute NSM event process. */
838int
839ospf_nsm_event (struct thread *thread)
840{
841 int event;
842 int next_state;
843 struct ospf_neighbor *nbr;
844 struct in_addr router_id;
845 int old_state;
846 struct ospf_interface *oi;
847
848 nbr = THREAD_ARG (thread);
849 event = THREAD_VAL (thread);
850 router_id = nbr->router_id;
851
852 old_state = nbr->state;
853 oi = nbr->oi ;
854
855 /* Call function. */
856 next_state = (*(NSM [nbr->state][event].func))(nbr);
857
858 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
859 deleted. */
aa2737a0
PJ
860 if (event == NSM_KillNbr
861 || event == NSM_InactivityTimer
862 || event == NSM_LLDown)
2d59836a 863 {
864 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
2a42e285 865 zlog_debug ("NSM[%s:%s]: neighbor deleted",
2d59836a 866 IF_NAME (oi), inet_ntoa (router_id));
867
868 /* Timers are canceled in ospf_nbr_free, moreover we cannot call
869 nsm_timer_set here because nbr is freed already!!!*/
870 /*nsm_timer_set (nbr);*/
871
872 return 0;
873 }
874
875 if (! next_state)
876 next_state = NSM [nbr->state][event].next_state;
ba0beb4a
PJ
877 else if (NSM [nbr->state][event].next_state != NSM_DependUpon)
878 {
879 /* There's a mismatch between the FSM tables and what an FSM
880 * action/state-change function returned. State changes which
881 * do not have conditional/DependUpon next-states should not
882 * try set next_state.
883 */
884 zlog_warn ("NSM[%s:%s]: %s (%s): "
885 "Warning: action tried to change next_state to %s",
886 IF_NAME (oi), inet_ntoa (nbr->router_id),
887 LOOKUP (ospf_nsm_state_msg, nbr->state),
888 ospf_nsm_event_str [event],
889 LOOKUP (ospf_nsm_state_msg, next_state));
890
891 next_state = NSM [nbr->state][event].next_state;
892 }
2d59836a 893
894 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
2a42e285 895 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
2d59836a 896 inet_ntoa (nbr->router_id),
897 LOOKUP (ospf_nsm_state_msg, nbr->state),
898 ospf_nsm_event_str [event]);
899
900 /* If state is changed. */
901 if (next_state != nbr->state)
902 nsm_change_state (nbr, next_state);
903
904 /* Make sure timer is set. */
905 nsm_timer_set (nbr);
906
907 return 0;
908}
909
910/* Check loading state. */
911void
912ospf_check_nbr_loading (struct ospf_neighbor *nbr)
913{
914 if (nbr->state == NSM_Loading)
915 {
916 if (ospf_ls_request_isempty (nbr))
917 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
918 else if (nbr->ls_req_last == NULL)
919 ospf_ls_req_event (nbr);
920 }
921}