]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Huge changes. Neighbor and interface state machines rewritten.
authorOndrej Filip <feela@network.cz>
Mon, 18 Oct 1999 21:48:51 +0000 (21:48 +0000)
committerOndrej Filip <feela@network.cz>
Mon, 18 Oct 1999 21:48:51 +0000 (21:48 +0000)
It should be cleaner now, I'm preparing for file splitting.
Maybe I added some minor bugs. :-(

proto/ospf/ospf.c
proto/ospf/ospf.h

index ce08bc223ba19220d52f2e7a58ec94e82e7d5f53..831f183792da97a4118cc72baacb53033c43b505 100644 (file)
@@ -255,16 +255,195 @@ electdr(list nl)
 }
 
 void
-backupseen(struct ospf_iface *ifa)
+install_inactim(struct ospf_neighbor *n)
 {
   struct proto *p;
-  struct ospf_neighbor *neigh,*ndr,*nbdr,me;
-  u32 myid;
+  struct ospf_iface *ifa;
 
+  ifa=n->ifa;
   p=(struct proto *)(ifa->proto);
 
-  tm_stop(ifa->wait_timer);
-  DBG("%s: Stoping wait timer\n",p->name);
+  if(n->inactim==NULL)
+  {
+    n->inactim=tm_new(p->pool);
+    n->inactim->data=n;
+    n->inactim->randomize=0;
+    n->inactim->hook=neighbor_timer_hook;
+    n->inactim->recurrent=0;
+    DBG("%s: Installing inactivity timer.\n", p->name);
+  }
+}
+
+void
+restart_inactim(struct ospf_neighbor *n)
+{
+  tm_start(n->inactim,n->ifa->deadc*n->ifa->helloint);
+}
+
+void
+restart_hellotim(struct ospf_iface *ifa)
+{
+  tm_start(ifa->hello_timer,ifa->helloint);
+}
+
+void
+restart_waittim(struct ospf_iface *ifa)
+{
+  tm_start(ifa->wait_timer,ifa->waitint);
+}
+
+int
+can_do_adj(struct ospf_neighbor *n)
+{
+  struct ospf_iface *ifa;
+  struct proto *p;
+  int i;
+
+  ifa=n->ifa;
+  p=(struct proto *)(ifa->proto);
+  i=0;
+
+  switch(ifa->type)
+  {
+    case OSPF_IT_PTP:
+    case OSPF_IT_VLINK:
+      i=1;
+      break;
+    case OSPF_IT_BCAST:
+    case OSPF_IT_NBMA:
+      switch(ifa->state)
+      {
+        case OSPF_IS_DOWN:
+          die("%s: Iface %s in down state?", p->name, ifa->iface->name);
+          break;
+        case OSPF_IS_WAITING:
+          DBG("%s: Neighbor? on iface %s\n",p->name, ifa->iface->name);
+          break;
+        case OSPF_IS_DROTHER:
+          if(((n->rid==ifa->drid) || (n->rid==ifa->bdrid))
+            && (n->state==NEIGHBOR_2WAY)) i=1;
+          break;
+        case OSPF_IS_PTP:
+        case OSPF_IS_BACKUP:
+        case OSPF_IS_DR:
+          if(n->state==NEIGHBOR_2WAY) i=1;
+          break;
+        default:
+          die("%s: Iface %s in unknown state?",p->name, ifa->iface->name);
+          break;
+      }
+      break;
+    default:
+      die("%s: Iface %s is unknown type?",p->name, ifa->iface->name);
+      break;
+  }
+  DBG("%s: Iface %s can_do_adj=%d\n",p->name, ifa->iface->name,i);
+  return i;
+}
+
+void
+ospf_neigh_sm(struct ospf_neighbor *n, int event)
+       /* Interface state machine */
+{
+  struct proto *p;
+
+  p=(struct proto *)(n->ifa->proto);
+
+  switch(event)
+  {
+    case INM_START:
+      neigh_chstate(n,NEIGHBOR_ATTEMPT);
+      /* FIXME No NBMA now */
+      break;
+    case INM_HELLOREC:
+      switch(n->state)
+      {
+        case NEIGHBOR_ATTEMPT:
+       case NEIGHBOR_DOWN:
+         neigh_chstate(n,NEIGHBOR_INIT);
+       default:
+          restart_inactim(n);
+         break;
+      }
+      break;
+    case INM_2WAYREC:
+      if(n->state==NEIGHBOR_INIT)
+      {
+        /* Can In build adjacency? */
+        neigh_chstate(n,NEIGHBOR_2WAY);
+       if(can_do_adj(n))
+        {
+          neigh_chstate(n,NEIGHBOR_EXSTART);
+          tryadj(n,p);
+        }
+      }
+      break;
+    case INM_NEGDONE:
+      if(n->state==NEIGHBOR_EXSTART)
+      {
+        neigh_chstate(n,NEIGHBOR_EXCHANGE);
+        /* FIXME Go on... */
+      }
+      break;
+    case INM_EXDONE:
+      break;
+    case INM_LOADDONE:
+      break;
+    case INM_ADJOK:
+        switch(n->state)
+        {
+          case NEIGHBOR_2WAY:
+        /* Can In build adjacency? */
+            if(can_do_adj(n))
+            {
+              neigh_chstate(n,NEIGHBOR_EXSTART);
+              tryadj(n,p);
+            }
+            break;
+          default:
+           if(n->state>=NEIGHBOR_EXSTART)
+              if(!can_do_adj(n))
+              {
+                neigh_chstate(n,NEIGHBOR_2WAY);
+               /* FIXME Stop timers, kill database... */
+              }
+            break;
+        }
+      break;
+    case INM_SEQMIS:
+    case INM_BADLSREQ:
+      if(n->state>=NEIGHBOR_EXCHANGE)
+      {
+        neigh_chstate(n,NEIGHBOR_EXSTART);
+       /* Go on....*/
+      }
+      break;
+    case INM_KILLNBR:
+    case INM_LLDOWN:
+    case INM_INACTTIM:
+      neigh_chstate(n,NEIGHBOR_DOWN);
+      break;
+    case INM_1WAYREC:
+      if(n->state>=NEIGHBOR_2WAY)
+      {
+        neigh_chstate(n,NEIGHBOR_DOWN);
+      }
+      break;
+    default:
+      die("%s: INM - Unknown event?",p->name);
+      break;
+  }
+}
+
+
+void
+bdr_election(struct ospf_iface *ifa, struct proto *p)
+{
+  struct ospf_neighbor *neigh,*ndr,*nbdr,me;
+  u32 myid, ndrid, nbdrid;
+  int doadj;
+
+  p=(struct proto *)(ifa->proto);
 
   DBG("%s: (B)DR election.\n",p->name);
 
@@ -280,7 +459,7 @@ backupseen(struct ospf_iface *ifa)
 
   nbdr=electbdr(ifa->neigh_list);
   ndr=electdr(ifa->neigh_list);
+
   if(ndr==NULL) ndr=nbdr;
 
   if(((ifa->drid==myid) && (ndr->rid!=myid))
@@ -297,11 +476,18 @@ backupseen(struct ospf_iface *ifa)
     nbdr=electbdr(ifa->neigh_list);
     ndr=electdr(ifa->neigh_list);
   }
+
   if(ndr==NULL) ifa->drid=0;
-  else ifa->drid=ndr->rid;
+  if(ndr==NULL) ndrid=0;
+  else ndrid=ndr->rid;
+
+  if(nbdr==NULL) nbdrid=0;
+  else nbdrid=nbdr->rid;
 
-  if(nbdr==NULL) ifa->bdrid=0;
-  else ifa->bdrid=me.bdr=nbdr->rid;
+  doadj=0;
+  if((ifa->drid!=ndrid) || (ifa->bdrid!=nbdrid)) doadj=1;
+  ifa->drid=ndrid;
+  ifa->bdrid=nbdrid;
 
   DBG("%s: DR=%u, BDR=%u\n",p->name, ifa->drid, ifa->bdrid);
 
@@ -313,6 +499,85 @@ backupseen(struct ospf_iface *ifa)
   }
 
   rem_node(NODE &me);
