0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-17 08:38:42 +00:00

Vastly improved OSPF reconfiguration.

Now it can handle a change in iface pattern structure.
It can add, remove and reconfigure interfaces, vlinks and areas.
This commit is contained in:
Ondrej Zajicek 2011-03-17 15:53:36 +01:00
parent 93e868c730
commit 8e48831a97
12 changed files with 695 additions and 533 deletions

View File

@ -22,8 +22,13 @@ static struct ospf_stubnet_config *this_stubnet;
#ifdef OSPFv2
static void
finish_iface_config(struct ospf_iface_patt *ip)
ospf_iface_finish(void)
{
struct ospf_iface_patt *ip = OSPF_PATT;
if (ip->deadint == 0)
ip->deadint = ip->deadc * ip->helloint;
ip->passwords = get_passwords();
if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
@ -36,13 +41,57 @@ finish_iface_config(struct ospf_iface_patt *ip)
#ifdef OSPFv3
static void
finish_iface_config(struct ospf_iface_patt *ip)
ospf_iface_finish(void)
{
struct ospf_iface_patt *ip = OSPF_PATT;
if (ip->deadint == 0)
ip->deadint = ip->deadc * ip->helloint;
if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
cf_error("Authentication not supported in OSPFv3");
}
#endif
static void
ospf_area_finish(void)
{
if ((this_area->areaid == 0) && (this_area->stub != 0))
cf_error( "Backbone area cannot be stub");
}
static void
ospf_proto_finish(void)
{
struct ospf_config *cf = OSPF_CFG;
if (EMPTY_LIST(cf->area_list))
cf_error( "No configured areas in OSPF");
int areano = 0;
int backbone = 0;
struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list)
{
areano++;
if (ac->areaid == 0)
backbone = 1;
}
cf->abr = areano > 1;
if (cf->abr && !backbone)
{
struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
add_head(&cf->area_list, NODE ac);
init_list(&ac->patt_list);
init_list(&ac->net_list);
init_list(&ac->stubnet_list);
}
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
cf_error( "No configured areas in OSPF");
}
CF_DECLS
CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
@ -58,12 +107,13 @@ CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT)
CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}')
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
ospf_proto_start: proto_start OSPF {
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config));
this_proto->preference = DEF_PREF_OSPF;
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
OSPF_CFG->tick = DEFAULT_OSPFTICK;
}
@ -80,22 +130,21 @@ ospf_proto_item:
| ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
| ospf_area '}'
| ospf_area
;
ospf_area_start: AREA idval '{' {
ospf_area_start: AREA idval {
this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2;
this_area->stub = 0;
init_list(&this_area->patt_list);
init_list(&this_area->vlink_list);
init_list(&this_area->net_list);
init_list(&this_area->stubnet_list);
}
;
ospf_area: ospf_area_start ospf_area_opts
ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(); }
;
ospf_area_opts:
@ -138,7 +187,7 @@ ospf_stubnet_item:
;
ospf_vlink:
ospf_vlink_start '{' ospf_vlink_opts '}' { finish_iface_config(OSPF_PATT); }
ospf_vlink_start '{' ospf_vlink_opts '}' { ospf_iface_finish(); }
| ospf_vlink_start
;
@ -152,7 +201,7 @@ ospf_vlink_item:
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; }
| DEAD expr { OSPF_PATT->dead = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
@ -164,15 +213,16 @@ ospf_vlink_start: VIRTUAL LINK idval
{
if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone");
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
add_tail(&this_area->vlink_list, NODE this_ipatt);
add_tail(&OSPF_CFG->vlink_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
OSPF_PATT->voa = this_area->areaid;
OSPF_PATT->vid = $3;
OSPF_PATT->helloint = HELLOINT_D;
OSPF_PATT->rxmtint = RXMTINT_D;
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->dead = 0;
OSPF_PATT->deadint = 0;
OSPF_PATT->type = OSPF_IT_VLINK;
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->autype = OSPF_AUTH_NONE;
@ -185,10 +235,8 @@ ospf_iface_item:
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; }
| DEAD expr { OSPF_PATT->dead = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
| TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
| TYPE BCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
@ -198,6 +246,8 @@ ospf_iface_item:
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
| STUB bool { OSPF_PATT->stub = $2 ; }
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
@ -281,7 +331,7 @@ ospf_iface_start:
OSPF_PATT->priority = PRIORITY_D;
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->dead = 0;
OSPF_PATT->deadint = 0;
OSPF_PATT->type = OSPF_IT_UNDEF;
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->autype = OSPF_AUTH_NONE;
@ -300,7 +350,7 @@ ospf_iface_opt_list:
;
ospf_iface:
ospf_iface_start iface_patt_list ospf_iface_opt_list { finish_iface_config(OSPF_PATT); }
ospf_iface_start iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
;
opttext:

View File

@ -88,7 +88,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
#else /* OSPFv3 */
tmp = ntohs(ps->deadint);
#endif
if (tmp != ifa->dead)
if (tmp != ifa->deadint)
{
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
return;
@ -217,13 +217,13 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
if (ifa->type == OSPF_IT_NBMA)
{
if ((ifa->priority == 0) && (n->priority > 0))
ospf_hello_send(NULL, 0, n);
ospf_hello_send(NULL, OHS_HELLO, n);
}
ospf_neigh_sm(n, INM_HELLOREC);
}
void
ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
ospf_hello_send(timer *timer, int kind, struct ospf_neighbor *dirn)
{
struct ospf_iface *ifa;
struct ospf_hello_packet *pkt;
@ -231,7 +231,6 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
struct proto *p;
struct ospf_neighbor *neigh, *n1;
u16 length;
u32 *pp;
int i;
struct nbma_node *nb;
@ -276,27 +275,31 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
pkt->options = ifa->oa->options;
#ifdef OSPFv2
pkt->deadint = htonl(ifa->dead);
pkt->deadint = htonl(ifa->deadint);
pkt->dr = htonl(ipa_to_u32(ifa->drip));
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
#else /* OSPFv3 */
pkt->deadint = htons(ifa->dead);
pkt->deadint = htons(ifa->deadint);
pkt->dr = htonl(ifa->drid);
pkt->bdr = htonl(ifa->bdrid);
#endif
/* Fill all neighbors */
i = 0;
pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
WALK_LIST(neigh, ifa->neigh_list)
if (kind != OHS_SHUTDOWN)
{
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
WALK_LIST(neigh, ifa->neigh_list)
{
OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
break;
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
{
log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->iface->name);
break;
}
*(pp + i) = htonl(neigh->rid);
i++;
}
*(pp + i) = htonl(neigh->rid);
i++;
}
length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
@ -319,7 +322,7 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
int to_all = ifa->state > OSPF_IS_DROTHER;
int me_elig = ifa->priority > 0;
if (poll) /* Poll timer */
if (kind == OHS_POLL) /* Poll timer */
{
WALK_LIST(nb, ifa->nbma_list)
if (!nb->found && (to_all || (me_elig && nb->eligible)))

View File

@ -12,6 +12,10 @@
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n, ip_addr faddr);
void ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn);
void ospf_hello_send(timer *timer, int kind, struct ospf_neighbor *dirn);
#define OHS_HELLO 0
#define OHS_POLL 1
#define OHS_SHUTDOWN 2
#endif /* _BIRD_OSPF_HELLO_H_ */

View File

@ -21,13 +21,13 @@ char *ospf_it[] = { "broadcast", "nbma", "ptp", "ptmp", "virtual link" };
static void
poll_timer_hook(timer * timer)
{
ospf_hello_send(timer, 1, NULL);
ospf_hello_send(timer, OHS_POLL, NULL);
}
static void
hello_timer_hook(timer * timer)
{
ospf_hello_send(timer, 0, NULL);
ospf_hello_send(timer, OHS_HELLO, NULL);
}
static void
@ -40,6 +40,8 @@ wait_timer_hook(timer * timer)
ospf_iface_sm(ifa, ISM_WAITF);
}
static void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);
u32
rxbufsize(struct ospf_iface *ifa)
{
@ -163,7 +165,13 @@ ospf_iface_down(struct ospf_iface *ifa)
if (ifa->type != OSPF_IT_VLINK)
{
OSPF_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
#ifdef OSPFv2
OSPF_TRACE(D_EVENTS, "Removing interface %s (%I/%d) from area %R",
ifa->iface->name, ifa->addr->prefix, ifa->addr->pxlen, ifa->oa->areaid);
#else
OSPF_TRACE(D_EVENTS, "Removing interface %s (IID %d) from area %R",
ifa->iface->name, ifa->instance_id, ifa->oa->areaid);
#endif
/* First of all kill all the related vlinks */
WALK_LIST(iff, po->iface_list)
@ -207,14 +215,25 @@ ospf_iface_down(struct ospf_iface *ifa)
}
static void
void
ospf_iface_remove(struct ospf_iface *ifa)
{
struct proto *p = &ifa->oa->po->proto;
if (ifa->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Removing vlink to %R via area %R", ifa->vid, ifa->voa->areaid);
ospf_iface_sm(ifa, ISM_DOWN);
rem_node(NODE ifa);
rfree(ifa->pool);
}
void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
if (ifa->state > OSPF_IS_DOWN)
ospf_hello_send(ifa->hello_timer, OHS_SHUTDOWN, NULL);
}
/**
* ospf_iface_chstate - handle changes of interface state
* @ifa: OSPF interface
@ -357,7 +376,7 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
}
static u8
ospf_iface_classify(struct iface *ifa, struct ifa *addr)
ospf_iface_classify_int(struct iface *ifa, struct ifa *addr)
{
if (ipa_nonzero(addr->opposite))
return (ifa->flags & IF_MULTICAST) ? OSPF_IT_PTP : OSPF_IT_PTMP;
@ -372,6 +391,13 @@ ospf_iface_classify(struct iface *ifa, struct ifa *addr)
return OSPF_IT_PTP;
}
static inline u8
ospf_iface_classify(u8 type, struct ifa *addr)
{
return (type != OSPF_IT_UNDEF) ? type : ospf_iface_classify_int(addr->iface, addr);
}
struct ospf_iface *
ospf_iface_find(struct proto_ospf *p, struct iface *what)
{
@ -401,23 +427,69 @@ ospf_iface_add(struct object_lock *lock)
ospf_iface_sm(ifa, (ifa->check_link && !(ifa->iface->flags & IF_LINK_UP)) ? ISM_LOOP : ISM_UP);
}
void
ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
struct ospf_area_config *ac, struct ospf_iface_patt *ip)
static inline void
add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
{
struct proto *p = &po->proto;
struct pool *pool = rp_new(p->pool, "OSPF Interface");
struct nbma_node *n = mb_alloc(ifa->pool, sizeof(struct nbma_node));
add_tail(&ifa->nbma_list, NODE n);
n->ip = src->ip;
n->eligible = src->eligible;
n->found = found;
}
static int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{
if (! addr)
return 0;
/*
* We cannot properly support multiple OSPF ifaces on real iface
* with multiple prefixes, therefore we force OSPF ifaces with
* non-primary IP prefixes to be stub.
*/
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
if (! (addr->flags & IA_PRIMARY))
return 1;
#endif
/* a loopback/dummy address */
if ((addr->pxlen == MAX_PREFIX_LENGTH) && ipa_zero(addr->opposite))
return 1;
return ip->stub;
}
void
ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
{
struct proto *p = &oa->po->proto;
struct iface *iface = addr ? addr->iface : NULL;
struct pool *pool;
struct ospf_iface *ifa;
struct nbma_node *nbma, *nb;
struct nbma_node *nb;
struct object_lock *lock;
struct ospf_area *oa;
if (ip->type != OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Adding interface %s", iface->name);
if (ip->type == OSPF_IT_VLINK)
OSPF_TRACE(D_EVENTS, "Adding vlink to %R via area %R", ip->vid, ip->voa);
else
{
#ifdef OSPFv2
OSPF_TRACE(D_EVENTS, "Adding interface %s (%I/%d) to area %R",
iface->name, addr->prefix, addr->pxlen, oa->areaid);
#else
OSPF_TRACE(D_EVENTS, "Adding interface %s (IID %d) to area %R",
iface->name, ip->instance_id, oa->areaid);
#endif
}
pool = rp_new(p->pool, "OSPF Interface");
ifa = mb_allocz(pool, sizeof(struct ospf_iface));
ifa->iface = iface;
ifa->addr = addr;
ifa->oa = oa;
ifa->cf = ip;
ifa->pool = pool;
ifa->cost = ip->cost;
@ -428,7 +500,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
ifa->pollint = ip->pollint;
ifa->strictnbma = ip->strictnbma;
ifa->waitint = ip->waitint;
ifa->dead = (ip->dead == 0) ? ip->deadc * ifa->helloint : ip->dead;
ifa->deadint = ip->deadint;
ifa->stub = ospf_iface_stubby(ip, addr);
ifa->ioprob = OSPF_I_OK;
ifa->rxbuf = ip->rxbuf;
@ -444,14 +516,7 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
ifa->instance_id = ip->instance_id;
#endif
if (ip->type == OSPF_IT_UNDEF)
ifa->type = ospf_iface_classify(iface, addr);
else
ifa->type = ip->type;
/* a loopback/dummy address */
if ((addr->pxlen == MAX_PREFIX_LENGTH) && ipa_zero(addr->opposite))
ifa->stub = 1;
ifa->type = ospf_iface_classify(ip->type, addr);
/* Check validity of interface type */
int old_type = ifa->type;
@ -479,16 +544,8 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
init_list(&ifa->nbma_list);
WALK_LIST(nb, ip->nbma_list)
{
if (!ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
continue;
nbma = mb_alloc(pool, sizeof(struct nbma_node));
nbma->ip = nb->ip;
nbma->eligible = nb->eligible;
nbma->found = 0;
add_tail(&ifa->nbma_list, NODE nbma);
}
if (ipa_in_net(nb->ip, addr->prefix, addr->pxlen))
add_nbma_node(ifa, nb, 0);
DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
ifa->hello_timer = tm_new(pool);
@ -518,26 +575,11 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
}
ifa->state = OSPF_IS_DOWN;
add_tail(&po->iface_list, NODE ifa);
ifa->oa = NULL;
WALK_LIST(oa, po->area_list)
{
if (oa->areaid == ac->areaid)
{
ifa->oa = oa;
break;
}
}
if (!ifa->oa)
bug("Cannot add any area to accepted Interface");
else
add_tail(&oa->po->iface_list, NODE ifa);
if (ifa->type == OSPF_IT_VLINK)
{
ifa->oa = po->backbone;
ifa->voa = oa;
ifa->voa = ospf_find_area(oa->po, ip->voa);
ifa->vid = ip->vid;
return; /* Don't lock, don't add sockets */
}
@ -564,14 +606,209 @@ ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr,
olock_acquire(lock);
}
int
ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
{
struct proto *p = &ifa->oa->po->proto;
struct nbma_node *nb, *nbx;
char *ifname = (ifa->type != OSPF_IT_VLINK) ? ifa->iface->name : "vlink";
/* Type could be changed in ospf_iface_new(),
but if config values are same then also results are same */
int old_type = ospf_iface_classify(ifa->cf->type, ifa->addr);
int new_type = ospf_iface_classify(new->type, ifa->addr);
if (old_type != new_type)
return 0;
int new_stub = ospf_iface_stubby(new, ifa->addr);
if (ifa->stub != new_stub)
return 0;
ifa->cf = new;
ifa->marked = 0;
/* HELLO TIMER */
if (ifa->helloint != new->helloint)
{
OSPF_TRACE(D_EVENTS, "Changing hello interval on interface %s from %d to %d",
ifname, ifa->helloint, new->helloint);
ifa->helloint = new->helloint;
ifa->hello_timer->recurrent = ifa->helloint;
tm_start(ifa->hello_timer, ifa->helloint);
}
/* RXMT TIMER */
if (ifa->rxmtint != new->rxmtint)
{
OSPF_TRACE(D_EVENTS, "Changing retransmit interval on interface %s from %d to %d",
ifname, ifa->rxmtint, new->rxmtint);
ifa->rxmtint = new->rxmtint;
}
/* POLL TIMER */
if (ifa->pollint != new->pollint)
{
OSPF_TRACE(D_EVENTS, "Changing poll interval on interface %s from %d to %d",
ifname, ifa->pollint, new->pollint);
ifa->pollint = new->helloint;
ifa->poll_timer->recurrent = ifa->pollint;
tm_start(ifa->poll_timer, ifa->pollint);
}
/* WAIT TIMER */
if (ifa->waitint != new->waitint)
{
OSPF_TRACE(D_EVENTS, "Changing wait interval on interface %s from %d to %d",
ifname, ifa->waitint, new->waitint);
ifa->waitint = new->waitint;
if (ifa->wait_timer->expires != 0)
tm_start(ifa->wait_timer, ifa->waitint);
}
/* DEAD TIMER */
if (ifa->deadint != new->deadint)
{
OSPF_TRACE(D_EVENTS, "Changing dead interval on interface %s from %d to %d",
ifname, ifa->deadint, new->deadint);
ifa->deadint = new->deadint;
}
/* INFTRANS */
if (ifa->inftransdelay != new->inftransdelay)
{
OSPF_TRACE(D_EVENTS, "Changing transmit delay on interface %s from %d to %d",
ifname, ifa->inftransdelay, new->inftransdelay);
ifa->inftransdelay = new->inftransdelay;
}
#ifdef OSPFv2
/* AUTHENTICATION */
if (ifa->autype != new->autype)
{
OSPF_TRACE(D_EVENTS, "Changing authentication type on interface %s", ifname);
ifa->autype = new->autype;
}
/* Update passwords */
ifa->passwords = new->passwords;
#endif
/* Remaining options are just for proper interfaces */
if (ifa->type == OSPF_IT_VLINK)
return 1;
/* COST */
if (ifa->cost != new->cost)
{
OSPF_TRACE(D_EVENTS, "Changing cost on interface %s from %d to %d",
ifname, ifa->cost, new->cost);
ifa->cost = new->cost;
}
/* PRIORITY */
if (ifa->priority != new->priority)
{
OSPF_TRACE(D_EVENTS, "Changing priority on interface %s from %d to %d",
ifname, ifa->priority, new->priority);
ifa->priority = new->priority;
}
/* STRICT NBMA */
if (ifa->strictnbma != new->strictnbma)
{
OSPF_TRACE(D_EVENTS, "Changing NBMA strictness on interface %s", ifname);
ifa->strictnbma = new->strictnbma;
}
/* NBMA LIST - remove or update old */
WALK_LIST_DELSAFE(nb, nbx, ifa->nbma_list)
{
struct nbma_node *nb2 = find_nbma_node_in(&new->nbma_list, nb->ip);
if (nb2)
{
if (nb->eligible != nb2->eligible)
{
OSPF_TRACE(D_EVENTS, "Changing eligibility of neighbor %I on interface %s",
nb->ip, ifname);
nb->eligible = nb2->eligible;
}
}
else
{
OSPF_TRACE(D_EVENTS, "Removing NBMA neighbor %I on interface %s",
nb->ip, ifname);
rem_node(NODE nb);
mb_free(nb);
}
}
/* NBMA LIST - add new */
WALK_LIST(nb, new->nbma_list)
{
if (!ipa_in_net(nb->ip, ifa->addr->prefix, ifa->addr->pxlen))
continue;
if (! find_nbma_node(ifa, nb->ip))
{
OSPF_TRACE(D_EVENTS, "Adding NBMA neighbor %I on interface %s",
nb->ip, ifname);
add_nbma_node(ifa, nb, !!find_neigh_by_ip(ifa, nb->ip));
}
}
/* RX BUFF */
if (ifa->rxbuf != new->rxbuf)
{
OSPF_TRACE(D_EVENTS, "Changing rxbuf interface %s from %d to %d",
ifname, ifa->rxbuf, new->rxbuf);
ifa->rxbuf = new->rxbuf;
ospf_iface_change_mtu(ifa->oa->po, ifa);
}
/* LINK */
if (ifa->check_link != new->check_link)
{
OSPF_TRACE(D_EVENTS, "%s link check on interface %s",
new->check_link ? "Enabling" : "Disabling", ifname);
ifa->check_link = new->check_link;
if (!(ifa->iface->flags & IF_LINK_UP))
ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
}
/* ECMP weight */
if (ifa->ecmp_weight != new->ecmp_weight)
{
OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
ifname, (int)ifa->ecmp_weight + 1, (int)new->ecmp_weight + 1);
ifa->ecmp_weight = new->ecmp_weight;
}
/* instance_id is not updated - it is part of key */
return 1;
}
#ifdef OSPFv2
static inline struct ospf_iface_patt *
ospf_iface_patt_find(struct ospf_area_config *ac, struct ifa *a)
{
return (struct ospf_iface_patt *) iface_patt_find(&ac->patt_list, a->iface, a);
}
void
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
{
struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_config *cf = (struct ospf_config *) (p->cf);
if (a->flags & IA_SECONDARY)
return;
@ -583,16 +820,14 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
if (flags & IF_CHANGE_UP)
{
int done = 0;
struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list)
struct ospf_area *oa;
WALK_LIST(oa, po->area_list)
{
struct ospf_iface_patt *ip = (struct ospf_iface_patt *)
iface_patt_find(&ac->patt_list, a->iface, a);
if (ip)
struct ospf_iface_patt *ip;
if (ip = ospf_iface_patt_find(oa->ac, a))
{
if (!done)
ospf_iface_new(po, a->iface, a, ac, ip);
ospf_iface_new(oa, a, ip);
done++;
}
}
@ -613,23 +848,72 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
}
}
#else /* OSPFv3 */
static inline int iflag_test(u32 *a, u8 i)
static struct ospf_iface *
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
{
return a[i / 32] & (1u << (i % 32));
struct ospf_iface *ifa;
WALK_LIST(ifa, oa->po->iface_list)
if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->type != OSPF_IT_VLINK))
return ifa;
return NULL;
}
static inline void iflag_set(u32 *a, u8 i)
void
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
a[i / 32] |= (1u << (i % 32));
struct ospf_iface_patt *ip;
struct iface *iface;
struct ifa *a;
WALK_LIST(iface, iface_list)
WALK_LIST(a, iface->addrs)
{
if (a->flags & IA_SECONDARY)
continue;
if (a->scope <= SCOPE_LINK)
continue;
if (ip = ospf_iface_patt_find(oa->ac, a))
{
/* Main inner loop */
struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a);
if (ifa)
{
if (ospf_iface_reconfigure(ifa, ip))
continue;
/* Hard restart */
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
ospf_iface_new(oa, a, ip);
}
}
}
#else /* OSPFv3 */
struct ospf_iface_patt *
ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
{
struct ospf_iface_patt *pt, *res = NULL;
WALK_LIST(pt, ac->patt_list)
if ((pt->instance_id >= iid) && (iface_patt_match(&pt->i, iface, NULL)) &&
(!res || (pt->instance_id < res->instance_id)))
res = pt;
return res;
}
void
ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
{
struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_config *cf = (struct ospf_config *) (p->cf);
if (a->flags & IA_SECONDARY)
return;
@ -643,40 +927,26 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
{
if (flags & IF_CHANGE_UP)
{
u32 found_all[8] = {};
struct ospf_area_config *ac;
int done0 = 0;
struct ospf_area *oa;
WALK_LIST(ac, cf->area_list)
WALK_LIST(oa, po->area_list)
{
u32 found_new[8] = {};
struct iface_patt *pt;
int iid = 0;
WALK_LIST(pt, ac->patt_list)
struct ospf_iface_patt *ip;
while (ip = ospf_iface_patt_find(oa->ac, a->iface, iid))
{
if (iface_patt_match(pt, a->iface, a))
{
struct ospf_iface_patt *ipt = (struct ospf_iface_patt *) pt;
/* If true, we already assigned that IID and we skip
this to implement first-match behavior */
if (iflag_test(found_new, ipt->instance_id))
continue;
/* If true, we already assigned that in a different area,
we log collision */
if (iflag_test(found_all, ipt->instance_id))
{
log(L_WARN "%s: Interface %s (IID %d) matches for multiple areas",
p->name, a->iface->name, ipt->instance_id);
continue;
}
iflag_set(found_all, ipt->instance_id);
iflag_set(found_new, ipt->instance_id);
ospf_iface_new(po, a->iface, a, ac, ipt);
}
ospf_iface_new(oa, a, ip);
if (ip->instance_id == 0)
done0++;
iid = ip->instance_id + 1;
}
}
if (done0 > 1)
log(L_WARN "%s: Interface %s matches for multiple areas",
p->name, a->iface->name);
}
if (flags & IF_CHANGE_DOWN)
@ -706,15 +976,64 @@ ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
}
}
#endif
static struct ospf_iface *
ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a, int iid)
{
struct ospf_iface *ifa;
WALK_LIST(ifa, oa->po->iface_list)
if ((ifa->addr == a) && (ifa->oa == oa) && (ifa->instance_id == iid) && (ifa->type != OSPF_IT_VLINK))
return ifa;
return NULL;
}
void
ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
struct ospf_iface_patt *ip;
struct iface *iface;
struct ifa *a;
WALK_LIST(iface, iface_list)
WALK_LIST(a, iface->addrs)
{
if (a->flags & IA_SECONDARY)
continue;
if (a->scope != SCOPE_LINK)
continue;
int iid = 0;
while (ip = ospf_iface_patt_find(nac, iface, iid))
{
iid = ip->instance_id + 1;
/* Main inner loop */
struct ospf_iface *ifa = ospf_iface_find_by_key(oa, a, ip->instance_id);
if (ifa)
{
if (ospf_iface_reconfigure(ifa, ip))
continue;
/* Hard restart */
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
ospf_iface_new(oa, a, ip);
}
}
}
#endif
static void
ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
{
struct proto *p = &po->proto;
struct ospf_packet *op;
struct ospf_neighbor *n;
OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s.", ifa->iface->name);
OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s", ifa->iface->name);
if (ifa->sk)
{
@ -755,11 +1074,13 @@ void
ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
{
struct proto_ospf *po = (struct proto_ospf *) p;
/*
if (iface->flags & IF_IGNORE)
return;
*/
/* Going up means that there are no such ifaces yet */
/* Going up means that there are no such ifaces yet */
if (flags & IF_CHANGE_UP)
return;
@ -817,7 +1138,7 @@ ospf_iface_info(struct ospf_iface *ifa)
cli_msg(-1015, "\tPoll timer: %u", ifa->pollint);
}
cli_msg(-1015, "\tWait timer: %u", ifa->waitint);
cli_msg(-1015, "\tDead timer: %u", ifa->dead);
cli_msg(-1015, "\tDead timer: %u", ifa->deadint);
cli_msg(-1015, "\tRetransmit timer: %u", ifa->rxmtint);
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
{
@ -828,9 +1149,3 @@ ospf_iface_info(struct ospf_iface *ifa)
}
}
void
ospf_iface_shutdown(struct ospf_iface *ifa)
{
init_list(&ifa->neigh_list);
hello_timer_hook(ifa->hello_timer);
}

View File

@ -16,10 +16,11 @@ struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
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_iface_info(struct ospf_iface *ifa);
void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
void ospf_iface_remove(struct ospf_iface *ifa);
void ospf_iface_shutdown(struct ospf_iface *ifa);
void ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, struct ospf_area_config *ac, struct ospf_iface_patt *ip);
void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);
void ospf_set_rxbuf_size(struct ospf_iface *ifa, u32 rxbuf);
int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac);
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
@ -27,5 +28,4 @@ static inline struct nbma_node *
find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
{ return find_nbma_node_in(&ifa->nbma_list, ip); }
#endif /* _BIRD_OSPF_IFACE_H_ */

