mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			599 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			599 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *	BIRD -- OSPF Topological Database
 | |
|  *
 | |
|  *	(c) 1999        Martin Mares <mj@ucw.cz>
 | |
|  *	(c) 1999 - 2000 Ondrej Filip <feela@network.cz>
 | |
|  *
 | |
|  *	Can be freely distributed and used under the terms of the GNU GPL.
 | |
|  */
 | |
| 
 | |
| #include "nest/bird.h"
 | |
| #include "lib/string.h"
 | |
| 
 | |
| #include "ospf.h"
 | |
| 
 | |
| #define HASH_DEF_ORDER 6		/* FIXME: Increase */
 | |
| #define HASH_HI_MARK *4
 | |
| #define HASH_HI_STEP 2
 | |
| #define HASH_HI_MAX 16
 | |
| #define HASH_LO_MARK /5
 | |
| #define HASH_LO_STEP 2
 | |
| #define HASH_LO_MIN 8
 | |
| 
 | |
| void *
 | |
| originate_rt_lsa_body(struct ospf_area *oa, u16 *length, struct proto_ospf *p)
 | |
| {
 | |
|   struct ospf_iface *ifa;
 | |
|   int j=0,k=0,v=0,e=0,b=0;
 | |
|   u16 i=0;
 | |
|   struct ospf_lsa_rt *rt;
 | |
|   struct ospf_lsa_rt_link *ln;
 | |
|   struct ospf_neighbor *neigh;
 | |
|   struct top_hash_entry *old;
 | |
|   struct proto_ospf *po=(struct proto_ospf *)p;
 | |
| 
 | |
|   DBG("%s: Originating RT_lsa body for area \"%I\".\n", po->proto.name,
 | |
|     oa->areaid);
 | |
| 
 | |
|   WALK_LIST (ifa, p->iface_list)
 | |
|   {
 | |
|     if((ifa->an==oa->areaid) && (ifa->state!=OSPF_IS_DOWN))
 | |
|     {
 | |
|       i++;
 | |
|       if(ifa->type==OSPF_IT_VLINK) v=1;
 | |
|     }
 | |
|   }
 | |
|   rt=mb_allocz(p->proto.pool, sizeof(struct ospf_lsa_rt)+
 | |
|     i*sizeof(struct ospf_lsa_rt_link));
 | |
|   if((p->areano>1) && (!oa->stub)) e=1;
 | |
|   rt->VEB=(v>>LSA_RT_V)+(e>>LSA_RT_E)+(b>>LSA_RT_B);
 | |
|   ln=(struct ospf_lsa_rt_link *)(rt+1);
 | |
| 
 | |
|   WALK_LIST (ifa, p->iface_list)
 | |
|   {
 | |
|     if((ifa->an==oa->areaid) && (ifa->state!=OSPF_IS_DOWN))
 | |
|     {
 | |
|       if(ifa->state==OSPF_IS_LOOP)
 | |
|       {
 | |
|         ln->type=3;
 | |
| 	ln->id=ipa_to_u32(ifa->iface->addr->ip);
 | |
| 	ln->data=0xffffffff;
 | |
| 	ln->metric=0;
 | |
| 	ln->notos=0;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         switch(ifa->type)
 | |
| 	{
 | |
|           case OSPF_IT_PTP:		/* rfc2328 - pg126 */
 | |
|             neigh=(struct ospf_neighbor *)HEAD(ifa->neigh_list);
 | |
| 	    if((neigh!=NULL) || (neigh->state==NEIGHBOR_FULL))
 | |
| 	    {
 | |
|                ln->type=LSART_PTP;
 | |
|                ln->id=neigh->rid;
 | |
|                ln->metric=ifa->cost;
 | |
|                ln->notos=0;
 | |
|                if(ifa->iface->flags && IA_UNNUMBERED)
 | |
|                {
 | |
|                  ln->data=ifa->iface->index;
 | |
|                }
 | |
|                else
 | |
|                {
 | |
|                  ln->id=ipa_to_u32(ifa->iface->addr->ip);
 | |
|                }
 | |
| 	    }
 | |
| 	    else
 | |
| 	    {
 | |
| 	      if(ifa->state==OSPF_IS_PTP)
 | |
|               {
 | |
| 		ln->type=LSART_STUB;
 | |
| 		ln->id=ln->id=ipa_to_u32(ifa->iface->addr->opposite);
 | |
| 		ln->metric=ifa->cost;
 | |
| 		ln->notos=0;
 | |
| 		ln->data=0xffffffff;
 | |
|               }
 | |
|               else
 | |
|               {
 | |
| 		i--; /* No link added */
 | |
|               }
 | |
| 	    }
 | |
|             break;
 | |
| 	  case OSPF_IT_BCAST: /*FIXME Go on */
 | |
| 	  case OSPF_IT_NBMA:
 | |
|             if(ifa->state==OSPF_IS_WAITING)
 | |
|             {
 | |
|               ln->type=LSART_STUB;
 | |
| 	      ln->id=ipa_to_u32(ifa->iface->addr->prefix);
 | |
| 	      ln->data=ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
 | |
|               ln->metric=ifa->cost;
 | |
|               ln->notos=0;
 | |
|             }
 | |
| 	    else
 | |
|             {
 | |
|               j=0,k=0;
 | |
|               WALK_LIST(neigh, ifa->neigh_list)
 | |
| 	      {
 | |
| 	        if((neigh->rid==ifa->drid) &&
 | |
| 	          (neigh->state==NEIGHBOR_FULL)) k=1;
 | |
| 		if(neigh->state==NEIGHBOR_FULL) j=1;
 | |
| 	      }
 | |
|               if(((ifa->state==OSPF_IS_DR) && (j==1)) || (k==1))
 | |
| 	      {
 | |
| 	        ln->type=LSART_NET;
 | |
| 		ln->id=ipa_to_u32(ifa->drip);
 | |
| 		ln->data=ipa_to_u32(ifa->iface->addr->ip);
 | |
| 		ln->metric=ifa->cost;
 | |
| 		ln->notos=0;
 | |
| 	      }
 | |
| 	      else
 | |
| 	      {
 | |
|                 ln->type=LSART_STUB;
 | |
|   	        ln->id=ipa_to_u32(ifa->iface->addr->prefix);
 | |
| 	        ln->data=ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
 | |
|                 ln->metric=ifa->cost;
 | |
|                 ln->notos=0;
 | |
| 	      }
 | |
|             }
 | |
| 	    break;
 | |
| 	  case OSPF_IT_VLINK:	/* FIXME Add virtual links! */
 | |
| 	    i--;
 | |
| 	    break;
 | |
| 	}
 | |
|       }
 | |
|       if(ifa->type==OSPF_IT_VLINK) v=1;
 | |
|     }
 | |
|     ln=(ln+1);
 | |
|   }
 | |
|   rt->links=i;
 | |
|   *length=i*sizeof(struct ospf_lsa_rt_link)+sizeof(struct ospf_lsa_rt)+
 | |
|     sizeof(struct ospf_lsa_header);
 | |
|   return rt;
 | |
| }
 | |
