Adds support for iface link detection to OSPF.

This commit is contained in:
Ondrej Zajicek 2010-11-13 14:19:23 +01:00
parent fe181e7c63
commit d9e7e1b13d
6 changed files with 203 additions and 171 deletions

View file

@ -192,13 +192,14 @@ ospf_iface_item:
| TYPE POINTOPOINT { OSPF_PATT->type = OSPF_IT_PTP ; } | TYPE POINTOPOINT { OSPF_PATT->type = OSPF_IT_PTP ; }
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; } | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
| STUB bool { OSPF_PATT->stub = $2 ; } | STUB bool { OSPF_PATT->stub = $2 ; }
| LINK bool { OSPF_PATT->use_link = $2 ; }
| NEIGHBORS '{' ipa_list '}' | NEIGHBORS '{' ipa_list '}'
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; } | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; } | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; } | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
| RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; } | RX BUFFER LARGE { OSPF_PATT->rxbuf = OSPF_RXBUF_LARGE ; }
| RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; } | RX BUFFER NORMAL { OSPF_PATT->rxbuf = OSPF_RXBUF_NORMAL ; }
| RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if ($3 < OSPF_RXBUF_MINSIZE) cf_error("Buffer size is too small") ; } | RX BUFFER expr { OSPF_PATT->rxbuf = $3 ; if (($3 < OSPF_RXBUF_MINSIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
| password_list | password_list
; ;
@ -275,6 +276,7 @@ ospf_iface_start:
OSPF_PATT->type = OSPF_IT_UNDEF; OSPF_PATT->type = OSPF_IT_UNDEF;
OSPF_PATT->strictnbma = 0; OSPF_PATT->strictnbma = 0;
OSPF_PATT->stub = 0; OSPF_PATT->stub = 0;
OSPF_PATT->use_link = 1;
init_list(&OSPF_PATT->nbma_list); init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->autype = OSPF_AUTH_NONE; OSPF_PATT->autype = OSPF_AUTH_NONE;
reset_passwords(); reset_passwords();

View file

@ -60,10 +60,7 @@ rxbufsize(struct ospf_iface *ifa)
static int static int
ospf_sk_open(struct ospf_iface *ifa) ospf_sk_open(struct ospf_iface *ifa)
{ {
sock *sk; sock *sk = sk_new(ifa->pool);
struct proto *p = &ifa->oa->po->proto;
sk = sk_new(p->pool);
sk->type = SK_IP; sk->type = SK_IP;
sk->dport = OSPF_PROTO; sk->dport = OSPF_PROTO;
sk->saddr = IPA_NONE; sk->saddr = IPA_NONE;
@ -162,72 +159,6 @@ ospf_sk_leave_dr(struct ospf_iface *ifa)
ifa->sk_dr = 0; ifa->sk_dr = 0;
} }
static inline void
ospf_sk_close(struct ospf_iface *ifa)
{
ASSERT(ifa->sk);
rfree(ifa->sk);
ifa->sk = NULL;
}
/**
* ospf_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.
*/
void
ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
{
struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
u8 oldstate = ifa->state;
if (oldstate != state)
{
ifa->state = state;
if (ifa->type == OSPF_IT_VLINK)
{
OSPF_TRACE(D_EVENTS,
"Changing state of virtual link %R from \"%s\" into \"%s\".",
ifa->vid, ospf_is[oldstate], ospf_is[state]);
}
else
{
OSPF_TRACE(D_EVENTS,
"Changing state of iface: %s from \"%s\" into \"%s\".",
ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
if (ifa->iface->flags & IF_MULTICAST)
{
if ((ifa->type != OSPF_IT_NBMA) && (ifa->ioprob == OSPF_I_OK) &&
((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)))
ospf_sk_join_dr(ifa);
else
ospf_sk_leave_dr(ifa);
if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
{
ifa->net_lsa->lsa.age = LSA_MAXAGE;
if (state >= OSPF_IS_WAITING)
{
ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
}
if (can_flush_lsa(po))
flush_lsa(ifa->net_lsa, po);
ifa->net_lsa = NULL;
}
}
// FIXME flushling of link LSA
}
}
}
static void static void
ospf_iface_down(struct ospf_iface *ifa) ospf_iface_down(struct ospf_iface *ifa)
{ {
@ -254,6 +185,15 @@ ospf_iface_down(struct ospf_iface *ifa)
ospf_neigh_remove(n); ospf_neigh_remove(n);
} }
if (ifa->hello_timer)
tm_stop(ifa->hello_timer);
if (ifa->poll_timer)
tm_stop(ifa->poll_timer);
if (ifa->wait_timer)
tm_stop(ifa->wait_timer);
if (ifa->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
{ {
ifa->vifa = NULL; ifa->vifa = NULL;
@ -262,18 +202,70 @@ ospf_iface_down(struct ospf_iface *ifa)
ifa->sk = NULL; ifa->sk = NULL;
ifa->cost = 0; ifa->cost = 0;
ifa->vip = IPA_NONE; ifa->vip = IPA_NONE;
return;
} }
else }
static void
ospf_iface_remove(struct ospf_iface *ifa)
{ {
ospf_sk_close(ifa); ospf_iface_sm(ifa, ISM_DOWN);
rfree(ifa->wait_timer);
rfree(ifa->hello_timer);
rfree(ifa->poll_timer);
rfree(ifa->lock);
rem_node(NODE ifa); rem_node(NODE ifa);
mb_free(ifa); rfree(ifa->pool);
} }
/**
* ospf_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.
*/
void
ospf_iface_chstate(struct ospf_iface *ifa, u8 state)
{
struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto;
u8 oldstate = ifa->state;
if (oldstate == state)
return;
ifa->state = state;
if (ifa->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Changing state of virtual link %R from %s to %s",
ifa->vid, ospf_is[oldstate], ospf_is[state]);
else
OSPF_TRACE(D_EVENTS, "Changing state of iface %s from %s to %s",
ifa->iface->name, ospf_is[oldstate], ospf_is[state]);
if (ifa->type == OSPF_IT_BCAST)
{
if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))
ospf_sk_join_dr(ifa);
else
ospf_sk_leave_dr(ifa);
}
if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL))
{
ifa->net_lsa->lsa.age = LSA_MAXAGE;
if (state >= OSPF_IS_WAITING)
ospf_lsupd_flush_nlsa(po, ifa->net_lsa);
if (can_flush_lsa(po))
flush_lsa(ifa->net_lsa, po);
ifa->net_lsa = NULL;
}
if ((oldstate > OSPF_IS_LOOP) && (state <= OSPF_IS_LOOP))
ospf_iface_down(ifa);
schedule_rt_lsa(ifa->oa);
// FIXME flushling of link LSA
} }
/** /**
@ -281,21 +273,22 @@ ospf_iface_down(struct ospf_iface *ifa)
* @ifa: OSPF interface * @ifa: OSPF interface
* @event: event comming to state machine * @event: event comming to state machine
* *
* This fully respects 9.3 of RFC 2328 except we don't use %LOOP state of * This fully respects 9.3 of RFC 2328 except we have slightly
* interface. * different handling of %DOWN and %LOOP state. We remove intefaces
* that are %DOWN. %DOWN state is used when an interface is waiting
* for a lock. %LOOP state is used when an interface does not have a
* link.
*/ */
void void
ospf_iface_sm(struct ospf_iface *ifa, int event) ospf_iface_sm(struct ospf_iface *ifa, int event)
{ {
struct ospf_area *oa = ifa->oa;
DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface", DBG("SM on %s %s. Event is '%s'\n", (ifa->type == OSPF_IT_VLINK) ? "vlink" : "iface",
ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]); ifa->iface ? ifa->iface->name : "(none)" , ospf_ism[event]);
switch (event) switch (event)
{ {
case ISM_UP: case ISM_UP:
if (ifa->state == OSPF_IS_DOWN) if (ifa->state <= OSPF_IS_LOOP)
{ {
/* Now, nothing should be adjacent */ /* Now, nothing should be adjacent */
if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_VLINK)) if ((ifa->type == OSPF_IT_PTP) || (ifa->type == OSPF_IT_VLINK))
@ -319,10 +312,10 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
tm_start(ifa->poll_timer, ifa->pollint); tm_start(ifa->poll_timer, ifa->pollint);
hello_timer_hook(ifa->hello_timer); hello_timer_hook(ifa->hello_timer);
}
schedule_link_lsa(ifa); schedule_link_lsa(ifa);
schedule_rt_lsa(ifa->oa); }
break; break;
case ISM_BACKS: case ISM_BACKS:
case ISM_WAITF: case ISM_WAITF:
if (ifa->state == OSPF_IS_WAITING) if (ifa->state == OSPF_IS_WAITING)
@ -330,6 +323,7 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
bdr_election(ifa); bdr_election(ifa);
} }
break; break;
case ISM_NEICH: case ISM_NEICH:
if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) || if ((ifa->state == OSPF_IS_DROTHER) || (ifa->state == OSPF_IS_DR) ||
(ifa->state == OSPF_IS_BACKUP)) (ifa->state == OSPF_IS_BACKUP))
@ -338,19 +332,22 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
schedule_rt_lsa(ifa->oa); schedule_rt_lsa(ifa->oa);
} }
break; break;
case ISM_DOWN:
ospf_iface_chstate(ifa, OSPF_IS_DOWN);
ospf_iface_down(ifa);
schedule_rt_lsa(oa);
break;
/*
case ISM_LOOP: case ISM_LOOP:
if (ifa->sk && ifa->use_link)
ospf_iface_chstate(ifa, OSPF_IS_LOOP); ospf_iface_chstate(ifa, OSPF_IS_LOOP);
break; break;
case ISM_UNLOOP: case ISM_UNLOOP:
/* Immediate go UP */
if (ifa->state == OSPF_IS_LOOP)
ospf_iface_sm(ifa, ISM_UP);
break;
case ISM_DOWN:
ospf_iface_chstate(ifa, OSPF_IS_DOWN); ospf_iface_chstate(ifa, OSPF_IS_DOWN);
break; break;
*/
default: default:
bug("OSPF_I_SM - Unknown event?"); bug("OSPF_I_SM - Unknown event?");
break; break;
@ -391,8 +388,6 @@ ospf_iface_add(struct object_lock *lock)
struct proto_ospf *po = ifa->oa->po; struct proto_ospf *po = ifa->oa->po;
struct proto *p = &po->proto; struct proto *p = &po->proto;
ifa->lock = lock;
if (ospf_sk_open(ifa)) if (ospf_sk_open(ifa))
{ {
if (ifa->type != OSPF_IT_NBMA) if (ifa->type != OSPF_IT_NBMA)
@ -405,8 +400,8 @@ ospf_iface_add(struct object_lock *lock)
ifa->stub = 1; ifa->stub = 1;
} }
ifa->state = OSPF_IS_DOWN; /* Do iface UP, unless there is no link and we use link detection */
ospf_iface_sm(ifa, ISM_UP); ospf_iface_sm(ifa, (ifa->use_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP);
} }
void void
@ -414,6 +409,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
struct ospf_area_config *ac, struct ospf_iface_patt *ip) struct ospf_area_config *ac, struct ospf_iface_patt *ip)
{ {
struct proto *p = &po->proto; struct proto *p = &po->proto;
struct pool *pool = rp_new(p->pool, "OSPF Interface");
struct ospf_iface *ifa; struct ospf_iface *ifa;
struct nbma_node *nbma, *nb; struct nbma_node *nbma, *nb;
struct object_lock *lock; struct object_lock *lock;
@ -422,9 +418,10 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
if (ip->type != OSPF_IT_VLINK) if (ip->type != OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Adding interface %s", iface->name); OSPF_TRACE(D_EVENTS, "Adding interface %s", iface->name);
ifa = mb_allocz(p->pool, sizeof(struct ospf_iface)); ifa = mb_allocz(pool, sizeof(struct ospf_iface));
ifa->iface = iface; ifa->iface = iface;
ifa->addr = addr; ifa->addr = addr;
ifa->pool = pool;
ifa->cost = ip->cost; ifa->cost = ip->cost;
ifa->rxmtint = ip->rxmtint; ifa->rxmtint = ip->rxmtint;
@ -438,6 +435,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
ifa->stub = ospf_iface_stubby(ip, addr); ifa->stub = ospf_iface_stubby(ip, addr);
ifa->ioprob = OSPF_I_OK; ifa->ioprob = OSPF_I_OK;
ifa->rxbuf = ip->rxbuf; ifa->rxbuf = ip->rxbuf;
ifa->use_link = ip->use_link;
#ifdef OSPFv2 #ifdef OSPFv2
ifa->autype = ip->autype; ifa->autype = ip->autype;
@ -475,40 +473,41 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen)) if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
continue; continue;
nbma = mb_alloc(p->pool, sizeof(struct nbma_node)); nbma = mb_alloc(pool, sizeof(struct nbma_node));
nbma->ip = nb->ip; nbma->ip = nb->ip;
nbma->eligible = nb->eligible; nbma->eligible = nb->eligible;
add_tail(&ifa->nbma_list, NODE nbma); add_tail(&ifa->nbma_list, NODE nbma);
} }
/* Add hello timer */ DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
ifa->hello_timer = tm_new(p->pool); ifa->hello_timer = tm_new(pool);
ifa->hello_timer->data = ifa; ifa->hello_timer->data = ifa;
ifa->hello_timer->randomize = 0; ifa->hello_timer->randomize = 0;
ifa->hello_timer->hook = hello_timer_hook; ifa->hello_timer->hook = hello_timer_hook;
ifa->hello_timer->recurrent = ifa->helloint; ifa->hello_timer->recurrent = ifa->helloint;
DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
if (ifa->type == OSPF_IT_NBMA) if (ifa->type == OSPF_IT_NBMA)
{ {
ifa->poll_timer = tm_new(p->pool); DBG("%s: Installing poll timer. (%u)\n", p->name, ifa->pollint);
ifa->poll_timer = tm_new(pool);
ifa->poll_timer->data = ifa; ifa->poll_timer->data = ifa;
ifa->poll_timer->randomize = 0; ifa->poll_timer->randomize = 0;
ifa->poll_timer->hook = poll_timer_hook; ifa->poll_timer->hook = poll_timer_hook;
ifa->poll_timer->recurrent = ifa->pollint; 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); if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
{
DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint);
ifa->wait_timer = tm_new(pool);
ifa->wait_timer->data = ifa; ifa->wait_timer->data = ifa;
ifa->wait_timer->randomize = 0; ifa->wait_timer->randomize = 0;
ifa->wait_timer->hook = wait_timer_hook; ifa->wait_timer->hook = wait_timer_hook;
ifa->wait_timer->recurrent = 0; 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; ifa->state = OSPF_IS_DOWN;
add_tail(&po->iface_list, NODE ifa);
ifa->oa = NULL; ifa->oa = NULL;
WALK_LIST(oa, po->area_list) WALK_LIST(oa, po->area_list)
@ -539,7 +538,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
* Therefore, we store such info to lock->addr field. * Therefore, we store such info to lock->addr field.
*/ */
lock = olock_new(p->pool); lock = olock_new(pool);
#ifdef OSPFv2 #ifdef OSPFv2
lock->addr = ifa->addr->prefix; lock->addr = ifa->addr->prefix;
#else /* OSPFv3 */ #else /* OSPFv3 */
@ -597,7 +596,7 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
{ {
if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a)) if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
ospf_iface_sm(ifa, ISM_DOWN); ospf_iface_remove(ifa);
/* See a note in ospf_iface_notify() */ /* See a note in ospf_iface_notify() */
} }
} }
@ -675,7 +674,7 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
{ {
if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a)) if ((ifa->type != OSPF_IT_VLINK) && (ifa->addr == a))
ospf_iface_sm(ifa, ISM_DOWN); ospf_iface_remove(ifa);
/* See a note in ospf_iface_notify() */ /* See a note in ospf_iface_notify() */
} }
} }
@ -725,36 +724,44 @@ ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
} }
} }
static void
ospf_iface_notify(struct proto_ospf *po, unsigned flags, struct ospf_iface *ifa)
{
if (flags & IF_CHANGE_DOWN)
{
ospf_iface_remove(ifa);
return;
}
if (flags & IF_CHANGE_LINK)
ospf_iface_sm(ifa, (ifa->iface->flags & IF_LINK_UP) ? ISM_UNLOOP : ISM_LOOP);
if (flags & IF_CHANGE_MTU)
ospf_iface_change_mtu(po, ifa);
}
void void
ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface) ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
{ {
struct proto_ospf *po = (struct proto_ospf *) p; struct proto_ospf *po = (struct proto_ospf *) p;
DBG("%s: If notify called\n", p->name);
if (iface->flags & IF_IGNORE) if (iface->flags & IF_IGNORE)
return; return;
if (flags & IF_CHANGE_DOWN) /* Going up means that there are no such ifaces yet */
{ if (flags & IF_CHANGE_UP)
return;
struct ospf_iface *ifa, *ifx; struct ospf_iface *ifa, *ifx;
WALK_LIST_DELSAFE(ifa, ifx, po->iface_list) WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface)) if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface))
ospf_iface_sm(ifa, ISM_DOWN); ospf_iface_notify(po, flags, ifa);
/* We use here that even shutting down iface also shuts down /* We use here that even shutting down iface also shuts down
the vlinks, but vlinks are not freed and stays in the the vlinks, but vlinks are not freed and stays in the
iface_list even when down */ iface_list even when down */
} }
if (flags & IF_CHANGE_MTU)
{
struct ospf_iface *ifa;
WALK_LIST(ifa, po->iface_list)
if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface))
ospf_iface_change_mtu(po, ifa);
}
}
void void
ospf_iface_info(struct ospf_iface *ifa) ospf_iface_info(struct ospf_iface *ifa)
{ {

View file

@ -13,7 +13,7 @@
void ospf_iface_chstate(struct ospf_iface *ifa, u8 state); void ospf_iface_chstate(struct ospf_iface *ifa, u8 state);
void ospf_iface_sm(struct ospf_iface *ifa, int event); void ospf_iface_sm(struct ospf_iface *ifa, int event);
struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what); struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
void ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface); void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a); void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
void ospf_iface_info(struct ospf_iface *ifa); void ospf_iface_info(struct ospf_iface *ifa);
void ospf_iface_shutdown(struct ospf_iface *ifa); void ospf_iface_shutdown(struct ospf_iface *ifa);

