Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / neighbor.c @ a7a7372a

History | View | Annotate | Download (15.5 KB)

1
/*
2
 *        BIRD -- OSPF
3
 *
4
 *        (c) 1999--2004 Ondrej Filip <feela@network.cz>
5
 *        (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
6
 *        (c) 2009--2014 CZ.NIC z.s.p.o.
7
 *
8
 *        Can be freely distributed and used under the terms of the GNU GPL.
9
 */
10

    
11
#include "ospf.h"
12

    
13
char *ospf_ns[] = { "    down",
14
  " attempt",
15
  "    init",
16
  "    2way",
17
  " exstart",
18
  "exchange",
19
  " loading",
20
  "    full"
21
};
22

    
23
const char *ospf_inm[] =
24
  { "hello received", "neighbor start", "2-way received",
25
  "negotiation done", "exstart done", "bad ls request", "load done",
26
  "adjacency ok?", "sequence mismatch", "1-way received", "kill neighbor",
27
  "inactivity timer", "line down"
28
};
29

    
30
static void neigh_chstate(struct ospf_neighbor *n, u8 state);
31
static void neighbor_timer_hook(timer * timer);
32
static void rxmt_timer_hook(timer * timer);
33
static void ackd_timer_hook(timer * t);
34

    
35
static void
36
init_lists(struct ospf_proto *p, struct ospf_neighbor *n)
37
{
38
  s_init_list(&(n->lsrql));
39
  n->lsrqh = ospf_top_new(p, n->pool);
40

    
41
  s_init_list(&(n->lsrtl));
42
  n->lsrth = ospf_top_new(p, n->pool);
43
}
44

    
45
static void
46
release_lsrtl(struct ospf_proto *p, struct ospf_neighbor *n)
47
{
48
  struct top_hash_entry *ret, *en;
49

    
50
  WALK_SLIST(ret, n->lsrtl)
51
  {
52
    en = ospf_hash_find_entry(p->gr, ret);
53
    if (en)
54
      en->ret_count--;
55
  }
56
}
57

    
58
/* Resets LSA request and retransmit lists.
59
 * We do not reset DB summary list iterator here, 
60
 * it is reset during entering EXCHANGE state.
61
 */
62
static void
63
reset_lists(struct ospf_proto *p, struct ospf_neighbor *n)
64
{
65
  release_lsrtl(p,n);
66
  ospf_top_free(n->lsrqh);
67
  ospf_top_free(n->lsrth);
68
  init_lists(p, n);
69
}
70

    
71
struct ospf_neighbor *
72
ospf_neighbor_new(struct ospf_iface *ifa)
73
{
74
  struct ospf_proto *p = ifa->oa->po;
75
  struct pool *pool = rp_new(p->p.pool, "OSPF Neighbor");
76
  struct ospf_neighbor *n = mb_allocz(pool, sizeof(struct ospf_neighbor));
77

    
78
  n->pool = pool;
79
  n->ifa = ifa;
80
  add_tail(&ifa->neigh_list, NODE n);
81
  n->adj = 0;
82
  n->csn = 0;
83
  n->state = NEIGHBOR_DOWN;
84

    
85
  init_lists(p, n);
86
  s_init(&(n->dbsi), &(p->lsal));
87

    
88
  n->inactim = tm_new(pool);
89
  n->inactim->data = n;
90
  n->inactim->randomize = 0;
91
  n->inactim->hook = neighbor_timer_hook;
92
  n->inactim->recurrent = 0;
93
  DBG("%s: Installing inactivity timer.\n", p->p.name);
94

    
95
  n->rxmt_timer = tm_new(pool);
96
  n->rxmt_timer->data = n;
97
  n->rxmt_timer->randomize = 0;
98
  n->rxmt_timer->hook = rxmt_timer_hook;
99
  n->rxmt_timer->recurrent = ifa->rxmtint;
100
  tm_start(n->rxmt_timer, n->ifa->rxmtint);
101
  DBG("%s: Installing rxmt timer.\n", p->p.name);
102

    
103
  n->ackd_timer = tm_new(pool);
104
  n->ackd_timer->data = n;
105
  n->ackd_timer->randomize = 0;
106
  n->ackd_timer->hook = ackd_timer_hook;
107
  n->ackd_timer->recurrent = ifa->rxmtint / 2;
108
  init_list(&n->ackl[ACKL_DIRECT]);
109
  init_list(&n->ackl[ACKL_DELAY]);
110
  tm_start(n->ackd_timer, n->ifa->rxmtint / 2);
111
  DBG("%s: Installing ackd timer.\n", p->p.name);
112

    
113
  return (n);
114
}
115

    
116
/**
117
 * neigh_chstate - handles changes related to new or lod state of neighbor
118
 * @n: OSPF neighbor
119
 * @state: new state
120
 *
121
 * Many actions have to be taken acording to a change of state of a neighbor. It
122
 * starts rxmt timers, call interface state machine etc.
123
 */
