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