blob: 1d100848c77252c2206b51f93b680efebea90cfe [file] [log] [blame]
paul2d598362003-01-17 23:48:42 +00001/*
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"
vincent5e4914c2005-09-29 16:34:30 +000050#include "ospfd/ospf_snmp.h"
paul2d598362003-01-17 23:48:42 +000051
52void nsm_reset_nbr (struct ospf_neighbor *);
53
54
55/* OSPF NSM Timer functions. */
paul4dadc292005-05-06 21:37:42 +000056static int
paul2d598362003-01-17 23:48:42 +000057ospf_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
paul4dadc292005-05-06 21:37:42 +000073static int
paul2d598362003-01-17 23:48:42 +000074ospf_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))
ajs2a42e282004-12-08 18:43:03 +000085 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
paul2d598362003-01-17 23:48:42 +000086 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
paul4dadc292005-05-06 21:37:42 +0000100static void
paul2d598362003-01-17 23:48:42 +0000101nsm_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
142
143/* OSPF NSM functions. */
paul4dadc292005-05-06 21:37:42 +0000144static int
paul2d598362003-01-17 23:48:42 +0000145nsm_ignore (struct ospf_neighbor *nbr)
146{
147 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000148 zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: nsm_ignore called",
paul2d598362003-01-17 23:48:42 +0000149 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
150
151 return 0;
152}
153
paul4dadc292005-05-06 21:37:42 +0000154static int
paul2d598362003-01-17 23:48:42 +0000155nsm_hello_received (struct ospf_neighbor *nbr)
156{
157 /* Start or Restart Inactivity Timer. */
158 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
159
160 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
161 nbr->v_inactivity);
162
163 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
164 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
165
166 return 0;
167}
168
paul4dadc292005-05-06 21:37:42 +0000169static int
paul2d598362003-01-17 23:48:42 +0000170nsm_start (struct ospf_neighbor *nbr)
171{
172
173 nsm_reset_nbr (nbr);
174
175 if (nbr->nbr_nbma)
176 OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
177
178 OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
179
180 OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
181 nbr->v_inactivity);
182
183 return 0;
184}
185
paul4dadc292005-05-06 21:37:42 +0000186static int
paul2d598362003-01-17 23:48:42 +0000187nsm_twoway_received (struct ospf_neighbor *nbr)
188{
189 struct ospf_interface *oi;
190 int next_state = NSM_TwoWay;
191
192 oi = nbr->oi;
193
194 /* These netowork types must be adjacency. */
195 if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
196 oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
197 oi->type == OSPF_IFTYPE_VIRTUALLINK)
198 next_state = NSM_ExStart;
199
200 /* Router itself is the DRouter or the BDRouter. */
201 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) ||
202 IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
203 next_state = NSM_ExStart;
204
205 /* Neighboring Router is the DRouter or the BDRouter. */
206 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router) ||
207 IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router))
208 next_state = NSM_ExStart;
209
210 return next_state;
211}
212
213int
214ospf_db_summary_count (struct ospf_neighbor *nbr)
215{
216 return ospf_lsdb_count_all (&nbr->db_sum);
217}
218
219int
220ospf_db_summary_isempty (struct ospf_neighbor *nbr)
221{
222 return ospf_lsdb_isempty (&nbr->db_sum);
223}
224
paul4dadc292005-05-06 21:37:42 +0000225static int
paul68980082003-03-25 05:07:42 +0000226ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
paul2d598362003-01-17 23:48:42 +0000227{
paul09e4efd2003-01-18 00:12:02 +0000228#ifdef HAVE_OPAQUE_LSA
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". */
233 if (lsa->oi != nbr->oi)
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 }
246#endif /* HAVE_OPAQUE_LSA */
247
paul2d598362003-01-17 23:48:42 +0000248 /* Stay away from any Local Translated Type-7 LSAs */
249 if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
250 return 0;
paul2d598362003-01-17 23:48:42 +0000251
252 if (IS_LSA_MAXAGE (lsa))
253 ospf_ls_retransmit_add (nbr, lsa);
254 else
255 ospf_lsdb_add (&nbr->db_sum, lsa);
256
257 return 0;
258}
259
260void
261ospf_db_summary_clear (struct ospf_neighbor *nbr)
262{
263 struct ospf_lsdb *lsdb;
264 int i;
265
266 lsdb = &nbr->db_sum;
267 for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
268 {
269 struct route_table *table = lsdb->type[i].db;
270 struct route_node *rn;
271
272 for (rn = route_top (table); rn; rn = route_next (rn))
273 if (rn->info)
274 ospf_lsdb_delete (&nbr->db_sum, rn->info);
275 }
276}
277
278
279
paul2d598362003-01-17 23:48:42 +0000280/* The area link state database consists of the router-LSAs,
281 network-LSAs and summary-LSAs contained in the area structure,
paul68980082003-03-25 05:07:42 +0000282 along with the AS-external-LSAs contained in the global structure.
283 AS-external-LSAs are omitted from a virtual neighbor's Database
paul2d598362003-01-17 23:48:42 +0000284 summary list. AS-external-LSAs are omitted from the Database
285 summary list if the area has been configured as a stub. */
paul4dadc292005-05-06 21:37:42 +0000286static int
paul2d598362003-01-17 23:48:42 +0000287nsm_negotiation_done (struct ospf_neighbor *nbr)
288{
paul68980082003-03-25 05:07:42 +0000289 struct ospf_area *area = nbr->oi->area;
290 struct ospf_lsa *lsa;
291 struct route_node *rn;
paul2d598362003-01-17 23:48:42 +0000292
paul68980082003-03-25 05:07:42 +0000293 LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
294 ospf_db_summary_add (nbr, lsa);
295 LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
296 ospf_db_summary_add (nbr, lsa);
297 LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
298 ospf_db_summary_add (nbr, lsa);
299 LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
300 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000301
paul2d598362003-01-17 23:48:42 +0000302#ifdef HAVE_OPAQUE_LSA
303 /* Process only if the neighbor is opaque capable. */
304 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
305 {
paul68980082003-03-25 05:07:42 +0000306 LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
307 ospf_db_summary_add (nbr, lsa);
308 LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
309 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000310 }
311#endif /* HAVE_OPAQUE_LSA */
312
hassof4833e92005-06-20 20:42:26 +0000313 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
paul68980082003-03-25 05:07:42 +0000319 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);
paul2d598362003-01-17 23:48:42 +0000323
324#ifdef HAVE_OPAQUE_LSA
paul68980082003-03-25 05:07:42 +0000325 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
326 && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
327 && area->external_routing == OSPF_AREA_DEFAULT))
328 LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
329 ospf_db_summary_add (nbr, lsa);
paul2d598362003-01-17 23:48:42 +0000330#endif /* HAVE_OPAQUE_LSA */
331
paul2d598362003-01-17 23:48:42 +0000332 return 0;
333}
334
paul4dadc292005-05-06 21:37:42 +0000335static int
paul2d598362003-01-17 23:48:42 +0000336nsm_exchange_done (struct ospf_neighbor *nbr)
337{
paul2d598362003-01-17 23:48:42 +0000338 if (ospf_ls_request_isempty (nbr))
339 return NSM_Full;
340
341 /* Cancel dd retransmit timer. */
342 /* OSPF_NSM_TIMER_OFF (nbr->t_db_desc); */
343
344 /* Send Link State Request. */
345 ospf_ls_req_send (nbr);
346
347 return NSM_Loading;
348}
349
paul4dadc292005-05-06 21:37:42 +0000350static int
paul2d598362003-01-17 23:48:42 +0000351nsm_bad_ls_req (struct ospf_neighbor *nbr)
352{
353 /* Clear neighbor. */
354 nsm_reset_nbr (nbr);
355
356 return 0;
357}
358
paul4dadc292005-05-06 21:37:42 +0000359static int
paul2d598362003-01-17 23:48:42 +0000360nsm_adj_ok (struct ospf_neighbor *nbr)
361{
362 struct ospf_interface *oi;
363 int next_state;
364 int flag = 0;
365
366 oi = nbr->oi;
367 next_state = nbr->state;
368
369 /* These netowork types must be adjacency. */
paul68980082003-03-25 05:07:42 +0000370 if (oi->type == OSPF_IFTYPE_POINTOPOINT
371 || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
372 || oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul2d598362003-01-17 23:48:42 +0000373 flag = 1;
374
375 /* Router itself is the DRouter or the BDRouter. */
paul68980082003-03-25 05:07:42 +0000376 if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
377 || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)))
paul2d598362003-01-17 23:48:42 +0000378 flag = 1;
379
paul68980082003-03-25 05:07:42 +0000380 if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
381 || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
paul2d598362003-01-17 23:48:42 +0000382 flag = 1;
383
384 if (nbr->state == NSM_TwoWay && flag == 1)
385 next_state = NSM_ExStart;
386 else if (nbr->state >= NSM_ExStart && flag == 0)
387 next_state = NSM_TwoWay;
388
389 return next_state;
390}
391
paul4dadc292005-05-06 21:37:42 +0000392static int
paul2d598362003-01-17 23:48:42 +0000393nsm_seq_number_mismatch (struct ospf_neighbor *nbr)
394{
395 /* Clear neighbor. */
396 nsm_reset_nbr (nbr);
397
398 return 0;
399}
400
paul4dadc292005-05-06 21:37:42 +0000401static int
paul2d598362003-01-17 23:48:42 +0000402nsm_oneway_received (struct ospf_neighbor *nbr)
403{
404 /* Clear neighbor. */
405 nsm_reset_nbr (nbr);
406
407 return 0;
408}
409
410void
411nsm_reset_nbr (struct ospf_neighbor *nbr)
412{
413 /* Clear Database Summary list. */
414 if (!ospf_db_summary_isempty (nbr))
415 ospf_db_summary_clear (nbr);
416
417 /* Clear Link State Request list. */
418 if (!ospf_ls_request_isempty (nbr))
419 ospf_ls_request_delete_all (nbr);
420
421 /* Clear Link State Retransmission list. */
422 if (!ospf_ls_retransmit_isempty (nbr))
423 ospf_ls_retransmit_clear (nbr);
424
425 /* Cancel thread. */
426 OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
427 OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
428 OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
429 OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
430
431#ifdef HAVE_OPAQUE_LSA
432 if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
433 UNSET_FLAG (nbr->options, OSPF_OPTION_O);
434#endif /* HAVE_OPAQUE_LSA */
435}
436
paul4dadc292005-05-06 21:37:42 +0000437static int
paul2d598362003-01-17 23:48:42 +0000438nsm_kill_nbr (struct ospf_neighbor *nbr)
439{
440 /* call it here because we cannot call it from ospf_nsm_event */
441 nsm_change_state (nbr, NSM_Down);
442
443 /* Reset neighbor. */
444 nsm_reset_nbr (nbr);
445
446 if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
447 {
448 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
449
450 nbr_nbma->nbr = NULL;
451 nbr_nbma->state_change = nbr->state_change;
452
453 nbr->nbr_nbma = NULL;
454
455 OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
456 nbr_nbma->v_poll);
457
458 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000459 zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
paul2d598362003-01-17 23:48:42 +0000460 IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));
461 }
462
463 /* Delete neighbor from interface. */
464 ospf_nbr_delete (nbr);
465
466 return 0;
467}
468
paul4dadc292005-05-06 21:37:42 +0000469static int
paul2d598362003-01-17 23:48:42 +0000470nsm_inactivity_timer (struct ospf_neighbor *nbr)
471{
472 /* Kill neighbor. */
473 nsm_kill_nbr (nbr);
474
475 return 0;
476}
477
paul4dadc292005-05-06 21:37:42 +0000478static int
paul2d598362003-01-17 23:48:42 +0000479nsm_ll_down (struct ospf_neighbor *nbr)
480{
481 /* Reset neighbor. */
482 /*nsm_reset_nbr (nbr);*/
483
484 /* Kill neighbor. */
485 nsm_kill_nbr (nbr);
486
487 return 0;
488}
489
490/* Neighbor State Machine */
491struct {
paul4dadc292005-05-06 21:37:42 +0000492 int (*func) (struct ospf_neighbor *);
paul2d598362003-01-17 23:48:42 +0000493 int next_state;
494} NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
495{
496 {
497 /* DependUpon: dummy state. */
498 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
499 { nsm_ignore, NSM_DependUpon }, /* HelloReceived */
500 { nsm_ignore, NSM_DependUpon }, /* Start */
501 { nsm_ignore, NSM_DependUpon }, /* 2-WayReceived */
502 { nsm_ignore, NSM_DependUpon }, /* NegotiationDone */
503 { nsm_ignore, NSM_DependUpon }, /* ExchangeDone */
504 { nsm_ignore, NSM_DependUpon }, /* BadLSReq */
505 { nsm_ignore, NSM_DependUpon }, /* LoadingDone */
506 { nsm_ignore, NSM_DependUpon }, /* AdjOK? */
507 { nsm_ignore, NSM_DependUpon }, /* SeqNumberMismatch */
508 { nsm_ignore, NSM_DependUpon }, /* 1-WayReceived */
509 { nsm_ignore, NSM_DependUpon }, /* KillNbr */
510 { nsm_ignore, NSM_DependUpon }, /* InactivityTimer */
511 { nsm_ignore, NSM_DependUpon }, /* LLDown */
512 },
513 {
514 /* Down: */
515 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
516 { nsm_hello_received, NSM_Init }, /* HelloReceived */
517 { nsm_start, NSM_Attempt }, /* Start */
518 { nsm_ignore, NSM_Down }, /* 2-WayReceived */
519 { nsm_ignore, NSM_Down }, /* NegotiationDone */
520 { nsm_ignore, NSM_Down }, /* ExchangeDone */
521 { nsm_ignore, NSM_Down }, /* BadLSReq */
522 { nsm_ignore, NSM_Down }, /* LoadingDone */
523 { nsm_ignore, NSM_Down }, /* AdjOK? */
524 { nsm_ignore, NSM_Down }, /* SeqNumberMismatch */
525 { nsm_ignore, NSM_Down }, /* 1-WayReceived */
526 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
527 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
528 { nsm_ll_down, NSM_Down }, /* LLDown */
529 },
530 {
531 /* Attempt: */
532 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
533 { nsm_hello_received, NSM_Init }, /* HelloReceived */
534 { nsm_ignore, NSM_Attempt }, /* Start */
535 { nsm_ignore, NSM_Attempt }, /* 2-WayReceived */
536 { nsm_ignore, NSM_Attempt }, /* NegotiationDone */
537 { nsm_ignore, NSM_Attempt }, /* ExchangeDone */
538 { nsm_ignore, NSM_Attempt }, /* BadLSReq */
539 { nsm_ignore, NSM_Attempt }, /* LoadingDone */
540 { nsm_ignore, NSM_Attempt }, /* AdjOK? */
541 { nsm_ignore, NSM_Attempt }, /* SeqNumberMismatch */
542 { nsm_ignore, NSM_Attempt }, /* 1-WayReceived */
543 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
544 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
545 { nsm_ll_down, NSM_Down }, /* LLDown */
546 },
547 {
548 /* Init: */
549 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
550 { nsm_hello_received, NSM_Init }, /* HelloReceived */
551 { nsm_ignore, NSM_Init }, /* Start */
552 { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */
553 { nsm_ignore, NSM_Init }, /* NegotiationDone */
554 { nsm_ignore, NSM_Init }, /* ExchangeDone */
555 { nsm_ignore, NSM_Init }, /* BadLSReq */
556 { nsm_ignore, NSM_Init }, /* LoadingDone */
557 { nsm_ignore, NSM_Init }, /* AdjOK? */
558 { nsm_ignore, NSM_Init }, /* SeqNumberMismatch */
559 { nsm_ignore, NSM_Init }, /* 1-WayReceived */
560 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
561 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
562 { nsm_ll_down, NSM_Down }, /* LLDown */
563 },
564 {
565 /* 2-Way: */
566 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
567 { nsm_hello_received, NSM_TwoWay }, /* HelloReceived */
568 { nsm_ignore, NSM_TwoWay }, /* Start */
569 { nsm_ignore, NSM_TwoWay }, /* 2-WayReceived */
570 { nsm_ignore, NSM_TwoWay }, /* NegotiationDone */
571 { nsm_ignore, NSM_TwoWay }, /* ExchangeDone */
572 { nsm_ignore, NSM_TwoWay }, /* BadLSReq */
573 { nsm_ignore, NSM_TwoWay }, /* LoadingDone */
574 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
575 { nsm_ignore, NSM_TwoWay }, /* SeqNumberMismatch */
576 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
577 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
578 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
579 { nsm_ll_down, NSM_Down }, /* LLDown */
580 },
581 {
582 /* ExStart: */
583 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
584 { nsm_hello_received, NSM_ExStart }, /* HelloReceived */
585 { nsm_ignore, NSM_ExStart }, /* Start */
586 { nsm_ignore, NSM_ExStart }, /* 2-WayReceived */
587 { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */
588 { nsm_ignore, NSM_ExStart }, /* ExchangeDone */
589 { nsm_ignore, NSM_ExStart }, /* BadLSReq */
590 { nsm_ignore, NSM_ExStart }, /* LoadingDone */
591 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
592 { nsm_ignore, NSM_ExStart }, /* SeqNumberMismatch */
593 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
594 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
595 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
596 { nsm_ll_down, NSM_Down }, /* LLDown */
597 },
598 {
599 /* Exchange: */
600 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
601 { nsm_hello_received, NSM_Exchange }, /* HelloReceived */
602 { nsm_ignore, NSM_Exchange }, /* Start */
603 { nsm_ignore, NSM_Exchange }, /* 2-WayReceived */
604 { nsm_ignore, NSM_Exchange }, /* NegotiationDone */
605 { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */
606 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
607 { nsm_ignore, NSM_Exchange }, /* LoadingDone */
608 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
609 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
610 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
611 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
612 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
613 { nsm_ll_down, NSM_Down }, /* LLDown */
614 },
615 {
616 /* Loading: */
617 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
618 { nsm_hello_received, NSM_Loading }, /* HelloReceived */
619 { nsm_ignore, NSM_Loading }, /* Start */
620 { nsm_ignore, NSM_Loading }, /* 2-WayReceived */
621 { nsm_ignore, NSM_Loading }, /* NegotiationDone */
622 { nsm_ignore, NSM_Loading }, /* ExchangeDone */
623 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
624 { nsm_ignore, NSM_Full }, /* LoadingDone */
625 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
626 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
627 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
628 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
629 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
630 { nsm_ll_down, NSM_Down }, /* LLDown */
631 },
632 { /* Full: */
633 { nsm_ignore, NSM_DependUpon }, /* NoEvent */
634 { nsm_hello_received, NSM_Full }, /* HelloReceived */
635 { nsm_ignore, NSM_Full }, /* Start */
636 { nsm_ignore, NSM_Full }, /* 2-WayReceived */
637 { nsm_ignore, NSM_Full }, /* NegotiationDone */
638 { nsm_ignore, NSM_Full }, /* ExchangeDone */
639 { nsm_bad_ls_req, NSM_ExStart }, /* BadLSReq */
640 { nsm_ignore, NSM_Full }, /* LoadingDone */
641 { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */
642 { nsm_seq_number_mismatch, NSM_ExStart }, /* SeqNumberMismatch */
643 { nsm_oneway_received, NSM_Init }, /* 1-WayReceived */
644 { nsm_kill_nbr, NSM_Down }, /* KillNbr */
645 { nsm_inactivity_timer, NSM_Down }, /* InactivityTimer */
646 { nsm_ll_down, NSM_Down }, /* LLDown */
647 },
648};
649
hassoeb1ce602004-10-08 08:17:22 +0000650const static char *ospf_nsm_event_str[] =
paul2d598362003-01-17 23:48:42 +0000651{
652 "NoEvent",
653 "HelloReceived",
654 "Start",
655 "2-WayReceived",
656 "NegotiationDone",
657 "ExchangeDone",
658 "BadLSReq",
659 "LoadingDone",
660 "AdjOK?",
661 "SeqNumberMismatch",
662 "1-WayReceived",
663 "KillNbr",
664 "InactivityTimer",
665 "LLDown",
666};
667
668void
669nsm_change_state (struct ospf_neighbor *nbr, int state)
670{
paul68980082003-03-25 05:07:42 +0000671 struct ospf_interface *oi = nbr->oi;
paul2d598362003-01-17 23:48:42 +0000672 struct ospf_area *vl_area = NULL;
673 u_char old_state;
674 int x;
675 int force = 1;
676
677 /* Logging change of status. */
678 if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
ajs2a42e282004-12-08 18:43:03 +0000679 zlog_debug ("NSM[%s:%s]: State change %s -> %s",
paul2d598362003-01-17 23:48:42 +0000680 IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
681 LOOKUP (ospf_nsm_state_msg, nbr->state),
682 LOOKUP (ospf_nsm_state_msg, state));
683
684 /* Preserve old status. */
685 old_state = nbr->state;
686
687 /* Change to new status. */
688 nbr->state = state;
689
690 /* Statistics. */
691 nbr->state_change++;
692
paul2d598362003-01-17 23:48:42 +0000693 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
paul68980082003-03-25 05:07:42 +0000694 vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000695
vincent5e4914c2005-09-29 16:34:30 +0000696#ifdef HAVE_SNMP
697 /* Terminal state or regression */
698 if ((state == NSM_Full) || (state == NSM_TwoWay) || (state < old_state))
699 {
700 /* ospfVirtNbrStateChange */
701 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
702 ospfTrapVirtNbrStateChange(nbr);
703 /* ospfNbrStateChange trap */
704 else
705 /* To/From FULL, only managed by DR */
706 if (((state != NSM_Full) && (old_state != NSM_Full)) ||
707 (oi->state == ISM_DR))
708 ospfTrapNbrStateChange(nbr);
709 }
710#endif
711
paul2d598362003-01-17 23:48:42 +0000712 /* One of the neighboring routers changes to/from the FULL state. */
713 if ((old_state != NSM_Full && state == NSM_Full) ||
714 (old_state == NSM_Full && state != NSM_Full))
ajs3aa8d5f2004-12-11 18:00:06 +0000715 {
paul2d598362003-01-17 23:48:42 +0000716 if (state == NSM_Full)
717 {
718 oi->full_nbrs++;
719 oi->area->full_nbrs++;
720
paul68980082003-03-25 05:07:42 +0000721 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000722
723 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
724 if (++vl_area->full_vls == 1)
paul68980082003-03-25 05:07:42 +0000725 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000726
727 /* kevinm: refresh any redistributions */
paul68980082003-03-25 05:07:42 +0000728 for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
729 {
730 if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
731 continue;
732 ospf_external_lsa_refresh_type (oi->ospf, x, force);
733 }
paul2d598362003-01-17 23:48:42 +0000734 }
735 else
736 {
737 oi->full_nbrs--;
738 oi->area->full_nbrs--;
739
paul68980082003-03-25 05:07:42 +0000740 ospf_check_abr_status (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000741
742 if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
743 if (vl_area->full_vls > 0)
744 if (--vl_area->full_vls == 0)
paul68980082003-03-25 05:07:42 +0000745 ospf_schedule_abr_task (oi->ospf);
paul2d598362003-01-17 23:48:42 +0000746
747 /* clear neighbor retransmit list */
748 if (!ospf_ls_retransmit_isempty (nbr))
749 ospf_ls_retransmit_clear (nbr);
750 }
751
ajs3aa8d5f2004-12-11 18:00:06 +0000752 zlog_info ("nsm_change_state(%s, %s -> %s): "
753 "scheduling new router-LSA origination",
754 inet_ntoa (nbr->router_id),
755 LOOKUP(ospf_nsm_state_msg, old_state),
756 LOOKUP(ospf_nsm_state_msg, state));
paul2d598362003-01-17 23:48:42 +0000757
758 ospf_router_lsa_timer_add (oi->area);
759
760 if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
761 {
762 struct ospf_area *vl_area =
paul68980082003-03-25 05:07:42 +0000763 ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
paul2d598362003-01-17 23:48:42 +0000764
765 if (vl_area)
766 ospf_router_lsa_timer_add (vl_area);
767 }
768
769 /* Originate network-LSA. */
770 if (oi->state == ISM_DR)
771 {
772 if (oi->network_lsa_self && oi->full_nbrs == 0)
773 {
774 ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
775 ospf_lsa_unlock (oi->network_lsa_self);
776 oi->network_lsa_self = NULL;
777 OSPF_TIMER_OFF (oi->t_network_lsa_self);
778 }
779 else
780 ospf_network_lsa_timer_add (oi);
781 }
782 }
783
784#ifdef HAVE_OPAQUE_LSA
785 ospf_opaque_nsm_change (nbr, old_state);
786#endif /* HAVE_OPAQUE_LSA */
787
788 /* Start DD exchange protocol */
789 if (state == NSM_ExStart)
790 {
791 if (nbr->dd_seqnum == 0)
792 nbr->dd_seqnum = time (NULL);
793 else
794 nbr->dd_seqnum++;
795
796 nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
797 ospf_db_desc_send (nbr);
798 }
799
800 /* clear cryptographic sequence number */
801 if (state == NSM_Down)
802 nbr->crypt_seqnum = 0;
803
804 /* Generete NeighborChange ISM event. */
805#ifdef BUGGY_ISM_TRANSITION
806 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
807 (old_state >= NSM_TwoWay && state < NSM_TwoWay))
808 OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
809#else /* BUGGY_ISM_TRANSITION */
810 switch (oi->state) {
811 case ISM_DROther:
812 case ISM_Backup:
813 case ISM_DR:
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 break;
818 default:
819 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
820 break;
821 }
822#endif /* BUGGY_ISM_TRANSITION */
823
824 /* Performance hack. Send hello immideately when some neighbor enter
825 Init state. This whay we decrease neighbor discovery time. Gleb.*/
826 if (state == NSM_Init)
827 {
828 OSPF_ISM_TIMER_OFF (oi->t_hello);
829 OSPF_ISM_TIMER_ON (oi->t_hello, ospf_hello_timer, 1);
830 }
831
832 /* Preserve old status? */
833}
834
835/* Execute NSM event process. */
836int
837ospf_nsm_event (struct thread *thread)
838{
839 int event;
840 int next_state;
841 struct ospf_neighbor *nbr;
842 struct in_addr router_id;
843 int old_state;
844 struct ospf_interface *oi;
845
846 nbr = THREAD_ARG (thread);
847 event = THREAD_VAL (thread);
848 router_id = nbr->router_id;
849
850 old_state = nbr->state;
851 oi = nbr->oi ;
852
853 /* Call function. */
854 next_state = (*(NSM [nbr->state][event].func))(nbr);
855
856 /* When event is NSM_KillNbr or InactivityTimer, the neighbor is
857 deleted. */
858 if (event == NSM_KillNbr || event == NSM_InactivityTimer)
859 {
860 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000861 zlog_debug ("NSM[%s:%s]: neighbor deleted",
paul2d598362003-01-17 23:48:42 +0000862 IF_NAME (oi), inet_ntoa (router_id));
863
864 /* Timers are canceled in ospf_nbr_free, moreover we cannot call
865 nsm_timer_set here because nbr is freed already!!!*/
866 /*nsm_timer_set (nbr);*/
867
868 return 0;
869 }
870
871 if (! next_state)
872 next_state = NSM [nbr->state][event].next_state;
873
874 if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
ajs2a42e282004-12-08 18:43:03 +0000875 zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (oi),
paul2d598362003-01-17 23:48:42 +0000876 inet_ntoa (nbr->router_id),
877 LOOKUP (ospf_nsm_state_msg, nbr->state),
878 ospf_nsm_event_str [event]);
879
880 /* If state is changed. */
881 if (next_state != nbr->state)
882 nsm_change_state (nbr, next_state);
883
884 /* Make sure timer is set. */
885 nsm_timer_set (nbr);
886
887 return 0;
888}
889
890/* Check loading state. */
891void
892ospf_check_nbr_loading (struct ospf_neighbor *nbr)
893{
894 if (nbr->state == NSM_Loading)
895 {
896 if (ospf_ls_request_isempty (nbr))
897 OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
898 else if (nbr->ls_req_last == NULL)
899 ospf_ls_req_event (nbr);
900 }
901}