| 
 | |
| void
 | |
| addifa_rtlsa(struct ospf_iface *ifa)
 | |
| {
 | |
|   struct ospf_area *oa;
 | |
|   struct proto_ospf *po=ifa->proto;
 | |
|   u32 rtid;
 | |
|   struct top_graph_rtlsa_link *li, *lih;
 | |
| 
 | |
|   rtid=po->proto.cf->global->router_id;
 | |
|   DBG("%s: New OSPF area \"%d\" adding.\n", po->proto.name, ifa->an);
 | |
|   oa=NULL;
 | |
| 
 | |
| 
 | |
|   WALK_LIST(NODE oa,po->area_list)
 | |
|   {
 | |
|     if(oa->areaid==ifa->an) break;
 | |
|   }
 | |
| 
 | |
|   if(EMPTY_LIST(po->area_list) || (oa->areaid!=ifa->an))	/* New area */
 | |
|   {
 | |
|     struct ospf_lsa_header *lsa;
 | |
| 
 | |
|     oa=mb_allocz(po->proto.pool, sizeof(struct ospf_area));
 | |
|     add_tail(&po->area_list,NODE oa);
 | |
|     oa->areaid=ifa->an;
 | |
|     oa->gr=ospf_top_new(po);
 | |
|     s_init_list(&(oa->lsal));
 | |
|     oa->rt=NULL;
 | |
|     oa->po=po;
 | |
|     oa->disp_timer=tm_new(po->proto.pool);
 | |
|     oa->disp_timer->data=oa;
 | |
|     oa->disp_timer->randomize=0;
 | |
|     oa->disp_timer->hook=area_disp;
 | |
|     oa->disp_timer->recurrent=DISPTICK;
 | |
|     oa->lage=now;
 | |
|     tm_start(oa->disp_timer,DISPTICK);
 | |
|     oa->calcrt=1;
 | |
|     oa->origrt=0;
 | |
|     fib_init(&oa->infib,po->proto.pool,sizeof(struct infib),16,init_infib);
 | |
|     	/* FIXME 16?? (Oh, sweet 16.... :-) */
 | |
|     po->areano++;
 | |
|     DBG("%s: New OSPF area \"%d\" added.\n", po->proto.name, ifa->an);
 | |
|     ifa->oa=oa;
 | |
|     schedule_rt_lsa(oa);
 | |
|   }
 | |
|   else ifa->oa=oa;
 | |
| }
 | |
