Many bugfixes (I don't remember all of them):

Added link ID calculation for external routes with same prefix but
	different mask.
Bugfix in NET lsa origination.
Bugfix in NET hashing.
Bugfix in LSA installing.
This commit is contained in:
Ondrej Filip 2000-06-05 02:23:20 +00:00
parent 2d37d36c67
commit 273fd2c164
6 changed files with 148 additions and 55 deletions

View file

@ -11,6 +11,8 @@
void void
flush_lsa(struct top_hash_entry *en, struct ospf_area *oa) flush_lsa(struct top_hash_entry *en, struct ospf_area *oa)
{ {
debug("Going to remove node: Type: %u, Id: %I, Rt: %I, Age: %u\n",
en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age);
s_rem_node(SNODE en); s_rem_node(SNODE en);
ospf_hash_delete(oa->gr,en); ospf_hash_delete(oa->gr,en);
} }
@ -368,7 +370,6 @@ lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
if((l1->age==LSA_MAXAGE)&&(l2->age!=LSA_MAXAGE)) return CMP_NEWER; if((l1->age==LSA_MAXAGE)&&(l2->age!=LSA_MAXAGE)) return CMP_NEWER;
if((l2->age==LSA_MAXAGE)&&(l1->age!=LSA_MAXAGE)) return CMP_OLDER; if((l2->age==LSA_MAXAGE)&&(l1->age!=LSA_MAXAGE)) return CMP_OLDER;
debug("Abs=%u\n",abs(l1->age-l2->age));
if(abs(l1->age-l2->age)>LSA_MAXAGEDIFF) if(abs(l1->age-l2->age)>LSA_MAXAGEDIFF)
return l1->age<l2->age ? CMP_NEWER : CMP_OLDER; return l1->age<l2->age ? CMP_NEWER : CMP_OLDER;
@ -384,8 +385,6 @@ lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa,
unsigned i; unsigned i;
struct top_hash_entry *en; struct top_hash_entry *en;
if(body==NULL) die("AA");
if((en=ospf_hash_find_header(oa->gr,lsa))==NULL) if((en=ospf_hash_find_header(oa->gr,lsa))==NULL)
{ {
en=ospf_hash_get_header(oa->gr,lsa); en=ospf_hash_get_header(oa->gr,lsa);
@ -407,9 +406,12 @@ lsa_install_new(struct ospf_lsa_header *lsa, void *body, struct ospf_area *oa,
} }
} }
} }
if(change) s_rem_node(SNODE en); s_rem_node(SNODE en);
} }
DBG("Inst lsa: Id: %I, Rt: %I, Type: %u, Age: %u, Sum: %u, Sn: 0x%x\n",
lsa->id, lsa->rt, lsa->type, lsa->age, lsa->checksum, lsa->sn);
s_add_tail(&oa->lsal, SNODE en); s_add_tail(&oa->lsal, SNODE en);
en->inst_t=now; en->inst_t=now;
if(en->lsa_body!=NULL) mb_free(en->lsa_body); if(en->lsa_body!=NULL) mb_free(en->lsa_body);

View file

@ -308,12 +308,12 @@ ospf_lsupd_rx(struct ospf_lsupd_packet *ps, struct proto *p,
continue; continue;
} }
ntohlsah(lsa,&lsatmp); ntohlsah(lsa,&lsatmp);
debug("Update Type: %u ID: %I RT: %I, Sn: 0x%08x Age: %u, Sum: %u\n", DBG("Update Type: %u ID: %I RT: %I, Sn: 0x%08x Age: %u, Sum: %u\n",
lsatmp.type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age, lsatmp.type, lsatmp.id, lsatmp.rt, lsatmp.sn, lsatmp.age,
lsatmp.checksum); lsatmp.checksum);
lsadb=ospf_hash_find_header(oa->gr, &lsatmp); lsadb=ospf_hash_find_header(oa->gr, &lsatmp);
if(lsadb) if(lsadb)
debug("I have Type: %u ID: %I RT: %I, Sn: 0x%08x Age: %u, Sum: %u\n", DBG("I have Type: %u ID: %I RT: %I, Sn: 0x%08x Age: %u, Sum: %u\n",
lsadb->lsa.type, lsadb->lsa.id, lsadb->lsa.rt, lsadb->lsa.sn, lsadb->lsa.type, lsadb->lsa.id, lsadb->lsa.rt, lsadb->lsa.sn,
lsadb->lsa.age, lsadb->lsa.checksum); lsadb->lsa.age, lsadb->lsa.checksum);

