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