| 
 | |
| void
 | |
| originate_rt_lsa(struct ospf_area *oa)
 | |
| {
 | |
|   struct ospf_lsa_header lsa;
 | |
|   struct proto_ospf *po=oa->po;
 | |
|   u32 rtid=po->proto.cf->global->router_id;
 | |
|   struct top_hash_entry *en;
 | |
|   void *body;
 | |
| 
 | |
|   debug("%s: Originating RT_lsa for area \"%I\".\n",po->proto.name,oa->areaid);
 | |
| 
 | |
|   lsa.age=0;
 | |
|   lsa.id=rtid;
 | |
|   lsa.type=LSA_T_RT;
 | |
|   lsa.rt=rtid;
 | |
|   lsa.options=0;
 | |
|   if(oa->rt==NULL)
 | |
|   {
 | |
|     lsa.sn=LSA_INITSEQNO;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     lsa.sn=oa->rt->lsa.sn+1;
 | |
|   }
 | |
|   body=originate_rt_lsa_body(oa, &lsa.length, po);
 | |
|   lsasum_calculate(&lsa,body,po);
 | |
|   en=lsa_install_new(&lsa, body, oa, &po->proto);
 | |
|   oa->rt=en;
 | |
|   flood_lsa(NULL,NULL,&oa->rt->lsa,po,NULL,oa,1);
 | |
| }
 | |
| 
 | |
| void *
 | |
| originate_net_lsa_body(struct ospf_iface *ifa, u16 *length,
 | |
|   struct proto_ospf *po)
 | |
| {
 | |
|   u16 i=1;
 | |
|   struct ospf_neighbor *n;
 | |
|   u32 *body;
 | |
|   struct ospf_lsa_net *net;
 | |
| 
 | |
|   net=mb_alloc(po->proto.pool,sizeof(u32)*(ifa->fadj+1)+
 | |
|     sizeof(struct ospf_lsa_net));
 | |
|   net->netmask=ipa_mkmask(ifa->iface->addr->pxlen);
 | |
| 
 | |
|   body=(u32 *)(net+1);
 | |
|   i=1;
 | |
|   *body=po->proto.cf->global->router_id;
 | |
|   WALK_LIST(n,ifa->neigh_list)
 | |
|   {
 | |
|     if(n->state==NEIGHBOR_FULL)
 | |
|     {
 | |
|       *(body+i)=n->rid;
 | |
|       i++;
 | |
|     }
 | |
|   }
 | |
|   *length=i*sizeof(u32)+sizeof(struct ospf_lsa_header)+
 | |
|     sizeof(struct ospf_lsa_net);
 | |
|   return net;
 | |
| }
 | |