View File

@ -23,6 +23,18 @@ flush_lsa(struct top_hash_entry *en, struct proto_ospf *po)
ospf_hash_delete(po->gr, en);
}
void
ospf_flush_area(struct proto_ospf *po, u32 areaid)
{
struct top_hash_entry *en, *nxt;
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
{
if ((LSA_SCOPE(&en->lsa) == LSA_SCOPE_AREA) && (en->domain == areaid))
flush_lsa(en, po);
}
}
/**
* ospf_age
* @po: ospf protocol

View File

@ -36,5 +36,7 @@ int lsa_validate(struct ospf_lsa_header *lsa, void *body);
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
void ospf_age(struct proto_ospf *po);
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
void ospf_flush_area(struct proto_ospf *po, u32 areaid);
#endif /* _BIRD_OSPF_LSALIB_H_ */

View File

@ -349,7 +349,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
case NEIGHBOR_DOWN:
neigh_chstate(n, NEIGHBOR_INIT);
default:
tm_start(n->inactim, n->ifa->dead); /* Restart inactivity timer */
tm_start(n->inactim, n->ifa->deadint); /* Restart inactivity timer */
break;
}
break;
@ -548,16 +548,6 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
return NULL;
}
struct ospf_area *
ospf_find_area(struct proto_ospf *po, u32 aid)
{
struct ospf_area *oa;
WALK_LIST(oa, po->area_list)
if (((struct ospf_area *) oa)->areaid == aid)
return oa;
return NULL;
}
/* Neighbor is inactive for a long time. Remove it. */
static void
neighbor_timer_hook(timer * timer)