+
+  if(doadj)
+  {
+    WALK_LIST (neigh, ifa->neigh_list)
+    {
+      ospf_neigh_sm(neigh, INM_ADJOK);
+    }
+  }
+}
+
+void
+downint(struct ospf_iface *ifa)
+{
+  /* FIXME: Delete all neighbors! */
+}
+
+void
+ospf_int_sm(struct ospf_iface *ifa, int event)
+{
+  struct proto *p;
+
+  p=(struct proto *)(ifa->proto);
+
+  DBG("%s: SM on iface %s. Event is %d.\n",
+    p->name, ifa->iface->name, event);
+
+  switch(event)
+  {
+    case ISM_UP:
+      if(ifa->state==OSPF_IS_DOWN)
+      {
+        restart_hellotim(ifa);
+        if((ifa->type==OSPF_IT_PTP) || (ifa->type==OSPF_IT_VLINK))
+        {
+          iface_chstate(ifa, OSPF_IS_PTP);
+        }
+        else
+        {
+          if(ifa->priority==0)
+          {
+            iface_chstate(ifa, OSPF_IS_DROTHER);
+          } 
+          else
+          {
+             iface_chstate(ifa, OSPF_IS_WAITING);
+             restart_waittim(ifa);
+          }
+        }
+      }
+      break;
+    case ISM_BACKS:
+    case ISM_WAITF:
+      if(ifa->state==OSPF_IS_WAITING)
+      {
+        bdr_election(ifa ,p);
+      }
+      break;
+    case ISM_NEICH:
+      if((ifa->state==OSPF_IS_DROTHER) || (ifa->state==OSPF_IS_DR) ||
+        (ifa->state==OSPF_IS_BACKUP))
+      {
+        bdr_election(ifa ,p);
+      }
+    case ISM_DOWN:
+      iface_chstate(ifa, OSPF_IS_DOWN);
+      downint(ifa);
+      break;
+    case ISM_LOOP:     /* Useless? */
+      iface_chstate(ifa, OSPF_IS_LOOP);
+      downint(ifa);
+      break;
+    case ISM_UNLOOP:
+      iface_chstate(ifa, OSPF_IS_DOWN);
+      break;
+    default:
+      die("%s: ISM - Unknown event?",p->name);
+      break;
+  }
+       
 }
 
 void