| 
 | |
| void
 | |
| originate_net_lsa(struct ospf_iface *ifa, struct proto_ospf *po)
 | |
| {
 | |
|   struct ospf_lsa_header lsa;
 | |
|   u32 rtid=po->proto.cf->global->router_id;
 | |
|   struct top_hash_entry *en;
 | |
|   void *body;
 | |
| 
 | |
|   debug("%s: Originating Net lsa for iface \"%s\".\n", po->proto.name,
 | |
|     ifa->iface->name);
 | |
| 
 | |
|   if((ifa->state!=OSPF_IS_DR)||(ifa->fadj==0))
 | |
|   {
 | |
|     if(ifa->nlsa==NULL) return;
 | |
| 
 | |
|     ifa->nlsa->lsa.sn+=1;
 | |
|     ifa->nlsa->lsa.age=LSA_MAXAGE;
 | |
|     flood_lsa(NULL,NULL,&ifa->nlsa->lsa,po,NULL,ifa->oa,0);
 | |
|     s_rem_node(SNODE ifa->nlsa);
 | |
|     ospf_hash_delete(ifa->oa->gr, ifa->nlsa);
 | |
|     schedule_rtcalc(ifa->oa);
 | |
|     ifa->nlsa=NULL;
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   lsa.age=0;
 | |
|   lsa.id=ipa_to_u32(ifa->iface->addr->ip);
 | |
|   lsa.type=LSA_T_NET;
 | |
|   lsa.rt=rtid;
 | |
|   lsa.options=0;
 | |
|   if(ifa->nlsa==NULL)
 | |
|   {
 | |
|     lsa.sn=LSA_INITSEQNO;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     lsa.sn=ifa->nlsa->lsa.sn+1;
 | |
|   }
 | |
| 
 | |
|   body=originate_net_lsa_body(ifa, &lsa.length, po);
 | |
|   lsasum_calculate(&lsa,body,po);
 | |
|   ifa->nlsa=lsa_install_new(&lsa, body, ifa->oa, &po->proto);
 | |
|   flood_lsa(NULL,NULL,&ifa->nlsa->lsa,po,NULL,ifa->oa,1);
 | |
| }
 | |
| 
 | |
| static void *
 | |
| originate_ext_lsa_body(net *n, rte *e, struct proto_ospf *po, struct ea_list *attrs)
 | |
| {
 | |
|   struct proto *p=&po->proto;
 | |
|   struct ospf_lsa_ext *ext;
 | |
|   struct ospf_lsa_ext_tos *et;
 | |
|   neighbor *nn;
 | |
|   u32 m1 = ea_get_int(attrs, EA_OSPF_METRIC1, 0);
 | |
|   u32 m2 = ea_get_int(attrs, EA_OSPF_METRIC2, 0);
 | |
|   u32 tag = ea_get_int(attrs, EA_OSPF_TAG, 0);
 | |
|   int inas=0;
 | |
| 
 | |
|   ext=mb_alloc(p->pool,sizeof(struct ospf_lsa_ext)+
 | |
|     sizeof(struct ospf_lsa_ext_tos));
 | |
|   ext->netmask=ipa_mkmask(n->n.pxlen);
 | |
| 
 | |
|   et=(struct ospf_lsa_ext_tos *)(ext+1);
 | |
| 
 | |
|   if(!m2)
 | |
|     {
 | |
|       et->etos=0;
 | |
|       et->metric=m1;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       et->etos=0x80;
 | |
|       et->metric=m2;
 | |
|     }
 | |
|   et->padding=0;
 | |
|   et->tag=tag;
 | |
|   if(ipa_compare(e->attrs->gw,ipa_from_u32(0))!=0)
 | |
|   {
 | |
|      if(find_iface((struct proto_ospf *)p, e->attrs->iface)!=NULL) inas=1;
 | |
|   }
 | |
|     
 | |
|   if(!inas) et->fwaddr= ipa_from_u32(0);
 | |
|   else et->fwaddr=e->attrs->gw;
 | |
|   return ext;
 | |
| }
 | |
| 
 | |
| void
 | |
| originate_ext_lsa(net *n, rte *e, struct proto_ospf *po, struct ea_list *attrs)
 | |
| {
 | |
|   struct ospf_lsa_header lsa;
 | |
|   u32 rtid=po->proto.cf->global->router_id;
 | |
|   struct top_hash_entry *en=NULL;
 | |
|   void *body=NULL;
 | |
|   struct ospf_area *oa;
 | |
| 
 | |
|   debug("%s: Originating Ext lsa for %I/%d.\n", po->proto.name, n->n.prefix,
 | |
|     n->n.pxlen);
 | |
| 
 | |
|   lsa.age=0;
 | |
|   lsa.id=ipa_to_u32(n->n.prefix);
 | |
|   lsa.type=LSA_T_EXT;
 | |
|   lsa.rt=rtid;
 | |
|   lsa.sn=LSA_INITSEQNO;
 | |
|   body=originate_ext_lsa_body(n, e, po, attrs);
 | |
|   lsa.length=sizeof(struct ospf_lsa_ext)+sizeof(struct ospf_lsa_ext_tos)+
 | |
|     sizeof(struct ospf_lsa_header);
 | |
|   lsasum_calculate(&lsa,body,po);
 | |
|   WALK_LIST(oa, po->area_list)
 | |
|   {
 | |
|     en=lsa_install_new(&lsa, body, oa, &po->proto);
 | |
|     flood_lsa(NULL,NULL,&en->lsa,po,NULL,oa,1);
 | |
|     body=originate_ext_lsa_body(n, e, po, attrs);
 | |
|   }
 | |
|   mb_free(body);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| ospf_top_ht_alloc(struct top_graph *f)
 | |
| {
 | |
|   f->hash_size = 1 << f->hash_order;
 | |
|   f->hash_mask = f->hash_size - 1;
 | |
|   if (f->hash_order > HASH_HI_MAX - HASH_HI_STEP)
 | |
|     f->hash_entries_max = ~0;
 | |
|   else
 | |
|     f->hash_entries_max = f->hash_size HASH_HI_MARK;
 | |
|   if (f->hash_order < HASH_LO_MIN + HASH_LO_STEP)
 | |
|     f->hash_entries_min = 0;
 | |
|   else
 | |
|     f->hash_entries_min = f->hash_size HASH_LO_MARK;
 | |
|   DBG("Allocating OSPF hash of order %d: %d hash_entries, %d low, %d high\n",
 | |
|       f->hash_order, f->hash_size, f->hash_entries_min, f->hash_entries_max);
 | |
|   f->hash_table = mb_alloc(f->pool, f->hash_size * sizeof(struct top_hash_entry *));
 | |
|   bzero(f->hash_table, f->hash_size * sizeof(struct top_hash_entry *));
 | |
| }
 | |
| 
 | |
| static inline void
 | |
| ospf_top_ht_free(struct top_hash_entry **h)
 | |
| {
 | |
|   mb_free(h);
 | |
| }
 | |
| 
 | |
| static inline u32
 | |
| ospf_top_hash_u32(u32 a)
 | |
| {
 | |
|   /* Shamelessly stolen from IP address hashing in ipv4.h */
 | |
|   a ^= a >> 16;
 | |
|   a ^= a << 10;
 | |
|   return a;
 | |
| }
 | |
| 
 | |
| static inline unsigned
 | |
| ospf_top_hash(struct top_graph *f, u32 lsaid, u32 rtrid, u32 type)
 | |
| {
 | |
| #if 1	/* Dirty patch to make rt table calculation work. */
 | |
|   return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32((type==2) ? lsaid : rtrid) + type) & f->hash_mask;
 | |
| #else
 | |
|   return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32(rtrid) + type) & f->hash_mask;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| struct top_graph *
 | |
| ospf_top_new(struct proto_ospf *p)
 | |
| {
 | |
|   struct top_graph *f;
 | |
| 
 | |
|   f = mb_allocz(p->proto.pool, sizeof(struct top_graph));
 | |
|   f->pool = p->proto.pool;
 | |
|   f->hash_slab = sl_new(f->pool, sizeof(struct top_hash_entry));
 | |
|   f->hash_order = HASH_DEF_ORDER;
 | |
|   ospf_top_ht_alloc(f);
 | |
|   f->hash_entries = 0;
 | |
|   f->hash_entries_min = 0;
 | |
|   return f;
 | |
| }
 | |
| 
 | |
| void
 | |
| ospf_top_free(struct top_graph *f)
 | |
| {
 | |
|   rfree(f->hash_slab);
 | |
|   ospf_top_ht_free(f->hash_table);
 | |
|   mb_free(f);
 | |
| }
 | |
| 
 | |
| static void
 | |
| ospf_top_rehash(struct top_graph *f, int step)
 | |
| {
 | |
|   unsigned int oldn, oldh;
 | |
|   struct top_hash_entry **n, **oldt, **newt, *e, *x;
 | |
| 
 | |
|   oldn = f->hash_size;
 | |
|   oldt = f->hash_table;
 | |
|   DBG("Re-hashing topology hash from order %d to %d\n", f->hash_order, f->hash_order+step);
 | |
|   f->hash_order += step;
 | |
|   ospf_top_ht_alloc(f);
 | |
|   newt = f->hash_table;
 | |
| 
 | |
|   for(oldh=0; oldh < oldn; oldh++)
 | |
|     {
 | |
|       e = oldt[oldh];
 | |
|       while (e)
 | |
| 	{
 | |
| 	  x = e->next;
 | |
| 	  n = newt + ospf_top_hash(f, e->lsa.id, e->lsa.rt, e->lsa.type);
 | |
| 	  e->next = *n;
 | |
| 	  *n = e;
 | |
| 	  e = x;
 | |
| 	}
 | |
|     }
 | |
|   ospf_top_ht_free(oldt);
 | |
| }
 | |
| 
 | |
| struct top_hash_entry *
 | |
| ospf_hash_find_header(struct top_graph *f, struct ospf_lsa_header *h)
 | |
| {
 | |
|   return ospf_hash_find(f,h->id,h->rt,h->type);
 | |
| }
 | |
| 
 | |
| struct top_hash_entry *
 | |
| ospf_hash_get_header(struct top_graph *f, struct ospf_lsa_header *h)
 | |
| {
 | |
|   return ospf_hash_get(f,h->id,h->rt,h->type);
 | |
| }
 | |
| 
 | |
| struct top_hash_entry *
 | |
| ospf_hash_find(struct top_graph *f, u32 lsa, u32 rtr, u32 type)
 | |
| {
 | |
|   struct top_hash_entry *e = f->hash_table[ospf_top_hash(f, lsa, rtr, type)];
 | |
| 
 | |
| #if 1
 | |
|   if(type==2 && lsa==rtr)
 | |
|   {
 | |
|     while (e && (e->lsa.id != lsa || e->lsa.type != 2 ))
 | |
|       e = e->next;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     while (e && (e->lsa.id != lsa || e->lsa.type != type || e->lsa.rt != rtr))
 | |
|       e = e->next;
 | |
|   }
 | |
| #else
 | |
|   while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type))
 | |