124
static void
125
neigh_chstate(struct ospf_neighbor *n, u8 state)
126
{
127
  struct ospf_iface *ifa = n->ifa;
128
  struct ospf_proto *p = ifa->oa->po;
129
  u8 old_state = n->state;
130
  int old_fadj = ifa->fadj;
131

    
132
  if (state == old_state)
133
    return;
134

    
135
  OSPF_TRACE(D_EVENTS, "Neighbor %I changes state from %s to %s",
136
             n->ip, ospf_ns[old_state], ospf_ns[state]);
137

    
138
  n->state = state;
139

    
140
  if ((state == NEIGHBOR_2WAY) && (old_state < NEIGHBOR_2WAY))
141
    ospf_iface_sm(ifa, ISM_NEICH);
142
  if ((state < NEIGHBOR_2WAY) && (old_state >= NEIGHBOR_2WAY))
143
    ospf_iface_sm(ifa, ISM_NEICH);
144

    
145
  /* Increase number of partial adjacencies */
146
  if ((state == NEIGHBOR_EXCHANGE) || (state == NEIGHBOR_LOADING))
147
    p->padj++;
148

    
149
  /* Decrease number of partial adjacencies */
150
  if ((old_state == NEIGHBOR_EXCHANGE) || (old_state == NEIGHBOR_LOADING))
151
    p->padj--;
152

    
153
  /* Increase number of full adjacencies */
154
  if (state == NEIGHBOR_FULL)
155
    ifa->fadj++;
156

    
157
  /* Decrease number of full adjacencies */
158
  if (old_state == NEIGHBOR_FULL)
159
    ifa->fadj--;
160

    
161
  if (ifa->fadj != old_fadj)
162
  {
163
    /* RFC 2328 12.4 Event 4 - neighbor enters/leaves Full state */
164
    ospf_notify_rt_lsa(ifa->oa);
165
    ospf_notify_net_lsa(ifa);
166

    
167
    /* RFC 2328 12.4 Event 8 - vlink state change */
168
    if (ifa->type == OSPF_IT_VLINK)
169
      ospf_notify_rt_lsa(ifa->voa);
170
  }
171

    
172
  if (state == NEIGHBOR_EXSTART)
173
  {
174
    /* First time adjacency */
175
    if (n->adj == 0)
176
      n->dds = random_u32();
177

    
178
    n->dds++;
179
    n->myimms = DBDES_IMMS;
180
  }
181

    
182
  if (state > NEIGHBOR_EXSTART)
183
    n->myimms &= ~DBDES_I;
184
}
185

    
186
static inline u32 neigh_get_id(struct ospf_proto *p, struct ospf_neighbor *n)
187
{ return ospf_is_v2(p) ? ipa_to_u32(n->ip) : n->rid; }
188

    
189
static struct ospf_neighbor *
190
elect_bdr(struct ospf_proto *p, list nl)
191
{
192
  struct ospf_neighbor *neigh, *n1, *n2;
193
  u32 nid;
194

    
195
  n1 = NULL;
196
  n2 = NULL;
197
  WALK_LIST(neigh, nl)                        /* First try those decl. themselves */
198
  {
199
    nid = neigh_get_id(p, neigh);
200

    
201
    if (neigh->state >= NEIGHBOR_2WAY)        /* Higher than 2WAY */
202
      if (neigh->priority > 0)                /* Eligible */
203
        if (neigh->dr != nid)                /* And not decl. itself DR */
204
        {
205
          if (neigh->bdr == nid)        /* Declaring BDR */
206
          {
207
            if (n1 != NULL)
208
            {
209
              if (neigh->priority > n1->priority)
210
                n1 = neigh;
211
              else if (neigh->priority == n1->priority)
212
                if (neigh->rid > n1->rid)
213
                  n1 = neigh;
214
            }
215
            else
216
            {
217
              n1 = neigh;
218
            }
219
          }
220
          else                        /* And NOT declaring BDR */
221
          {
222
            if (n2 != NULL)
223
            {
224
              if (neigh->priority > n2->priority)
225
                n2 = neigh;
226
              else if (neigh->priority == n2->priority)
227
                if (neigh->rid > n2->rid)
228
                  n2 = neigh;
229
            }
230
            else
231
            {
232
              n2 = neigh;
233
            }
234
          }
235
        }
236
  }
237
  if (n1 == NULL)
238
    n1 = n2;
239

    
240
  return (n1);
241
}
242

    
243
static struct ospf_neighbor *
244
elect_dr(struct ospf_proto *p, list nl)
245
{
246
  struct ospf_neighbor *neigh, *n;
247
  u32 nid;
248

    
249
  n = NULL;
250
  WALK_LIST(neigh, nl)                        /* And now DR */
251
  {
252
    nid = neigh_get_id(p, neigh);
253

    
254
    if (neigh->state >= NEIGHBOR_2WAY)        /* Higher than 2WAY */
255
      if (neigh->priority > 0)                /* Eligible */
256
        if (neigh->dr == nid)                /* And declaring itself DR */
257
        {
258
          if (n != NULL)
259
          {
260
            if (neigh->priority > n->priority)
261
              n = neigh;
262
            else if (neigh->priority == n->priority)
263
              if (neigh->rid > n->rid)
264
                n = neigh;
265
          }
266
          else
267
          {
268
            n = neigh;
269
          }
270
        }
271
  }
272

    
273
  return (n);
274
}
275

    
276
static int
277
can_do_adj(struct ospf_neighbor *n)
278
{
279
  struct ospf_iface *ifa = n->ifa;
280
  struct ospf_proto *p = ifa->oa->po;
281
  int i = 0;
282

    
283
  switch (ifa->type)
284
  {
285
  case OSPF_IT_PTP:
286
  case OSPF_IT_PTMP:
287
  case OSPF_IT_VLINK:
288
    i = 1;
289
    break;
290
  case OSPF_IT_BCAST:
291
  case OSPF_IT_NBMA:
292
    switch (ifa->state)
293
    {
294
    case OSPF_IS_DOWN:
295
    case OSPF_IS_LOOP:
296
      bug("%s: Iface %s in down state?", p->p.name, ifa->ifname);
297
      break;
298
    case OSPF_IS_WAITING:
299
      DBG("%s: Neighbor? on iface %s\n", p->p.name, ifa->ifname);
300
      break;
301
    case OSPF_IS_DROTHER:
302
      if (((n->rid == ifa->drid) || (n->rid == ifa->bdrid))
303
          && (n->state >= NEIGHBOR_2WAY))
304
        i = 1;
305
      break;
306
    case OSPF_IS_PTP:
307
    case OSPF_IS_BACKUP:
308
    case OSPF_IS_DR:
309
      if (n->state >= NEIGHBOR_2WAY)
310
        i = 1;
311
      break;
312
    default:
313
      bug("%s: Iface %s in unknown state?", p->p.name, ifa->ifname);
314
      break;
315
    }
316
    break;
317
  default:
318
    bug("%s: Iface %s is unknown type?", p->p.name, ifa->ifname);
319
    break;
320
  }
321
  DBG("%s: Iface %s can_do_adj=%d\n", p->p.name, ifa->ifname, i);
322
  return i;
323
}
324

    
325
/**
326
 * ospf_neigh_sm - ospf neighbor state machine
327
 * @n: neighor
328
 * @event: actual event
329
 *
330
 * This part implements the neighbor state machine as described in 10.3 of
331
 * RFC 2328. The only difference is that state %NEIGHBOR_ATTEMPT is not
332
 * used. We discover neighbors on nonbroadcast networks in the
333
 * same way as on broadcast networks. The only difference is in
334
 * sending hello packets. These are sent to IPs listed in
335
 * @ospf_iface->nbma_list .
336
 */