@@ -364,12 +629,6 @@ ospf_hello_rx(struct ospf_hello_packet *ps, struct proto *p,
     log("%s: New neighbor found: %u.", p->name,nrid);
     n=mb_alloc(p->pool, sizeof(struct ospf_neighbor));
     add_tail(&ifa->neigh_list, NODE n);
-    n->inactim=tm_new(p->pool);
-    n->inactim->data=n;
-    n->inactim->randomize=0;
-    n->inactim->hook=neighbor_timer_hook;
-    n->inactim->recurrent=0;
-    DBG("%s: Installing inactivity timer.\n", p->name);
     n->rid=nrid;
     n->dr=ntohl(ps->dr);
     n->bdr=ntohl(ps->bdr);
@@ -377,98 +636,70 @@ ospf_hello_rx(struct ospf_hello_packet *ps, struct proto *p,
     n->options=ps->options;
     n->ifa=ifa;
     n->adj=0;
-    neigh_chstate(n,NEIGHBOR_INIT);
+    neigh_chstate(n,NEIGHBOR_DOWN);
+    install_inactim(n);
   }
-  tm_start(n->inactim,ifa->deadc*ifa->helloint);
+  ospf_neigh_sm(n, INM_HELLOREC);
 
-  twoway=0;
   pnrid=(u32 *)((struct ospf_hello_packet *)(ps+1));
 
+  twoway=0;
   for(i=0;i<size-(sizeof(struct ospf_hello_packet));i++)
   {
     if(ntohl(*(pnrid+i))==p->cf->global->router_id)
     {
-      twoway=1;
       DBG("%s: Twoway received. %u\n", p->name, nrid);
+      ospf_neigh_sm(n, INM_2WAYREC);
+      twoway=1;
       break;
     }
   }
 
-  if(twoway)
-  {
-    if(n->state<NEIGHBOR_2WAY) neigh_chstate(n,NEIGHBOR_2WAY);
-  }
-  else
-  {
-    if(n->state>=NEIGHBOR_2WAY)
-    {
-      /* FIXME Delete all learnt */
-      neigh_chstate(n,NEIGHBOR_INIT);
-    }
-  }
+  if(!twoway) ospf_neigh_sm(n, INM_1WAYREC);
 
   /* Check priority change */
   if(n->priority!=(n->priority=ps->priority))
   {
-    /* FIXME NeighborChange */;
+    ospf_int_sm(ifa, ISM_NEICH);
   }
 
   /* Check neighbor's designed router idea */
   if((n->rid!=ntohl(ps->dr)) && (ntohl(ps->bdr)==0) &&
-    (ifa->state==OSPF_IS_WAITING) && (n->state>=NEIGHBOR_2WAY))
+    (n->state>=NEIGHBOR_2WAY))
   {
-    backupseen(ifa);
+    ospf_int_sm(ifa, ISM_BACKS);
+    DBG("BACKS");
   }
   if((n->rid==ntohl(ps->dr)) && (n->dr!=ntohl(ps->dr)))
   {
-    /* FIXME NeighborChange */;
+    ospf_int_sm(ifa, ISM_NEICH);
   }
   if((n->rid==n->dr) && (n->dr!=ntohl(ps->dr)))
   {
-    /* FIXME NeighborChange */;
+    ospf_int_sm(ifa, ISM_NEICH);
   }
   n->dr=ntohl(ps->dr); /* And update it */
 
   /* Check neighbor's backup designed router idea */
