summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2011-03-17 15:53:36 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2011-03-17 15:53:36 +0100
commit8e48831a970a784a979446813191628790d477f1 (patch)
treee3c2e1c2a13ab2249d42b87ce26a1dc02d3faaaf
parent93e868c730dc0b1825b2a685e0b066c051b1cb07 (diff)
downloadbird-8e48831a970a784a979446813191628790d477f1.tar
bird-8e48831a970a784a979446813191628790d477f1.zip
Vastly improved OSPF reconfiguration.
Now it can handle a change in iface pattern structure. It can add, remove and reconfigure interfaces, vlinks and areas.
-rw-r--r--proto/ospf/config.Y82
-rw-r--r--proto/ospf/hello.c31
-rw-r--r--proto/ospf/hello.h6
-rw-r--r--proto/ospf/iface.c519
-rw-r--r--proto/ospf/iface.h8
-rw-r--r--proto/ospf/lsalib.c12
-rw-r--r--proto/ospf/lsalib.h2
-rw-r--r--proto/ospf/neighbor.c12
-rw-r--r--proto/ospf/neighbor.h1
-rw-r--r--proto/ospf/ospf.c483
-rw-r--r--proto/ospf/ospf.h59
-rw-r--r--proto/ospf/topology.c3
12 files changed, 690 insertions, 528 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 321bd8d..f3a87d6 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -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:
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index 47b84a4..76c95c4 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -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)))
diff --git a/proto/ospf/hello.h b/proto/ospf/hello.h
index 5d73c09..3675c05 100644
--- a/proto/ospf/hello.h
+++ b/proto/ospf/hello.h
@@ -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_ */
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index e7c9e72..faee634 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -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);
}
+static inline void
+add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
+{
+ 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 proto_ospf *po, struct iface *iface, struct ifa *addr,
- struct ospf_area_config *ac, struct ospf_iface_patt *ip)
+ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip)
{
- struct proto *p = &po->proto;
- struct pool *pool = rp_new(p->pool, "OSPF Interface");
+ 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 struct ospf_iface *
+ospf_iface_find_by_key(struct ospf_area *oa, struct ifa *a)
+{
+ 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 int iflag_test(u32 *a, u8 i)
+void
+ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
{
- return 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);
+ }
+ }
}
-static inline void iflag_set(u32 *a, u8 i)
+
+#else /* OSPFv3 */
+
+struct ospf_iface_patt *
+ospf_iface_patt_find(struct ospf_area_config *ac, struct iface *iface, int iid)
{
- a[i / 32] |= (1u << (i % 32));
+ 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);
-}
diff --git a/proto/ospf/iface.h b/proto/ospf/iface.h
index f9631eb..3f88772 100644
--- a/proto/ospf/iface.h
+++ b/proto/ospf/iface.h
@@ -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_ */
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index 2f52fe9..224c345 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -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
diff --git a/proto/ospf/lsalib.h b/proto/ospf/lsalib.h
index 8a949d8..0b556ec 100644
--- a/proto/ospf/lsalib.h
+++ b/proto/ospf/lsalib.h
@@ -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_ */
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index 98c9de5..642365b 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -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)
diff --git a/proto/ospf/neighbor.h b/proto/ospf/neighbor.h
index dcaa12d..f593fae 100644
--- a/proto/ospf/neighbor.h
+++ b/proto/ospf/neighbor.h
@@ -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);
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index e10a405..ce913f7 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -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);
-
- if (oa->areaid == 0)
- {
- po->backbone = oa;
- if (oa->stub) log(L_ERR "Backbone cannot be stub. Ignoring!");
- oa->stub = 0;
- }
+ ospf_area_add(po, ac, 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);
+ oa = ospf_find_area(po, nac->areaid);
+ if (oa)
+ ospf_area_reconfigure(oa, nac);
+ else
+ ospf_area_add(po, nac, 1);
+ }
- if (!iface_patts_equal(&oldac->patt_list, &newac->patt_list,
- (void *) ospf_patt_compare))
- return 0;
+ /* 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);
+ }
- WALK_LIST(ifa, po->iface_list)
+ /* Delete remaining ifaces and areas */
+ WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
+ if (ifa->marked)
{
- /* 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);
- }
- }
- }
+ ospf_iface_shutdown(ifa);
+ ospf_iface_remove(ifa);
}
- oldac = (struct ospf_area_config *)(NODE(oldac))->next;
- newac = (struct ospf_area_config *)(NODE(newac))->next;
- }
-
- if (((NODE(oldac))->next) != ((NODE(newac))->next))
- return 0; /* One is not null */
+ WALK_LIST_DELSAFE(oa, oax, po->area_list)
+ if (oa->marked)
+ ospf_area_remove(oa);
- return 1; /* Everything OK :-) */
+ schedule_rtcalc(po);
+
+ return 1;
}
+
void
ospf_sh_neigh(struct proto *p, char *iff)
{
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 75ffb6d..74a8e31 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -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
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 9e693e1..1403e72 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -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++;