337
void
338
ospf_neigh_sm(struct ospf_neighbor *n, int event)
339
{
340
  struct ospf_proto *p = n->ifa->oa->po;
341

    
342
  DBG("Neighbor state machine for neighbor %I, event '%s'\n", n->ip,
343
             ospf_inm[event]);
344

    
345
  switch (event)
346
  {
347
  case INM_START:
348
    neigh_chstate(n, NEIGHBOR_ATTEMPT);
349
    /* NBMA are used different way */
350
    break;
351

    
352
  case INM_HELLOREC:
353
    if ((n->state == NEIGHBOR_DOWN) ||
354
        (n->state == NEIGHBOR_ATTEMPT))
355
      neigh_chstate(n, NEIGHBOR_INIT);
356

    
357
    /* Restart inactivity timer */
358
    tm_start(n->inactim, n->ifa->deadint);
359
    break;
360

    
361
  case INM_2WAYREC:
362
    if (n->state < NEIGHBOR_2WAY)
363
      neigh_chstate(n, NEIGHBOR_2WAY);
364
    if ((n->state == NEIGHBOR_2WAY) && can_do_adj(n))
365
      neigh_chstate(n, NEIGHBOR_EXSTART);
366
    break;
367

    
368
  case INM_NEGDONE:
369
    if (n->state == NEIGHBOR_EXSTART)
370
    {
371
      neigh_chstate(n, NEIGHBOR_EXCHANGE);
372

    
373
      /* Reset DB summary list iterator */
374
      s_get(&(n->dbsi));
375
      s_init(&(n->dbsi), &p->lsal);
376

    
377
      /* Add MaxAge LSA entries to retransmission list */
378
      ospf_add_flushed_to_lsrt(p, n);
379

    
380
      /* FIXME: Why is this here ? */
381
      ospf_reset_lsack_queue(n);
382
    }
383
    else
384
      bug("NEGDONE and I'm not in EXSTART?");
385
    break;
386

    
387
  case INM_EXDONE:
388
    neigh_chstate(n, NEIGHBOR_LOADING);
389
    break;
390

    
391
  case INM_LOADDONE:
392
    neigh_chstate(n, NEIGHBOR_FULL);
393
    break;
394

    
395
  case INM_ADJOK:
396
    switch (n->state)
397
    {
398
    case NEIGHBOR_2WAY:
399
      /* Can In build adjacency? */
400
      if (can_do_adj(n))
401
      {
402
        neigh_chstate(n, NEIGHBOR_EXSTART);
403
      }
404
      break;
405
    default:
406
      if (n->state >= NEIGHBOR_EXSTART)
407
        if (!can_do_adj(n))
408
        {
409
          reset_lists(p,n);
410
          neigh_chstate(n, NEIGHBOR_2WAY);
411
        }
412
      break;
413
    }
414
    break;
415

    
416
  case INM_SEQMIS:
417
  case INM_BADLSREQ:
418
    if (n->state >= NEIGHBOR_EXCHANGE)
419
    {
420
      reset_lists(p, n);
421
      neigh_chstate(n, NEIGHBOR_EXSTART);
422
    }
423
    break;
424

    
425
  case INM_KILLNBR:
426
  case INM_LLDOWN:
427
  case INM_INACTTIM:
428
    reset_lists(p, n);
429
    neigh_chstate(n, NEIGHBOR_DOWN);
430
    break;
431

    
432
  case INM_1WAYREC:
433
    reset_lists(p, n);
434
    neigh_chstate(n, NEIGHBOR_INIT);
435
    break;
436

    
437
  default:
438
    bug("%s: INM - Unknown event?", p->p.name);
439
    break;
440
  }
441
}
442

    
443
/**
444
 * ospf_dr_election - (Backup) Designed Router election
445
 * @ifa: actual interface
446
 *
447
 * When the wait timer fires, it is time to elect (Backup) Designated Router.
448
 * Structure describing me is added to this list so every electing router
449
 * has the same list. Backup Designated Router is elected before Designated
450
 * Router. This process is described in 9.4 of RFC 2328.
451
 */
