bird/proto/ospf/iface.c
2000-05-30 18:21:51 +00:00

401 lines
9.4 KiB
C

/*
* BIRD -- OSPF
*
* (c) 1999 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "ospf.h"
char *ospf_is[]={ "down", "loop", "waiting", "point-to-point", "drother",
"backup", "dr" };
char *ospf_ism[]={ "interface up", "wait timer fired", "backup seen",
"neighbor change", "loop indicated", "unloop indicated", "interface down"};
void
iface_chstate(struct ospf_iface *ifa, u8 state)
{
struct proto *p;
if(ifa->state!=state)
{
p=(struct proto *)(ifa->proto);
debug("%s: Changing state of iface: %s from \"%s\" into \"%s\".\n",
p->name, ifa->iface->name, ospf_is[ifa->state], ospf_is[state]);
ifa->state=state;
if(ifa->iface->flags & IF_MULTICAST)
{
if((state==OSPF_IS_BACKUP)||(state==OSPF_IS_DR))
{
if(ifa->dr_sk==NULL)
{
DBG("%s: Adding new multicast socket for (B)DR\n", p->name);
ifa->dr_sk=sk_new(p->pool);
ifa->dr_sk->type=SK_IP_MC;
ifa->dr_sk->dport=OSPF_PROTO;
ifa->dr_sk->saddr=AllDRouters;
ifa->dr_sk->daddr=AllDRouters;
ifa->dr_sk->tos=IP_PREC_INTERNET_CONTROL;
ifa->dr_sk->ttl=1;
ifa->dr_sk->rx_hook=ospf_rx_hook;
ifa->dr_sk->tx_hook=ospf_tx_hook;
ifa->dr_sk->err_hook=ospf_err_hook;
ifa->dr_sk->iface=ifa->iface;
ifa->dr_sk->rbsize=ifa->iface->mtu;
ifa->dr_sk->tbsize=ifa->iface->mtu;
ifa->dr_sk->data=(void *)ifa;
if(sk_open(ifa->dr_sk)!=0)
{
DBG("%s: SK_OPEN: new? mc open failed.\n", p->name);
}
}
}
else
{
if(ifa->dr_sk!=NULL) rfree(ifa->dr_sk);
}
}
}
}
void
downint(struct ospf_iface *ifa)
{
struct ospf_neighbor *n;
struct proto *p=&ifa->proto->proto;
struct proto_ospf *po=ifa->proto;
WALK_LIST(n,ifa->neigh_list)
{
debug("%s: Removing neighbor %I\n", p->name, n->ip);
ospf_neigh_remove(n);
}
rem_node(NODE ifa);
if(ifa->hello_sk!=NULL)
{
sk_close(ifa->hello_sk);
rfree(ifa->hello_sk);
}
if(ifa->dr_sk!=NULL)
{
sk_close(ifa->dr_sk);
rfree(ifa->dr_sk);
}
if(ifa->ip_sk!=NULL)
{
sk_close(ifa->ip_sk);
rfree(ifa->ip_sk);
}
if(ifa->wait_timer!=NULL)
{
tm_stop(ifa->wait_timer);
rfree(ifa->wait_timer);
}
mb_free(ifa);
}
void
ospf_int_sm(struct ospf_iface *ifa, int event)
{
struct proto *p=(struct proto *)(ifa->proto);
struct proto_ospf *po=ifa->proto;
debug("%s: SM on iface %s. Event is \"%s\".\n",
p->name, ifa->iface->name, ospf_ism[event]);
switch(event)
{
case ISM_UP:
if(ifa->state==OSPF_IS_DOWN)
{
/* Now, nothing should be adjacent */
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);
}
}
addifa_rtlsa(ifa);
}
originate_rt_lsa(ifa->oa,po);
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);
originate_rt_lsa(ifa->oa,po);
}
break;
case ISM_DOWN:
iface_chstate(ifa, OSPF_IS_DOWN);
downint(ifa);
originate_rt_lsa(ifa->oa,po);
break;
case ISM_LOOP: /* Useless? */
iface_chstate(ifa, OSPF_IS_LOOP);
downint(ifa);
originate_rt_lsa(ifa->oa,po);
break;
case ISM_UNLOOP:
iface_chstate(ifa, OSPF_IS_DOWN);
originate_rt_lsa(ifa->oa,po);
break;
default:
die("%s: ISM - Unknown event?",p->name);
break;
}
}
sock *
ospf_open_mc_socket(struct ospf_iface *ifa)
{
sock *mcsk;
struct proto *p;
p=(struct proto *)(ifa->proto);
mcsk=sk_new(p->pool);
mcsk->type=SK_IP_MC;
mcsk->dport=OSPF_PROTO;
mcsk->saddr=AllSPFRouters;
mcsk->daddr=AllSPFRouters;
mcsk->tos=IP_PREC_INTERNET_CONTROL;
mcsk->ttl=1;
mcsk->rx_hook=ospf_rx_hook;
mcsk->tx_hook=ospf_tx_hook;
mcsk->err_hook=ospf_err_hook;
mcsk->iface=ifa->iface;
mcsk->rbsize=ifa->iface->mtu;
mcsk->tbsize=ifa->iface->mtu;
mcsk->data=(void *)ifa;
if(sk_open(mcsk)!=0)
{
DBG("%s: SK_OPEN: mc open failed.\n",p->name);
return(NULL);
}
DBG("%s: SK_OPEN: mc opened.\n",p->name);
return(mcsk);
}
sock *
ospf_open_ip_socket(struct ospf_iface *ifa)
{
sock *ipsk;
struct proto *p;
p=(struct proto *)(ifa->proto);
ipsk=sk_new(p->pool);
ipsk->type=SK_IP;
ipsk->dport=OSPF_PROTO;
ipsk->saddr=ifa->iface->addr->ip;
ipsk->tos=IP_PREC_INTERNET_CONTROL;
ipsk->ttl=1;
ipsk->rx_hook=ospf_rx_hook;
ipsk->tx_hook=ospf_tx_hook;
ipsk->err_hook=ospf_err_hook;
ipsk->iface=ifa->iface;
ipsk->rbsize=ifa->iface->mtu;
ipsk->tbsize=ifa->iface->mtu;
ipsk->data=(void *)ifa;
if(sk_open(ipsk)!=0)
{
DBG("%s: SK_OPEN: ip open failed.\n",p->name);
return(NULL);
}
DBG("%s: SK_OPEN: ip opened.\n",p->name);
return(ipsk);
}
/*
* This will later decide, wheter use iface for OSPF or not
* depending on config
*/
u8
is_good_iface(struct proto *p, struct iface *iface)
{
if(iface->flags & IF_UP)
{
if(!(iface->flags & IF_IGNORE)) return 1;
}
return 0;
}
/* Of course, it's NOT true now */
u8
ospf_iface_clasify(struct iface *ifa, struct proto *p)
{
/* FIXME: Latter I'll use config - this is incorrect */
DBG("%s: Iface flags=%x.\n", p->name, ifa->flags);
if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
(IF_MULTIACCESS|IF_MULTICAST))
{
DBG("%s: Clasifying BCAST.\n", p->name);
return OSPF_IT_BCAST;
}
if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
IF_MULTIACCESS)
{
DBG("%s: Clasifying NBMA.\n", p->name);
return OSPF_IT_NBMA;
}
DBG("%s: Clasifying P-T-P.\n", p->name);
return OSPF_IT_PTP;
}
void
ospf_add_timers(struct ospf_iface *ifa, pool *pool)
{
struct proto *p;
p=(struct proto *)(ifa->proto);
/* Add hello timer */
ifa->hello_timer=tm_new(pool);
ifa->hello_timer->data=ifa;
ifa->hello_timer->randomize=0;
if(ifa->helloint==0) ifa->helloint=HELLOINT_D;
ifa->hello_timer->hook=hello_timer_hook;
ifa->hello_timer->recurrent=ifa->helloint;
DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
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);
if(ifa->rxmtint==0) ifa->rxmtint=RXMTINT_D;
}
void
ospf_iface_default(struct ospf_iface *ifa)
{
u8 i;
ifa->oa=NULL;
ifa->an=0; /* FIXME This should respect config */
ifa->cost=COST_D;
ifa->rxmtint=RXMTINT_D;
ifa->inftransdelay=INFTRANSDELAY_D;
ifa->priority=PRIORITY_D;
ifa->helloint=HELLOINT_D;
ifa->deadc=DEADC_D;
ifa->autype=0;
for(i=0;i<8;i++) ifa->aukey[i]=0;
ifa->options=2;
ifa->drip=ipa_from_u32(0x00000000);
ifa->drid=0;
ifa->bdrip=ipa_from_u32(0x00000000);
ifa->bdrid=0;
ifa->type=ospf_iface_clasify(ifa->iface, (struct proto *)ifa->proto);
}
struct ospf_iface*
find_iface(struct proto_ospf *p, struct iface *what)
{
struct ospf_iface *i;
WALK_LIST (i, p->iface_list)
if ((i)->iface == what)
return i;
return NULL;
}
void
ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
{
struct ospf_iface *ifa;
sock *mcsk;
struct ospf_config *c;
c=(struct ospf_config *)(p->cf);
DBG("%s: If notify called\n", p->name);
if (iface->flags & IF_IGNORE)
return;
if((flags & IF_CHANGE_UP) && is_good_iface(p, iface))
{
debug("%s: using interface %s.\n", p->name, iface->name);
/* FIXME: Latter I'll use config - this is incorrect */
ifa=mb_allocz(p->pool, sizeof(struct ospf_iface));
ifa->proto=(struct proto_ospf *)p;
ifa->iface=iface;
ospf_iface_default(ifa);
if(ifa->type!=OSPF_IT_NBMA)
{
if((ifa->hello_sk=ospf_open_mc_socket(ifa))==NULL)
{
log("%s: Huh? could not open mc socket on interface %s?", p->name,
iface->name);
mb_free(ifa);
log("%s: Ignoring this interface\n", p->name);
return;
}
ifa->dr_sk=NULL;
if((ifa->ip_sk=ospf_open_ip_socket(ifa))==NULL)
{
log("%s: Huh? could not open ip socket on interface %s?", p->name,
iface->name);
mb_free(ifa);
log("%s: Ignoring this interface\n", p->name);
return;
}
init_list(&(ifa->neigh_list));
}
/* FIXME: This should read config */
ifa->helloint=0;
ifa->waitint=0;
ospf_add_timers(ifa,p->pool);
add_tail(&((struct proto_ospf *)p)->iface_list, NODE ifa);
ifa->state=OSPF_IS_DOWN;
ifa->nlsa=NULL;
ifa->fadj=0;
ospf_int_sm(ifa, ISM_UP);
}
if(flags & IF_CHANGE_DOWN)
{
if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
{
debug(" OSPF: killing interface %s.\n", iface->name);
ospf_int_sm(ifa, ISM_DOWN);
}
}
if(flags & IF_CHANGE_MTU)
{
if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
{
debug(" OSPF: changing MTU on interface %s.\n", iface->name);
/* FIXME: change MTU */
}
}
}