]> git.proxmox.com Git - mirror_frr.git/blame - ospfd/ospf_nsm.c
bgpd: Disable connected check for next hop on eBGP peers
[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 *);
6b0655a2 53
2d59836a 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}
6b0655a2 159
2d59836a 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
8b6912c2
DS
173 /* Send proactive ARP requests */
174 if (nbr->state < NSM_Exchange)
175 ospf_proactively_arp (nbr);
176
2d59836a 177 return 0;
178}
179
4dadc291 180static int
2d59836a 181nsm_start (struct ospf_neighbor *nbr)
182{
2d59836a 183 if (nbr->nbr_nbma)
184 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
185
186 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
187
188 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
189 nbr->v_inactivity);
190
8b6912c2
DS
191 /* Send proactive ARP requests */
192 ospf_proactively_arp (nbr);
193
2d59836a 194 return 0;
195}
196
4dadc291 197static int
2d59836a 198nsm_twoway_received (struct ospf_neighbor *nbr)
199{
8b6912c2
DS
200 int adj = nsm_should_adj (nbr);
201
202 /* Send proactive ARP requests */
203 if (adj)
204 ospf_proactively_arp (nbr);
205
206 return (adj ? NSM_ExStart : NSM_TwoWay);
2d59836a 207}
208
209int
210ospf_db_summary_count (struct ospf_neighbor *nbr)
211{
212 return ospf_lsdb_count_all (&nbr->db_sum);
213}
214
215int
216ospf_db_summary_isempty (struct ospf_neighbor *nbr)
217{
218 return ospf_lsdb_isempty (&nbr->db_sum);
219}
220
4dadc291 221static int
68980084 222ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
2d59836a 223{
09e4efdc 224#ifdef HAVE_OPAQUE_LSA
225 switch (lsa->data->type)
226 {
227 case OSPF_OPAQUE_LINK_LSA:
228 /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
d71ea652 229 if (nbr->oi && ospf_if_exists (lsa->oi) != nbr->oi)
09e4efdc 230 return 0;
231 break;
232 case OSPF_OPAQUE_AREA_LSA:
233 /*
234 * It is assured by the caller function "nsm_negotiation_done()"
235 * that every given LSA belongs to the same area with "nbr".
236 */
237 break;
238 case OSPF_OPAQUE_AS_LSA:
239 default:
240 break;
241 }
242#endif /* HAVE_OPAQUE_LSA */
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#ifdef HAVE_OPAQUE_LSA
302 /* Process only if the neighbor is opaque capable. */
303 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
304 {
68980084 305 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
306 ospf_db_summary_add (nbr, lsa);
307 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
308 ospf_db_summary_add (nbr, lsa);
2d59836a 309 }
310#endif /* HAVE_OPAQUE_LSA */
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
323#ifdef HAVE_OPAQUE_LSA
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#endif /* HAVE_OPAQUE_LSA */
330
2d59836a 331 return 0;
332}
333
4dadc291 334static int
2d59836a 335nsm_exchange_done (struct ospf_neighbor *nbr)
336{
2d59836a 337 if (ospf_ls_request_isempty (nbr))
338 return NSM_Full;
339
2d59836a 340 /* Send Link State Request. */
341 ospf_ls_req_send (nbr);
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
384#ifdef HAVE_OPAQUE_LSA
385 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
386 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
387#endif /* HAVE_OPAQUE_LSA */
388}
389
4dadc291 390static int
2d59836a 391nsm_kill_nbr (struct ospf_neighbor *nbr)
392{
478aab98 393 /* killing nbr_self is invalid */
478aab98 394 if (nbr == nbr->oi->nbr_self)
1f2c2743
PJ
395 {
396 assert (nbr != nbr->oi->nbr_self);
397 return 0;
398 }
478aab98 399
2d59836a 400 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
401 {
402 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
403
404 nbr_nbma->nbr = NULL;
405 nbr_nbma->state_change = nbr->state_change;
406
407 nbr->nbr_nbma = NULL;
408
409 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
410 nbr_nbma->v_poll);
411
412 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
2a42e285 413 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
2d59836a 414 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
415 }
416
2d59836a 417 return 0;
418}
419
2d59836a 420/* Neighbor State Machine */
421struct {
4dadc291 422 int (*func) (struct ospf_neighbor *);
2d59836a 423 int next_state;
424} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
425{
426 {
427 /* DependUpon: dummy state. */
539e1523 428 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 429 { NULL, NSM_DependUpon }, /* PacketReceived */
539e1523
PJ
430 { NULL, NSM_DependUpon }, /* Start */
431 { NULL, NSM_DependUpon }, /* 2-WayReceived */
432 { NULL, NSM_DependUpon }, /* NegotiationDone */
433 { NULL, NSM_DependUpon }, /* ExchangeDone */
434 { NULL, NSM_DependUpon }, /* BadLSReq */
435 { NULL, NSM_DependUpon }, /* LoadingDone */
436 { NULL, NSM_DependUpon }, /* AdjOK? */
437 { NULL, NSM_DependUpon }, /* SeqNumberMismatch */
438 { NULL, NSM_DependUpon }, /* 1-WayReceived */
439 { NULL, NSM_DependUpon }, /* KillNbr */
440 { NULL, NSM_DependUpon }, /* InactivityTimer */
441 { NULL, NSM_DependUpon }, /* LLDown */
2d59836a 442 },
1f2c2743
PJ
443 {
444 /* Deleted: dummy state. */
539e1523 445 { NULL, NSM_Deleted }, /* NoEvent */
57c5c652 446 { NULL, NSM_Deleted }, /* PacketReceived */
539e1523
PJ
447 { NULL, NSM_Deleted }, /* Start */
448 { NULL, NSM_Deleted }, /* 2-WayReceived */
449 { NULL, NSM_Deleted }, /* NegotiationDone */
450 { NULL, NSM_Deleted }, /* ExchangeDone */
451 { NULL, NSM_Deleted }, /* BadLSReq */
452 { NULL, NSM_Deleted }, /* LoadingDone */
453 { NULL, NSM_Deleted }, /* AdjOK? */
454 { NULL, NSM_Deleted }, /* SeqNumberMismatch */
455 { NULL, NSM_Deleted }, /* 1-WayReceived */
456 { NULL, NSM_Deleted }, /* KillNbr */
457 { NULL, NSM_Deleted }, /* InactivityTimer */
458 { NULL, NSM_Deleted }, /* LLDown */
1f2c2743 459 },
2d59836a 460 {
461 /* Down: */
539e1523 462 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 463 { nsm_packet_received, NSM_Init }, /* PacketReceived */
2d59836a 464 { nsm_start, NSM_Attempt }, /* Start */
539e1523
PJ
465 { NULL, NSM_Down }, /* 2-WayReceived */
466 { NULL, NSM_Down }, /* NegotiationDone */
467 { NULL, NSM_Down }, /* ExchangeDone */
468 { NULL, NSM_Down }, /* BadLSReq */
469 { NULL, NSM_Down }, /* LoadingDone */
470 { NULL, NSM_Down }, /* AdjOK? */
471 { NULL, NSM_Down }, /* SeqNumberMismatch */
472 { NULL, NSM_Down }, /* 1-WayReceived */
1f2c2743 473 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
474 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
475 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 476 },
477 {
478 /* Attempt: */
539e1523 479 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 480 { nsm_packet_received, NSM_Init }, /* PacketReceived */
539e1523
PJ
481 { NULL, NSM_Attempt }, /* Start */
482 { NULL, NSM_Attempt }, /* 2-WayReceived */
483 { NULL, NSM_Attempt }, /* NegotiationDone */
484 { NULL, NSM_Attempt }, /* ExchangeDone */
485 { NULL, NSM_Attempt }, /* BadLSReq */
486 { NULL, NSM_Attempt }, /* LoadingDone */
487 { NULL, NSM_Attempt }, /* AdjOK? */
488 { NULL, NSM_Attempt }, /* SeqNumberMismatch */
489 { NULL, NSM_Attempt }, /* 1-WayReceived */
1f2c2743 490 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
491 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
492 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 493 },
494 {
495 /* Init: */
539e1523 496 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 497 { nsm_packet_received, NSM_Init }, /* PacketReceived */
539e1523 498 { NULL, NSM_Init }, /* Start */
2d59836a 499 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
539e1523
PJ
500 { NULL, NSM_Init }, /* NegotiationDone */
501 { NULL, NSM_Init }, /* ExchangeDone */
502 { NULL, NSM_Init }, /* BadLSReq */
503 { NULL, NSM_Init }, /* LoadingDone */
504 { NULL, NSM_Init }, /* AdjOK? */
505 { NULL, NSM_Init }, /* SeqNumberMismatch */
506 { NULL, NSM_Init }, /* 1-WayReceived */
1f2c2743 507 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
508 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
509 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 510 },
511 {
512 /* 2-Way: */
539e1523 513 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 514 { nsm_packet_received, NSM_TwoWay }, /* HelloReceived */
539e1523
PJ
515 { NULL, NSM_TwoWay }, /* Start */
516 { NULL, NSM_TwoWay }, /* 2-WayReceived */
517 { NULL, NSM_TwoWay }, /* NegotiationDone */
518 { NULL, NSM_TwoWay }, /* ExchangeDone */
519 { NULL, NSM_TwoWay }, /* BadLSReq */
520 { NULL, NSM_TwoWay }, /* LoadingDone */
2d59836a 521 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
539e1523
PJ
522 { NULL, NSM_TwoWay }, /* SeqNumberMismatch */
523 { NULL, NSM_Init }, /* 1-WayReceived */
1f2c2743 524 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
525 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
526 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 527 },
528 {
529 /* ExStart: */
539e1523 530 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 531 { nsm_packet_received, NSM_ExStart }, /* PacaketReceived */
539e1523
PJ
532 { NULL, NSM_ExStart }, /* Start */
533 { NULL, NSM_ExStart }, /* 2-WayReceived */
2d59836a 534 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
539e1523
PJ
535 { NULL, NSM_ExStart }, /* ExchangeDone */
536 { NULL, NSM_ExStart }, /* BadLSReq */
537 { NULL, NSM_ExStart }, /* LoadingDone */
2d59836a 538 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
539e1523
PJ
539 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
540 { NULL, NSM_Init }, /* 1-WayReceived */
1f2c2743 541 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
542 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
543 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 544 },
545 {
546 /* Exchange: */
539e1523 547 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 548 { nsm_packet_received, NSM_Exchange }, /* PacketReceived */
539e1523
PJ
549 { NULL, NSM_Exchange }, /* Start */
550 { NULL, NSM_Exchange }, /* 2-WayReceived */
551 { NULL, NSM_Exchange }, /* NegotiationDone */
2d59836a 552 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
539e1523
PJ
553 { NULL, NSM_ExStart }, /* BadLSReq */
554 { NULL, NSM_Exchange }, /* LoadingDone */
2d59836a 555 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
539e1523
PJ
556 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
557 { NULL, NSM_Init }, /* 1-WayReceived */
1f2c2743 558 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
559 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
560 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 561 },
562 {
563 /* Loading: */
539e1523 564 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 565 { nsm_packet_received, NSM_Loading }, /* PacketReceived */
539e1523
PJ
566 { NULL, NSM_Loading }, /* Start */
567 { NULL, NSM_Loading }, /* 2-WayReceived */
568 { NULL, NSM_Loading }, /* NegotiationDone */
569 { NULL, NSM_Loading }, /* ExchangeDone */
570 { NULL, NSM_ExStart }, /* BadLSReq */
571 { NULL, NSM_Full }, /* LoadingDone */
2d59836a 572 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
539e1523
PJ
573 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
574 { NULL, NSM_Init }, /* 1-WayReceived */
1f2c2743 575 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
576 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
577 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 578 },
579 { /* Full: */
539e1523 580 { NULL, NSM_DependUpon }, /* NoEvent */
57c5c652 581 { nsm_packet_received, NSM_Full }, /* PacketReceived */
539e1523
PJ
582 { NULL, NSM_Full }, /* Start */
583 { NULL, NSM_Full }, /* 2-WayReceived */
584 { NULL, NSM_Full }, /* NegotiationDone */
585 { NULL, NSM_Full }, /* ExchangeDone */
586 { NULL, NSM_ExStart }, /* BadLSReq */
587 { NULL, NSM_Full }, /* LoadingDone */
2d59836a 588 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
539e1523
PJ
589 { NULL, NSM_ExStart }, /* SeqNumberMismatch */
590 { NULL, NSM_Init }, /* 1-WayReceived */
1f2c2743 591 { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */
539e1523
PJ
592 { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */
593 { nsm_kill_nbr, NSM_Deleted }, /* LLDown */
2d59836a 594 },
595};
596
30a2231a 597static const char *ospf_nsm_event_str[] =
2d59836a 598{
599 "NoEvent",
57c5c652 600 "PacketReceived",
2d59836a 601 "Start",
602 "2-WayReceived",
603 "NegotiationDone",
604 "ExchangeDone",
605 "BadLSReq",
606 "LoadingDone",
607 "AdjOK?",
608 "SeqNumberMismatch",
609 "1-WayReceived",
610 "KillNbr",
611 "InactivityTimer",
612 "LLDown",
613};
614
3d63f380
PJ
615static void
616nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event)
617{
618 /* Logging change of status. */
619 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
620 zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)",
621 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
622 LOOKUP (ospf_nsm_state_msg, nbr->state),
623 LOOKUP (ospf_nsm_state_msg, next_state),
624 ospf_nsm_event_str [event]);
625
626 /* Optionally notify about adjacency changes */
627 if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
628 (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
629 (next_state == NSM_Full) || (next_state < nbr->state)))
630 zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)",
631 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
632 LOOKUP (ospf_nsm_state_msg, nbr->state),
633 LOOKUP (ospf_nsm_state_msg, next_state),
634 ospf_nsm_event_str [event]);
635
3fed4160
PJ
636 /* Advance in NSM */
637 if (next_state > nbr->state)
2518efd1 638 nbr->ts_last_progress = recent_relative_time ();
3fed4160
PJ
639 else /* regression in NSM */
640 {
2518efd1 641 nbr->ts_last_regress = recent_relative_time ();
3fed4160
PJ
642 nbr->last_regress_str = ospf_nsm_event_str [event];
643 }
90c33177 644
3d63f380
PJ
645#ifdef HAVE_SNMP
646 /* Terminal state or regression */
647 if ((next_state == NSM_Full)
648 || (next_state == NSM_TwoWay)
649 || (next_state < nbr->state))
650 {
651 /* ospfVirtNbrStateChange */
652 if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK)
653 ospfTrapVirtNbrStateChange(nbr);
654 /* ospfNbrStateChange trap */
655 else
656 /* To/From FULL, only managed by DR */
657 if (((next_state != NSM_Full) && (nbr->state != NSM_Full))
658 || (nbr->oi->state == ISM_DR))
659 ospfTrapNbrStateChange(nbr);
660 }
661#endif
662}
663
de54b26c 664static void
2d59836a 665nsm_change_state (struct ospf_neighbor *nbr, int state)
666{
68980084 667 struct ospf_interface *oi = nbr->oi;
2d59836a 668 struct ospf_area *vl_area = NULL;
669 u_char old_state;
670 int x;
671 int force = 1;
672
2d59836a 673 /* Preserve old status. */
674 old_state = nbr->state;
675
676 /* Change to new status. */
677 nbr->state = state;
678
679 /* Statistics. */
680 nbr->state_change++;
681
2d59836a 682 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
68980084 683 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
d7e60dd7 684
7a9d983e
CF
685 /* Generate NeighborChange ISM event.
686 *
687 * In response to NeighborChange, DR election is rerun. The information
688 * from the election process is required by the router-lsa construction.
689 *
690 * Therefore, trigger the event prior to refreshing the LSAs. */
691 switch (oi->state) {
692 case ISM_DROther:
693 case ISM_Backup:
694 case ISM_DR:
695 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
696 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
697 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
698 break;
699 default:
700 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
701 break;
702 }
703
2d59836a 704 /* One of the neighboring routers changes to/from the FULL state. */
705 if ((old_state != NSM_Full && state == NSM_Full) ||
706 (old_state == NSM_Full && state != NSM_Full))
3aa8d5f9 707 {
2d59836a 708 if (state == NSM_Full)
709 {
710 oi->full_nbrs++;
711 oi->area->full_nbrs++;
712
68980084 713 ospf_check_abr_status (oi->ospf);
2d59836a 714
715 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
716 if (++vl_area->full_vls == 1)
68980084 717 ospf_schedule_abr_task (oi->ospf);
2d59836a 718
719 /* kevinm: refresh any redistributions */
68980084 720 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
721 {
7c8ff89e
DS
722 struct list *red_list;
723 struct listnode *node;
724 struct ospf_redist *red;
725
726 if (x == ZEBRA_ROUTE_OSPF6)
727 continue;
728
729 red_list = oi->ospf->redist[x];
730 if (!red_list)
731 continue;
732
733 for (ALL_LIST_ELEMENTS_RO(red_list, node, red))
734 ospf_external_lsa_refresh_type (oi->ospf, x, red->instance, force);
68980084 735 }
9fd4958a
DN
736 /* XXX: Clearly some thing is wrong with refresh of external LSAs
737 * this added to hack around defaults not refreshing after a timer
738 * jump.
739 */
740 ospf_external_lsa_refresh_default (oi->ospf);
2d59836a 741 }
742 else
743 {
744 oi->full_nbrs--;
745 oi->area->full_nbrs--;
746
68980084 747 ospf_check_abr_status (oi->ospf);
2d59836a 748
749 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
750 if (vl_area->full_vls > 0)
751 if (--vl_area->full_vls == 0)
68980084 752 ospf_schedule_abr_task (oi->ospf);
2d59836a 753 }
754
3aa8d5f9 755 zlog_info ("nsm_change_state(%s, %s -> %s): "
756 "scheduling new router-LSA origination",
757 inet_ntoa (nbr->router_id),
758 LOOKUP(ospf_nsm_state_msg, old_state),
759 LOOKUP(ospf_nsm_state_msg, state));
2d59836a 760
c363d386 761 ospf_router_lsa_update_area (oi->area);
2d59836a 762
763 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
764 {
765 struct ospf_area *vl_area =
68980084 766 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
2d59836a 767
768 if (vl_area)
c363d386 769 ospf_router_lsa_update_area (vl_area);
2d59836a 770 }
771
772 /* Originate network-LSA. */
773 if (oi->state == ISM_DR)
774 {
775 if (oi->network_lsa_self && oi->full_nbrs == 0)
776 {
777 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
1fe6ed38 778 ospf_lsa_unlock (&oi->network_lsa_self);
2d59836a 779 oi->network_lsa_self = NULL;
2d59836a 780 }
781 else
c363d386 782 ospf_network_lsa_update (oi);
2d59836a 783 }
784 }
785
786#ifdef HAVE_OPAQUE_LSA
787 ospf_opaque_nsm_change (nbr, old_state);
788#endif /* HAVE_OPAQUE_LSA */
789
d1b1cd8f
PJ
790 /* State changes from > ExStart to <= ExStart should clear any Exchange
791 * or Full/LSA Update related lists and state.
792 * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
d1b1cd8f 793 */
539e1523 794 if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
d1b1cd8f
PJ
795 nsm_clear_adj (nbr);
796
2d59836a 797 /* Start DD exchange protocol */
798 if (state == NSM_ExStart)
799 {
800 if (nbr->dd_seqnum == 0)
2518efd1 801 nbr->dd_seqnum = quagga_time (NULL);
2d59836a 802 else
803 nbr->dd_seqnum++;
804
805 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
806 ospf_db_desc_send (nbr);
807 }
808
809 /* clear cryptographic sequence number */
810 if (state == NSM_Down)
811 nbr->crypt_seqnum = 0;
812
2d59836a 813 /* Preserve old status? */
814}
815
816/* Execute NSM event process. */
817int
818ospf_nsm_event (struct thread *thread)
819{
820 int event;
821 int next_state;
822 struct ospf_neighbor *nbr;
2d59836a 823
824 nbr = THREAD_ARG (thread);
825 event = THREAD_VAL (thread);
2d59836a 826
3d63f380
PJ
827 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
828 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi),
829 inet_ntoa (nbr->router_id),
830 LOOKUP (ospf_nsm_state_msg, nbr->state),
831 ospf_nsm_event_str [event]);
832
539e1523 833 next_state = NSM [nbr->state][event].next_state;
2d59836a 834
539e1523
PJ
835 /* Call function. */
836 if (NSM [nbr->state][event].func != NULL)
ba0beb4a 837 {
539e1523 838 int func_state = (*(NSM [nbr->state][event].func))(nbr);
ba0beb4a 839
539e1523
PJ
840 if (NSM [nbr->state][event].next_state == NSM_DependUpon)
841 next_state = func_state;
842 else if (func_state)
843 {
844 /* There's a mismatch between the FSM tables and what an FSM
845 * action/state-change function returned. State changes which
846 * do not have conditional/DependUpon next-states should not
847 * try set next_state.
848 */
849 zlog_warn ("NSM[%s:%s]: %s (%s): "
850 "Warning: action tried to change next_state to %s",
851 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
852 LOOKUP (ospf_nsm_state_msg, nbr->state),
853 ospf_nsm_event_str [event],
854 LOOKUP (ospf_nsm_state_msg, func_state));
855 }
ba0beb4a 856 }
2d59836a 857
539e1523
PJ
858 assert (next_state != NSM_DependUpon);
859
2d59836a 860 /* If state is changed. */
861 if (next_state != nbr->state)
3d63f380
PJ
862 {
863 nsm_notice_state_change (nbr, next_state, event);
864 nsm_change_state (nbr, next_state);
865 }
2d59836a 866
867 /* Make sure timer is set. */
868 nsm_timer_set (nbr);
869
1f2c2743
PJ
870 /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
871 * is deleted.
872 *
873 * Rather than encode knowledge here of which events lead to NBR
874 * delete, we take our cue from the NSM table, via the dummy
875 * 'Deleted' neighbour state.
876 */
877 if (nbr->state == NSM_Deleted)
878 ospf_nbr_delete (nbr);
879
2d59836a 880 return 0;
881}
882
883/* Check loading state. */
884void
885ospf_check_nbr_loading (struct ospf_neighbor *nbr)
886{
887 if (nbr->state == NSM_Loading)
888 {
889 if (ospf_ls_request_isempty (nbr))
890 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
891 else if (nbr->ls_req_last == NULL)
892 ospf_ls_req_event (nbr);
893 }
894}