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