View file

@ -269,7 +269,7 @@ ospf_init(struct proto_config *c)
p->reload_routes = ospf_reload_routes; p->reload_routes = ospf_reload_routes;
p->accept_ra_types = RA_OPTIMAL; p->accept_ra_types = RA_OPTIMAL;
p->rt_notify = ospf_rt_notify; p->rt_notify = ospf_rt_notify;
p->if_notify = ospf_iface_notify; p->if_notify = ospf_if_notify;
p->ifa_notify = ospf_ifa_notify; p->ifa_notify = ospf_ifa_notify;
p->rte_better = ospf_rte_better; p->rte_better = ospf_rte_better;
p->rte_same = ospf_rte_same; p->rte_same = ospf_rte_same;
@ -728,7 +728,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
} }
/* POLL TIMER */ /* POLL TIMER */
if (oldip->pollint != newip->pollint) if ((oldip->pollint != newip->pollint) && ifa->poll_timer)
{ {
ifa->pollint = newip->helloint; ifa->pollint = newip->helloint;
ifa->poll_timer->recurrent = ifa->pollint; ifa->poll_timer->recurrent = ifa->pollint;
@ -758,6 +758,15 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
ospf_iface_change_mtu(po, ifa); ospf_iface_change_mtu(po, ifa);
} }
/* LINK */
if (oldip->use_link != newip->use_link)
{
ifa->use_link = newip->use_link;
if (!(ifa->iface->flags & IF_LINK_UP))
ospf_iface_sm(ifa, ifa->use_link ? ISM_LOOP : ISM_UNLOOP);
}
/* strict nbma */ /* strict nbma */
if ((oldip->strictnbma == 0) && (newip->strictnbma != 0)) if ((oldip->strictnbma == 0) && (newip->strictnbma != 0))
{ {
@ -819,7 +828,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
} }
/* WAIT */ /* WAIT */
if (oldip->waitint != newip->waitint) if ((oldip->waitint != newip->waitint) && ifa->wait_timer)
{ {
ifa->waitint = newip->waitint; ifa->waitint = newip->waitint;
if (ifa->wait_timer->expires != 0) if (ifa->wait_timer->expires != 0)
@ -890,7 +899,7 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
} }
if (!found) if (!found)
{ {
nb1 = mb_alloc(p->pool, sizeof(struct nbma_node)); nb1 = mb_alloc(ifa->pool, sizeof(struct nbma_node));
nb1->ip = nb2->ip; nb1->ip = nb2->ip;
nb1->eligible = nb2->eligible; nb1->eligible = nb2->eligible;
add_tail(&ifa->nbma_list, NODE nb1); add_tail(&ifa->nbma_list, NODE nb1);

View file

@ -162,7 +162,7 @@ struct ospf_iface
struct iface *iface; /* Nest's iface */ struct iface *iface; /* Nest's iface */
struct ifa *addr; /* IP prefix associated with that OSPF iface */ struct ifa *addr; /* IP prefix associated with that OSPF iface */
struct ospf_area *oa; struct ospf_area *oa;
struct object_lock *lock; pool *pool;
sock *sk; /* IP socket (for DD ...) */ sock *sk; /* IP socket (for DD ...) */
list neigh_list; /* List of neigbours */ list neigh_list; /* List of neigbours */
u32 cost; /* Cost of iface */ u32 cost; /* Cost of iface */
@ -187,8 +187,8 @@ struct ospf_iface
#endif #endif
ip_addr drip; /* Designated router */ ip_addr drip; /* Designated router */
u32 drid;
ip_addr bdrip; /* Backup DR */ ip_addr bdrip; /* Backup DR */
u32 drid;
u32 bdrid; u32 bdrid;
#ifdef OSPFv3 #ifdef OSPFv3
@ -207,7 +207,7 @@ struct ospf_iface
u8 stub; /* Inactive interface */ u8 stub; /* Inactive interface */
u8 state; /* Interface state machine */ u8 state; /* Interface state machine */
#define OSPF_IS_DOWN 0 /* Not working */ #define OSPF_IS_DOWN 0 /* Not working */
#define OSPF_IS_LOOP 1 /* Should never happen */ #define OSPF_IS_LOOP 1 /* Iface with no link */
#define OSPF_IS_WAITING 2 /* Waiting for Wait timer */ #define OSPF_IS_WAITING 2 /* Waiting for Wait timer */
#define OSPF_IS_PTP 3 /* PTP operational */ #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_DROTHER 4 /* I'm on BCAST or NBMA and I'm not DR */
@ -243,7 +243,8 @@ struct ospf_iface
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */ #define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
u8 sk_spf; /* Socket is a member of SPFRouters group */ u8 sk_spf; /* Socket is a member of SPFRouters group */
u8 sk_dr; /* Socket is a member of DRouters group */ u8 sk_dr; /* Socket is a member of DRouters group */
u32 rxbuf; u16 rxbuf; /* Buffer size */
u8 use_link; /* Whether iface link change is used */
}; };
struct ospf_md5 struct ospf_md5
@ -678,8 +679,8 @@ struct ospf_neighbor
#define ISM_WAITF 1 /* Wait timer fired */ #define ISM_WAITF 1 /* Wait timer fired */
#define ISM_BACKS 2 /* Backup seen */ #define ISM_BACKS 2 /* Backup seen */
#define ISM_NEICH 3 /* Neighbor change */ #define ISM_NEICH 3 /* Neighbor change */
// #define ISM_LOOP 4 /* Loop indicated */ #define ISM_LOOP 4 /* Link down */
// #define ISM_UNLOOP 5 /* Unloop indicated */ #define ISM_UNLOOP 5 /* Link up */
#define ISM_DOWN 6 /* Interface down */ #define ISM_DOWN 6 /* Interface down */
/* Definitions for neighbor state machine */ /* Definitions for neighbor state machine */
@ -751,7 +752,8 @@ struct ospf_iface_patt
u32 strictnbma; u32 strictnbma;
u32 stub; u32 stub;
u32 vid; u32 vid;
u32 rxbuf; u16 rxbuf;
u8 use_link;
#define OSPF_RXBUF_NORMAL 0 #define OSPF_RXBUF_NORMAL 0
#define OSPF_RXBUF_LARGE 1 #define OSPF_RXBUF_LARGE 1
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */

