Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (11.3 KB)

1
/*
2
 *        BIRD -- OSPF
3
 *
4
 *        (c) 1999 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
char *ospf_ns[]={"    down",
12
                 " attempt",
13
                 "    init",
14
                 "    2way",
15
                 " exstart",
16
                 "exchange",
17
                 " loading",
18
                 "    full"};
19

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

    
25
void
26
neigh_chstate(struct ospf_neighbor *n, u8 state)
27
{
28
  u8 oldstate;
29

    
30
  oldstate=n->state;
31

    
32
  if(oldstate!=state)
33
  {
34
    struct ospf_iface *ifa=n->ifa;
35
    struct proto_ospf *po=ifa->oa->po;
36
    struct proto *p=&po->proto;
37

    
38
    n->state=state;
39

    
40
    debug("%s: Neighbor %I changes state from \"%s\" to \"%s\".\n",
41
      p->name, n->ip, ospf_ns[oldstate], ospf_ns[state]);
42

    
43
    if((state==NEIGHBOR_2WAY) && (oldstate<NEIGHBOR_2WAY))
44
      ospf_int_sm(ifa, ISM_NEICH);
45
    if((state<NEIGHBOR_2WAY) && (oldstate>=NEIGHBOR_2WAY))
46
      ospf_int_sm(ifa, ISM_NEICH);
47

    
48
    if(oldstate==NEIGHBOR_FULL)        /* Decrease number of adjacencies */
49
    {
50
      ifa->fadj--;
51
      schedule_rt_lsa(ifa->oa);
52
      originate_net_lsa(ifa,po);
53
    }
54
  
55
    if(state==NEIGHBOR_FULL)        /* Increase number of adjacencies */
56
    {
57
      ifa->fadj++;
58
      schedule_rt_lsa(ifa->oa);
59
      originate_net_lsa(ifa,po);
60
    }
61
    if(oldstate>=NEIGHBOR_EXSTART && state<NEIGHBOR_EXSTART)
62
    {
63
      /* Stop RXMT timer */
64
      tm_stop(n->rxmt_timer);
65
    }
66
    if(state==NEIGHBOR_EXSTART)
67
    {
68
      if(n->adj==0)        /* First time adjacency */
69
      {
70
        n->dds=random_u32();
71
      }
72
      n->dds++;
73
      n->myimms.byte=0;
74
      n->myimms.bit.ms=1;
75
      n->myimms.bit.m=1;
76
      n->myimms.bit.i=1;
77
      tm_start(n->rxmt_timer,1);        /* Or some other number ? */
78
    }
79
    if(state<NEIGHBOR_EXCHANGE) tm_stop(n->lsrr_timer);
80
  }