452
void
453
ospf_dr_election(struct ospf_iface *ifa)
454
{
455
  struct ospf_proto *p = ifa->oa->po;
456
  struct ospf_neighbor *neigh, *ndr, *nbdr, me;
457
  u32 myid = p->router_id;
458

    
459
  DBG("(B)DR election.\n");
460

    
461
  me.state = NEIGHBOR_2WAY;
462
  me.rid = myid;
463
  me.priority = ifa->priority;
464
  me.ip = ifa->addr->ip;
465

    
466
  me.dr  = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid;
467
  me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
468
  me.iface_id = ifa->iface_id;
469

    
470
  add_tail(&ifa->neigh_list, NODE & me);
471

    
472
  nbdr = elect_bdr(p, ifa->neigh_list);
473
  ndr = elect_dr(p, ifa->neigh_list);
474

    
475
  if (ndr == NULL)
476
    ndr = nbdr;
477

    
478
  /* 9.4. (4) */
479
  if (((ifa->drid == myid) && (ndr != &me))
480
      || ((ifa->drid != myid) && (ndr == &me))
481
      || ((ifa->bdrid == myid) && (nbdr != &me))
482
      || ((ifa->bdrid != myid) && (nbdr == &me)))
483
  {
484
    me.dr = ndr ? neigh_get_id(p, ndr) : 0;
485
    me.bdr = nbdr ? neigh_get_id(p, nbdr) : 0;
486

    
487
    nbdr = elect_bdr(p, ifa->neigh_list);
488
    ndr = elect_dr(p, ifa->neigh_list);
489

    
490
    if (ndr == NULL)
491
      ndr = nbdr;
492
  }
493

    
494
  rem_node(NODE & me);
495

    
496

    
497
  u32 old_drid = ifa->drid;
498
  u32 old_bdrid = ifa->bdrid;
499
 
500
  ifa->drid = ndr ? ndr->rid : 0;
501
  ifa->drip = ndr ? ndr->ip  : IPA_NONE;
502
  ifa->dr_iface_id = ndr ? ndr->iface_id : 0;
503

    
504
  ifa->bdrid = nbdr ? nbdr->rid : 0;
505
  ifa->bdrip = nbdr ? nbdr->ip  : IPA_NONE;
506

    
507
  DBG("DR=%R, BDR=%R\n", ifa->drid, ifa->bdrid);
508

    
509
  if (ifa->drid == myid)
510
    ospf_iface_chstate(ifa, OSPF_IS_DR);
511
  else if (ifa->bdrid == myid)
512
    ospf_iface_chstate(ifa, OSPF_IS_BACKUP);
513
  else
514
    ospf_iface_chstate(ifa, OSPF_IS_DROTHER);
515

    
516
  /* Review neighbor adjacencies if DR or BDR changed */
517
  if ((ifa->drid != old_drid) || (ifa->bdrid != old_bdrid))
518
    WALK_LIST(neigh, ifa->neigh_list)
519
      if (neigh->state >= NEIGHBOR_2WAY)
520
        ospf_neigh_sm(neigh, INM_ADJOK);
521

    
522
  /* RFC 2328 12.4 Event 3 - DR change */
523
  if (ifa->drid != old_drid)
524
    ospf_notify_rt_lsa(ifa->oa);
525
}
526

    
527
struct ospf_neighbor *
528
find_neigh(struct ospf_iface *ifa, u32 rid)
529
{
530
  struct ospf_neighbor *n;
531
  WALK_LIST(n, ifa->neigh_list)
532
    if (n->rid == rid)
533
      return n;
534
  return NULL;
535
}
536

    
537
struct ospf_neighbor *
538
find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
539
{
540
  struct ospf_neighbor *n;
541
  WALK_LIST(n, ifa->neigh_list)
542
    if (ipa_equal(n->ip, ip))
543
      return n;
544
  return NULL;
545
}
546

    
547
/* Neighbor is inactive for a long time. Remove it. */
548
static void
549
neighbor_timer_hook(timer * timer)
550
{
551
  struct ospf_neighbor *n = (struct ospf_neighbor *) timer->data;
552
  struct ospf_iface *ifa = n->ifa;
553
  struct ospf_proto *p = ifa->oa->po;
554

    
555
  OSPF_TRACE(D_EVENTS, "Inactivity timer fired on interface %s for neighbor %I",
556
             ifa->ifname, n->ip);
557
  ospf_neigh_remove(n);
558
}
559

    
560
void
561
ospf_neigh_remove(struct ospf_neighbor *n)
562
{
563
  struct ospf_iface *ifa = n->ifa;
564
  struct ospf_proto *p = ifa->oa->po;
565

    
566
  if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
567
  {
568
    struct nbma_node *nn = find_nbma_node(ifa, n->ip);
569
    if (nn)
570
      nn->found = 0;
571
  }
572

    
573
  neigh_chstate(n, NEIGHBOR_DOWN);
574

    
575
  s_get(&(n->dbsi));
576
  release_lsrtl(p, n);
577
  rem_node(NODE n);
578
  rfree(n->pool);
579
  OSPF_TRACE(D_EVENTS, "Deleting neigbor %R", n->rid);
580
}
581

    
582
static void
583
ospf_neigh_bfd_hook(struct bfd_request *req)
584
{
585
  struct ospf_neighbor *n = req->data;
586
  struct ospf_proto *p = n->ifa->oa->po;
587

    
588
  if (req->down)
589
  {
590
    OSPF_TRACE(D_EVENTS, "BFD session down for %I on %s", n->ip, n->ifa->ifname);
591
    ospf_neigh_remove(n);
592
  }
593
}
594

    
595
void
596
ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
597
{
598
  if (use_bfd && !n->bfd_req)
599
    n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip, n->ifa->iface,
600
                                     ospf_neigh_bfd_hook, n);
