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