81
}
82

    
83
struct ospf_neighbor *
84
electbdr(list nl)
85
{
86
  struct ospf_neighbor *neigh,*n1,*n2;
87

    
88
  n1=NULL;
89
  n2=NULL;
90
  WALK_LIST (neigh, nl)                /* First try those decl. themselves */
91
  {
92
    if(neigh->state>=NEIGHBOR_2WAY)        /* Higher than 2WAY */
93
      if(neigh->priority>0)                /* Eligible */
94
        if(neigh->rid!=neigh->dr)        /* And not declaring itself DR */
95
        {
96
          if(neigh->rid==neigh->bdr)        /* Declaring BDR */
97
          {
98
            if(n1!=NULL)
99
            {
100
              if(neigh->priority>n1->priority) n1=neigh;
101
              else if(neigh->priority==n1->priority)
102
                  if(neigh->rid>n1->rid) n1=neigh;
103
            }
104
            else
105
            {
106
              n1=neigh;
107
            }
108
          }
109
          else                                /* And NOT declaring BDR */
110
          {
111
            if(n2!=NULL)
112
            {
113
              if(neigh->priority>n2->priority) n2=neigh;
114
              else if(neigh->priority==n2->priority)
115
                  if(neigh->rid>n2->rid) n2=neigh;
116
            }
117
            else
118
            {
119
              n2=neigh;
120
            }
121
          }
122
      }
123
  }
124
  if(n1==NULL) n1=n2;
125

    
126
  return(n1);
127
}
128

    
129
struct ospf_neighbor *
130
electdr(list nl)
131
{
132
  struct ospf_neighbor *neigh,*n;
133

    
134
  n=NULL;
135
  WALK_LIST (neigh, nl)        /* And now DR */
136
  {
137
    if(neigh->state>=NEIGHBOR_2WAY)        /* Higher than 2WAY */
138
      if(neigh->priority>0)                /* Eligible */
139
        if(neigh->rid==neigh->dr)        /* And declaring itself DR */
140
        {
141
          if(n!=NULL)
142
          {
143
            if(neigh->priority>n->priority) n=neigh;
144
            else if(neigh->priority==n->priority)
145
                if(neigh->rid>n->rid) n=neigh;
146
          }
147
          else
148
          {
149
            n=neigh;
150
          }
151
      }
152
  }
153

    
154
  return(n);
155
}
156

    
157
int
158
can_do_adj(struct ospf_neighbor *n)
159
{
160
  struct ospf_iface *ifa;
161
  struct proto *p;
162
  int i;
163

    
164
  ifa=n->ifa;
165
  p=(struct proto *)(ifa->proto);
166
  i=0;
167

    
168
  switch(ifa->type)
169
  {
170
    case OSPF_IT_PTP:
171
    case OSPF_IT_VLINK:
172
      i=1;
173
      break;
174
    case OSPF_IT_BCAST:
175
    case OSPF_IT_NBMA:
176
      switch(ifa->state)
177
      {
178
        case OSPF_IS_DOWN:
179
          die("%s: Iface %s in down state?", p->name, ifa->iface->name);
180
          break;
181
        case OSPF_IS_WAITING:
182
          DBG("%s: Neighbor? on iface %s\n",p->name, ifa->iface->name);
183
          break;
184
        case OSPF_IS_DROTHER:
185
          if(((n->rid==ifa->drid) || (n->rid==ifa->bdrid))
186
            && (n->state>=NEIGHBOR_2WAY)) i=1;
187
          break;
188
        case OSPF_IS_PTP:
189
        case OSPF_IS_BACKUP:
190
        case OSPF_IS_DR:
191
          if(n->state>=NEIGHBOR_2WAY) i=1;
192
          break;
193
        default:
194
          die("%s: Iface %s in unknown state?",p->name, ifa->iface->name);
195
          break;
196
      }
197
      break;
198
    default:
199
      die("%s: Iface %s is unknown type?",p->name, ifa->iface->name);
200
      break;
201
  }
202
  DBG("%s: Iface %s can_do_adj=%d\n",p->name, ifa->iface->name,i);
203
  return i;
204
}
205

    
206
void
207
ospf_neigh_sm(struct ospf_neighbor *n, int event)
208
        /* Interface state machine */
