Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / rt.c @ e8ab1680

History | View | Annotate | Download (16.3 KB)

1
/*
2
 *        BIRD -- OSPF
3
 *
4
 *        (c) 2000 Ondrej Filip <feela@network.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
#include "ospf.h"
10

    
11
void
12
init_infib(struct fib_node *fn)
13
{
14
  struct infib *f=(struct infib *)fn;
15

    
16
  f->metric=LSINFINITY;
17
  f->oldmetric=LSINFINITY;
18
  f->en=NULL;
19
  f->olden=NULL;
20
}
21

    
22
void
23
init_efib(struct fib_node *fn)
24
{
25
  struct extfib *f=(struct extfib *)fn;
26

    
27
  f->metric=LSINFINITY;
28
  f->metric2=LSINFINITY;
29
  f->nh=ipa_from_u32(0);
30
  f->nhi=NULL;
31
  f->oldmetric=LSINFINITY;
32
  f->oldmetric2=LSINFINITY;
33
  f->oldnh=ipa_from_u32(0);
34
}
35

    
36
/**
37
 * ospf_rt_spfa - calculate internal routes
38
 * @oa: OSPF area
39
 *
40
 * Calculation of internal paths in area is described in 16.1 of RFC 2328.
41
 * It's based on Dijkstra shortest path tree algorithmus.
42
 * RFC recommends to add ASBR routers into routing table. I don't do this
43
 * and latter parts of routing table calculation looks directly into LSA
44
 * Database. This function is invoked from area_disp().
45
 */
