Statistics
| Branch: | Revision:

iof-bird-daemon / proto / ospf / neighbor.c @ 43e75f38

History | View | Annotate | Download (9.36 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", "attempt", "init", "2way", "exstart", "exchange",
12
  "loading", "full"};
13

    
14
const char *ospf_inm[]={ "hello received", "neighbor start", "2-way received",
15
  "negotiation done", "exstart done", "bad ls request", "load done",
16
  "adjacency ok?", "sequence mismatch", "1-way received", "kill neighbor",
17
  "inactivity timer", "line down" };
18

    
19
void
20
neigh_chstate(struct ospf_neighbor *n, u8 state)
21
{
22
  struct ospf_iface *ifa;
23
  struct proto *p;
24
  u8 oldstate;
25

    
26
  oldstate=n->state;
27

    
28
  if(oldstate!=state)
29
  {
30
    ifa=n->ifa;
31
    n->state=state;
32
    if(oldstate==NEIGHBOR_FULL)        /* Decrease number of adjacencies */
33
    {
34
      ifa->fadj--;
35
      n->state=state;
36
      originate_rt_lsa(ifa->oa,ifa->oa->po);
37
      originate_net_lsa(ifa,ifa->oa->po);
38
    }
39
    p=(struct proto *)(ifa->proto);
40
  
41
    debug("%s: Neighbor %I changes state from \"%s\" to \"%s\".\n",
42
      p->name, n->ip, ospf_ns[oldstate], ospf_ns[state]);
43
    if(state==NEIGHBOR_FULL)        /* Increase number of adjacencies */
44
    {
45
      ifa->fadj++;
46
      originate_rt_lsa(n->ifa->oa,n->ifa->oa->po);
47
      originate_net_lsa(ifa,ifa->oa->po);
48
    }
49
    if(oldstate>=NEIGHBOR_EXSTART && state<NEIGHBOR_EXSTART)
50
    {
51
      tm_stop(n->rxmt_timer);
52
      /* Stop RXMT timers */
53
    }
54
    if(state==NEIGHBOR_EXSTART)
55
    {
56
      if(n->adj==0)        /* First time adjacency */
57
      {
58
        n->dds=random_u32();
59
      }
60
      n->dds++;
61
      n->myimms.byte=0;
62
      n->myimms.bit.ms=1;
63
      n->myimms.bit.m=1;
64
      n->myimms.bit.i=1;
65
      tm_start(n->rxmt_timer,1);        /* Or some other number ? */
66
    }
67
    if(state<NEIGHBOR_EXCHANGE) tm_stop(n->lsrr_timer);
68
  }
69
}
70

    
71
struct ospf_neighbor *
72
electbdr(list nl)
73
{
74
  struct ospf_neighbor *neigh,*n1,*n2;
75

    
76
  n1=NULL;
77
  n2=NULL;
78
  WALK_LIST (neigh, nl)                /* First try those decl. themselves */
79
  {
80
    if(neigh->state>=NEIGHBOR_2WAY)        /* Higher than 2WAY */
81
      if(neigh->priority>0)                /* Eligible */
82
        if(neigh->rid!=neigh->dr)        /* And not declaring itself DR */
83
        {
84
          if(neigh->rid==neigh->bdr)        /* Declaring BDR */
85
          {
86
            if(n1!=NULL)
87
            {
88
              if(neigh->priority>n1->priority) n1=neigh;
89
              else if(neigh->priority==n1->priority)
90
                  if(neigh->rid>n1->rid) n1=neigh;
91
            }
92
            else
93
            {
94
              n1=neigh;
95
            }
96
          }
97
          else                                /* And NOT declaring BDR */
98
          {
99
            if(n2!=NULL)
100
            {
101
              if(neigh->priority>n2->priority) n2=neigh;
102
              else if(neigh->priority==n2->priority)
103
                  if(neigh->rid>n2->rid) n2=neigh;
104
            }
105
            else
106
            {
107
              n2=neigh;
108
            }
109
          }
110
      }
111
  }
112
  if(n1==NULL) n1=n2;
113

    
114
  return(n1);
115
}
116

    
117
struct ospf_neighbor *
118
electdr(list nl)
119
{
120
  struct ospf_neighbor *neigh,*n;
121

    
122
  n=NULL;
123
  WALK_LIST (neigh, nl)        /* And now DR */
124
  {
125
    if(neigh->state>=NEIGHBOR_2WAY)        /* Higher than 2WAY */
126
      if(neigh->priority>0)                /* Eligible */
127
        if(neigh->rid==neigh->dr)        /* And declaring itself DR */
128
        {
129
          if(n!=NULL)
130
          {
131
            if(neigh->priority>n->priority) n=neigh;
132
            else if(neigh->priority==n->priority)
133
                if(neigh->rid>n->rid) n=neigh;
134
          }
135
          else
136
          {
137
            n=neigh;
138
          }
139
      }
140
  }
141

    
142
  return(n);
143
}
144

    
145
int
146
can_do_adj(struct ospf_neighbor *n)
147
{
148
  struct ospf_iface *ifa;
149
  struct proto *p;
150
  int i;
151

    
152
  ifa=n->ifa;
153
  p=(struct proto *)(ifa->proto);
154
  i=0;
155

    
156
  switch(ifa->type)
157
  {
158
    case OSPF_IT_PTP:
159
    case OSPF_IT_VLINK:
160
      i=1;
161
      break;
162
    case OSPF_IT_BCAST:
163
    case OSPF_IT_NBMA:
164
      switch(ifa->state)
165
      {
166
        case OSPF_IS_DOWN:
167
          die("%s: Iface %s in down state?", p->name, ifa->iface->name);
168
          break;
169
        case OSPF_IS_WAITING:
170
          DBG("%s: Neighbor? on iface %s\n",p->name, ifa->iface->name);
171
          break;
172
        case OSPF_IS_DROTHER:
173
          if(((n->rid==ifa->drid) || (n->rid==ifa->bdrid))
174
            && (n->state==NEIGHBOR_2WAY)) i=1;
175
          break;
176
        case OSPF_IS_PTP:
177
        case OSPF_IS_BACKUP:
178
        case OSPF_IS_DR:
179
          if(n->state==NEIGHBOR_2WAY) i=1;
180
          break;
181
        default:
182
          die("%s: Iface %s in unknown state?",p->name, ifa->iface->name);
183
          break;
184
      }
185
      break;
186
    default:
187
      die("%s: Iface %s is unknown type?",p->name, ifa->iface->name);
188
      break;
189
  }
190
  DBG("%s: Iface %s can_do_adj=%d\n",p->name, ifa->iface->name,i);
191
  return i;
192
}
193

    
194
void
195
ospf_neigh_sm(struct ospf_neighbor *n, int event)
196
        /* Interface state machine */