-  if((n->rid==ntohl(ps->bdr)) && (ifa->state==OSPF_IS_WAITING)
-    && (n->state>=NEIGHBOR_2WAY))
+  if((n->rid==ntohl(ps->bdr)) && (n->state>=NEIGHBOR_2WAY))
   {
-    backupseen(ifa);
+    ospf_int_sm(ifa, ISM_BACKS);
+    DBG("BACKS");
   }
   if((n->rid==ntohl(ps->bdr)) && (n->bdr!=ntohl(ps->bdr)))
   {
-    /* FIXME NeighborChange */;
+    ospf_int_sm(ifa, ISM_NEICH);
   }
   if((n->rid==n->bdr) && (n->bdr!=ntohl(ps->bdr)))
   {
-    /* FIXME NeighborChange */;
+    ospf_int_sm(ifa, ISM_NEICH);
   }
   n->bdr=ntohl(ps->bdr);       /* And update it */
 
-
-  switch(ifa->state)
-  {
-    case OSPF_IS_DOWN:
-      die("%s: Iface %s in down state?", p->name, ifa->iface->name);
-      break;
-    case OSPF_IS_WAITING:
-      DBG("%s: Neighbor? on iface %s\n",p->name, ifa->iface->name);
-      break;
-    case OSPF_IS_DROTHER:
-      if(((n->rid==ifa->drid) || (n->rid==ifa->bdrid))
-        && (n->state==NEIGHBOR_2WAY)) tryadj(n,p);
-      break;
-    case OSPF_IS_PTP:
-    case OSPF_IS_BACKUP:
-    case OSPF_IS_DR:
-      if(n->state==NEIGHBOR_2WAY) tryadj(n,p);
-      break;
-    default:
-      die("%s: Iface %s in unknown state?",p->name, ifa->iface->name);
-      break;
-  }
+  ospf_neigh_sm(n, INM_HELLOREC);
 }
 