View file

@ -247,12 +247,25 @@ ospf_rt_notify(struct proto *p, net *n, rte *new, rte *old, ea_list *attrs)
u32 rtid=po->proto.cf->global->router_id; u32 rtid=po->proto.cf->global->router_id;
struct ospf_area *oa; struct ospf_area *oa;
struct top_hash_entry *en; struct top_hash_entry *en;
u32 pr=ipa_to_u32(n->n.prefix);
struct ospf_lsa_ext *ext;
int i;
/* Flush old external LSA */ /* Flush old external LSA */
WALK_LIST(oa, po->area_list) WALK_LIST(oa, po->area_list)
{ {
if(en=ospf_hash_find(oa->gr, ipa_to_u32(n->n.prefix), rtid, LSA_T_EXT)) for(i=0;i<MAXNETS;i++,pr++)
net_flush_lsa(en,po,oa); {
if(en=ospf_hash_find(oa->gr, pr, rtid, LSA_T_EXT))
{
ext=en->lsa_body;
if(ipa_compare(ext->netmask, ipa_mkmask(n->n.pxlen))==0)
{
net_flush_lsa(en,po,oa);
break;
}
}
}
} }
} }
} }

View file

@ -11,6 +11,7 @@
#define SIPH 64 /* FIXME Size Of IP header */ #define SIPH 64 /* FIXME Size Of IP header */
#define MAXNETS 10
#include "nest/bird.h" #include "nest/bird.h"

View file