197
{
198
  struct proto *p=(struct proto *)(n->ifa->proto);
199
  struct proto_ospf *po=n->ifa->proto;
200

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

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

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

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

    
325
  if(ndr==NULL) ndr=nbdr;
326

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

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

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

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

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

    
349
  doadj=0;
350
  if((ifa->drid!=ndrid) || (ifa->bdrid!=nbdrid)) doadj=1;
351
  ifa->drid=ndrid;
352
  if((tmp=find_neigh(ifa,ndrid))==NULL) die("Error i BDR election.\n");
353
  ifa->drip=tmp->ip;
354
  ifa->bdrid=nbdrid;
355
  if((tmp=find_neigh(ifa,nbdrid))==NULL) die("Error i BDR election.\n");
356
  ifa->bdrip=tmp->ip;
357

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

    
360
  if(myid==ifa->drid) iface_chstate(ifa, OSPF_IS_DR);
361
  else
362
  {
363
    if(myid==ifa->bdrid) iface_chstate(ifa, OSPF_IS_BACKUP);
364
    else iface_chstate(ifa, OSPF_IS_DROTHER);
365
  }
366

    
367
  rem_node(NODE &me);
368

    
369
  if(doadj)
370
  {
371
    WALK_LIST (neigh, ifa->neigh_list)
372
    {
373
      ospf_neigh_sm(neigh, INM_ADJOK);
374
    }
375
  }
376
}
377

    
378
struct ospf_neighbor *
379
find_neigh(struct ospf_iface *ifa, u32 rid)
380
{
381
  struct ospf_neighbor *n;
382

    
383
  WALK_LIST (n, ifa->neigh_list)
384
    if(n->rid == rid)
385
      return n;
386
  return NULL;
387
}
388

    
389
struct ospf_neighbor *
390
find_neigh_noifa(struct proto_ospf *po, u32 rid)
391
{
392
  struct ospf_neighbor *n;
393
  struct ospf_iface *ifa;
394

    
395
  WALK_LIST (ifa, po->iface_list)
396
    if((n=find_neigh(ifa, rid))!=NULL)
397
      return n;
398
  return NULL;
399
}
400

    
401
struct ospf_area *
402
ospf_find_area(struct proto_ospf *po, u32 aid)
403
{
404
  struct ospf_area *oa;
405
  WALK_LIST(NODE oa,po->area_list)
406
    if(((struct ospf_area *)oa)->areaid==aid) return oa;
407
  return NULL;
408
}
409

    
410