+
 int
 ospf_rx_hook(sock *sk, int size)
 {
@@ -697,8 +928,8 @@ ospf_iface_clasify(struct iface *ifa)
   if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
     (IF_MULTIACCESS|IF_MULTICAST))
   {
-     DBG(" OSPF: Clasifying BROADCAST.\n");
-     return OSPF_IT_BROADCAST;
+     DBG(" OSPF: Clasifying BCAST.\n");
+     return OSPF_IT_BCAST;
   }
   if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
     IF_MULTIACCESS)
@@ -799,12 +1030,11 @@ wait_timer_hook(timer *timer)
   p=(struct proto *)(ifa->proto);
   debug("%s: Wait timer fired on interface %s.\n",
     p->name, ifa->iface->name);
-  if(ifa->state=OSPF_IS_WAITING) backupseen(ifa);
-  else die("%s: Wait timer fired I'm not in WAITING state?", p->name);
+  ospf_int_sm(ifa, ISM_WAITF);
 }
 
 void
-ospf_add_timers(struct ospf_iface *ifa, pool *pool, u16 wait)
+ospf_add_timers(struct ospf_iface *ifa, pool *pool)
 {
   struct proto *p;
 
@@ -816,7 +1046,7 @@ ospf_add_timers(struct ospf_iface *ifa, pool *pool, u16 wait)
   if(ifa->helloint==0) ifa->helloint=HELLOINT_D;
   ifa->hello_timer->hook=hello_timer_hook;
   ifa->hello_timer->recurrent=ifa->helloint;
-  tm_start(ifa->hello_timer,ifa->helloint);
+  DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
 
   ifa->rxmt_timer=tm_new(pool);
   ifa->rxmt_timer->data=ifa;
@@ -824,21 +1054,15 @@ ospf_add_timers(struct ospf_iface *ifa, pool *pool, u16 wait)
   if(ifa->rxmtint==0) ifa->rxmtint=RXMTINT_D;
   ifa->rxmt_timer->hook=rxmt_timer_hook;
   ifa->rxmt_timer->recurrent=ifa->rxmtint;
-
-  DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
-  if((ifa->type!=OSPF_IT_PTP))
-  {
-    /* Install wait timer on NOT-PtP interfaces */
-    ifa->wait_timer=tm_new(pool);
-    ifa->wait_timer->data=ifa;
-    ifa->wait_timer->randomize=0;
-    ifa->wait_timer->hook=wait_timer_hook;
-    ifa->wait_timer->recurrent=0;
-    ifa->state=OSPF_IS_WAITING;
-    tm_start(ifa->wait_timer,(wait!=0 ? wait : WAIT_DMH*ifa->helloint));
-    DBG("%s: Installing wait timer. (%u)\n", p->name, (wait!=0 ? wait : WAIT_DMH*ifa->helloint));
-  }
-  else ifa->state=OSPF_IS_PTP;
+  DBG("%s: Installing rxmt timer. (%u)\n", p->name, ifa->rxmtint);
+
+  ifa->wait_timer=tm_new(pool);
+  ifa->wait_timer->data=ifa;
+  ifa->wait_timer->randomize=0;
+  ifa->wait_timer->hook=wait_timer_hook;
+  ifa->wait_timer->recurrent=0;
+  if(ifa->waitint==0) ifa->waitint= WAIT_DMH*ifa->helloint;
+  DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint);
 }
 
 void
@@ -917,11 +1141,12 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
 
       init_list(&(ifa->neigh_list));
     }
-    /* FIXME: NBMA? */
     /* FIXME: This should read config */
     ifa->helloint=0;
-    ospf_add_timers(ifa,p->pool,0);
+    ifa->waitint=0;
+    ospf_add_timers(ifa,p->pool);
     add_tail(&((struct proto_ospf *)p)->iface_list, NODE ifa);
+    ospf_int_sm(ifa, ISM_UP);
   }
 
   if(flags & IF_CHANGE_DOWN)
@@ -929,7 +1154,7 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
     if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
     {
       debug(" OSPF: killing interface %s.\n", iface->name);
-      /* FIXME: This should delete ifaces */
+      ospf_int_sm(ifa, ISM_DOWN);
     }
   }
 