@ -8,8 +8,6 @@
#include "ospf.h" #include "ospf.h"
#define LOCAL_DEBUG
void void
init_infib(struct fib_node *fn) init_infib(struct fib_node *fn)
{ {
@ -57,12 +55,16 @@ ospf_rt_spfa(struct ospf_area *oa)
en->color=OUTSPF; en->color=OUTSPF;
en->dist=LSINFINITY; en->dist=LSINFINITY;
en->nhi=NULL; en->nhi=NULL;
en->nh=ipa_from_u32(0);
DBG("Infinitying Type: %u, Id: %I, Rt: %I\n", en->lsa.type, en->lsa.id,
en->lsa.rt);
} }
FIB_WALK(in,nftmp) FIB_WALK(in,nftmp)
{ {
nf=(struct infib *)nftmp; nf=(struct infib *)nftmp;
nf->metric=LSINFINITY; nf->metric=LSINFINITY;
nf->en=NULL;
} }
FIB_WALK_END; FIB_WALK_END;
@ -109,16 +111,22 @@ ospf_rt_spfa(struct ospf_area *oa)
nf=fib_get(in,&ip, ipa_mklen(ipa_from_u32(rtl->data))); nf=fib_get(in,&ip, ipa_mklen(ipa_from_u32(rtl->data)));
if(nf->metric>(met=act->dist+rtl->metric)) if(nf->metric>(met=act->dist+rtl->metric))
{ {
DBG(" Adding stub route....\n");
if(oa->rt==act) break;
if(act->nhi==NULL) break;
nf->metric=met; nf->metric=met;
nf->en=act; nf->en=act;
DBG(" Adding stub route: %I\n",ip);
DBG(" Next hop=%I\n",nf->en->nh);
} }
else DBG(" NOT adding stub route: %I\n",ip);
break; break;
case LSART_VLNK: case LSART_VLNK:
DBG("Ignoring\n"); DBG("Ignoring\n");
continue; continue;
break; break;
case LSART_NET: case LSART_NET:
tmp=ospf_hash_find(oa->gr,rtl->id,rtl->id,LSA_T_NET); tmp=ospf_hash_find(oa->gr,rtl->data,rtl->id,LSA_T_NET);
if(tmp==NULL) DBG("Fuck!\n"); if(tmp==NULL) DBG("Fuck!\n");
else DBG("Found. :-)\n"); else DBG("Found. :-)\n");
break; break;
@ -130,10 +138,12 @@ ospf_rt_spfa(struct ospf_area *oa)
log("Unknown link type in router lsa."); log("Unknown link type in router lsa.");
break; break;
} }
if(tmp) DBG("Going to add cand, Mydist: %u, Req: %u\n",
tmp->dist, act->dist+rtl->metric);
add_cand(&oa->cand,tmp,act,act->dist+rtl->metric,oa); add_cand(&oa->cand,tmp,act,act->dist+rtl->metric,oa);
} }
break; break;
case LSA_T_NET: /* FIXME Add to fib */ case LSA_T_NET:
ln=act->lsa_body; ln=act->lsa_body;
ip=ipa_and(ipa_from_u32(act->lsa.id),ln->netmask); ip=ipa_and(ipa_from_u32(act->lsa.id),ln->netmask);
nf=fib_get(in,&ip, ipa_mklen(ln->netmask)); nf=fib_get(in,&ip, ipa_mklen(ln->netmask));
@ -141,13 +151,13 @@ ospf_rt_spfa(struct ospf_area *oa)
{ {
nf->metric=act->dist; nf->metric=act->dist;
nf->en=act; nf->en=act;
DBG(" Adding into routing table\n");
} }
rts=(u32 *)(ln+1); rts=(u32 *)(ln+1);
for(i=0;i<(act->lsa.length-sizeof(struct ospf_lsa_header)- for(i=0;i<(act->lsa.length-sizeof(struct ospf_lsa_header)-
sizeof(struct ospf_lsa_net))/sizeof(u32);i++) sizeof(struct ospf_lsa_net))/sizeof(u32);i++)
{ {
DBG(" Working on router %I ",*(rts+i)); DBG(" Working on router %I ", *(rts+i));
tmp=ospf_hash_find(oa->gr, *(rts+i), *(rts+i), LSA_T_RT); tmp=ospf_hash_find(oa->gr, *(rts+i), *(rts+i), LSA_T_RT);
if(tmp!=NULL) DBG("Found :-)\n"); if(tmp!=NULL) DBG("Found :-)\n");
else DBG("Fuck!\n"); else DBG("Fuck!\n");
@ -170,8 +180,9 @@ again:
ln=en->lsa_body; ln=en->lsa_body;
ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen); ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
DBG("Deleting rt entry %I\n (IP: %I, GW: %I, Iface: %s)\n", if((en!=NULL)&&(en->nhi!=NULL))
nf->fn.prefix,ip,en->nh,en->nhi->name); DBG("Deleting rt entry %I\n (P: %x, GW: %I, Iface: %s)\n",
nf->fn.prefix, en, en->nh,en->nhi->name);
rte_update(p->table, ne, p, NULL); rte_update(p->table, ne, p, NULL);
/* Now delete my fib */ /* Now delete my fib */
@ -211,12 +222,12 @@ again:
a0.source=RTS_OSPF; a0.source=RTS_OSPF;
a0.scope=SCOPE_UNIVERSE; /* What's this good for? */ a0.scope=SCOPE_UNIVERSE; /* What's this good for? */
a0.cast=RTC_UNICAST; a0.cast=RTC_UNICAST;
a0.dest=RTD_ROUTER; if(ipa_to_u32(en->nh)==0) a0.dest=RTD_DEVICE;
else a0.dest=RTD_ROUTER;
a0.flags=0; a0.flags=0;
a0.aflags=0; a0.aflags=0;
a0.iface=en->nhi; a0.iface=en->nhi;
a0.gw=en->nh; a0.gw=en->nh;
a0.from=en->nh; /* FIXME Just a test */
ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen); ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
e=rte_get_temp(&a0); e=rte_get_temp(&a0);
e->u.ospf.metric1=nf->metric; e->u.ospf.metric1=nf->metric;
@ -225,8 +236,8 @@ again:
e->pflags = 0; e->pflags = 0;
e->net=ne; e->net=ne;
e->pref = p->preference; e->pref = p->preference;
DBG("Modifying rt entry %I\n (IP: %I, GW: %I, Iface: %s)\n", DBG("Modifying rt entry %I\n (GW: %I, Iface: %s)\n",
nf->fn.prefix,ip,en->nh,en->nhi->name); nf->fn.prefix,en->nh,en->nhi->name);
rte_update(p->table, ne, p, e); rte_update(p->table, ne, p, e);
} }
} }
@ -282,6 +293,9 @@ ospf_ext_spfa(struct proto_ospf *po) /* FIXME looking into inter-area */
le=en->lsa_body; le=en->lsa_body;
lt=(struct ospf_lsa_ext_tos *)(le+1); lt=(struct ospf_lsa_ext_tos *)(le+1);
DBG("%s: Working on LSA. ID: %I, RT: %I, Type: %u, Mask %I\n",
p->name,en->lsa.id,en->lsa.rt,en->lsa.type,le->netmask);
if(lt->metric==LSINFINITY) continue; if(lt->metric==LSINFINITY) continue;
ip=ipa_and(ipa_from_u32(en->lsa.id),le->netmask); ip=ipa_and(ipa_from_u32(en->lsa.id),le->netmask);
mlen=ipa_mklen(le->netmask); mlen=ipa_mklen(le->netmask);
@ -296,11 +310,10 @@ ospf_ext_spfa(struct proto_ospf *po) /* FIXME looking into inter-area */
WALK_LIST(atmp,po->area_list) WALK_LIST(atmp,po->area_list)
{ {
if((nf=fib_find(&atmp->infib,&ip, mlen))!=NULL) break; if((nf=fib_find(&atmp->infib,&ip, mlen))!=NULL) continue;
/* Some intra area path exists */
} }
if(nf!=NULL) continue; /* Some intra area path exists */
absr=NULL; absr=NULL;
absroa=NULL; absroa=NULL;
nnhi=NULL; nnhi=NULL;
@ -320,7 +333,11 @@ ospf_ext_spfa(struct proto_ospf *po) /* FIXME looking into inter-area */
} }
} }
} }
if((absr==NULL)||(absr->dist==LSINFINITY)) continue; if((absr==NULL)||(absr->dist==LSINFINITY))
{
DBG("ABSR is null or its dist=INF\n");
continue;
}
if(ipa_compare(lt->fwaddr,ipa_from_u32(0))==0) if(ipa_compare(lt->fwaddr,ipa_from_u32(0))==0)
{ {
@ -346,7 +363,13 @@ ospf_ext_spfa(struct proto_ospf *po) /* FIXME looking into inter-area */
break; break;
} }
} }
if(nf==NULL) continue;
if(nf==NULL)
{
DBG("Cannot find network route (GW=%I\n",lt->fwaddr);
continue;
}
if(lt->etos>0) if(lt->etos>0)
{ {
met=nf->metric; met=nf->metric;
@ -385,6 +408,7 @@ ospf_ext_spfa(struct proto_ospf *po) /* FIXME looking into inter-area */
if((neigh=find_neigh_noifa(po,absr->lsa.rt))==NULL) if((neigh=find_neigh_noifa(po,absr->lsa.rt))==NULL)
{ {
DBG("Cannot find neighbor\n");
continue; continue;
} }
nn=neigh_find(p,&neigh->ip,0); nn=neigh_find(p,&neigh->ip,0);
@ -438,7 +462,6 @@ noch:
a0.aflags=0; a0.aflags=0;
a0.iface=nf->nhi; a0.iface=nf->nhi;
a0.gw=nf->nh; a0.gw=nf->nh;
a0.from=nf->nh; /* FIXME Just a test */
ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen); ne=net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
e=rte_get_temp(&a0); e=rte_get_temp(&a0);
e->u.ospf.metric1=nf->metric; e->u.ospf.metric1=nf->metric;
@ -526,22 +549,65 @@ calc_next_hop(struct top_hash_entry *par, struct top_hash_entry *en,
struct ospf_neighbor *neigh; struct ospf_neighbor *neigh;
struct proto *p=&oa->po->proto; struct proto *p=&oa->po->proto;
struct proto_ospf *po=oa->po; struct proto_ospf *po=oa->po;
struct ospf_iface *ifa;
DBG(" Next hop called\n"); DBG(" Next hop called\n");
if(par==oa->rt) return; if(ipa_to_u32(par->nh)==0)
if(par->nhi==NULL)
{ {
neighbor *nn; neighbor *nn;
DBG(" Next hop calculating for id: %I rt: %I type: %u\n",en->lsa.id,en->lsa.rt,en->lsa.type); DBG(" Next hop calculating for id: %I rt: %I type: %u\n",en->lsa.id,en->lsa.rt,en->lsa.type);
if(par->lsa.type!=LSA_T_RT) return; if(par->lsa.type!=LSA_T_RT)
if((neigh=find_neigh_noifa(po,par->lsa.rt))==NULL) return; {
nn=neigh_find(p,&neigh->ip,0); if((neigh=find_neigh_noifa(po,par->lsa.rt))==NULL) return;
DBG(" Next hop calculated: %I\n", nn->addr); nn=neigh_find(p,&neigh->ip,0);
en->nh=nn->addr; DBG(" Next hop calculated: %I.\n", nn->addr);
en->nhi=nn->iface; en->nh=nn->addr;
return; en->nhi=nn->iface;
return;
}
else
{
if(par==oa->rt)
{
if(en->lsa.type==LSA_T_NET)
{
struct ospf_lsa_net *ne;
ne=en->lsa_body;
DBG("I'm parent (Net=%I)\n",(en->lsa.id & ipa_to_u32(ne->netmask)));
WALK_LIST(ifa, oa->po->iface_list)
{
if(ipa_to_u32(ipa_and(ifa->iface->addr->ip,
ipa_mkmask(ifa->iface->addr->pxlen))) ==
(en->lsa.id & ipa_to_u32(ne->netmask)))
{
en->nhi=ifa->iface;
en->nh=ipa_from_u32(0);
DBG("Ifa: %s\n",en->nhi->name);
return;
}
}
}
else
{
if((neigh=find_neigh_noifa(po,par->lsa.rt))==NULL) return;
nn=neigh_find(p,&neigh->ip,0);
en->nh=ipa_from_u32(0);
en->nhi=nn->iface;
}
return;
}
if((neigh=find_neigh_noifa(po,par->lsa.rt))==NULL) return;
nn=neigh_find(p,&neigh->ip,0);
DBG(" Next hop calculated: %I\n", nn->addr);
en->nh=nn->addr;
en->nhi=nn->iface;
return;
}
} }
en->nh=par->nh; en->nh=par->nh;
en->nhi=par->nhi; en->nhi=par->nhi;
DBG(" Next hop calculated: %I\n", en->nh); DBG(" Next hop calculated: %I..\n", en->nh);
} }

