~ubuntu-branches/ubuntu/breezy/quagga/breezy-security

« back to all changes in this revision

Viewing changes to ospfd/ospf_nsm.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-05-20 13:16:12 UTC
  • Revision ID: james.westby@ubuntu.com-20050520131612-pr6paalox60o3x3n
Tags: upstream-0.99.1
ImportĀ upstreamĀ versionĀ 0.99.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
54
/* OSPF NSM Timer functions. */
 
55
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
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
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
 
 
142
/* OSPF NSM functions. */
 
143
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
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
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
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
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
 
 
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
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
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
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
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
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
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
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
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
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) ();
 
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
}