46
void
47
ospf_rt_spfa(struct ospf_area *oa)
48
{
49
  struct top_hash_entry *en;
50
  u32 i,*rts;
51
  struct ospf_lsa_rt *rt;
52
  struct ospf_lsa_rt_link *rtl,*rr;
53
  struct fib *in=&oa->infib;
54
  struct infib *nf;
55
  struct fib_iterator fit;
56
  int age=0,flush=0;
57
  struct proto *p=&oa->po->proto;
58
  struct proto_ospf *po=oa->po;
59
  ip_addr ip;
60
  struct ospf_lsa_net *ln;
61

    
62
  OSPF_TRACE(D_EVENTS, "Starting routing table calculation for area %I",
63
    oa->areaid);
64

    
65
  if(oa->rt==NULL) return;
66

    
67
  FIB_WALK(in,nftmp)
68
  {
69
    nf=(struct infib *)nftmp;
70
    nf->metric=LSINFINITY;
71
    nf->en=NULL;
72
  }
73
  FIB_WALK_END;
74

    
75
  init_list(&oa->cand);                /* Empty list of candidates */
76
  oa->trcap=0;
77

    
78
  DBG("LSA db prepared, adding me into candidate list.\n");
79

    
80
  oa->rt->dist=0;
81
  oa->rt->color=CANDIDATE;
82
  add_head(&oa->cand, &oa->rt->cn);
83
  DBG("RT LSA: rt: %I, id: %I, type: %u\n",oa->rt->lsa.rt,
84
    oa->rt->lsa.id,oa->rt->lsa.type);
85

    
86
  while(!EMPTY_LIST(oa->cand))
87
  {
88
    struct top_hash_entry *act,*tmp;
89
    node *n;
90
    u16 met;
91

    
92
    n=HEAD(oa->cand);
93
    act=SKIP_BACK(struct top_hash_entry, cn, n);
94
    rem_node(n);
95

    
96
    DBG("Working on LSA: rt: %I, id: %I, type: %u\n",act->lsa.rt,
97
      act->lsa.id,act->lsa.type);
98

    
99
    act->color=INSPF;
100
    switch(act->lsa.type)
101
    {
102
      case LSA_T_RT:
103
        rt=(struct ospf_lsa_rt *)act->lsa_body;
104
        if(rt->veb.bit.v) oa->trcap=1;
105
        rr=(struct ospf_lsa_rt_link *)(rt+1);
106
        DBG("  Number of links: %u\n",rt->links);
107
        for(i=0;i<rt->links;i++)
108
        {
109
          tmp=NULL;
110
          rtl=(rr+i);
111
          DBG("     Working on link: %I (type: %u)  ",rtl->id,rtl->type);
112
          switch(rtl->type)
113
          {
114
            case LSART_STUB:
115
                /* This violates rfc2328! but I hope it's also correct. */
116
             DBG("\n");
117
             ip=ipa_from_u32(rtl->id);
118
             nf=fib_get(in,&ip, ipa_mklen(ipa_from_u32(rtl->data)));
119
             if(nf->metric>(met=act->dist+rtl->metric))
120
             {
121
               DBG("       Adding stub route....\n");
122
               if(oa->rt==act) break;
123
               if(act->nhi==NULL) break;
124
               nf->metric=met;
125
               nf->en=act;
126
               DBG("            Adding stub route: %I\n",ip);
127
               DBG("            Next hop=%I\n",nf->en->nh);
128
             }
129
             else DBG("            NOT adding stub route: %I\n",ip);
130
             break;
131
            case LSART_VLNK:
132
              DBG("Ignoring\n");
133
              continue;
134
              break;
135
            case LSART_NET:
136
              tmp=ospf_hash_find(oa->gr,rtl->id,rtl->id,LSA_T_NET);
137
              if(tmp==NULL) DBG("Not found!\n");
138
              else DBG("Found. :-)\n");
139
              break;
140
            case LSART_PTP:
141
              tmp=ospf_hash_find(oa->gr,rtl->id,rtl->id,LSA_T_RT);
142
              DBG("PTP found.\n");
143
              break;
144
            default:
145
              log("Unknown link type in router lsa.");
146
              break;
147
          }
148
          if(tmp) DBG("Going to add cand, Mydist: %u, Req: %u\n",
149
            tmp->dist, act->dist+rtl->metric);
150
          add_cand(&oa->cand,tmp,act,act->dist+rtl->metric,oa);
151
        }
152
        break;
153
      case LSA_T_NET:
154
        ln=act->lsa_body;
155
        ip=ipa_and(ipa_from_u32(act->lsa.id),ln->netmask);
156
        nf=fib_get(in,&ip, ipa_mklen(ln->netmask));
157
        if(nf->metric>act->dist)
158
        {
159
          nf->metric=act->dist;
160
          nf->en=act;
161
          DBG("    Adding into routing table\n");
162
        }
163
        rts=(u32 *)(ln+1);
164
        for(i=0;i<(act->lsa.length-sizeof(struct ospf_lsa_header)-
165
          sizeof(struct ospf_lsa_net))/sizeof(u32);i++)
166
        {
167
          DBG("     Working on router %I ", *(rts+i));
168
          tmp=ospf_hash_find(oa->gr, *(rts+i), *(rts+i), LSA_T_RT);
169
          if(tmp!=NULL) DBG("Found :-)\n");
170
          else DBG("Not found!\n");
171
          add_cand(&oa->cand,tmp,act,act->dist,oa);
172
        }
173
        break;
174
    }
175
  }
176
  /* Now sync our fib with nest's */
177
  DBG("Now syncing my rt table with nest's\n");
178
  FIB_ITERATE_INIT(&fit,in);
179
again:
180
  FIB_ITERATE_START(in,&fit,nftmp)
181
  {
182
    nf=(struct infib *)nftmp;
183
    if(nf->metric==LSINFINITY) 
184
    {
185
      net *ne;
186
      struct top_hash_entry *en=nf->en;
187
      ln=en->lsa_body;
188
  
189
      ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
190
      if((en!=NULL)&&(en->nhi!=NULL))
191
        DBG("Deleting rt entry %I\n     (P: %x, GW: %I, Iface: %s)\n",
192
        nf->fn.prefix, en, en->nh,en->nhi->name);
193
      rte_update(p->table, ne, p, NULL);
194

    
195
      /* Now delete my fib */
196
      FIB_ITERATE_PUT(&fit, nftmp);
197
      fib_delete(in, nftmp);
198
      goto again;
199
    }
200
    else
201
    {
202
      /* Update routing table */
203
      if(nf->en->nhi==NULL)
204
      {
205
        struct top_hash_entry *en=nf->en;
206
        struct ospf_neighbor *neigh;
207
        neighbor *nn;
208

    
209
        if((neigh=find_neigh_noifa(po,en->lsa.rt))==NULL)
210
        {
211
          goto skip;
212
        }
213
        nn=neigh_find(p,&neigh->ip,0);
214
        DBG("     Next hop calculated: %I\n", nn->addr);
215
        en->nh=nn->addr;
216
        en->nhi=nn->iface;
217
      }
218

    
219
      if((nf->en!=nf->olden)||(nf->metric!=nf->oldmetric))
220
      {
221
        net *ne;
222
        rta a0;
223
        rte *e;
224
        struct top_hash_entry *en=nf->en;
225
        ln=en->lsa_body;
226
  
227
        bzero(&a0, sizeof(a0));
228
  
229
        a0.proto=p;
230
        a0.source=RTS_OSPF;
231
        a0.scope=SCOPE_UNIVERSE;
232
        a0.cast=RTC_UNICAST;
233
        if(ipa_to_u32(en->nh)==0) a0.dest=RTD_DEVICE;
234
        else a0.dest=RTD_ROUTER;
235
        a0.flags=0;
236
        a0.aflags=0;
237
        a0.iface=en->nhi;
238
        if(ipa_in_net(en->nh,en->nhi->addr->ip,en->nhi->addr->pxlen))
239
        {
240
           a0.gw=IPA_NONE;
241
        }
242
        else
243
        {
244
           a0.gw=en->nh;
245
        }
246
        
247
        ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
248
        e=rte_get_temp(&a0);
249
        e->u.ospf.metric1=nf->metric;
250
        e->u.ospf.metric2=LSINFINITY;
251
        e->u.ospf.tag=0;
252
        e->pflags = 0;
253
        e->net=ne;
254
        e->pref = p->preference;
255
        DBG("Modifying rt entry %I\n     (GW: %I, Iface: %s)\n",
256
          nf->fn.prefix,en->nh,en->nhi->name);
257
        rte_update(p->table, ne, p, e);
258

    
259
        nf->olden=nf->en;
260
        nf->oldmetric=nf->metric;
261
      }
262
    }
263

    
264
  }
265
skip:
266
  FIB_ITERATE_END(nftmp);
267
  ospf_ext_spfa(po);
268
}
269

    
270
/**
271
 * ospf_ext_spfa - calculate external paths
272
 * @po: protocol
273
 *
274
 * After routing table for any area is calculated, calculation of external
275
 * path is invoked. This process is described in 16.6 of RFC 2328.
276
 * Inter- and Intra-area paths are always prefered over externals.
277
 */