|     e = e->next;
 | |
| #endif
 | |
|   return e;
 | |
| }
 | |
| 
 | |
| struct top_hash_entry *
 | |
| ospf_hash_get(struct top_graph *f, u32 lsa, u32 rtr, u32 type)
 | |
| {
 | |
|   struct top_hash_entry **ee = f->hash_table + ospf_top_hash(f, lsa, rtr, type);
 | |
|   struct top_hash_entry *e = *ee;
 | |
| 
 | |
|   while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type))
 | |
|     e = e->next;
 | |
|   if (e)
 | |
|     return e;
 | |
|   e = sl_alloc(f->hash_slab);
 | |
|   e->lsa.id = lsa;
 | |
|   e->lsa.rt = rtr;
 | |
|   e->lsa.type = type;
 | |
|   e->lsa_body = NULL;
 | |
|   e->nhi=NULL;
 | |
|   e->next=*ee;		/* MJ you forgot this :-) */
 | |
|   *ee=e;
 | |
|   if (f->hash_entries++ > f->hash_entries_max)
 | |
|     ospf_top_rehash(f, HASH_HI_STEP);
 | |
|   return e;
 | |
| }
 | |
| 
 | |
| void
 | |
| ospf_hash_delete(struct top_graph *f, struct top_hash_entry *e)
 | |