View File

@ -15,7 +15,6 @@ void ospf_neigh_sm(struct ospf_neighbor *n, int event);
void bdr_election(struct ospf_iface *ifa);
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
struct ospf_neighbor *find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
void ospf_neigh_remove(struct ospf_neighbor *n);
void ospf_sh_neigh_info(struct ospf_neighbor *n);

View File

@ -122,27 +122,95 @@ static void
add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
{
struct proto_ospf *po = oa->po;
struct proto *p = &po->proto;
struct area_net_config *anet;
struct area_net *antmp;
struct area_net_config *anc;
struct area_net *an;
fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 0, ospf_area_initfib);
fib_init(&oa->net_fib, po->proto.pool, sizeof(struct area_net), 0, ospf_area_initfib);
WALK_LIST(anet, ac->net_list)
WALK_LIST(anc, ac->net_list)
{
antmp = (struct area_net *) fib_get(&oa->net_fib, &anet->px.addr, anet->px.len);
antmp->hidden = anet->hidden;
an = (struct area_net *) fib_get(&oa->net_fib, &anc->px.addr, anc->px.len);
an->hidden = an->hidden;
}
}
static void
ospf_area_add(struct proto_ospf *po, struct ospf_area_config *ac, int reconf)
{
struct proto *p = &po->proto;
struct ospf_area *oa;
OSPF_TRACE(D_EVENTS, "Adding area %R", ac->areaid);
oa = mb_allocz(p->pool, sizeof(struct ospf_area));
add_tail(&po->area_list, NODE oa);
po->areano++;
oa->ac = ac;
oa->stub = ac->stub;
oa->areaid = ac->areaid;
oa->rt = NULL;
oa->po = po;
fib_init(&oa->rtr, p->pool, sizeof(ort), 0, ospf_rt_initort);
add_area_nets(oa, ac);
if (oa->areaid == 0)
po->backbone = oa;
#ifdef OSPFv2
oa->options = (oa->stub ? 0 : OPT_E);
#else /* OSPFv3 */
oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6;
#endif
if (reconf)
ospf_ifaces_reconfigure(oa, ac);
}
static void
ospf_area_remove(struct ospf_area *oa)
{
struct proto *p = &oa->po->proto;
OSPF_TRACE(D_EVENTS, "Removing area %R", oa->areaid);
/* We suppose that interfaces are already removed */
ospf_flush_area(oa->po, oa->areaid);
fib_free(&oa->rtr);
fib_free(&oa->net_fib);
oa->po->areano--;
rem_node(NODE oa);
mb_free(oa);
}
struct ospf_area *
ospf_find_area(struct proto_ospf *po, u32 aid)
{
struct ospf_area *oa;
WALK_LIST(oa, po->area_list)
if (((struct ospf_area *) oa)->areaid == aid)
return oa;
return NULL;
}
static struct ospf_iface *
ospf_find_vlink(struct proto_ospf *po, u32 voa, u32 vid)
{
struct ospf_iface *ifa;
WALK_LIST(ifa, po->iface_list)
if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa->areaid == voa) && (ifa->vid == vid))
return ifa;
return NULL;
}
static int
ospf_start(struct proto *p)
{
struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_config *c = (struct ospf_config *) (p->cf);
struct ospf_area_config *ac;
struct ospf_area *oa;
int vlinks = 0;
po->router_id = proto_get_router_id(p->cf);
po->rfc1583 = c->rfc1583;
@ -165,68 +233,14 @@ ospf_start(struct proto *p)
po->areano = 0;
po->gr = ospf_top_new(p->pool);
s_init_list(&(po->lsal));
if (EMPTY_LIST(c->area_list))
{
log(L_ERR "Cannot start, no OSPF areas configured!");
return PS_DOWN;
}
WALK_LIST(ac, c->area_list)
{
oa = mb_allocz(p->pool, sizeof(struct ospf_area));
add_tail(&po->area_list, NODE oa);
po->areano++;
oa->ac = ac;
oa->stub = ac->stub;
oa->areaid = ac->areaid;
oa->rt = NULL;
oa->po = po;
add_area_nets(oa, ac);
fib_init(&oa->rtr, p->pool, sizeof(ort), 0, ospf_rt_initort);
ospf_area_add(po, ac, 0);
if (oa->areaid == 0)
{
po->backbone = oa;
if (oa->stub) log(L_ERR "Backbone cannot be stub. Ignoring!");
oa->stub = 0;
}
if (!EMPTY_LIST(ac->vlink_list))
vlinks = 1;
#ifdef OSPFv2
oa->options = (oa->stub ? 0 : OPT_E);
#else /* OSPFv3 */
oa->options = OPT_R | (oa->stub ? 0 : OPT_E) | OPT_V6;
#endif
}
/* ABR is always in the backbone */
if (((po->areano > 1) || vlinks) && !po->backbone)
{
oa = mb_allocz(p->pool, sizeof(struct ospf_area));
add_tail(&po->area_list, NODE oa);
po->areano++;
oa->ac = NULL;
oa->stub = 0;
oa->areaid = 0;
oa->rt = NULL;
oa->po = po;
fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 0, ospf_area_initfib);
fib_init(&oa->rtr, p->pool, sizeof(ort), 0, ospf_rt_initort);
po->backbone = oa;
#ifdef OSPFv2
oa->options = OPT_E;
#else /* OSPFv3 */
oa->options = OPT_R | OPT_E | OPT_V6;
#endif
}
/* Add all virtual links as interfaces */
struct ospf_iface_patt *ipatt;
WALK_LIST(ac, c->area_list)
WALK_LIST(ipatt, ac->vlink_list)
ospf_iface_new(po, NULL, NULL, ac, ipatt);
/* Add all virtual links */
struct ospf_iface_patt *ic;
WALK_LIST(ic, c->vlink_list)
ospf_iface_new(po->backbone, NULL, ic);
return PS_UP;
}
@ -513,8 +527,7 @@ ospf_shutdown(struct proto *p)
/* And send to all my neighbors 1WAY */
WALK_LIST(ifa, po->iface_list)
if (ifa->state > OSPF_IS_DOWN)
ospf_iface_shutdown(ifa);
ospf_iface_shutdown(ifa);
/* Cleanup locked rta entries */
FIB_WALK(&po->rtf, nftmp)
@ -622,10 +635,22 @@ ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED)
}
}
static int
ospf_patt_compare(struct ospf_iface_patt *a, struct ospf_iface_patt *b)
static void
ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
return (a->type == b->type);
oa->ac = nac;
oa->stub = nac->stub;
ospf_ifaces_reconfigure(oa, nac);
/* Handle net_list */
fib_free(&oa->net_fib);
add_area_nets(oa, nac);
/* No need to handle stubnet_list */
oa->marked = 0;
schedule_rt_lsa(oa);
}
/**
@ -641,296 +666,70 @@ ospf_patt_compare(struct ospf_iface_patt *a, struct ospf_iface_patt *b)
static int
ospf_reconfigure(struct proto *p, struct proto_config *c)
{
struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_config *old = (struct ospf_config *) (p->cf);
struct ospf_config *new = (struct ospf_config *) c;
struct ospf_area_config *oldac, *newac;
struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_iface_patt *oldip, *newip;
struct ospf_iface *ifa;
struct nbma_node *nb1, *nb2, *nbnx;
struct ospf_area *oa = NULL;
int olddead, newdead;
struct ospf_area_config *nac;
struct ospf_area *oa, *oax;
struct ospf_iface *ifa, *ifx;
struct ospf_iface_patt *ip;
if (po->rfc1583 != new->rfc1583)
return 0;
schedule_rtcalc(po);
if (old->abr != new->abr)
return 0;
po->tick = new->tick;
po->ecmp = new->ecmp;
po->tick = new->tick;
po->disp_timer->recurrent = po->tick;
tm_start(po->disp_timer, 1);
oldac = HEAD(old->area_list);
newac = HEAD(new->area_list);
/* Mark all areas and ifaces */
WALK_LIST(oa, po->area_list)
oa->marked = 1;
/* I should get it in the same order */
WALK_LIST(ifa, po->iface_list)
ifa->marked = 1;
while (((NODE(oldac))->next != NULL) && ((NODE(newac))->next != NULL))
/* Add and update areas */
WALK_LIST(nac, new->area_list)
{
if (oldac->areaid != newac->areaid)
return 0;
WALK_LIST(oa, po->area_list)
if (oa->areaid == newac->areaid)
break;
if (!oa)
return 0;
oa->ac = newac;
oa->stub = newac->stub;
if (newac->stub && (oa->areaid == 0)) oa->stub = 0;
/* Check stubnet_list */
struct ospf_stubnet_config *oldsn = HEAD(oldac->stubnet_list);
struct ospf_stubnet_config *newsn = HEAD(newac->stubnet_list);
while (((NODE(oldsn))->next != NULL) && ((NODE(newsn))->next != NULL))
{
if (!ipa_equal(oldsn->px.addr, newsn->px.addr) ||
(oldsn->px.len != newsn->px.len) ||
(oldsn->hidden != newsn->hidden) ||
(oldsn->summary != newsn->summary) ||
(oldsn->cost != newsn->cost))
break;
oldsn = (struct ospf_stubnet_config *)(NODE(oldsn))->next;
newsn = (struct ospf_stubnet_config *)(NODE(newsn))->next;
}
/* If there is no change, both pointers should be NULL */
if (((NODE(oldsn))->next) != ((NODE(newsn))->next))
schedule_rt_lsa(oa);
/* Change net_list */
fib_free(&oa->net_fib);
add_area_nets(oa, newac);
if (!iface_patts_equal(&oldac->patt_list, &newac->patt_list,
(void *) ospf_patt_compare))
return 0;
WALK_LIST(ifa, po->iface_list)
{
/* FIXME: better handling of vlinks */
if (ifa->iface == NULL)
continue;
/* FIXME: better matching of interface_id in OSPFv3 */
if (oldip = (struct ospf_iface_patt *)
iface_patt_find(&oldac->patt_list, ifa->iface, ifa->addr))
{
/* Now reconfigure interface */
if (!(newip = (struct ospf_iface_patt *)
iface_patt_find(&newac->patt_list, ifa->iface, ifa->addr)))
return 0;
/* HELLO TIMER */
if (oldip->helloint != newip->helloint)
{
ifa->helloint = newip->helloint;
ifa->hello_timer->recurrent = ifa->helloint;
tm_start(ifa->hello_timer, ifa->helloint);
OSPF_TRACE(D_EVENTS,
"Changing hello interval on interface %s from %d to %d",
ifa->iface->name, oldip->helloint, newip->helloint);
}
/* POLL TIMER */
if ((oldip->pollint != newip->pollint) && ifa->poll_timer)
{
ifa->pollint = newip->helloint;
ifa->poll_timer->recurrent = ifa->pollint;
tm_start(ifa->poll_timer, ifa->pollint);
OSPF_TRACE(D_EVENTS,
"Changing poll interval on interface %s from %d to %d",
ifa->iface->name, oldip->pollint, newip->pollint);
}
/* COST */
if (oldip->cost != newip->cost)
{
ifa->cost = newip->cost;
OSPF_TRACE(D_EVENTS,
"Changing cost interface %s from %d to %d",
ifa->iface->name, oldip->cost, newip->cost);
schedule_rt_lsa(ifa->oa);
}
/* RX BUFF */
if (oldip->rxbuf != newip->rxbuf)
{
ifa->rxbuf = newip->rxbuf;
OSPF_TRACE(D_EVENTS,
"Changing rxbuf interface %s from %d to %d",
ifa->iface->name, oldip->rxbuf, newip->rxbuf);
ospf_iface_change_mtu(po, ifa);
}
/* LINK */
if (oldip->check_link != newip->check_link)
{
ifa->check_link = newip->check_link;
if (!(ifa->iface->flags & IF_LINK_UP))
ospf_iface_sm(ifa, ifa->check_link ? ISM_LOOP : ISM_UNLOOP);
}
/* ECMP weight */
if (oldip->ecmp_weight != newip->ecmp_weight)
{
ifa->ecmp_weight = newip->ecmp_weight;
OSPF_TRACE(D_EVENTS, "Changing ECMP weight of interface %s from %d to %d",
ifa->iface->name, (int)oldip->ecmp_weight + 1, (int)newip->ecmp_weight + 1);
}
/* strict nbma */
if ((oldip->strictnbma == 0) && (newip->strictnbma != 0))
{
ifa->strictnbma = newip->strictnbma;
OSPF_TRACE(D_EVENTS,
"Interface %s is now strict NBMA.", ifa->iface->name);
}
if ((oldip->strictnbma != 0) && (newip->strictnbma == 0))
{
ifa->strictnbma = newip->strictnbma;
OSPF_TRACE(D_EVENTS,
"Interface %s is no longer strict NBMA.",
ifa->iface->name);
}
/* stub */
int old_stub = ospf_iface_stubby(oldip, ifa->addr);
int new_stub = ospf_iface_stubby(newip, ifa->addr);
if (!old_stub && new_stub)
{
ifa->stub = 1;
OSPF_TRACE(D_EVENTS, "Interface %s is now stub.", ifa->iface->name);
}
if (old_stub && !new_stub && (ifa->ioprob == OSPF_I_OK))
{
ifa->stub = 0;
OSPF_TRACE(D_EVENTS, "Interface %s is no longer stub.", ifa->iface->name);
}
#ifdef OSPFv2
/* AUTHENTICATION */
if (oldip->autype != newip->autype)
{
ifa->autype = newip->autype;
OSPF_TRACE(D_EVENTS,
"Changing authentication type on interface %s",
ifa->iface->name);
}
/* Add *passwords */
ifa->passwords = newip->passwords;
#endif
/* priority */
if (oldip->priority != newip->priority)
{
ifa->priority = newip->priority;
OSPF_TRACE(D_EVENTS,
"Changing priority on interface %s from %d to %d",
ifa->iface->name, oldip->priority, newip->priority);
}
/* RXMT */
if (oldip->rxmtint != newip->rxmtint)
{
ifa->rxmtint = newip->rxmtint;
OSPF_TRACE(D_EVENTS,
"Changing retransmit interval on interface %s from %d to %d",
ifa->iface->name, oldip->rxmtint, newip->rxmtint);
}
/* WAIT */
if ((oldip->waitint != newip->waitint) && ifa->wait_timer)
{
ifa->waitint = newip->waitint;
if (ifa->wait_timer->expires != 0)
tm_start(ifa->wait_timer, ifa->waitint);
OSPF_TRACE(D_EVENTS,
"Changing wait interval on interface %s from %d to %d",
ifa->iface->name, oldip->waitint, newip->waitint);
}
/* INFTRANS */
if (oldip->inftransdelay != newip->inftransdelay)
{
ifa->inftransdelay = newip->inftransdelay;
OSPF_TRACE(D_EVENTS,
"Changing transmit delay on interface %s from %d to %d",
ifa->iface->name, oldip->inftransdelay,
newip->inftransdelay);
}
/* DEAD */
olddead = (oldip->dead == 0) ? oldip->deadc * oldip->helloint : oldip->dead;
newdead = (newip->dead == 0) ? newip->deadc * newip->helloint : newip->dead;
if (olddead != newdead)
{
ifa->dead = newdead;
OSPF_TRACE(D_EVENTS,
"Changing dead interval on interface %s from %d to %d",
ifa->iface->name, olddead, newdead);
}
/* NBMA LIST */
/* First remove old */
WALK_LIST_DELSAFE(nb1, nbnx, ifa->nbma_list)
{
nb2 = find_nbma_node_in(&newip->nbma_list, nb1->ip);
if (nb2)
{
if (nb1->eligible != nb2->eligible)
{
nb1->eligible = nb2->eligible;
OSPF_TRACE(D_EVENTS, "Changing neighbor eligibility %I on interface %s",
nb1->ip, ifa->iface->name);
}
}
else
{
OSPF_TRACE(D_EVENTS,
"Removing NBMA neighbor %I on interface %s",
nb1->ip, ifa->iface->name);
rem_node(NODE nb1);
mb_free(nb1);
}
}
/* And then add new */
WALK_LIST(nb2, newip->nbma_list)
{
if (!ipa_in_net(nb2->ip, ifa->addr->prefix, ifa->addr->pxlen))
continue;
if (find_nbma_node(ifa, nb2->ip) == NULL)
{
nb1 = mb_alloc(ifa->pool, sizeof(struct nbma_node));
nb1->ip = nb2->ip;
nb1->eligible = nb2->eligible;
nb1->found = !!find_neigh_by_ip(ifa, nb1->ip);
add_tail(&ifa->nbma_list, NODE nb1);
OSPF_TRACE(D_EVENTS,
"Adding NBMA neighbor %I on interface %s",
nb1->ip, ifa->iface->name);
}
}
}
}
oldac = (struct ospf_area_config *)(NODE(oldac))->next;
newac = (struct ospf_area_config *)(NODE(newac))->next;
oa = ospf_find_area(po, nac->areaid);
if (oa)
ospf_area_reconfigure(oa, nac);
else
ospf_area_add(po, nac, 1);
}
if (((NODE(oldac))->next) != ((NODE(newac))->next))
return 0; /* One is not null */
/* Add and update vlinks */
WALK_LIST(ip, new->vlink_list)
{
ifa = ospf_find_vlink(po, ip->voa, ip->vid);
if (ifa)
ospf_iface_reconfigure(ifa, ip);
else
ospf_iface_new(po->backbone, NULL, ip);
}
return 1; /* Everything OK :-) */
/* Delete remaining ifaces and areas */
WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
if (ifa->marked)
{
ospf_iface_shutdown(ifa);
ospf_iface_remove(ifa);
}
WALK_LIST_DELSAFE(oa, oax, po->area_list)
if (oa->marked)
ospf_area_remove(oa);
schedule_rtcalc(po);
return 1;
}
void
ospf_sh_neigh(struct proto *p, char *iff)
{

View File

@ -81,9 +81,11 @@ struct ospf_config
{
struct proto_config c;
unsigned tick;
int rfc1583;
byte rfc1583;
byte abr;
int ecmp;
list area_list;
list vlink_list;
};
struct nbma_node
@ -121,11 +123,10 @@ struct ospf_area_config
{
node n;
u32 areaid;
int stub;
u32 stub;
list patt_list;
list vlink_list;
list net_list;
list stubnet_list;
list net_list; /* List of aggregate networks for that area */
list stubnet_list; /* List of stub networks added to Router LSA */
};
@ -167,6 +168,7 @@ struct ospf_iface
struct iface *iface; /* Nest's iface */
struct ifa *addr; /* IP prefix associated with that OSPF iface */
struct ospf_area *oa;
struct ospf_iface_patt *cf;
pool *pool;
sock *sk; /* IP socket (for DD ...) */
list neigh_list; /* List of neigbours */
@ -174,7 +176,7 @@ struct ospf_iface
u32 waitint; /* number of sec before changing state from wait */
u32 rxmtint; /* number of seconds between LSA retransmissions */
u32 pollint; /* Poll interval */
u32 dead; /* after "deadint" missing hellos is router dead */
u32 deadint; /* after "deadint" missing hellos is router dead */
u32 vid; /* Id of peer of virtual link */
ip_addr vip; /* IP of peer of virtual link */
struct ospf_iface *vifa; /* OSPF iface which the vlink goes through */
@ -252,8 +254,8 @@ struct ospf_iface
#define OSPF_I_OK 0 /* Everything OK */
#define OSPF_I_SK 1 /* Socket open failed */
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
// u8 sk_spf; /* Socket is a member of SPFRouters group */
u8 sk_dr; /* Socket is a member of DRouters group */
u8 marked; /* Used in OSPF reconfigure */
u16 rxbuf; /* Buffer size */
u8 check_link; /* Whether iface link change is used */
u8 ecmp_weight; /* Weight used for ECMP */
@ -715,14 +717,15 @@ struct ospf_area
node n;
u32 areaid;
struct ospf_area_config *ac; /* Related area config, might be NULL */
int origrt; /* Rt lsa origination scheduled? */
struct top_hash_entry *rt; /* My own router LSA */
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
list cand; /* List of candidates for RT calc. */
struct fib net_fib; /* Networks to advertise or not */
unsigned stub;
int trcap; /* Transit capability? */
u32 stub; /* 0 or stub area cost */
u32 options; /* Optional features */
byte origrt; /* Rt lsa origination scheduled? */
byte trcap; /* Transit capability? */
byte marked; /* Used in OSPF reconfigure */
struct proto_ospf *po;
struct fib rtr; /* Routing tables for routers */
};
@ -753,18 +756,20 @@ struct proto_ospf
struct ospf_iface_patt
{
struct iface_patt i;
u32 type;
u32 stub;
u32 cost;
u32 helloint;
u32 rxmtint;
u32 pollint;
u32 inftransdelay;
u32 priority;
u32 waitint;
u32 deadc;
u32 dead;
u32 type;
u32 deadint;
u32 inftransdelay;
u32 priority;
u32 strictnbma;
u32 stub;
list nbma_list;
u32 voa;
u32 vid;
u16 rxbuf;
u8 check_link;
@ -772,9 +777,7 @@ struct ospf_iface_patt
#define OSPF_RXBUF_NORMAL 0
#define OSPF_RXBUF_LARGE 1
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
list nbma_list;
u32 autype; /* Not really used in OSPFv3 */
u32 autype; /* Not really used in OSPFv3 */
#define OSPF_AUTH_NONE 0
#define OSPF_AUTH_SIMPLE 1
#define OSPF_AUTH_CRYPT 2
@ -789,24 +792,6 @@ struct ospf_iface_patt
#endif
};
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
static inline int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{
/*
* We cannot properly support multiple OSPF ifaces on real iface
* with multiple prefixes, therefore we force OSPF ifaces with
* non-primary IP prefixes to be stub.
*/
return ip->stub || !(addr->flags & IA_PRIMARY);
}
#else
static inline int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr UNUSED)
{
return ip->stub;
}
#endif
int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
struct linpool *pool);
@ -816,6 +801,8 @@ void schedule_rt_lsa(struct ospf_area *oa);
void schedule_rtcalc(struct proto_ospf *po);
void schedule_net_lsa(struct ospf_iface *ifa);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
#ifdef OSPFv3
void schedule_link_lsa(struct ospf_iface *ifa);
#else

View File

@ -1176,6 +1176,7 @@ static void *
originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
{
struct proto_ospf *po = oa->po;
struct ospf_config *cf = (struct ospf_config *) (po->proto.cf);
struct ospf_iface *ifa;
struct ospf_lsa_prefix *lp;
struct ifa *vlink_addr = NULL;
@ -1234,7 +1235,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
/* If there are some configured vlinks, add some global address,
which will be used as a vlink endpoint. */
if (oa->ac && !EMPTY_LIST(oa->ac->vlink_list) && !host_addr && vlink_addr)
if (!EMPTY_LIST(cf->vlink_list) && !host_addr && vlink_addr)
{
lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0);
i++;