278
void
279
ospf_ext_spfa(struct proto_ospf *po)        /* FIXME looking into inter-area */
280
{
281
  struct top_hash_entry *en,*etmp,*absr;
282
  struct fib *ef=&po->efib;
283
  struct extfib *nf;
284
  struct infib *inf;
285
  struct fib_iterator fit;
286
  struct ospf_area *oa=NULL,*atmp,*absroa;
287
  struct proto *p=&po->proto;
288
  struct ospf_lsa_ext *le;
289
  struct ospf_lsa_ext_tos *lt;
290
  struct ospf_lsa_rt *rt;
291
  int mlen;
292
  ip_addr ip,nnh;
293
  struct iface *nnhi=NULL;
294
  u16 met,met2;
295
  u32 tag;
296
  neighbor *nn;
297

    
298
  OSPF_TRACE(D_EVENTS,"Starting routing table calculation for ext routes");
299

    
300
  FIB_WALK(ef,nftmp)
301
  {
302
    nf=(struct extfib *)nftmp;
303
    nf->metric=LSINFINITY;
304
    nf->metric2=LSINFINITY;
305
  }
306
  FIB_WALK_END;
307

    
308
  WALK_LIST(oa,po->area_list)
309
  {
310
    if(!oa->stub) break;
311
  }
312

    
313
  if(oa==NULL) return;
314

    
315
  WALK_SLIST(en,oa->lsal)
316
  {
317
    if(en->lsa.type!=LSA_T_EXT) continue;
318
    if(en->lsa.age==LSA_MAXAGE) continue;
319
    if(en->lsa.rt==p->cf->global->router_id) continue;
320

    
321
    le=en->lsa_body;
322
    lt=(struct ospf_lsa_ext_tos *)(le+1);
323

    
324
    DBG("%s: Working on LSA. ID: %I, RT: %I, Type: %u, Mask %I\n",
325
        p->name,en->lsa.id,en->lsa.rt,en->lsa.type,le->netmask);
326

    
327
    if(lt->metric==LSINFINITY) continue;
328
    ip=ipa_and(ipa_from_u32(en->lsa.id),le->netmask);
329
    mlen=ipa_mklen(le->netmask);
330
    if((mlen<0)||(mlen>32))
331
    {
332
      log("%s: Invalid mask in LSA. ID: %I, RT: %I, Type: %u, Mask %I",
333
        p->name,en->lsa.id,en->lsa.rt,en->lsa.type,le->netmask);
334
      continue;
335
    }
336

    
337
    nf=NULL;
338

    
339
    WALK_LIST(atmp,po->area_list)
340
    {
341
      if((nf=fib_find(&atmp->infib,&ip, mlen))!=NULL) break;
342
    }
343

    
344
    if(nf!=NULL) continue;        /* Some intra area path exists */
345

    
346
    absr=NULL;
347
    absroa=NULL;
348
    nnhi=NULL;
349
    nnh=IPA_NONE;
350

    
351
    met=0;met2=0;tag=0;
352

    
353
    WALK_LIST(atmp,po->area_list)        /*
354
                                         * Find shortest path
355
                                         * to advertising router 
356
                                         */
357
    {
358
      if((etmp=ospf_hash_find(atmp->gr,en->lsa.rt,en->lsa.rt,LSA_T_RT))!=NULL)
359
      {
360
        if((absr==NULL) || (absr->dist>etmp->dist) ||
361
          ((etmp->dist==absr->dist) && (absroa->areaid<atmp->areaid)))
362
        {
363
          absr=etmp;
364
          absroa=atmp;
365
          break;
366
        }
367
      }
368
    }
369

    
370
    if((absr==NULL)||(absr->dist==LSINFINITY)||
371
      (((struct ospf_lsa_rt *)(absr->lsa_body))->veb.bit.e==0))
372
    {
373
      DBG("ASBR is null or its dist=INF\n");
374
      continue;
375
    }
376

    
377
    if(ipa_compare(lt->fwaddr,ipa_from_u32(0))==0)
378
    {
379
      if(lt->etos>0)        /* FW address == 0 */
380
      {
381
        met=absr->dist;
382
        met2=lt->metric;
383
      }
384
      else
385
      {
386
        met=absr->dist+lt->metric;
387
        met2=LSINFINITY;
388
      }
389
      tag=lt->tag;
390
    }
391
    else                /* FW address !=0 */
392
    {
393
      inf=NULL;
394
      WALK_LIST(atmp,po->area_list)
395
      {
396
        if((inf=fib_route(&atmp->infib,lt->fwaddr,32))!=NULL)
397
        {
398
          break;
399
        }
400
      }
401

    
402
      if(inf==NULL)
403
      {
404
        DBG("Cannot find network route (GW=%I)\n",lt->fwaddr);
405
        continue;
406
      }
407

    
408
      if(lt->etos>0)
409
      {
410
        met=inf->metric;
411
        met2=lt->metric;
412
      }
413
      else
414
      {
415
        met=inf->metric+lt->metric;
416
        met2=LSINFINITY;
417
      }
418
      tag=lt->tag;
419

    
420
      if((nn=neigh_find(p,&lt->fwaddr,0))!=NULL)
421
      {
422
        nnh=lt->fwaddr;
423
        nnhi=nn->iface;
424
      }
425
      else
426
      {
427
        nnh=inf->en->nh;
428
        nnhi=inf->en->nhi;
429
      }
430
    }
431

    
432
    nf=fib_get(ef,&ip, mlen);
433
    if((nf->metric==LSINFINITY) ||        /* nf is new */
434
       ((met<nf->metric)&&(nf->metric2==met2)) || /* both E1 or E2
435
                                                   * with same metric */
436
      ((met2<nf->metric2)&&(nf->metric2!=LSINFINITY)) || /* E2 smaller and
437
                                                          * 1st is not E1 */
438
      ((nf->metric2!=LSINFINITY)&&(met2==LSINFINITY)))        /* 2nd is E1 and
439
                                                         * 1st is E2 */
440
    {
441
      if(nf->metric!=LSINFINITY)
442
        OSPF_TRACE(D_EVENTS,
443
          "Rewritting %I/%d met=%d, met2=%d, nmet=%d, nmet2=%d",
444
        ip, mlen, nf->metric, nf->metric2, met, met2);
445
      nf->metric=met;
446
      nf->metric2=met2;
447
      nf->tag=tag;
448

    
449
      if(nnhi!=NULL)
450
      {
451
        nf->nh=nnh;
452
        nf->nhi=nnhi;
453
      }
454
      else
455
      {
456
        if(ipa_compare(absr->nh,ipa_from_u32(0))==0)
457
        {
458
          struct ospf_neighbor *neigh;
459

    
460
          if((neigh=find_neigh_noifa(po,absr->lsa.rt))==NULL)
461
          {
462
             DBG("Cannot find neighbor\n");
463
             continue;
464
          }
465
          nn=neigh_find(p,&neigh->ip,0);
466
          DBG("     Next hop calculated: %I\n", nn->addr);
467
          nf->nh=nn->addr;
468
          nf->nhi=nn->iface;
469
        }
470
        else
471
        {
472
          nf->nh=absr->nh;
473
          nf->nhi=absr->nhi;
474
        }
475
      }
476
    }
477
  }
478

    
479
  DBG("Now syncing my rt table with nest's\n");
480
  FIB_ITERATE_INIT(&fit,ef);
481
noch:
482
  FIB_ITERATE_START(ef,&fit,nftmp)
483
  {
484
    nf=(struct extfib *)nftmp;
485
    if(nf->metric==LSINFINITY) 
486
    {
487
      net *ne;
488
  
489
      ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
490
      DBG("Deleting rt entry %I\n     (IP: %I, GW: %I)\n",
491
        nf->fn.prefix,ip,nf->nh);
492
      rte_update(p->table, ne, p, NULL);
493

    
494
      /* Now delete my fib */
495
      FIB_ITERATE_PUT(&fit, nftmp);
496
      fib_delete(ef, nftmp);
497
      goto noch;
498
    }
499
    else
500
      if((nf->metric!=nf->oldmetric)||(nf->metric2!=nf->oldmetric2)||
501
         (!ipa_equal(nf->nh,nf->oldnh))||(nf->tag!=nf->oldtag))
502
      {
503
        net *ne;
504
        rta a0;
505
        rte *e;
506
    
507
        bzero(&a0, sizeof(a0));
508
    
509
        a0.proto=p;
510
        a0.source=RTS_OSPF_EXT;
511
        a0.scope=SCOPE_UNIVERSE;
512
        a0.cast=RTC_UNICAST;
513
        a0.dest=RTD_ROUTER;
514
        a0.flags=0;
515
        a0.aflags=0;
516
        a0.iface=nf->nhi;
517
        a0.gw=nf->nh;
518
        ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
519
        e=rte_get_temp(&a0);
520
        e->u.ospf.metric1=nf->metric;
521
        e->u.ospf.metric2=nf->metric2;
522
        e->u.ospf.tag=nf->tag;
523
        e->pflags = 0;
524
        e->net=ne;
525
        e->pref = p->preference;
526
        DBG("Modifying rt entry %I\n     (IP: %I, GW: %I)\n",
527
          nf->fn.prefix,ip,nf->nh);
528
        rte_update(p->table, ne, p, e);
529

    
530
        nf->oldmetric=nf->metric;
531
        nf->oldmetric2=nf->metric2;
532
        nf->oldnh=nf->nh;
533
        nf->oldtag=nf->tag;
534
      }
535
  }
536
let:
537
  FIB_ITERATE_END(nftmp);
538
}
539

    
540
/* Add LSA into list of candidates in Dijkstra alogithm */
541
void
542
add_cand(list *l, struct top_hash_entry *en, struct top_hash_entry *par, 
543
  u16 dist, struct ospf_area *oa)