| {
 | |
|   unsigned int h = ospf_top_hash(f, e->lsa.id, e->lsa.rt, e->lsa.type);
 | |
|   struct top_hash_entry **ee = f->hash_table + h;
 | |
| 
 | |
|   while (*ee)
 | |
|     {
 | |
|       if (*ee == e)
 | |
| 	{
 | |
| 	  *ee = e->next;
 | |
| 	  sl_free(f->hash_slab, e);
 | |
| 	  if (f->hash_entries-- < f->hash_entries_min)
 | |
| 	    ospf_top_rehash(f, -HASH_LO_STEP);
 | |
| 	  return;
 | |
| 	}
 | |
|       ee = &((*ee)->next);
 | |
|     }
 | |
|   bug("ospf_hash_delete() called for invalid node");
 | |
| }
 | |
| 
 | |
| void
 | |
| ospf_top_dump(struct top_graph *f)
 | |
| {
 | |
|   unsigned int i;
 | |
|   debug("Hash entries: %d\n", f->hash_entries);
 | |
| 
 | |
|   for(i=0; i<f->hash_size; i++)
 | |
|     {
 | |
|       struct top_hash_entry *e = f->hash_table[i];
 | |
|       while (e)
 | |
| 	{
 | |
| 	  debug("\t%1x %8I %8I %4u 0x%08x\n", e->lsa.type, e->lsa.id,
 | |
|             e->lsa.rt, e->lsa.age, e->lsa.sn);
 | |
| 	  e = e->next;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* This is very uneficient, please don't call it often */
 | |
| 
 | |
| /* I should also test for every LSA if it's in some link state
 | |
|  * retransmision list for every neighbor. I will not test it.
 | |
|  * It can happen that I'll receive some strange ls ack's.
 | |
|  */
 | |
| 
 | |
| int
 | |
| can_flush_lsa(struct ospf_area *oa)
 | |
| {
 | |
|   struct ospf_iface *ifa;
 | |
|   struct ospf_neighbor *n;
 | |
|   struct proto_ospf *po=oa->po;
 | |
| 
 | |
|   WALK_LIST(ifa, iface_list)
 | |
|   {
 | |
|     if(ifa->oa==oa)
 | |
|     {
 | |
|       WALK_LIST(n, ifa->neigh_list)
 | |
|       {
 | |
|         if((n->state==NEIGHBOR_EXCHANGE)||(n->state==NEIGHBOR_LOADING))
 | |
| 	{
 | |
| 	  return 0;
 | |
| 	}
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return 1;
 | |
| }
 |