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