544
{
545
  node *prev,*n;
546
  int flag=0,added=0;
547
  struct top_hash_entry *act;
548
  struct proto *p=&oa->po->proto;
549

    
550
  if(en==NULL) return;
551
  if(en->lsa.age==LSA_MAXAGE) return;
552
  /* FIXME Does it have link back? Test it! */
553
  if(en->color==INSPF) return;
554

    
555
  if(dist>=en->dist) return;
556
  /*
557
   * FIXME The line above is not a bug, but we don't support
558
   * multiple next hops. I'll start as soon as nest will
559
   */
560
  DBG("     Adding candidate: rt: %I, id: %I, type: %u\n",en->lsa.rt,en->lsa.id,en->lsa.type);
561

    
562
  en->nhi=NULL;
563
  
564
  calc_next_hop(en, par, oa);
565

    
566
  if(en->color==CANDIDATE)        /* We found a shorter path */
567
  {
568
    rem_node(&en->cn);
569
  }
570

    
571
  en->dist=dist;
572
  en->color=CANDIDATE;
573

    
574
  prev=NULL;
575

    
576
  if(EMPTY_LIST(*l))
577
  {
578
    add_head(l,&en->cn);
579
  }
580
  else
581
  {
582
    WALK_LIST(n,*l)
583
    {
584
      act=SKIP_BACK(struct top_hash_entry, cn, n);
585
      if((act->dist>dist)||
586
        ((act->dist==dist)&&(act->lsa.type==LSA_T_NET)))
587
      {
588
        if(prev==NULL) add_head(l,&en->cn);
589
        else insert_node(&en->cn,prev);
590
        added=1;
591
        break;
592
      }
593
      prev=n;
594
    }
595

    
596
    if(!added)
597
    {
598
      add_tail(l,&en->cn);
599
    }
600
  }
601
  /* FIXME Some VLINK stuff should be here */
602
}
603

    
604
void
605
calc_next_hop(struct top_hash_entry *en, struct top_hash_entry *par,
606
  struct ospf_area *oa)
