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