209
{
210
  struct proto *p=(struct proto *)(n->ifa->proto);
211
  struct proto_ospf *po=n->ifa->proto;
212

    
213
  DBG("%s: Neighbor state machine for neighbor %I, event \"%s\".\n",
214
    p->name, n->rid, ospf_inm[event]);
215

    
216
  switch(event)
217
  {
218
    case INM_START:
219
      neigh_chstate(n,NEIGHBOR_ATTEMPT);
220
      /* FIXME No NBMA now */
221
      break;
222
    case INM_HELLOREC:
223
      switch(n->state)
224
      {
225
        case NEIGHBOR_ATTEMPT:
226
        case NEIGHBOR_DOWN:
227
          neigh_chstate(n,NEIGHBOR_INIT);
228
        default:
229
          restart_inactim(n);
230
          break;
231
      }
232
      break;
233
    case INM_2WAYREC:
234
      if(n->state<NEIGHBOR_2WAY) neigh_chstate(n,NEIGHBOR_2WAY);
235
      if((n->state==NEIGHBOR_2WAY) && can_do_adj(n))
236
        neigh_chstate(n,NEIGHBOR_EXSTART);
237
      break;
238
    case INM_NEGDONE:
239
      if(n->state==NEIGHBOR_EXSTART)
240
      {
241
        neigh_chstate(n,NEIGHBOR_EXCHANGE);
242
        s_init_list(&(n->lsrql));
243
        n->lsrqh=ospf_top_new(n->ifa->proto);
244
        s_init_list(&(n->lsrtl));
245
        n->lsrth=ospf_top_new(n->ifa->proto);
246
        s_init(&(n->dbsi), &(n->ifa->oa->lsal));
247
        s_init(&(n->lsrqi), &(n->lsrql));
248
        s_init(&(n->lsrti), &(n->lsrtl));
249
        tm_start(n->lsrr_timer,n->ifa->rxmtint);
250
        tm_start(n->ackd_timer,n->ifa->rxmtint/2);
251
      }
252
      else die("NEGDONE and I'm not in EXSTART?");
253
      break;
254
    case INM_EXDONE:
255
        neigh_chstate(n,NEIGHBOR_LOADING);
256
      break;
257
    case INM_LOADDONE:
258
        neigh_chstate(n,NEIGHBOR_FULL);
259
      break;
260
    case INM_ADJOK:
261
        switch(n->state)
262
        {
263
          case NEIGHBOR_2WAY:
264
            /* Can In build adjacency? */
265
            if(can_do_adj(n))
266
            {
267
              neigh_chstate(n,NEIGHBOR_EXSTART);
268
            }
269
            break;
270
          default:
271
            if(n->state>=NEIGHBOR_EXSTART)
272
              if(!can_do_adj(n))
273
              {
274
                neigh_chstate(n,NEIGHBOR_2WAY);
275
              }
276
            break;
277
        }
278
      break;
279
    case INM_SEQMIS:
280
    case INM_BADLSREQ:
281
      debug("%s: Bad LS req!\n", p->name);
282
      if(n->state>=NEIGHBOR_EXCHANGE)
283
      {
284
        neigh_chstate(n,NEIGHBOR_EXSTART);
285
      }
286
      break;
287
    case INM_KILLNBR:
288
    case INM_LLDOWN:
289
    case INM_INACTTIM:
290
      neigh_chstate(n,NEIGHBOR_DOWN);
291
      break;
292
    case INM_1WAYREC:
293
      neigh_chstate(n,NEIGHBOR_INIT);
294
      break;
295
    default:
296
      die("%s: INM - Unknown event?",p->name);
297
      break;
298
  }
299
}
300

    
301
void
302
bdr_election(struct ospf_iface *ifa, struct proto *p)
303
{
304
  struct ospf_neighbor *neigh,*ndr,*nbdr,me,*tmp;
305
  u32 myid, ndrid, nbdrid;
306
  int doadj;
307

    
308
  p=(struct proto *)(ifa->proto);
309

    
310
  DBG("%s: (B)DR election.\n",p->name);
311

    
312
  myid=p->cf->global->router_id;
313

    
314
  me.state=NEIGHBOR_2WAY;
315
  me.rid=myid;
316
  me.priority=ifa->priority;
317
  me.dr=ifa->drid;
318
  me.bdr=ifa->bdrid;
319
  me.ip=ifa->iface->addr->ip;
320

    
321
  add_tail(&ifa->neigh_list, NODE &me);
322

    
323
  nbdr=electbdr(ifa->neigh_list);
324
  ndr=electdr(ifa->neigh_list);
325

    
326
  if(ndr==NULL) ndr=nbdr;                /* FIXME is this correct? */
327

    
328
  if(((ifa->drid==myid) && (ndr!=&me))
329
    || ((ifa->drid!=myid) && (ndr==&me))
330
    || ((ifa->bdrid==myid) && (nbdr!=&me)) 
331
    || ((ifa->bdrid!=myid) && (nbdr==&me)))
332
  {
333
    if(ndr==NULL) ifa->drid=me.dr=0;
334
    else ifa->drid=me.dr=ndr->rid;
335

    
336
    if(nbdr==NULL) ifa->bdrid=me.bdr=0;
337
    else ifa->bdrid=me.bdr=nbdr->rid;
338

    
339
    nbdr=electbdr(ifa->neigh_list);
340
    ndr=electdr(ifa->neigh_list);
341
  }
342

    
343
  if(ndr==NULL) ifa->drid=0;
344
  if(ndr==NULL) ndrid=0;
345
  else ndrid=ndr->rid;
346

    
347
  if(nbdr==NULL) nbdrid=0;
348
  else nbdrid=nbdr->rid;
349

    
350
  doadj=0;
351
  if((ifa->drid!=ndrid) || (ifa->bdrid!=nbdrid)) doadj=1;
352
  ifa->drid=ndrid;
353
  if(ndrid==0)
354
  {
355
    ifa->drid=0;
356
    ifa->drip=ipa_from_u32(0);
357
  }
358
  else
359
  {
360
    if((tmp=find_neigh(ifa,ndrid))==NULL)
361
      die("Error in DR election.");
362
    ifa->drid=ndrid;
363
    ifa->drip=tmp->ip;
364
  }
365

    
366
  if(nbdrid==0)
367
  {
368
    ifa->bdrid=0;
369
    ifa->bdrip=ipa_from_u32(0);
370
  }
371
  else
372
  {
373
    if((tmp=find_neigh(ifa,nbdrid))==NULL)
374
      die("Error in BDR election.");
375
    ifa->bdrid=nbdrid;
376
    ifa->bdrip=tmp->ip;
377
  }
378

    
379
  DBG("%s: DR=%I, BDR=%I\n",p->name, ifa->drid, ifa->bdrid);
380

    
381
  if(myid==ifa->drid) iface_chstate(ifa, OSPF_IS_DR);
382
  else
383
  {
384
    if(myid==ifa->bdrid) iface_chstate(ifa, OSPF_IS_BACKUP);
385
    else iface_chstate(ifa, OSPF_IS_DROTHER);
386
  }
387

    
388
  rem_node(NODE &me);
389

    
390
  if(doadj)
391
  {
392
    WALK_LIST (neigh, ifa->neigh_list)
393
    {
394
      ospf_neigh_sm(neigh, INM_ADJOK);
395
    }
396
  }
397
}
398

    
399
struct ospf_neighbor *
400
find_neigh(struct ospf_iface *ifa, u32 rid)
401
{
402
  struct ospf_neighbor *n;
403

    
404
  WALK_LIST (n, ifa->neigh_list)
405
    if(n->rid == rid)
406
      return n;
407
  return NULL;
408
}
409

    
410
struct ospf_neighbor *
411
find_neigh_noifa(struct proto_ospf *po, u32 rid)
412
{
413
  struct ospf_neighbor *n;
414
  struct ospf_iface *ifa;
415

    
416
  WALK_LIST (ifa, po->iface_list)
417
    if((n=find_neigh(ifa, rid))!=NULL)
418
      return n;
419
  return NULL;
420
}
421

    
422
struct ospf_area *
423
ospf_find_area(struct proto_ospf *po, u32 aid)
424
{
425
  struct ospf_area *oa;
426
  WALK_LIST(NODE oa,po->area_list)
427
    if(((struct ospf_area *)oa)->areaid==aid) return oa;
428
  return NULL;
429
}
430

    
431
/* Neighbor is inactive for a long time. Remove it. */
432
void
433
neighbor_timer_hook(timer *timer)
434
{
435
  struct ospf_neighbor *n;
436
  struct ospf_iface *ifa;
437
  struct proto *p;
438

    
439
  n=(struct ospf_neighbor *)timer->data;
440
  ifa=n->ifa;
441
  p=(struct proto *)(ifa->proto);
442
  debug("%s: Inactivity timer fired on interface %s for neighbor %I.\n",
443
    p->name, ifa->iface->name, n->ip);
444
  ospf_neigh_remove(n);
445
}
446

    
447
void
448
ospf_neigh_remove(struct ospf_neighbor *n)
449
{
450
  struct ospf_iface *ifa;
451
  struct proto *p;
452

    
453
  ifa=n->ifa;
454
  p=(struct proto *)(ifa->proto);
455
  neigh_chstate(n, NEIGHBOR_DOWN);
456
  tm_stop(n->inactim);
457
  rfree(n->inactim);
458
  if(n->rxmt_timer!=NULL)
459
  {
460
    tm_stop(n->rxmt_timer);
461
    rfree(n->rxmt_timer);
462
  }
463
  if(n->lsrr_timer!=NULL)
464
  {
465
    tm_stop(n->lsrr_timer);
466
    rfree(n->lsrr_timer);
467
  }
468
  if(n->ackd_timer!=NULL)
469
  {
470
    tm_stop(n->ackd_timer);
471
    rfree(n->ackd_timer);
472
  }
473
  if(n->ldbdes!=NULL)
474
  {
475
    mb_free(n->ldbdes);
476
  }
477
  if(n->lsrqh!=NULL)
478
  {
479
    ospf_top_free(n->lsrqh);
480
  }
481
  if(n->lsrth!=NULL)
482
  {
483
    ospf_top_free(n->lsrth);
484
  }
485
  rem_node(NODE n);
486
  mb_free(n);
487
  debug("%s: Deleting neigbor.\n", p->name);
488
}
489

    
490
void
491
ospf_sh_neigh_info(struct ospf_neighbor *n)
492
{
493
   struct ospf_iface *ifa=n->ifa;
494
   char *pos="other";
495
   char etime[6];
496
   int exp,sec,min;
497

    
498
   exp=n->inactim->expires-now;
499
   sec=exp-(exp/60);
500
   min=(exp-sec)/60;
501
   if(min>59)
502
   {
503
     bsprintf(etime,"-Inf-");
504
   }
505
   else
506
   {
507
     bsprintf(etime,"%02u:%02u", min, sec);
508
   }
509
   
510
   if(n->rid==ifa->drid) pos="dr   ";
511
   if(n->rid==ifa->bdrid) pos="bdr  ";
512

    
513

    
514
   cli_msg(-1013,"%-18I\t%3u\t%s/%s\t%-5s\t%-18I\t%-10s",n->rid, n->priority,
515
     ospf_ns[n->state], pos, etime, n->ip,ifa->iface->name);
516
}