View file

@ -120,8 +120,8 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length, struct proto_ospf *p)
if(((ifa->state==OSPF_IS_DR) && (j==1)) || (k==1)) if(((ifa->state==OSPF_IS_DR) && (j==1)) || (k==1))
{ {
ln->type=LSART_NET; ln->type=LSART_NET;
ln->id=ipa_to_u32(ifa->drip); ln->id=ifa->drid;
ln->data=ipa_to_u32(ifa->iface->addr->ip); ln->data=ipa_to_u32(ifa->drip);
ln->metric=ifa->cost; ln->metric=ifa->cost;
ln->notos=0; ln->notos=0;
} }
@ -227,6 +227,7 @@ originate_rt_lsa(struct ospf_area *oa)
en=lsa_install_new(&lsa, body, oa, &po->proto); en=lsa_install_new(&lsa, body, oa, &po->proto);
oa->rt=en; oa->rt=en;
flood_lsa(NULL,NULL,&oa->rt->lsa,po,NULL,oa,1); flood_lsa(NULL,NULL,&oa->rt->lsa,po,NULL,oa,1);
schedule_rtcalc(oa);
} }
void * void *
@ -300,6 +301,8 @@ originate_net_lsa(struct ospf_iface *ifa, struct proto_ospf *po)
body=originate_net_lsa_body(ifa, &lsa.length, po); body=originate_net_lsa_body(ifa, &lsa.length, po);
lsasum_calculate(&lsa,body,po); lsasum_calculate(&lsa,body,po);
ifa->nlsa=lsa_install_new(&lsa, body, ifa->oa, &po->proto); ifa->nlsa=lsa_install_new(&lsa, body, ifa->oa, &po->proto);
debug("NetLsa: Id: %I, Sum: %u Sn: 0x%x\n",ifa->nlsa->lsa.id,
ifa->nlsa->lsa.checksum, ifa->nlsa->lsa.sn);
flood_lsa(NULL,NULL,&ifa->nlsa->lsa,po,NULL,ifa->oa,1); flood_lsa(NULL,NULL,&ifa->nlsa->lsa,po,NULL,ifa->oa,1);
} }
@ -350,7 +353,10 @@ originate_ext_lsa(net *n, rte *e, struct proto_ospf *po, struct ea_list *attrs)
u32 rtid=po->proto.cf->global->router_id; u32 rtid=po->proto.cf->global->router_id;
struct top_hash_entry *en=NULL; struct top_hash_entry *en=NULL;
void *body=NULL; void *body=NULL;
struct proto *p=&po->proto;
struct ospf_area *oa; struct ospf_area *oa;
struct ospf_lsa_ext *ext1,*ext2;
int i;
debug("%s: Originating Ext lsa for %I/%d.\n", po->proto.name, n->n.prefix, debug("%s: Originating Ext lsa for %I/%d.\n", po->proto.name, n->n.prefix,
n->n.pxlen); n->n.pxlen);
@ -363,6 +369,28 @@ originate_ext_lsa(net *n, rte *e, struct proto_ospf *po, struct ea_list *attrs)
body=originate_ext_lsa_body(n, e, po, attrs); body=originate_ext_lsa_body(n, e, po, attrs);
lsa.length=sizeof(struct ospf_lsa_ext)+sizeof(struct ospf_lsa_ext_tos)+ lsa.length=sizeof(struct ospf_lsa_ext)+sizeof(struct ospf_lsa_ext_tos)+
sizeof(struct ospf_lsa_header); sizeof(struct ospf_lsa_header);
ext1=body;
oa=HEAD(po->area_list);
for(i=0;i<MAXNETS;i++)
{
if((en=ospf_hash_find_header(oa->gr, &lsa))!=NULL)
{
ext2=en->lsa_body;
if(ipa_compare(ext1->netmask,ext2->netmask)!=0) lsa.id++;
else break;
}
else break;
}
if(i==MAXNETS)
{
log("%s: got more routes for one network then %d, ignoring",p->name,
MAXNETS);
mb_free(body);
return;
}
lsasum_calculate(&lsa,body,po); lsasum_calculate(&lsa,body,po);
WALK_LIST(oa, po->area_list) WALK_LIST(oa, po->area_list)
{ {
@ -411,11 +439,7 @@ ospf_top_hash_u32(u32 a)
static inline unsigned static inline unsigned
ospf_top_hash(struct top_graph *f, u32 lsaid, u32 rtrid, u32 type) 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; return (ospf_top_hash_u32(lsaid) + ospf_top_hash_u32(rtrid) + type) & f->hash_mask;
#endif
} }
struct top_graph * struct top_graph *
@ -486,21 +510,8 @@ 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)]; 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)) while (e && (e->lsa.id != lsa || e->lsa.rt != rtr || e->lsa.type != type))
e = e->next; e = e->next;
#endif
return e; return e;
} }