bird/proto/ospf/iface.c

535 lines
13 KiB
C
Raw Normal View History

/*
* BIRD -- OSPF
*
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "ospf.h"
2000-04-19 01:54:06 +08:00
char *ospf_is[]={ "down", "loop", "waiting", "point-to-point", "drother",
"backup", "dr" };
2000-04-19 03:22:49 +08:00
char *ospf_ism[]={ "interface up", "wait timer fired", "backup seen",
"neighbor change", "loop indicated", "unloop indicated", "interface down"};
char *ospf_it[]={ "broadcast", "nbma", "point-to-point", "virtual link" };
void
poll_timer_hook(timer *timer)
{
ospf_hello_send(timer, 1, NULL);
}
void
hello_timer_hook(timer *timer)
{
ospf_hello_send(timer, 0, NULL);
}
void
wait_timer_hook(timer *timer)
{
struct ospf_iface *ifa;
struct proto *p;
ifa=(struct ospf_iface *)timer->data;
p=(struct proto *)(ifa->proto);
OSPF_TRACE(D_EVENTS, "Wait timer fired on interface %s.",
ifa->iface->name);
ospf_int_sm(ifa, ISM_WAITF);
}
2000-06-08 06:10:46 +08:00
/**
* iface_chstate - handle changes of interface state
* @ifa: OSPF interface
* @state: new state
*
* Many actions must be taken according to interface state changes. New network
* LSAs must be originated, flushed, new multicast sockets to listen for messages for
* %ALLDROUTERS have to be opened, etc.
2000-06-08 06:10:46 +08:00
*/
void
iface_chstate(struct ospf_iface *ifa, u8 state)
{
2000-06-05 13:06:22 +08:00
struct proto_ospf *po=ifa->proto;
struct proto *p=&po->proto;
u8 oldstate;
if(ifa->state!=state)
{
2000-06-06 10:34:57 +08:00
OSPF_TRACE(D_EVENTS, "Changing state of iface: %s from \"%s\" into \"%s\".",
ifa->iface->name, ospf_is[ifa->state], ospf_is[state]);
2000-06-05 13:06:22 +08:00
oldstate=ifa->state;
ifa->state=state;
if(ifa->iface->flags & IF_MULTICAST)
{
if((state==OSPF_IS_BACKUP)||(state==OSPF_IS_DR))
{
2000-06-06 07:44:26 +08:00
if((ifa->dr_sk==NULL)&&(ifa->type!=OSPF_IT_NBMA))
{
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->sport=0;
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
{
2004-06-01 21:44:53 +08:00
rfree(ifa->dr_sk);
ifa->dr_sk=NULL;
}
if((oldstate==OSPF_IS_DR)&&(ifa->nlsa!=NULL))
2000-06-05 13:06:22 +08:00
{
ifa->nlsa->lsa.age=LSA_MAXAGE;
if(state>=OSPF_IS_WAITING)
{
net_flush_lsa(ifa->nlsa,po,ifa->oa);
}
2000-06-05 13:06:22 +08:00
if(can_flush_lsa(ifa->oa)) flush_lsa(ifa->nlsa,ifa->oa);
ifa->nlsa=NULL;
}
}
}
}
void
downint(struct ospf_iface *ifa)
{
struct ospf_neighbor *n,*nx;
2000-05-17 07:59:38 +08:00
struct proto *p=&ifa->proto->proto;
struct proto_ospf *po=ifa->proto;
WALK_LIST_DELSAFE(n,nx,ifa->neigh_list)
2000-05-17 07:59:38 +08:00
{
2000-06-07 19:55:36 +08:00
OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip);
2000-05-17 07:59:38 +08:00
ospf_neigh_remove(n);
}
rem_node(NODE ifa);
2004-06-01 21:29:08 +08:00
2004-06-01 21:44:53 +08:00
rfree(ifa->hello_sk);
rfree(ifa->dr_sk);
rfree(ifa->ip_sk);
2004-06-01 21:29:08 +08:00
2004-06-01 21:44:53 +08:00
rfree(ifa->wait_timer);
rfree(ifa->hello_timer);
rfree(ifa->poll_timer);
2004-06-01 21:29:08 +08:00
2000-06-06 08:46:00 +08:00
rfree(ifa->lock);
2000-05-17 07:59:38 +08:00
mb_free(ifa);
}
2000-06-08 06:10:46 +08:00
/**
* ospf_int_sm - OSPF interface state machine
* @ifa: OSPF interface
* @event: event comming to state machine
*
* This fully respect 9.3 of RFC 2328 except we don't use %LOOP state of
* interface.
*/
void
ospf_int_sm(struct ospf_iface *ifa, int event)
{
struct proto *p=(struct proto *)(ifa->proto);
struct proto_ospf *po=ifa->proto;
2000-06-01 02:55:57 +08:00
struct ospf_area *oa=ifa->oa;
2000-06-06 10:34:57 +08:00
OSPF_TRACE(D_EVENTS, "SM on iface %s. Event is \"%s\".",
ifa->iface->name, ospf_ism[event]);
switch(event)
{
case ISM_UP:
if(ifa->state==OSPF_IS_DOWN)
{
/* Now, nothing should be adjacent */
tm_start(ifa->hello_timer,ifa->helloint);
if(ifa->poll_timer)
tm_start(ifa->poll_timer,ifa->pollint);
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);
tm_start(ifa->wait_timer,ifa->waitint);
}
}
}
schedule_rt_lsa(ifa->oa);
break;
case ISM_BACKS:
case ISM_WAITF:
if(ifa->state==OSPF_IS_WAITING)
{
bdr_election(ifa);
}
break;
case ISM_NEICH:
if((ifa->state==OSPF_IS_DROTHER) || (ifa->state==OSPF_IS_DR) ||
(ifa->state==OSPF_IS_BACKUP))
{
bdr_election(ifa);
schedule_rt_lsa(ifa->oa);
}
break;
case ISM_DOWN:
iface_chstate(ifa, OSPF_IS_DOWN);
downint(ifa);
2000-06-01 02:55:57 +08:00
schedule_rt_lsa(oa);
break;
case ISM_LOOP: /* Useless? */
iface_chstate(ifa, OSPF_IS_LOOP);
downint(ifa);
schedule_rt_lsa(ifa->oa);
break;
case ISM_UNLOOP:
iface_chstate(ifa, OSPF_IS_DOWN);
schedule_rt_lsa(ifa->oa);
break;
default:
2000-06-06 09:00:34 +08:00
bug("%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);
2000-05-17 07:59:38 +08:00
mcsk=sk_new(p->pool);
mcsk->type=SK_IP_MC;
mcsk->sport=0;
2000-05-17 07:59:38 +08:00
mcsk->dport=OSPF_PROTO;
mcsk->saddr=AllSPFRouters;
2000-05-17 07:59:38 +08:00
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)
{
2000-05-17 07:59:38 +08:00
DBG("%s: SK_OPEN: mc open failed.\n",p->name);
return(NULL);
}
2000-05-17 07:59:38 +08:00
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);
}
u8
2000-02-24 07:13:10 +08:00
ospf_iface_clasify(struct iface *ifa, struct proto *p)
{
2000-02-24 07:23:19 +08:00
DBG("%s: Iface flags=%x.\n", p->name, ifa->flags);
if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
(IF_MULTIACCESS|IF_MULTICAST))
{
2000-02-24 07:13:10 +08:00
DBG("%s: Clasifying BCAST.\n", p->name);
return OSPF_IT_BCAST;
}
if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
IF_MULTIACCESS)
{
2000-02-24 07:13:10 +08:00
DBG("%s: Clasifying NBMA.\n", p->name);
return OSPF_IT_NBMA;
}
2000-02-24 07:13:10 +08:00
DBG("%s: Clasifying P-T-P.\n", p->name);
return OSPF_IT_PTP;
}
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)
{
2000-06-06 08:46:00 +08:00
struct proto_ospf *po=(struct proto_ospf *)p;
struct ospf_config *c=(struct ospf_config *)(p->cf);
struct ospf_area_config *ac;
struct ospf_iface_patt *ip=NULL;
2000-06-06 08:46:00 +08:00
struct ospf_iface *ifa;
struct object_lock *lock;
struct nbma_node *nbma,*nb;
u8 i;
sock *mcsk;
2000-02-24 07:13:10 +08:00
DBG("%s: If notify called\n", p->name);
if (iface->flags & IF_IGNORE)
return;
if(flags & IF_CHANGE_UP)
{
WALK_LIST(ac, c->area_list)
{
if(ip=(struct ospf_iface_patt *)
iface_patt_match(&ac->patt_list, iface)) break;
}
if(ip)
{
2000-06-06 10:34:57 +08:00
OSPF_TRACE(D_EVENTS, "Using interface %s.", iface->name);
ifa=mb_allocz(p->pool, sizeof(struct ospf_iface));
ifa->proto=po;
ifa->iface=iface;
ifa->an=ac->areaid;
ifa->cost=ip->cost;
ifa->rxmtint=ip->rxmtint;
ifa->inftransdelay=ip->inftransdelay;
ifa->priority=ip->priority;
ifa->helloint=ip->helloint;
ifa->pollint=ip->pollint;
ifa->strictnbma=ip->strictnbma;
ifa->waitint=ip->waitint;
ifa->deadc=ip->deadc;
ifa->stub=ip->stub;
ifa->autype=ip->autype;
memcpy(ifa->aukey,ip->password,8);
ifa->options=2; /* FIXME what options? */
if(ip->type==OSPF_IT_UNDEF)
ifa->type=ospf_iface_clasify(ifa->iface, (struct proto *)ifa->proto);
else ifa->type=ip->type;
init_list(&ifa->neigh_list);
init_list(&ifa->nbma_list);
WALK_LIST(nb,ip->nbma_list)
{
nbma=mb_alloc(p->pool,sizeof(struct nbma_node));
nbma->ip=nb->ip;
nbma->eligible=nb->eligible;
add_tail(&ifa->nbma_list, NODE nbma);
}
/* Add hello timer */
ifa->hello_timer=tm_new(p->pool);
ifa->hello_timer->data=ifa;
ifa->hello_timer->randomize=0;
ifa->hello_timer->hook=hello_timer_hook;
ifa->hello_timer->recurrent=ifa->helloint;
DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
if(ifa->type==OSPF_IT_NBMA)
{
ifa->poll_timer=tm_new(p->pool);
ifa->poll_timer->data=ifa;
ifa->poll_timer->randomize=0;
ifa->poll_timer->hook=poll_timer_hook;
ifa->poll_timer->recurrent=ifa->pollint;
DBG("%s: Installing poll timer. (%u)\n", p->name, ifa->pollint);
}
else ifa->poll_timer=NULL;
ifa->wait_timer=tm_new(p->pool);
ifa->wait_timer->data=ifa;
ifa->wait_timer->randomize=0;
ifa->wait_timer->hook=wait_timer_hook;
ifa->wait_timer->recurrent=0;
DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint);
add_tail(&((struct proto_ospf *)p)->iface_list, NODE ifa);
ifa->state=OSPF_IS_DOWN;
2000-06-06 08:46:00 +08:00
lock = olock_new( p->pool );
lock->addr = AllSPFRouters;
2000-06-06 19:50:48 +08:00
lock->type = OBJLOCK_IP;
2000-06-06 08:46:00 +08:00
lock->port = OSPF_PROTO;
lock->iface = iface;
lock->data = ifa;
2000-06-06 08:46:00 +08:00
lock->hook = ospf_ifa_add;
addifa_rtlsa(ifa);
2000-06-06 08:46:00 +08:00
olock_acquire(lock);
}
}
if(flags & IF_CHANGE_DOWN)
{
if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
{
2000-06-06 10:34:57 +08:00
OSPF_TRACE(D_EVENTS, "Killing interface %s.", iface->name);
ospf_int_sm(ifa, ISM_DOWN);
}
}
if(flags & IF_CHANGE_MTU)
{
if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
{
2004-06-05 02:51:29 +08:00
struct ospf_packet *op;
struct ospf_neighbor *n;
2000-06-06 10:34:57 +08:00
OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s.", iface->name);
2004-06-05 02:51:29 +08:00
sk_reallocate(ifa->hello_sk);
sk_reallocate(ifa->dr_sk);
sk_reallocate(ifa->ip_sk);
WALK_LIST(n,ifa->neigh_list)
{
op = (struct ospf_packet *)n->ldbdes;
n->ldbdes = mb_allocz(n->pool, iface->mtu);
if(ntohs(op->length) <= iface->mtu) /* If the packet in old buffer is bigger, let it filled by zeros */
memcpy(n->ldbdes, op, iface->mtu); /* If the packet is old is same or smaller, copy it */
rfree(op);
}
}
}
}
void
ospf_iface_info(struct ospf_iface *ifa)
{
int x;
char *strict="(strict)";
if((ifa->type!=OSPF_IT_NBMA)||(ifa->strictnbma==0)) strict="";
cli_msg(-1015,"Interface \"%s\":", ifa->iface->name);
cli_msg(-1015,"\tArea: %I (%u)", ifa->oa->areaid, ifa->oa->areaid);
cli_msg(-1015,"\tType: %s %s", ospf_it[ifa->type], strict);
cli_msg(-1015,"\tState: %s %s", ospf_is[ifa->state],
ifa->stub ? "(stub)" : "");
cli_msg(-1015,"\tPriority: %u", ifa->priority);
cli_msg(-1015,"\tCost: %u", ifa->cost);
cli_msg(-1015,"\tHello timer: %u", ifa->helloint);
if(ifa->type==OSPF_IT_NBMA)
{
cli_msg(-1015,"\tPoll timer: %u", ifa->pollint);
}
cli_msg(-1015,"\tWait timer: %u", ifa->waitint);
cli_msg(-1015,"\tDead timer: %u", ifa->deadc*ifa->helloint);
cli_msg(-1015,"\tRetransmit timer: %u", ifa->rxmtint);
if((ifa->type==OSPF_IT_BCAST)||(ifa->type==OSPF_IT_NBMA))
{
cli_msg(-1015,"\tDesigned router (ID): %I", ifa->drid);
cli_msg(-1015,"\tDesigned router (IP): %I", ifa->drip);
cli_msg(-1015,"\tBackup designed router (ID): %I", ifa->bdrid);
cli_msg(-1015,"\tBackup designed router (IP): %I", ifa->bdrip);
}
}
2000-06-06 08:46:00 +08:00
void
ospf_ifa_add(struct object_lock *lock)
{
struct ospf_iface *ifa=lock->data;
struct proto_ospf *po=ifa->proto;
2000-06-06 08:46:00 +08:00
struct iface *iface=lock->iface;
struct proto *p=&po->proto;
ifa->ioprob=OSPF_I_OK;
2000-06-06 08:46:00 +08:00
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);
log("%s: Declaring as stub.", p->name);
ifa->stub=1;
ifa->ioprob += OSPF_I_MC;
2000-06-06 08:46:00 +08:00
}
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);
log("%s: Declaring as stub.", p->name);
ifa->stub=1;
ifa->ioprob += OSPF_I_IP;
2000-06-06 08:46:00 +08:00
}
ifa->lock = lock;
ifa->state=OSPF_IS_DOWN;
ospf_int_sm(ifa, ISM_UP);
}
2000-06-08 06:10:46 +08:00
void
schedule_net_lsa(struct ospf_iface *ifa)
{
ifa->orignet=1;
}
void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
init_list(&ifa->neigh_list);
hello_timer_hook(ifa->hello_timer);
}