index a9860cf80cbf26336e417f6873c38bbca623ba6d..c3d4902963cc3337d9c8fea60234bbd288c57da1 100644 (file)
@@ -44,6 +44,7 @@ struct ospf_iface {
                           interface.  LSAs contained in the update */
   u8 priority;         /* A router priority for DR election */
   u16 helloint;                /* number of seconds between hello sending */
+  u16 waitint;         /* number of sec before changing state from wait */
   u32 deadc;           /* after "deadint" missing hellos is router dead */
   u16 autype;
   u8 aukey[8];
@@ -53,16 +54,18 @@ struct ospf_iface {
   ip_addr bdrip;       /* Backup DR */
   u32 bdrid;
   u8 type;             /* OSPF view of type */
-#define OSPF_IT_BROADCAST 0
+#define OSPF_IT_BCAST 0
 #define OSPF_IT_NBMA 1
 #define OSPF_IT_PTP 2
+#define OSPF_IT_VLINK 3
   u8 state;            /* Interface state machine */
-#define OSPF_IS_DOWN 0         /* Should never happen */
-#define OSPF_IS_WAITING 1      /* Waiting for Wait timer */
-#define OSPF_IS_PTP 2          /* PTP operational */
-#define OSPF_IS_DROTHER 3      /* I'm on BCAST or NBMA and I'm not DR */
-#define OSPF_IS_BACKUP 4       /* I'm BDR */
-#define OSPF_IS_DR 5           /* I'm DR */
+#define OSPF_IS_DOWN 0         /* Not working */
+#define OSPF_IS_LOOP 1         /* Should never happen */
+#define OSPF_IS_WAITING 2      /* Waiting for Wait timer */
+#define OSPF_IS_PTP 3          /* PTP operational */
+#define OSPF_IS_DROTHER 4      /* I'm on BCAST or NBMA and I'm not DR */
+#define OSPF_IS_BACKUP 5       /* I'm BDR */
+#define OSPF_IS_DR 6           /* I'm DR */
   timer *wait_timer;           /* WAIT timer */
   timer *hello_timer;          /* HELLOINT timer */
   timer *rxmt_timer;           /* RXMT timer */
@@ -73,8 +76,8 @@ struct ospf_iface {
 #define PRIORITY_D 1
 #define HELLOINT_D 10
 #define DEADC_D 4
-#define WAIT_DMH 2     /* Value of Wait timer - not found it in RFC 
-                        * - using 2*HELLO
+#define WAIT_DMH 3     /* Value of Wait timer - not found it in RFC 
+                        * - using 3*HELLO
                         */
 };
 
@@ -161,4 +164,28 @@ struct ospf_neighbor
   u8 adj;              /* built adjacency? */
 };
 
+/* Definitions for interface state machine */
+#define ISM_UP 0       /* Interface Up */
+#define ISM_WAITF 1    /* Wait timer fired */
+#define ISM_BACKS 2    /* Backup seen */
+#define ISM_NEICH 3    /* Neighbor change */
+#define ISM_LOOP 4     /* Loop indicated */
+#define ISM_UNLOOP 5   /* Unloop indicated */
+#define ISM_DOWN 6     /* Interface down */
+
+/* Definitions for neighbor state machine */
+#define INM_HELLOREC 0 /* Hello Received */
+#define INM_START 1    /* Neighbor start - for NBMA */
+#define INM_2WAYREC 2  /* 2-Way received */
+#define INM_NEGDONE 3  /* Negotiation done */
+#define INM_EXDONE 4   /* Exchange done */
+#define INM_BADLSREQ 5 /* Bad LS Request */
+#define INM_LOADDONE 6 /* Load done */
+#define INM_ADJOK 7    /* AdjOK? */
+#define INM_SEQMIS 8   /* Sequence number mismatch */
+#define INM_1WAYREC 9  /* 1-Way */
+#define INM_KILLNBR 10 /* Kill Neigbor */
+#define INM_INACTTIM 11        /* Inactivity timer */
+#define INM_LLDOWN 12  /* Line down */
+
 #endif /* _BIRD_OSPF_H_ */