601

    
602
  if (!use_bfd && n->bfd_req)
603
  {
604
    rfree(n->bfd_req);
605
    n->bfd_req = NULL;
606
  }
607
}
608

    
609

    
610
void
611
ospf_sh_neigh_info(struct ospf_neighbor *n)
612
{
613
  struct ospf_iface *ifa = n->ifa;
614
  char *pos = "other";
615
  char etime[6];
616
  int exp, sec, min;
617

    
618
  exp = n->inactim->expires - now;
619
  sec = exp % 60;
620
  min = exp / 60;
621
  if (min > 59)
622
  {
623
    bsprintf(etime, "-Inf-");
624
  }
625
  else
626
  {
627
    bsprintf(etime, "%02u:%02u", min, sec);
628
  }
629

    
630
  if (n->rid == ifa->drid)
631
    pos = "dr   ";
632
  else if (n->rid == ifa->bdrid)
633
    pos = "bdr  ";
634
  else if ((n->ifa->type == OSPF_IT_PTP) || (n->ifa->type == OSPF_IT_PTMP) ||
635
           (n->ifa->type == OSPF_IT_VLINK))
636
    pos = "ptp  ";
637

    
638
  cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
639
          ospf_ns[n->state], pos, etime, ifa->ifname, n->ip);
640
}
641

    
642
static void
643
rxmt_timer_hook(timer *t)
644
{
645
  struct ospf_neighbor *n = t->data;
646
  struct ospf_proto *p = n->ifa->oa->po;
647

    
648
  DBG("%s: RXMT timer fired on interface %s for neigh %I\n",
649
      p->p.name, n->ifa->ifname, n->ip);
650

    
651
  switch (n->state)
652
  {
653
  case NEIGHBOR_EXSTART:
654
    ospf_send_dbdes(p, n, 1);
655
    return;
656

    
657
  case NEIGHBOR_EXCHANGE:
658
  if (n->myimms & DBDES_MS)
659
    ospf_send_dbdes(p, n, 0);
660
  case NEIGHBOR_LOADING:
661
    ospf_send_lsreq(p, n);
662
    return;
663

    
664
  case NEIGHBOR_FULL:
665
    /* LSA retransmissions */
666
    if (!EMPTY_SLIST(n->lsrtl))
667
      ospf_rxmt_lsupd(p, n);
668
    return;
669

    
670
  default:
671
    return;
672
  }
673
}
674

    
675
static void
676
ackd_timer_hook(timer *t)
677
{
678
  struct ospf_neighbor *n = t->data;
679
  struct ospf_proto *p = n->ifa->oa->po;
680

    
681
  DBG("%s: ACKD timer fired on interface %s for neigh %I\n",
682
      p->p.name, n->ifa->ifname, n->ip);
683

    
684
  ospf_send_lsack(p, n, ACKL_DELAY);
685
}