View file

@ -241,9 +241,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
continue; continue;
/* BIRD does not support interface loops */
ASSERT(ifa->state != OSPF_IS_LOOP);
switch (ifa->type) switch (ifa->type)
{ {
case OSPF_IT_PTP: /* RFC2328 - 12.4.1.1 */ case OSPF_IT_PTP: /* RFC2328 - 12.4.1.1 */
@ -303,11 +300,24 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
continue; continue;
ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link)); ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
if (ifa->state == OSPF_IS_LOOP)
{
/* Host stub entry */
ln->type = LSART_STUB;
ln->id = ipa_to_u32(ifa->addr->ip);
ln->data = 0xffffffff;
ln->metric = 0;
ln->padding = 0;
}
else
{
/* Network stub entry */
ln->type = LSART_STUB; ln->type = LSART_STUB;
ln->id = ipa_to_u32(ifa->addr->prefix); ln->id = ipa_to_u32(ifa->addr->prefix);
ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen)); ln->data = ipa_to_u32(ipa_mkmask(ifa->addr->pxlen));
ln->metric = ifa->cost; ln->metric = ifa->cost;
ln->padding = 0; ln->padding = 0;
}
i++; i++;
} }
@ -384,9 +394,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length)
if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
continue; continue;
/* BIRD does not support interface loops */
ASSERT(ifa->state != OSPF_IS_LOOP);
/* RFC5340 - 4.4.3.2 */ /* RFC5340 - 4.4.3.2 */
switch (ifa->type) switch (ifa->type)
{ {
@ -1144,6 +1151,13 @@ update_link_lsa(struct ospf_iface *ifa)
ifa->origlink = 0; ifa->origlink = 0;
} }
static inline void
lsa_put_prefix(struct proto_ospf *po, ip_addr prefix, u32 pxlen, u32 cost)
{
put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(pxlen)), prefix, pxlen,
(pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA, cost);
}
static void * static void *
originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length) originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
{ {
@ -1154,7 +1168,6 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
int host_addr = 0; int host_addr = 0;
int net_lsa; int net_lsa;
int i = 0; int i = 0;
u8 flags;
ASSERT(po->lsab_used == 0); ASSERT(po->lsab_used == 0);
lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix)); lp = lsab_allocz(po, sizeof(struct ospf_lsa_prefix));
@ -1189,12 +1202,14 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
configured_stubnet(oa, a)) configured_stubnet(oa, a))
continue; continue;
flags = (a->pxlen < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; if (ifa->state == OSPF_IS_LOOP)
put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(a->pxlen)), lsa_put_prefix(po, a->ip, MAX_PREFIX_LENGTH, 0);
a->ip, a->pxlen, flags, ifa->cost); else
lsa_put_prefix(po, a->prefix, a->pxlen, ifa->cost);
i++; i++;
if (flags & OPT_PX_LA) if ((ifa->state == OSPF_IS_LOOP) ||
(a->pxlen == MAX_PREFIX_LENGTH))
host_addr = 1; host_addr = 1;
} }
} }
@ -1203,8 +1218,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
which will be used as a vlink endpoint. */ which will be used as a vlink endpoint. */
if (oa->ac && !EMPTY_LIST(oa->ac->vlink_list) && !host_addr && vlink_addr) if (oa->ac && !EMPTY_LIST(oa->ac->vlink_list) && !host_addr && vlink_addr)
{ {
put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(MAX_PREFIX_LENGTH)), lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0);
vlink_addr->ip, MAX_PREFIX_LENGTH, OPT_PX_LA, 0);
i++; i++;
} }
@ -1213,9 +1227,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
WALK_LIST(sn, oa->ac->stubnet_list) WALK_LIST(sn, oa->ac->stubnet_list)
if (!sn->hidden) if (!sn->hidden)
{ {
flags = (sn->px.len < MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; lsa_put_prefix(po, sn->px.addr, sn->px.len, sn->cost);
put_ipv6_prefix(lsab_alloc(po, IPV6_PREFIX_SPACE(sn->px.len)),
sn->px.addr, sn->px.len, flags, sn->cost);
i++; i++;
} }