607
{
608
  struct ospf_neighbor *neigh;
609
  struct proto *p=&oa->po->proto;
610
  struct proto_ospf *po=oa->po;
611
  struct ospf_iface *ifa;
612
  u32 myrid=p->cf->global->router_id;
613

    
614
  DBG("     Next hop called.\n");
615
  if(ipa_equal(par->nh,IPA_NONE))
616
  {
617
    neighbor *nn;
618
    DBG("     Next hop calculating for id: %I rt: %I type: %u\n",
619
      en->lsa.id,en->lsa.rt,en->lsa.type);
620

    
621
    if(par==oa->rt)
622
    {
623
      if(en->lsa.type==LSA_T_NET)
624
      {
625
        if(en->lsa.rt==myrid)
626
        {
627
          WALK_LIST(ifa,po->iface_list)
628
            if(ipa_compare(ifa->iface->addr->ip,ipa_from_u32(en->lsa.id))==0)
629
            {
630
              en->nhi=ifa->iface;
631
              return;
632
            }
633
          bug("I didn't find interface for my self originated LSA!\n");
634
        }
635
        else
636
        {
637
          ip_addr ip=ipa_from_u32(en->lsa.id);
638
          nn=neigh_find(p,&ip,0);
639
          if(nn) en->nhi=nn->iface;
640
          return;
641
        }
642
      }
643
      else
644
      {
645
        if((neigh=find_neigh_noifa(po,en->lsa.rt))==NULL) return;
646
        en->nhi=neigh->ifa->iface;
647
        en->nh=neigh->ip;        /* Yes, neighbor is it's own next hop */
648
        return;
649
      }
650
    }
651

    
652
    if(par->lsa.type==LSA_T_NET)
653
    {
654
      if(en->lsa.type==LSA_T_NET) bug("Parent for net is net?");
655
      if((en->nhi=par->nhi)==NULL)
656
        bug("Did not find next hop interface for INSPF lsa!");
657
      return;
658
    }
659
    else        /* Parent is some RT neighbor */
660
    {
661
      /* FIXME: I should probably hold ospf_iface in top_hash_entry */
662
      /* FIXME: Isn't this useless */
663
      neigh=NULL;
664
      WALK_LIST(ifa,po->iface_list)
665
      {
666
        if(ifa->iface==par->nhi)
667
        {
668
          if((neigh=find_neigh(ifa,par->lsa.rt))==NULL) return;
669
          break;
670
        }
671
      }
672
      if(neigh==NULL) bug("I cannot find my neighbor.");
673
      nn=neigh_find(p,&neigh->ip,0);
674
      if(nn)
675
      {
676
        en->nhi=nn->iface;
677
        en->nh=neigh->ip;
678
      }
679
      return;
680
    }
681
  }
682
  en->nh=par->nh;
683
  en->nhi=par->nhi;
684
  DBG("     Next hop calculated: %I.\n", en->nh);
685
}
686