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