summaryrefslogtreecommitdiffstats
path: root/proto/ospf
diff options
context:
space:
mode:
authorOndrej Filip <feela@network.cz>2004-06-25 18:39:53 +0200
committerOndrej Filip <feela@network.cz>2004-06-25 18:39:53 +0200
commit98ac61766d81d9f20c4a7c7e12859c3b82b24f4c (patch)
tree214b6571623582884aede8f634b146b330e72bc3 /proto/ospf
parent5ed68e46d781f8a14d3ef3ffd7fe3afc4a62260e (diff)
downloadbird-98ac61766d81d9f20c4a7c7e12859c3b82b24f4c.tar
bird-98ac61766d81d9f20c4a7c7e12859c3b82b24f4c.zip
A lot of changes:
- metric is 3 byte long now - summary lsa originating - more OSPF areas possible - virtual links - better E1/E2 routes handling - some bug fixes.. I have to do: - md5 auth (last mandatory item from rfc2328) - !!!!DEBUG!!!!! (mainly virtual link system has probably a lot of bugs) - 2328 appendig E
Diffstat (limited to 'proto/ospf')
-rw-r--r--proto/ospf/config.Y52
-rw-r--r--proto/ospf/dbdes.c34
-rw-r--r--proto/ospf/hello.c103
-rw-r--r--proto/ospf/iface.c221
-rw-r--r--proto/ospf/iface.h1
-rw-r--r--proto/ospf/lsack.c14
-rw-r--r--proto/ospf/lsalib.c57
-rw-r--r--proto/ospf/lsreq.c2
-rw-r--r--proto/ospf/lsupd.c12
-rw-r--r--proto/ospf/ospf.c162
-rw-r--r--proto/ospf/ospf.h76
-rw-r--r--proto/ospf/packet.c17
-rw-r--r--proto/ospf/packet.h6
-rw-r--r--proto/ospf/rt.c519
-rw-r--r--proto/ospf/rt.h11
-rw-r--r--proto/ospf/topology.c227
-rw-r--r--proto/ospf/topology.h12
17 files changed, 1086 insertions, 440 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 3a9904f..b484d79 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -17,7 +17,7 @@ static struct ospf_area_config *this_area;
static struct iface_patt *this_ipatt;
#define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt)
static struct nbma_node *this_nbma;
-static struct area_net *this_pref;
+static struct area_net_config *this_pref;
CF_DECLS
@@ -25,7 +25,7 @@ CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG)
CF_KEYWORDS(NEIGHBORS, RFC1583COMPAT, STUB, TICK, COST, RETRANSMIT)
CF_KEYWORDS(HELLO, TRANSMIT, PRIORITY, DEAD, NONBROADCAST, POINTOPOINT, TYPE)
CF_KEYWORDS(NONE, SIMPLE, AUTHENTICATION, PASSWORD, STRICT)
-CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN)
+CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, LINK)
%type <t> opttext
@@ -78,8 +78,46 @@ ospf_area_item:
| TICK expr { this_area->tick = $2 ; if($2<=0) cf_error("Tick must be greater than zero"); }
| NETWORKS '{' pref_list '}'
| INTERFACE ospf_iface_list
+ | ospf_vlink '}'
;
+ospf_vlink: ospf_vlink_start ospf_vlink_opts
+ ;
+
+ospf_vlink_opts:
+ /* empty */
+ | ospf_vlink_opts ospf_vlink_item ';'
+ ;
+
+ospf_vlink_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"); }
+ | WAIT expr { OSPF_PATT->waitint = $2 ; }
+ | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
+ | AUTHENTICATION NONE { OSPF_PATT->autype = AU_NONE ; }
+ | AUTHENTICATION SIMPLE { OSPF_PATT->autype = AU_SIMPLE ; }
+ | PASSWORD TEXT { memcpy(OSPF_PATT->password, $2, 8); }
+ ;
+
+ospf_vlink_start: VIRTUAL LINK '{'
+ {
+ 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->patt_list, NODE this_ipatt);
+ OSPF_PATT->cost = COST_D;
+ OSPF_PATT->helloint = HELLOINT_D;
+ OSPF_PATT->pollint = POLLINT_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->type = OSPF_IT_VLINK;
+ OSPF_PATT->autype = AU_NONE;
+ }
+;
+
ospf_iface_item:
COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error("Cost must be in range 1-65535"); }
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
@@ -95,8 +133,8 @@ ospf_iface_item:
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
| STUB bool { OSPF_PATT->stub = $2 ; }
| NEIGHBORS '{' ipa_list '}'
- | AUTHENTICATION NONE { OSPF_PATT->autype=AU_NONE ; }
- | AUTHENTICATION SIMPLE { OSPF_PATT->autype=AU_SIMPLE ; }
+ | AUTHENTICATION NONE { OSPF_PATT->autype = AU_NONE ; }
+ | AUTHENTICATION SIMPLE { OSPF_PATT->autype = AU_SIMPLE ; }
| PASSWORD TEXT { memcpy(OSPF_PATT->password, $2, 8); }
;
@@ -111,7 +149,7 @@ pref_item:
pref_el: prefix ';'
{
- this_pref = cfg_allocz(sizeof(struct area_net));
+ this_pref = cfg_allocz(sizeof(struct area_net_config));
add_tail(&this_area->net_list, NODE this_pref);
this_pref->px.addr = $1.addr;
this_pref->px.len = $1.len;
@@ -120,7 +158,7 @@ pref_el: prefix ';'
pref_hid: prefix HIDDEN ';'
{
- this_pref = cfg_allocz(sizeof(struct area_net));
+ this_pref = cfg_allocz(sizeof(struct area_net_config));
add_tail(&this_area->net_list, NODE this_pref);
this_pref->px.addr = $1.addr;
this_pref->px.len = $1.len;
@@ -172,7 +210,7 @@ ospf_iface_start:
OSPF_PATT->strictnbma = 0;
OSPF_PATT->stub = 0;
init_list(&OSPF_PATT->nbma_list);
- OSPF_PATT->autype=AU_NONE;
+ OSPF_PATT->autype = AU_NONE;
}
;
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index bff8bef..c345858 100644
--- a/proto/ospf/dbdes.c
+++ b/proto/ospf/dbdes.c
@@ -39,14 +39,14 @@ ospf_dbdes_send(struct ospf_neighbor *n)
pkt = (struct ospf_dbdes_packet *) (ifa->ip_sk->tbuf);
op = (struct ospf_packet *) pkt;
fill_ospf_pkt_hdr(ifa, pkt, DBDES_P);
- pkt->iface_mtu = htons(ifa->iface->mtu); /* FIXME NOT for VLINK! */
+ pkt->iface_mtu = htons(ifa->iface->mtu);
pkt->options = ifa->options;
pkt->imms = n->myimms;
pkt->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes_packet);
op->length = htons(length);
ospf_pkt_finalize(ifa, op);
- sk_send_to(ifa->ip_sk, length, n->ip, OSPF_PROTO);
+ ospf_send_to(ifa->ip_sk, length, n->ip);
OSPF_TRACE(D_PACKETS, "DB_DES (I) sent to %I via %s.", n->ip,
ifa->iface->name);
break;
@@ -79,20 +79,26 @@ ospf_dbdes_send(struct ospf_neighbor *n)
for (; i > 0; i--)
{
struct top_hash_entry *en;
-
en = (struct top_hash_entry *) sn;
- htonlsah(&(en->lsa), lsa);
- DBG("Working on: %d\n", i);
- DBG("\tX%01x %-1I %-1I %p\n", en->lsa.type, en->lsa.id,
- en->lsa.rt, en->lsa_body);
+
+ if ((n->ifa->type != OSPF_IT_VLINK) && (en->lsa.type != LSA_T_EXT))
+ {
+ htonlsah(&(en->lsa), lsa);
+ DBG("Working on: %d\n", i);
+ DBG("\tX%01x %-1I %-1I %p\n", en->lsa.type, en->lsa.id,
+ en->lsa.rt, en->lsa_body);
+
+ lsa++;
+ }
+ else i++; /* No lsa added */
if (sn == STAIL(n->ifa->oa->lsal))
- {
- i--;
- break; /* Should set some flag? */
- }
+ {
+ i--;
+ break;
+ }
+
sn = sn->next;
- lsa++;
}
if (sn == STAIL(n->ifa->oa->lsal))
@@ -130,7 +136,7 @@ ospf_dbdes_send(struct ospf_neighbor *n)
memcpy(ifa->ip_sk->tbuf, n->ldbdes, length);
/* Copy last sent packet again */
- sk_send_to(ifa->ip_sk, length, n->ip, OSPF_PROTO);
+ ospf_send_to(ifa->ip_sk, length, n->ip);
if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
@@ -245,8 +251,6 @@ ospf_dbdes_receive(struct ospf_dbdes_packet *ps,
ps->imms.byte);
break;
}
- if(ps->imms.bit.i) log("FUCK");
-
case NEIGHBOR_EXCHANGE:
if ((ps->imms.byte == n->imms.byte) && (ps->options == n->options) &&
(ntohl(ps->ddseq) == n->ddr))
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index a318a67..c805973 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -166,16 +166,20 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn)
struct ospf_hello_packet *pkt;
struct ospf_packet *op;
struct proto *p;
- struct ospf_neighbor *neigh;
+ struct ospf_neighbor *neigh, *n1;
u16 length;
u32 *pp;
- int i;
+ int i, send;
+ struct nbma_node *nb;
if (timer == NULL)
ifa = dirn->ifa;
else
ifa = (struct ospf_iface *) timer->data;
+ if (ifa->state == OSPF_IS_DOWN)
+ return;
+
if (ifa->stub)
return; /* Don't send any packet on stub iface */
@@ -184,13 +188,13 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn)
p->name, ifa->iface->name);
/* Now we should send a hello packet */
/* First a common packet header */
- if (ifa->type != OSPF_IT_NBMA)
+ if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_VLINK))
{
- pkt = (struct ospf_hello_packet *) (ifa->hello_sk->tbuf);
+ pkt = (struct ospf_hello_packet *) (ifa->ip_sk->tbuf);
}
else
{
- pkt = (struct ospf_hello_packet *) (ifa->ip_sk->tbuf);
+ pkt = (struct ospf_hello_packet *) (ifa->hello_sk->tbuf);
}
/* Now fill ospf_hello header */
@@ -224,56 +228,55 @@ ospf_hello_send(timer * timer, int poll, struct ospf_neighbor *dirn)
ospf_pkt_finalize(ifa, op);
/* And finally send it :-) */
- if (ifa->type != OSPF_IT_NBMA)
- {
- sk_send(ifa->hello_sk, length);
- }
- else /* NBMA */
+ switch(ifa->type)
{
- struct ospf_neighbor *n1;
- struct nbma_node *nb;
- int send;
-
- if (timer == NULL) /* Response to received hello */
- {
- sk_send_to(ifa->ip_sk, length, dirn->ip, OSPF_PROTO);
- }
- else
- {
- int toall = 0;
- int meeli = 0;
- if (ifa->state > OSPF_IS_DROTHER)
- toall = 1;
- if (ifa->priority > 0)
- meeli = 1;
-
- WALK_LIST(nb, ifa->nbma_list)
+ case OSPF_IT_NBMA:
+ if (timer == NULL) /* Response to received hello */
{
- send = 1;
- WALK_LIST(n1, ifa->neigh_list)
- {
- if (ipa_compare(nb->ip, n1->ip) == 0)
- {
- send = 0;
- break;
- }
- }
- if ((poll == 1) && (send))
- {
- if (toall || (meeli && nb->eligible))
- sk_send_to(ifa->ip_sk, length, nb->ip, OSPF_PROTO);
- }
+ ospf_send_to(ifa->ip_sk, length, dirn->ip);
}
- if (poll == 0)
+ else
{
- WALK_LIST(n1, ifa->neigh_list)
- {
- if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) ||
- (meeli && (n1->priority > 0)))
- sk_send_to(ifa->ip_sk, length, n1->ip, OSPF_PROTO);
- }
+ int toall = 0;
+ int meeli = 0;
+ if (ifa->state > OSPF_IS_DROTHER)
+ toall = 1;
+ if (ifa->priority > 0)
+ meeli = 1;
+
+ WALK_LIST(nb, ifa->nbma_list)
+ {
+ send = 1;
+ WALK_LIST(n1, ifa->neigh_list)
+ {
+ if (ipa_compare(nb->ip, n1->ip) == 0)
+ {
+ send = 0;
+ break;
+ }
+ }
+ if ((poll == 1) && (send))
+ {
+ if (toall || (meeli && nb->eligible))
+ ospf_send_to(ifa->ip_sk, length, nb->ip);
+ }
+ }
+ if (poll == 0)
+ {
+ WALK_LIST(n1, ifa->neigh_list)
+ {
+ if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) ||
+ (meeli && (n1->priority > 0)))
+ ospf_send_to(ifa->ip_sk, length, n1->ip);
+ }
+ }
}
- }
+ break;
+ case OSPF_IT_VLINK:
+ ospf_send_to(ifa->ip_sk, length, ifa->vip);
+ break;
+ default:
+ sk_send(ifa->hello_sk, length);
}
OSPF_TRACE(D_PACKETS, "Hello sent via %s", ifa->iface->name);
}
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 71b907a..bd8cddd 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -117,24 +117,34 @@ ospf_iface_down(struct ospf_iface *ifa)
{
struct ospf_neighbor *n, *nx;
struct proto *p = &ifa->proto->proto;
+ struct proto_ospf *po = ifa->proto;
+ struct ospf_iface *iff;
WALK_LIST_DELSAFE(n, nx, ifa->neigh_list)
{
OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip);
ospf_neigh_remove(n);
}
- rem_node(NODE ifa);
-
rfree(ifa->hello_sk);
rfree(ifa->dr_sk);
rfree(ifa->ip_sk);
- rfree(ifa->wait_timer);
- rfree(ifa->hello_timer);
- rfree(ifa->poll_timer);
-
- rfree(ifa->lock);
- mb_free(ifa);
+ if(ifa->type == OSPF_IT_VLINK)
+ {
+ ifa->ip_sk = NULL;
+ ifa->iface = NULL;
+ return;
+ }
+ else
+ {
+ rfree(ifa->wait_timer);
+ rfree(ifa->hello_timer);
+ rfree(ifa->poll_timer);
+ rfree(ifa->lock);
+ rem_node(NODE ifa);
+ mb_free(ifa);
+ }
+ /* FIXME: Should I down related VLINK also? */
}
/**
@@ -142,7 +152,7 @@ ospf_iface_down(struct ospf_iface *ifa)
* @ifa: OSPF interface
* @event: event comming to state machine
*
- * This fully respect 9.3 of RFC 2328 except we don't use %LOOP state of
+ * This fully respects 9.3 of RFC 2328 except we don't use %LOOP state of
* interface.
*/
void
@@ -260,6 +270,7 @@ ospf_open_ip_socket(struct ospf_iface *ifa)
ipsk->saddr = ifa->iface->addr->ip;
ipsk->tos = IP_PREC_INTERNET_CONTROL;
ipsk->ttl = 1;
+ if (ifa->type == OSPF_IT_VLINK) ipsk->ttl = 255;
ipsk->rx_hook = ospf_rx_hook;
ipsk->tx_hook = ospf_tx_hook;
ipsk->err_hook = ospf_err_hook;
@@ -307,6 +318,8 @@ ospf_iface_add(struct object_lock *lock)
struct iface *iface = lock->iface;
struct proto *p = &po->proto;
+ ifa->lock = lock;
+
ifa->ioprob = OSPF_I_OK;
if (ifa->type != OSPF_IT_NBMA)
@@ -330,13 +343,114 @@ ospf_iface_add(struct object_lock *lock)
ifa->stub = 1;
ifa->ioprob += OSPF_I_IP;
}
- ifa->lock = lock;
ifa->state = OSPF_IS_DOWN;
ospf_iface_sm(ifa, ISM_UP);
}
void
+ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ospf_area_config *ac, struct ospf_iface_patt *ip)
+{
+ struct proto *p = &po->proto;
+ struct ospf_iface *ifa;
+ struct nbma_node *nbma, *nb;
+ struct object_lock *lock;
+ struct ospf_area *oa;
+
+ ifa = mb_allocz(p->pool, sizeof(struct ospf_iface));
+ ifa->proto = po;
+ ifa->iface = iface;
+
+ ifa->an = ac->areaid;
+ ifa->cost = ip->cost;
+ ifa->rxmtint = ip->rxmtint;
+ ifa->inftransdelay = ip->inftransdelay;
+ ifa->priority = ip->priority;
+ ifa->helloint = ip->helloint;
+ ifa->pollint = ip->pollint;
+ ifa->strictnbma = ip->strictnbma;
+ ifa->waitint = ip->waitint;
+ ifa->deadc = ip->deadc;
+ ifa->stub = ip->stub;
+ ifa->autype = ip->autype;
+ memcpy(ifa->aukey, ip->password, 8);
+ ifa->options = 2; /* FIXME what options? */
+
+ if (ip->type == OSPF_IT_UNDEF)
+ ifa->type = ospf_iface_clasify(ifa->iface);
+ else
+ ifa->type = ip->type;
+
+ init_list(&ifa->neigh_list);
+ init_list(&ifa->nbma_list);
+ WALK_LIST(nb, ip->nbma_list)
+ {
+ nbma = mb_alloc(p->pool, sizeof(struct nbma_node));
+ nbma->ip = nb->ip;
+ nbma->eligible = nb->eligible;
+ add_tail(&ifa->nbma_list, NODE nbma);
+ }
+
+ /* Add hello timer */
+ ifa->hello_timer = tm_new(p->pool);
+ ifa->hello_timer->data = ifa;
+ ifa->hello_timer->randomize = 0;
+ ifa->hello_timer->hook = hello_timer_hook;
+ ifa->hello_timer->recurrent = ifa->helloint;
+ DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
+
+ if (ifa->type == OSPF_IT_NBMA)
+ {
+ ifa->poll_timer = tm_new(p->pool);
+ ifa->poll_timer->data = ifa;
+ ifa->poll_timer->randomize = 0;
+ ifa->poll_timer->hook = poll_timer_hook;
+ ifa->poll_timer->recurrent = ifa->pollint;
+ DBG("%s: Installing poll timer. (%u)\n", p->name, ifa->pollint);
+ }
+ else
+ ifa->poll_timer = NULL;
+
+ ifa->wait_timer = tm_new(p->pool);
+ ifa->wait_timer->data = ifa;
+ ifa->wait_timer->randomize = 0;
+ ifa->wait_timer->hook = wait_timer_hook;
+ ifa->wait_timer->recurrent = 0;
+ DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint);
+ add_tail(&((struct proto_ospf *) p)->iface_list, NODE ifa);
+ ifa->state = OSPF_IS_DOWN;
+
+ WALK_LIST(oa, po->area_list)
+ {
+ if (oa->areaid == ifa->an)
+ break;
+ }
+
+ if (EMPTY_LIST(po->area_list) || (oa->areaid != ifa->an)) /* New area */
+ bug("Cannot add any area to accepted Interface");
+ else
+ ifa->oa = oa;
+
+ if (ifa->type == OSPF_IT_VLINK)
+ {
+ ifa->oa = po->backbone;
+ ifa->voa = oa;
+ ifa->vid = ip->vid;
+ return; /* Don't lock, don't add sockets */
+ }
+
+ lock = olock_new(p->pool);
+ lock->addr = AllSPFRouters;
+ lock->type = OBJLOCK_IP;
+ lock->port = OSPF_PROTO;
+ lock->iface = iface;
+ lock->data = ifa;
+ lock->hook = ospf_iface_add;
+
+ olock_acquire(lock);
+}
+
+void
ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface)
{
struct proto_ospf *po = (struct proto_ospf *) p;
@@ -344,8 +458,6 @@ ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface)
struct ospf_area_config *ac;
struct ospf_iface_patt *ip = NULL;
struct ospf_iface *ifa;
- struct object_lock *lock;
- struct nbma_node *nbma, *nb;
struct ospf_area *oa;
DBG("%s: If notify called\n", p->name);
@@ -364,90 +476,7 @@ ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface)
if (ip)
{
OSPF_TRACE(D_EVENTS, "Using interface %s.", iface->name);
-
- ifa = mb_allocz(p->pool, sizeof(struct ospf_iface));
- ifa->proto = po;
- ifa->iface = iface;
-
- ifa->an = ac->areaid;
- ifa->cost = ip->cost;
- ifa->rxmtint = ip->rxmtint;
- ifa->inftransdelay = ip->inftransdelay;
- ifa->priority = ip->priority;
- ifa->helloint = ip->helloint;
- ifa->pollint = ip->pollint;
- ifa->strictnbma = ip->strictnbma;
- ifa->waitint = ip->waitint;
- ifa->deadc = ip->deadc;
- ifa->stub = ip->stub;
- ifa->autype = ip->autype;
- memcpy(ifa->aukey, ip->password, 8);
- ifa->options = 2; /* FIXME what options? */
-
- if (ip->type == OSPF_IT_UNDEF)
- ifa->type = ospf_iface_clasify(ifa->iface);
- else
- ifa->type = ip->type;
-
- init_list(&ifa->neigh_list);
- init_list(&ifa->nbma_list);
- WALK_LIST(nb, ip->nbma_list)
- {
- nbma = mb_alloc(p->pool, sizeof(struct nbma_node));
- nbma->ip = nb->ip;
- nbma->eligible = nb->eligible;
- add_tail(&ifa->nbma_list, NODE nbma);
- }
-
- /* Add hello timer */
- ifa->hello_timer = tm_new(p->pool);
- ifa->hello_timer->data = ifa;
- ifa->hello_timer->randomize = 0;
- ifa->hello_timer->hook = hello_timer_hook;
- ifa->hello_timer->recurrent = ifa->helloint;
- DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
-
- if (ifa->type == OSPF_IT_NBMA)
- {
- ifa->poll_timer = tm_new(p->pool);
- ifa->poll_timer->data = ifa;
- ifa->poll_timer->randomize = 0;
- ifa->poll_timer->hook = poll_timer_hook;
- ifa->poll_timer->recurrent = ifa->pollint;
- DBG("%s: Installing poll timer. (%u)\n", p->name, ifa->pollint);
- }
- else
- ifa->poll_timer = NULL;
-
- ifa->wait_timer = tm_new(p->pool);
- ifa->wait_timer->data = ifa;
- ifa->wait_timer->randomize = 0;
- ifa->wait_timer->hook = wait_timer_hook;
- ifa->wait_timer->recurrent = 0;
- DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint);
- add_tail(&((struct proto_ospf *) p)->iface_list, NODE ifa);
- ifa->state = OSPF_IS_DOWN;
-
- lock = olock_new(p->pool);
- lock->addr = AllSPFRouters;
- lock->type = OBJLOCK_IP;
- lock->port = OSPF_PROTO;
- lock->iface = iface;
- lock->data = ifa;
- lock->hook = ospf_iface_add;
-
- WALK_LIST(NODE oa, po->area_list)
- {
- if (oa->areaid == ifa->an)
- break;
- }
-
- if (EMPTY_LIST(po->area_list) || (oa->areaid != ifa->an)) /* New area */
- bug("Cannot add any area to accepted Interface");
- else
- ifa->oa = oa;
-
- olock_acquire(lock);
+ ospf_iface_new(po, iface, ac, ip);
}
}
diff --git a/proto/ospf/iface.h b/proto/ospf/iface.h
index 2c03d2a..556024b 100644
--- a/proto/ospf/iface.h
+++ b/proto/ospf/iface.h
@@ -16,5 +16,6 @@ struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
void ospf_iface_notify(struct proto *p, unsigned flags, struct iface *iface);
void ospf_iface_info(struct ospf_iface *ifa);
void ospf_iface_shutdown(struct ospf_iface *ifa);
+void ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ospf_area_config *ac, struct ospf_iface_patt *ip);
#endif /* _BIRD_OSPF_IFACE_H_ */
diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c
index 7d7238c..bdad866 100644
--- a/proto/ospf/lsack.c
+++ b/proto/ospf/lsack.c
@@ -78,16 +78,16 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
if (ifa->type == OSPF_IT_BCAST)
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- sk_send_to(sk, len, AllSPFRouters, OSPF_PROTO);
+ ospf_send_to(sk, len, AllSPFRouters);
else
- sk_send_to(sk, len, AllDRouters, OSPF_PROTO);
+ ospf_send_to(sk, len, AllDRouters);
}
else
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
- sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
+ ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
else
- sk_send_to_bdr(sk, len, ifa);
+ ospf_send_to_bdr(sk, len, ifa);
}
fill_ospf_pkt_hdr(n->ifa, pk, LSACK_P);
@@ -104,16 +104,16 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue)
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
{
- sk_send_to(sk, len, AllSPFRouters, OSPF_PROTO);
+ ospf_send_to(sk, len, AllSPFRouters);
}
else
{
- sk_send_to(sk, len, AllDRouters, OSPF_PROTO);
+ ospf_send_to(sk, len, AllDRouters);
}
}
else
{
- sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
+ ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
}
}
diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c
index e0871c8..02718da 100644
--- a/proto/ospf/lsalib.c
+++ b/proto/ospf/lsalib.c
@@ -13,8 +13,8 @@ flush_lsa(struct top_hash_entry *en, struct ospf_area *oa)
{
struct proto *p = &oa->po->proto;
OSPF_TRACE(D_EVENTS,
- "Going to remove node Type: %u, Id: %I, Rt: %I, Age: %u",
- en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age);
+ "Going to remove node Type: %u, Id: %I, Rt: %I, Age: %u, SN: 0x%x",
+ en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa.age, en->lsa.sn);
s_rem_node(SNODE en);
if (en->lsa_body != NULL)
mb_free(en->lsa_body);
@@ -56,6 +56,7 @@ ospf_age(struct ospf_area *oa)
en->dist = LSINFINITY;
en->nhi = NULL;
en->nh = ipa_from_u32(0);
+ en->lb = ipa_from_u32(0);
DBG("Infinitying Type: %u, Id: %I, Rt: %I\n", en->lsa.type, en->lsa.id,
en->lsa.rt);
}
@@ -164,8 +165,8 @@ htonlsab(void *h, void *n, u8 type, u16 len)
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
{
- struct ospf_lsa_summ *hs, *ns;
- struct ospf_lsa_summ_net *hn, *nn;
+ struct ospf_lsa_sum *hs, *ns;
+ union ospf_lsa_sum_tm *hn, *nn;
hs = h;
ns = n;
@@ -173,15 +174,16 @@ htonlsab(void *h, void *n, u8 type, u16 len)
ns->netmask = hs->netmask;
ipa_hton(ns->netmask);
- hn = (struct ospf_lsa_summ_net *) (hs + 1);
- nn = (struct ospf_lsa_summ_net *) (ns + 1);
+ hn = (union ospf_lsa_sum_tm *) (hs + 1);
+ nn = (union ospf_lsa_sum_tm *) (ns + 1);
- for (i = 0; i < ((len - sizeof(struct ospf_lsa_summ)) /
- sizeof(struct ospf_lsa_summ_net)); i++)
+ for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
+ sizeof(union ospf_lsa_sum_tm)); i++)
{
- (nn + i)->tos = (hn + i)->tos;
- (nn + i)->metric = htons((hn + i)->metric);
- (nn + i)->padding = 0;
+ (nn + i)->metric = htonl((hn + i)->metric);
+ //(nn + i)->tos = (hn + i)->tos;
+ //(nn + i)->metric = htons((hn + i)->metric);
+ //(nn + i)->padding = 0;
}
break;
}
@@ -202,9 +204,10 @@ htonlsab(void *h, void *n, u8 type, u16 len)
for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
sizeof(struct ospf_lsa_ext_tos)); i++)
{
- (nt + i)->etos = (ht + i)->etos;
- (nt + i)->padding = 0;
- (nt + i)->metric = htons((ht + i)->metric);
+ (nt + i)->etm.metric = htonl((ht + i)->etm.metric);
+ //(nt + i)->tos = (ht + i)->tos;
+ //(nt + i)->padding = 0;
+ //(nt + i)->metric = htons((ht + i)->metric);
(nt + i)->fwaddr = (ht + i)->fwaddr;
ipa_hton((nt + i)->fwaddr);
(nt + i)->tag = htonl((ht + i)->tag);
@@ -262,8 +265,8 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
{
- struct ospf_lsa_summ *hs, *ns;
- struct ospf_lsa_summ_net *hn, *nn;
+ struct ospf_lsa_sum *hs, *ns;
+ union ospf_lsa_sum_tm *hn, *nn;
hs = h;
ns = n;
@@ -271,15 +274,16 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
hs->netmask = ns->netmask;
ipa_ntoh(hs->netmask);
- hn = (struct ospf_lsa_summ_net *) (hs + 1);
- nn = (struct ospf_lsa_summ_net *) (ns + 1);
+ hn = (union ospf_lsa_sum_tm *) (hs + 1);
+ nn = (union ospf_lsa_sum_tm *) (ns + 1);
- for (i = 0; i < ((len - sizeof(struct ospf_lsa_summ)) /
- sizeof(struct ospf_lsa_summ_net)); i++)
+ for (i = 0; i < ((len - sizeof(struct ospf_lsa_sum)) /
+ sizeof(union ospf_lsa_sum_tm)); i++)
{
- (hn + i)->tos = (nn + i)->tos;
- (hn + i)->metric = ntohs((nn + i)->metric);
- (hn + i)->padding = 0;
+ (hn + i)->metric = ntohl((nn + i)->metric);
+ //(hn + i)->tos = (nn + i)->tos;
+ //(hn + i)->metric = ntohs((nn + i)->metric);
+ //(hn + i)->padding = 0;
}
break;
}
@@ -300,9 +304,10 @@ ntohlsab(void *n, void *h, u8 type, u16 len)
for (i = 0; i < ((len - sizeof(struct ospf_lsa_ext)) /
sizeof(struct ospf_lsa_ext_tos)); i++)
{
- (ht + i)->etos = (nt + i)->etos;
- (ht + i)->padding = 0;
- (ht + i)->metric = ntohs((nt + i)->metric);
+ (ht + i)->etm.metric = ntohl((nt + i)->etm.metric);
+ //(ht + i)->etos = (nt + i)->etos;
+ //(ht + i)->padding = 0;
+ //(ht + i)->metric = ntohs((nt + i)->metric);
(ht + i)->fwaddr = (nt + i)->fwaddr;
ipa_ntoh((ht + i)->fwaddr);
(ht + i)->tag = ntohl((nt + i)->tag);
diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c
index 98d2d06..23622fc 100644
--- a/proto/ospf/lsreq.c
+++ b/proto/ospf/lsreq.c
@@ -60,7 +60,7 @@ ospf_lsreq_send(struct ospf_neighbor *n)
i) * sizeof(struct ospf_lsreq_header);
op->length = htons(length);
ospf_pkt_finalize(n->ifa, op);
- sk_send_to(n->ifa->ip_sk, length, n->ip, OSPF_PROTO);
+ ospf_send_to(n->ifa->ip_sk, length, n->ip);
OSPF_TRACE(D_PACKETS, "LS request sent to: %I", n->rid);
}
diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c
index 2211891..0cefdd1 100644
--- a/proto/ospf/lsupd.c
+++ b/proto/ospf/lsupd.c
@@ -197,17 +197,17 @@ ospf_lsupd_flood(struct ospf_neighbor *n, struct ospf_lsa_header *hn,
if (ifa->type == OSPF_IT_NBMA)
{
if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR))
- sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
+ ospf_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
else
- sk_send_to_bdr(sk, len, ifa);
+ ospf_send_to_bdr(sk, len, ifa);
}
else
{
if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR) ||
(ifa->type == OSPF_IT_PTP))
- sk_send_to(sk, len, AllSPFRouters, OSPF_PROTO);
+ ospf_send_to(sk, len, AllSPFRouters);
else
- sk_send_to(sk, len, AllDRouters, OSPF_PROTO);
+ ospf_send_to(sk, len, AllDRouters);
}
}
}
@@ -253,7 +253,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
op->length = htons(len - SIPH);
ospf_pkt_finalize(n->ifa, op);
- sk_send_to(n->ifa->ip_sk, len - SIPH, n->ip, OSPF_PROTO);
+ ospf_send_to(n->ifa->ip_sk, len - SIPH, n->ip);
OSPF_TRACE(D_PACKETS, "LS upd sent to %I (%d LSAs)", n->ip, lsano);
DBG("LSupd: next packet\n");
@@ -277,7 +277,7 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l)
ospf_pkt_finalize(n->ifa, op);
OSPF_TRACE(D_PACKETS, "LS upd sent to %I (%d LSAs)", n->ip, lsano);
- sk_send_to(n->ifa->ip_sk, len - SIPH, n->ip, OSPF_PROTO);
+ ospf_send_to(n->ifa->ip_sk, len - SIPH, n->ip);
}
}
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index aca74cb..a1049e1 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -1,7 +1,7 @@
/*
* BIRD -- OSPF
*
- * (c) 1999 - 2000 Ondrej Filip <feela@network.cz>
+ * (c) 1999--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -75,6 +75,31 @@ static int ospf_rte_same(struct rte *new, struct rte *old);
static void area_disp(timer *timer);
static void ospf_disp(timer *timer);
+static void
+ospf_area_initfib(struct fib_node *fn)
+{
+ struct area_net *an = (struct area_net *) fn;
+ an->hidden = 0;
+ an->active = -1; /* Force to regenerate summary lsa */
+ /* ac->oldactive will be rewritten by ospf_rt_spf() */
+}
+
+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;
+
+ fib_init(&oa->net_fib, p->pool, sizeof(struct area_net), 16, ospf_area_initfib);
+
+ WALK_LIST(anet, ac->net_list)
+ {
+ antmp = (struct area_net *) fib_get(&oa->net_fib, &anet->px.addr, anet->px.len);
+ antmp->hidden = anet->hidden;
+ }
+}
static int
ospf_start(struct proto *p)
@@ -83,13 +108,12 @@ ospf_start(struct proto *p)
struct ospf_config *c = (struct ospf_config *) (p->cf);
struct ospf_area_config *ac;
struct ospf_area *oa;
- struct area_net *anet, *antmp;
po->rfc1583 = c->rfc1583;
po->ebit = 0;
po->tick = c->tick;
- po->disp_timer = tm_new(po->proto.pool);
+ po->disp_timer = tm_new(p->pool);
po->disp_timer->data = po;
po->disp_timer->randomize = 0;
po->disp_timer->hook = ospf_disp;
@@ -97,8 +121,7 @@ ospf_start(struct proto *p)
tm_start(po->disp_timer, 1);
init_list(&(po->iface_list));
init_list(&(po->area_list));
- fib_init(&po->rtf[0], p->pool, sizeof(ort), 16, ospf_rt_initort);
- fib_init(&po->rtf[1], p->pool, sizeof(ort), 16, ospf_rt_initort);
+ fib_init(&po->rtf, p->pool, sizeof(ort), 16, ospf_rt_initort);
po->areano = 0;
if (EMPTY_LIST(c->area_list))
{
@@ -108,7 +131,7 @@ ospf_start(struct proto *p)
WALK_LIST(ac, c->area_list)
{
- oa = mb_allocz(po->proto.pool, sizeof(struct ospf_area));
+ oa = mb_allocz(p->pool, sizeof(struct ospf_area));
add_tail(&po->area_list, NODE oa);
po->areano++;
oa->stub = ac->stub;
@@ -118,20 +141,27 @@ ospf_start(struct proto *p)
s_init_list(&(oa->lsal));
oa->rt = NULL;
oa->po = po;
- oa->disp_timer = tm_new(po->proto.pool);
+ oa->disp_timer = tm_new(p->pool);
oa->disp_timer->data = oa;
oa->disp_timer->randomize = 0;
oa->disp_timer->hook = area_disp;
oa->disp_timer->recurrent = oa->tick;
tm_start(oa->disp_timer, 2);
- init_list(&oa->net_list);
- WALK_LIST(anet, ac->net_list)
+ add_area_nets(oa, ac);
+ fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort);
+ if (oa->areaid == 0) po->backbone = oa;
+ }
+
+ /* Add all virtual links as interfaces */
+ if(po->backbone)
+ {
+ struct ospf_iface_patt *ipatt;
+ WALK_LIST(ac, c->area_list)
{
- antmp = mb_allocz(po->proto.pool, sizeof(struct area_net));
- antmp->px.addr = anet->px.addr;
- antmp->px.len = anet->px.len;
- antmp->hidden = anet->hidden;
- add_tail(&oa->net_list, NODE antmp);
+ WALK_LIST(ipatt, ac->patt_list)
+ {
+ if (ipatt->type == OSPF_IT_VLINK) ospf_iface_new(po, NULL, ac, ipatt);
+ }
}
}
return PS_UP;
@@ -189,42 +219,21 @@ ospf_init(struct proto_config *c)
static int
ospf_rte_better(struct rte *new, struct rte *old)
{
- /* FIXME this is wrong */
if (new->u.ospf.metric1 == LSINFINITY)
return 0;
- /* External paths are always longer that internal */
- if (((new->attrs->source == RTS_OSPF)
- || (new->attrs->source == RTS_OSPF_IA))
- && (old->attrs->source == RTS_OSPF_EXT))
- return 1;
- if (((old->attrs->source == RTS_OSPF)
- || (old->attrs->source == RTS_OSPF_IA))
- && (new->attrs->source == RTS_OSPF_EXT))
- return 0;
-
- if (new->u.ospf.metric2 < old->u.ospf.metric2)
- {
- if (old->u.ospf.metric2 == LSINFINITY)
- return 0; /* Old is E1, new is E2 */
- return 1; /* Both are E2 */
- }
+ if(new->attrs->source < old->attrs->source) return 1;
+ if(new->attrs->source > old->attrs->source) return 0;
- if (new->u.ospf.metric2 > old->u.ospf.metric2)
+ if(new->attrs->source == RTS_OSPF_EXT2)
{
- if (new->u.ospf.metric2 == LSINFINITY)
- return 1; /* New is E1, old is E2 */
- return 0; /* Both are E2 */
+ if(new->u.ospf.metric2 < old->u.ospf.metric2) return 1;
+ if(new->u.ospf.metric2 > old->u.ospf.metric2) return 0;
}
- /*
- * E2 metrics are the same. It means that:
- * 1) Paths are E2 with same metric
- * 2) Paths are E1.
- */
-
if (new->u.ospf.metric1 < old->u.ospf.metric1)
return 1;
+
return 0; /* Old is shorter or same */
}
@@ -466,29 +475,30 @@ ospf_get_status(struct proto *p, byte * buf)
static void
ospf_get_route_info(rte * rte, byte * buf, ea_list * attrs UNUSED)
{
- char met = ' ';
- char type = ' ';
+ char *type = "<bug>";
- if (rte->attrs->source == RTS_OSPF_EXT)
+ switch(rte->attrs->source)
{
- met = '1';
- type = 'E';
-
+ case RTS_OSPF:
+ type = "I";
+ break;
+ case RTS_OSPF_IA:
+ type = "IA";
+ break;
+ case RTS_OSPF_EXT1:
+ type = "E1";
+ break;
+ case RTS_OSPF_EXT2:
+ type = "E2";
+ break;
}
- if (rte->u.ospf.metric2 != LSINFINITY)
- met = '2';
- if (rte->attrs->source == RTS_OSPF_IA)
- type = 'A';
- if (rte->attrs->source == RTS_OSPF)
- type = 'I';
- buf += bsprintf(buf, " %c", type);
- if (met != ' ')
- buf += bsprintf(buf, "%c", met);
+
+ buf += bsprintf(buf, " %s", type);
buf += bsprintf(buf, " (%d/%d", rte->pref, rte->u.ospf.metric1);
- if (rte->u.ospf.metric2 != LSINFINITY)
+ if (rte->attrs->source == RTS_OSPF_EXT2)
buf += bsprintf(buf, "/%d", rte->u.ospf.metric2);
buf += bsprintf(buf, ")");
- if (rte->attrs->source == RTS_OSPF_EXT && rte->u.ospf.tag)
+ if ((rte->attrs->source == RTS_OSPF_EXT2 || rte->attrs->source == RTS_OSPF_EXT1) && rte->u.ospf.tag)
{
buf += bsprintf(buf, " [%x]", rte->u.ospf.tag);
}
@@ -578,19 +588,8 @@ ospf_reconfigure(struct proto *p, struct proto_config *c)
}
/* Change net_list */
- WALK_LIST_DELSAFE(anet, antmp, oa->net_list)
- {
- rem_node(NODE anet);
- mb_free(anet);
- }
- WALK_LIST(anet, ac2->net_list)
- {
- antmp = mb_alloc(p->pool, sizeof(struct area_net));
- antmp->px.addr = anet->px.addr;
- antmp->px.len = anet->px.len;
- antmp->hidden = anet->hidden;
- add_tail(&oa->net_list, NODE antmp);
- }
+ fib_free(&oa->net_fib);
+ add_area_nets(oa, ac2);
if (!iface_patts_equal(&ac1->patt_list, &ac2->patt_list,
(void *) ospf_patt_compare))
@@ -833,9 +832,8 @@ ospf_sh(struct proto *p)
struct proto_ospf *po = (struct proto_ospf *) p;
struct ospf_iface *ifa;
struct ospf_neighbor *n;
- int ifano;
- int nno;
- int adjno;
+ int ifano, nno, adjno, firstfib;
+ struct area_net *anet;
if (p->proto_state != PS_UP)
{
@@ -871,16 +869,20 @@ ospf_sh(struct proto *p)
cli_msg(-1014, "\t\tNumber of LSAs in DB:\t%u", oa->gr->hash_entries);
cli_msg(-1014, "\t\tNumber of neighbors:\t%u", nno);
cli_msg(-1014, "\t\tNumber of adjacent neighbors:\t%u", adjno);
- if (!EMPTY_LIST(oa->net_list))
+
+ firstfib = 1;
+ FIB_WALK(&oa->net_fib, nftmp)
{
- struct area_net *anet;
- cli_msg(-1014, "\t\tArea networks:");
- WALK_LIST(anet, oa->net_list)
+ anet = (struct area_net *) nftmp;
+ if(firstfib)
{
- cli_msg(-1014, "\t\t\t%1I/%u\t%s", anet->px.addr, anet->px.len,
- anet->hidden ? "Hidden" : "Advertise");
+ cli_msg(-1014, "\t\tArea networks:");
+ firstfib = 0;
}
+ cli_msg(-1014, "\t\t\t%1I/%u\t%s\t%s", anet->fn.prefix, anet->fn.pxlen,
+ anet->hidden ? "Hidden" : "Advertise", anet->active ? "Active" : "");
}
+ FIB_WALK_END;
}
cli_msg(0, "");
}
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 8c7eaa0..d1de12a 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -1,7 +1,7 @@
/*
* BIRD -- OSPF
*
- * (c) 1999 - 2000 Ondrej Filip <feela@network.cz>
+ * (c) 1999--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -50,7 +50,7 @@
#define LSREFRESHTIME 1800 /* 30 minutes */
#define MINLSINTERVAL 5
#define MINLSARRIVAL 1
-#define LSINFINITY 0xffff /* RFC says 0xffffff ??? */
+#define LSINFINITY 0xffffff
#define DEFAULT_OSPFTICK 5
#define DEFAULT_AREATICK 4
@@ -72,13 +72,18 @@ struct nbma_node
int eligible;
};
-struct area_net
+struct area_net_config
{
node n;
struct prefix px;
int hidden;
+};
+
+struct area_net
+{
+ struct fib_node fn;
+ int hidden;
int active;
- int oldactive;
};
struct ospf_area_config
@@ -113,6 +118,9 @@ struct ospf_iface
u32 rxmtint; /* number of seconds between LSA retransmissions */
u32 pollint; /* Poll interval */
u32 deadc; /* 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_area *voa; /* Area wich the vlink goes through */
u16 autype;
u8 aukey[8];
u8 options;
@@ -299,28 +307,61 @@ struct ospf_lsa_net
ip_addr netmask;
};
-struct ospf_lsa_summ
+struct ospf_lsa_sum
{
ip_addr netmask;
};
-struct ospf_lsa_summ_net
+
+struct ospf_lsa_ext
{
+ ip_addr netmask;
+};
+
+struct ospf_lsa_ext_etos
+{
+#ifdef _BIG_ENDIAN
+ u8 ebit:1;
+ u8 tos:7;
+ u8 padding1;
+ u16 padding2;
+#else
+ u16 padding2;
+ u8 padding1;
+ u8 tos:7;
+ u8 ebit:1;
+#endif
+};
+
+#define METRIC_MASK 0x00FFFFFF
+struct ospf_lsa_sum_tos
+{
+#ifdef _BIG_ENDIAN
u8 tos;
- u8 padding;
- u16 metric;
+ u8 padding1;
+ u16 padding2;
+#else
+ u16 padding2;
+ u8 padding1;
+ u8 tos;
+#endif
};
-struct ospf_lsa_ext
+union ospf_lsa_sum_tm
{
- ip_addr netmask;
+ struct ospf_lsa_sum_tos tos;
+ u32 metric;
+};
+
+union ospf_lsa_ext_etm
+{
+ struct ospf_lsa_ext_etos etos;
+ u32 metric;
};
struct ospf_lsa_ext_tos
{
- u8 etos;
- u8 padding;
- u16 metric;
+ union ospf_lsa_ext_etm etm;
ip_addr fwaddr;
u32 tag;
};
@@ -432,11 +473,12 @@ struct ospf_area
slist lsal; /* List of all LSA's */
struct top_hash_entry *rt; /* My own router LSA */
list cand; /* List of candidates for RT calc. */
- list net_list; /* Networks to advertise or not */
+ struct fib net_fib; /* Networks to advertise or not */
int stub;
int trcap; /* Transit capability? */
struct proto_ospf *po;
unsigned tick;
+ struct fib rtr; /* Routing tables for routers */
};
struct proto_ospf
@@ -448,9 +490,10 @@ struct proto_ospf
list iface_list; /* Interfaces we really use */
list area_list;
int areano; /* Number of area I belong to */
- struct fib rtf[2]; /* Routing tables */
+ struct fib rtf; /* Routing table */
int rfc1583; /* RFC1583 compatibility */
int ebit; /* Did I originate any ext lsa? */
+ struct ospf_area *backbone; /* If exists */
};
struct ospf_iface_patt
@@ -468,6 +511,7 @@ struct ospf_iface_patt
u32 autype;
u32 strictnbma;
u32 stub;
+ u32 vid;
/* must be in network byte order */
#define AU_NONE htons(0)
#define AU_SIMPLE htons(1)
@@ -493,6 +537,7 @@ void ospf_sh_iface(struct proto *p, char *iff);
#define EA_OSPF_METRIC2 EA_CODE(EAP_OSPF, 1)
#define EA_OSPF_TAG EA_CODE(EAP_OSPF, 2)
+#include "proto/ospf/rt.h"
#include "proto/ospf/hello.h"
#include "proto/ospf/packet.h"
#include "proto/ospf/iface.h"
@@ -503,6 +548,5 @@ void ospf_sh_iface(struct proto *p, char *iff);
#include "proto/ospf/lsupd.h"
#include "proto/ospf/lsack.h"
#include "proto/ospf/lsalib.h"
-#include "proto/ospf/rt.h"
#endif /* _BIRD_OSPF_H_ */
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 26cc4d4..4f5db66 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -226,19 +226,26 @@ ospf_err_hook(sock * sk, int err UNUSED)
}
void
-sk_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state)
+ospf_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state)
{
struct ospf_neighbor *n;
WALK_LIST(NODE n, ifa->neigh_list) if (n->state >= state)
- sk_send_to(sk, len, n->ip, OSPF_PROTO);
+ ospf_send_to(sk, len, n->ip);
}
void
-sk_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa)
+ospf_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa)
{
if (ipa_compare(ifa->drip, ipa_from_u32(0)) != 0)
- sk_send_to(sk, len, ifa->drip, OSPF_PROTO);
+ ospf_send_to(sk, len, ifa->drip);
if (ipa_compare(ifa->bdrip, ipa_from_u32(0)) != 0)
- sk_send_to(sk, len, ifa->bdrip, OSPF_PROTO);
+ ospf_send_to(sk, len, ifa->bdrip);
}
+
+void
+ospf_send_to(sock *sk, u16 len, ip_addr ip)
+{
+ sk_send_to(sk, len, ip, OSPF_PROTO);
+}
+
diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h
index fa2c85d..0742adf 100644
--- a/proto/ospf/packet.h
+++ b/proto/ospf/packet.h
@@ -16,7 +16,9 @@ void ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt);
int ospf_rx_hook(sock * sk, int size);
void ospf_tx_hook(sock * sk);
void ospf_err_hook(sock * sk, int err);
-void sk_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state);
-void sk_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa);
+void ospf_send_to_agt(sock * sk, u16 len, struct ospf_iface *ifa, u8 state);
+void ospf_send_to_bdr(sock * sk, u16 len, struct ospf_iface *ifa);
+void ospf_send_to(sock *sk, u16 len, ip_addr ip);
+
#endif /* _BIRD_OSPF_PACKET_H_ */
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 417aa7e..0360f8b 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -21,8 +21,6 @@ fill_ri(orta * orta)
{
orta->type = RTS_DUMMY;
orta->capa = 0;
-#define ORTA_ASBR 1
-#define ORTA_ABR 2
orta->oa = NULL;
orta->metric1 = LSINFINITY;
orta->metric2 = LSINFINITY;
@@ -37,13 +35,20 @@ ospf_rt_initort(struct fib_node *fn)
{
ort *ri = (ort *) fn;
fill_ri(&ri->n);
- ri->dest = ORT_UNDEF;
memcpy(&ri->o, &ri->n, sizeof(orta));
+ ri->efn = NULL;
}
/* If new is better return 1 */
+
+/*
+ * This is hard to understand:
+ * If rfc1583 is set to 1, it work likes normal route_better()
+ * But if it is set to 0, it prunes number of AS bondary
+ * routes before it starts the router decision
+ */
static int
-ri_better(struct proto_ospf *po, orta * new, orta * old)
+ri_better(struct proto_ospf *po, orta * new, ort *nefn, orta * old, ort *oefn, int rfc1583)
{
int newtype = new->type;
int oldtype = old->type;
@@ -54,41 +59,44 @@ ri_better(struct proto_ospf *po, orta * new, orta * old)
if (old->metric1 == LSINFINITY)
return 1;
- if (po->rfc1583)
+ if(!rfc1583)
{
- if ((newtype == RTS_OSPF) && (new->oa->areaid == 0)) newtype = RTS_OSPF_IA;
- if ((oldtype == RTS_OSPF) && (old->oa->areaid == 0)) oldtype = RTS_OSPF_IA;
- }
+ if(new->oa->areaid == 0) newtype = RTS_OSPF_IA;
+ if(old->oa->areaid == 0) oldtype = RTS_OSPF_IA;
+}
+
if (new->type < old->type)
return 1;
- if (new->metric2 < old->metric2)
- {
- if (old->metric2 == LSINFINITY)
- return 0; /* Old is E1, new is E2 */
+ if (new->type > old->type)
+ return 0;
- return 1; /* Both are E2 */
+ /* Same type */
+ if(new->type == RTS_OSPF_EXT2)
+ {
+ if (new->metric2 < old->metric2) return 1;
+ if (new->metric2 > old->metric2) return 0;
}
- if (new->metric2 > old->metric2)
+
+ if(((new->type == RTS_OSPF_EXT2) || (new->type == RTS_OSPF_EXT1)) && (!po->rfc1583))
{
- if (new->metric2 == LSINFINITY)
- return 1; /* New is E1, old is E2 */
+ int newtype = nefn->n.type;
+ int oldtype = oefn->n.type;
+
+ if(nefn->n.oa->areaid == 0) newtype = RTS_OSPF_IA;
+ if(oefn->n.oa->areaid == 0) oldtype = RTS_OSPF_IA;
- return 0; /* Both are E2 */
+ if(newtype < oldtype) return 1;
+ if(newtype > oldtype) return 0;
}
- /*
- * E2 metrics are the same. It means that: 1) Paths are E2 with same
- * metric 2) Paths are E1.
- */
if (new->metric1 < old->metric1)
return 1;
if (new->metric1 > old->metric1)
return 0;
- /* Metric 1 are the same */
if (new->oa->areaid > old->oa->areaid) return 1; /* Larger AREAID is preffered */
return 0; /* Old is shorter or same */
@@ -96,26 +104,35 @@ ri_better(struct proto_ospf *po, orta * new, orta * old)
static void
ri_install(struct proto_ospf *po, ip_addr prefix, int pxlen, int dest,
- orta * new)
+ orta * new, ort * ipath)
{
- ort *old = (ort *) fib_get(&po->rtf[dest], &prefix, pxlen);
+ struct ospf_area *oa = new->oa;
+ ort *old;
- if (ri_better(po, new, &old->n))
+ if (dest == ORT_NET)
{
- memcpy(&old->n, new, sizeof(orta));
+ struct area_net *anet;
+ old = (ort *) fib_get(&po->rtf, &prefix, pxlen);
+ if (ri_better(po, new, ipath, &old->n, old->efn, 1))
+ {
+ memcpy(&old->n, new, sizeof(orta));
+ old->efn = ipath;
+ }
+ if ((new->type == RTS_OSPF) && (anet = (struct area_net *)fib_route(&oa->net_fib, prefix, pxlen)))
+ anet->active = 1;
+ }
+ else
+ {
+ old = (ort *) fib_get(&oa->rtr, &prefix, pxlen);
+
+ if (ri_better(po, new, ipath, &old->n, old->efn, 1))
+ {
+ memcpy(&old->n, new, sizeof(orta));
+ old->efn = ipath;
+ }
}
}
-/**
- * ospf_rt_spf - calculate internal routes
- * @po: OSPF protocol
- *
- * Calculation of internal paths in an area is described in 16.1 of RFC 2328.
- * It's based on Dijkstra's shortest path tree algorithms.
- * RFC recommends to add ASBR routers into routing table. I don't do this
- * and latter parts of routing table calculation look directly into LSA
- * Database. This function is invoked from ospf_disp().
- */
static void
ospf_rt_spfa(struct ospf_area *oa)
{
@@ -126,6 +143,10 @@ ospf_rt_spfa(struct ospf_area *oa)
struct proto_ospf *po = oa->po;
struct ospf_lsa_net *ln;
orta nf;
+ struct ospf_iface *iface;
+ struct top_hash_entry *act, *tmp;
+ node *n;
+
if (oa->rt == NULL)
return;
@@ -149,9 +170,6 @@ ospf_rt_spfa(struct ospf_area *oa)
while (!EMPTY_LIST(oa->cand))
{
- struct top_hash_entry *act, *tmp;
- node *n;
-
n = HEAD(oa->cand);
act = SKIP_BACK(struct top_hash_entry, cn, n);
rem_node(n);
@@ -178,7 +196,7 @@ ospf_rt_spfa(struct ospf_area *oa)
nf.ar = act;
nf.nh = act->nh;
nf.ifa = act->nhi;
- ri_install(po, ipa_from_u32(act->lsa.id), 32, ORT_ROUTER, &nf);
+ ri_install(po, ipa_from_u32(act->lsa.id), 32, ORT_ROUTER, &nf, NULL);
}
rr = (struct ospf_lsa_rt_link *) (rt + 1);
DBG(" Number of links: %u\n", rt->links);
@@ -208,13 +226,9 @@ ospf_rt_spfa(struct ospf_area *oa)
nf.nh = act->nh;
nf.ifa = act->nhi;
ri_install(po, ipa_from_u32(rtl->id),
- ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf);
+ ipa_mklen(ipa_from_u32(rtl->data)), ORT_NET, &nf, NULL);
break;
- case LSART_VLNK: /* FIXME !!!!!!!! */
- DBG("Ignoring\n");
- continue;
- break;
case LSART_NET:
tmp = ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_NET);
if (tmp == NULL)
@@ -222,6 +236,8 @@ ospf_rt_spfa(struct ospf_area *oa)
else
DBG("Found. :-)\n");
break;
+
+ case LSART_VLNK:
case LSART_PTP:
tmp = ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_RT);
DBG("PTP found.\n");
@@ -247,7 +263,7 @@ ospf_rt_spfa(struct ospf_area *oa)
nf.nh = act->nh;
nf.ifa = act->nhi;
ri_install(po, ipa_and(ipa_from_u32(act->lsa.id), ln->netmask),
- ipa_mklen(ln->netmask), ORT_NET, &nf);
+ ipa_mklen(ln->netmask), ORT_NET, &nf, NULL);
rts = (u32 *) (ln + 1);
for (i = 0; i < (act->lsa.length - sizeof(struct ospf_lsa_header) -
@@ -264,9 +280,244 @@ ospf_rt_spfa(struct ospf_area *oa)
break;
}
}
+
+ /* Find new/lost VLINK peers */
+ WALK_LIST(iface, po->iface_list)
+ {
+ if ((iface->type == OSPF_IT_VLINK) && (iface->voa == oa))
+ {
+ if ((tmp = ospf_hash_find(oa->gr, iface->vid, iface->vid, LSA_T_RT)) &&
+ ipa_equal(tmp->lb, IPA_NONE))
+ {
+ DBG("Vlink peer found\n");
+ ospf_iface_sm(iface, ISM_UP); /* FIXME: Add slave iface! */
+ }
+ else
+ {
+ DBG("Vlink peer not found\n");
+ ospf_iface_sm(iface, ISM_DOWN);
+ }
+ }
+ }
+}
+
+static int
+link_back(struct ospf_area *oa, struct top_hash_entry *fol, struct top_hash_entry *pre)
+{
+ u32 i, *rts;
+ struct ospf_lsa_net *ln;
+ struct ospf_lsa_rt *rt;
+ struct ospf_lsa_rt_link *rtl, *rr;
+
+ if(!pre) return 0;
+ if(!fol) return 0;
+ switch (fol->lsa.type)
+ {
+ case LSA_T_RT:
+ rt = (struct ospf_lsa_rt *) fol->lsa_body;
+ rr = (struct ospf_lsa_rt_link *) (rt + 1);
+ for (i = 0; i < rt->links; i++)
+ {
+ rtl = (rr + i);
+ switch (rtl->type)
+ {
+ case LSART_STUB:
+ break;
+ case LSART_NET:
+ if (ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_NET) == pre)
+ {
+ fol->lb = ipa_from_u32(rtl->data);
+ return 1;
+ }
+ break;
+ case LSART_VLNK:
+ case LSART_PTP:
+ if (ospf_hash_find(oa->gr, rtl->id, rtl->id, LSA_T_RT) == pre)
+ {
+ fol->lb = ipa_from_u32(rtl->data);
+ return 1;
+ }
+ break;
+ default:
+ log("Unknown link type in router lsa.");
+ break;
+ }
+ }
+ break;
+ case LSA_T_NET:
+ ln = fol->lsa_body;
+ rts = (u32 *) (ln + 1);
+ for (i = 0; i < (fol->lsa.length - sizeof(struct ospf_lsa_header) -
+ sizeof(struct ospf_lsa_net)) / sizeof(u32); i++)
+ {
+ if (ospf_hash_find(oa->gr, *(rts + i), *(rts + i), LSA_T_RT) == pre)
+ {
+ return 1;
+ }
+ }
+ break;
+ default:
+ log("Unknown link type in router lsa.");
+ }
+ return 0;
+}
+
+static void
+ospf_rt_sum_tr(struct ospf_area *oa)
+{
+ struct proto *p = &oa->po->proto;
+ struct proto_ospf *po = oa->po;
+ struct ospf_area *bb, *atmp;
+ ip_addr *mask, ip, abrip;
+ struct top_hash_entry *en;
+ int mlen = -1, type = -1;
+ union ospf_lsa_sum_tm *tm;
+ ort *re = NULL, *abr;
+ orta nf;
+
+ bb = NULL;
+
+ WALK_LIST(atmp, po->area_list)
+ {
+ if(atmp->areaid == 0)
+ {
+ bb = atmp;
+ break;
+ }
+ }
+
+ if(!bb) return;
+
+ WALK_SLIST(en, oa->lsal)
+ {
+ if (en->lsa.age == LSA_MAXAGE)
+ continue;
+ if (en->dist == LSINFINITY)
+ continue;
+
+ if (en->lsa.rt == p->cf->global->router_id)
+ continue;
+
+ if((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
+ continue;
+
+ mask = (ip_addr *)en->lsa_body;
+
+ if (en->lsa.type == LSA_T_SUM_NET)
+ {
+ mlen = ipa_mklen(*mask);
+ ip = ipa_and(ipa_from_u32(en->lsa.id), *mask);
+ type = ORT_NET;
+ re = (ort *) fib_find(&po->rtf, &ip, 32);
+ }
+
+ if (en->lsa.type == LSA_T_SUM_RT)
+ {
+ ip = ipa_from_u32(en->lsa.id);
+ mlen = 32;
+ type = ORT_ROUTER;
+ re = (ort *) fib_find(&bb->rtr, &ip, 32);
+ }
+ if(!re) continue;
+ if(re->n.oa->areaid != 0) continue;
+ if((re->n.type != RTS_OSPF) && (re->n.type != RTS_OSPF_IA)) continue;
+
+ abrip = ipa_from_u32(en->lsa.rt);
+
+ abr = fib_find(&oa->rtr, &abrip, 32);
+ if(!abr) continue;
+
+ tm = (union ospf_lsa_sum_tm *)(mask + 1);
+
+ nf.type = re->n.type;
+ nf.capa = ORTA_ABR;
+ nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK);
+ nf.metric2 = LSINFINITY;
+ nf.oa = oa;
+ nf.ar = abr->n.ar;
+ nf.nh = abr->n.nh;
+ nf.ifa = abr->n.ifa;
+ ri_install(po, ip, mlen, type, &nf, NULL);
+ }
}
+
+
+static void
+ospf_rt_sum(struct ospf_area *oa)
+{
+ struct proto_ospf *po = oa->po;
+ struct proto *p = &po->proto;
+ struct top_hash_entry *en;
+ ip_addr *mask, ip, abrip;
+ struct area_net *anet;
+ orta nf;
+ ort *re, *abr;
+ int mlen = -1, type = -1;
+ union ospf_lsa_sum_tm *tm;
+ OSPF_TRACE(D_EVENTS, "Starting routing table calculation for inter-area routes");
+ WALK_SLIST(en, oa->lsal)
+ {
+ /* Page 169 (1) */
+ if (en->lsa.age == LSA_MAXAGE)
+ continue;
+ if (en->dist == LSINFINITY)
+ continue;
+
+ /* Page 169 (2) */
+ if (en->lsa.rt == p->cf->global->router_id)
+ continue;
+
+ if((en->lsa.type != LSA_T_SUM_RT) && (en->lsa.type != LSA_T_SUM_NET))
+ continue;
+
+ mask = (ip_addr *)en->lsa_body;
+
+ if (en->lsa.type == LSA_T_SUM_NET)
+ {
+ mlen = ipa_mklen(*mask);
+ ip = ipa_and(ipa_from_u32(en->lsa.id), *mask);
+ /* Page 169 (3) */
+ if ((anet = fib_route(&oa->net_fib, ip, mlen)) && anet->active)
+ continue;
+ type = ORT_NET;
+ }
+
+ if (en->lsa.type == LSA_T_SUM_RT)
+ {
+ ip = ipa_from_u32(en->lsa.id);
+ mlen = 32;
+ type = ORT_ROUTER;
+ }
+ abrip = ipa_from_u32(en->lsa.rt);
+
+ if (!(abr = (ort *) fib_find(&oa->rtr, &abrip, 32))) continue;
+ if (abr->n.metric1 == LSINFINITY) continue;
+ if (!(abr->n.capa & ORTA_ABR)) continue;
+
+ tm = (union ospf_lsa_sum_tm *)(mask + 1);
+
+ nf.type = RTS_OSPF_IA;
+ nf.capa = ORTA_ABR;
+ nf.metric1 = abr->n.metric1 + (tm->metric & METRIC_MASK);
+ nf.metric2 = LSINFINITY;
+ nf.oa = oa;
+ nf.ar = abr->n.ar;
+ nf.nh = abr->n.nh;
+ nf.ifa = abr->n.ifa;
+ ri_install(po, ip, mlen, type, &nf, NULL);
+ }
+}
+
+/**
+ * ospf_rt_spf - calculate internal routes
+ * @po: OSPF protocol
+ *
+ * Calculation of internal paths in an area is described in 16.1 of RFC 2328.
+ * It's based on Dijkstra's shortest path tree algorithms.
+ * This function is invoked from ospf_disp().
+ */
void
ospf_rt_spf(struct proto_ospf *po)
{
@@ -274,12 +525,14 @@ ospf_rt_spf(struct proto_ospf *po)
struct ospf_area *oa;
int i;
ort *ri;
+ struct area_net *anet;
+
+ if (po->areano == 0) return;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation");
/* Invalidate old routing table */
- for (i = 0; i < 2; i++)
- FIB_WALK(&po->rtf[i], nftmp)
+ FIB_WALK(&po->rtf, nftmp)
{
ri = (ort *) nftmp;
memcpy(&ri->o, &ri->n, sizeof(orta)); /* Backup old data */
@@ -290,25 +543,44 @@ ospf_rt_spf(struct proto_ospf *po)
WALK_LIST(oa, po->area_list)
{
+ FIB_WALK(&oa->rtr, nftmp)
+ {
+ ri = (ort *) nftmp;
+ memcpy(&ri->o, &ri->n, sizeof(orta)); /* Backup old data */
+ fill_ri(&ri->n);
+ }
+ FIB_WALK_END;
+
+ fib_free(&oa->rtr);
+ fib_init(&oa->rtr, p->pool, sizeof(ort), 16, ospf_rt_initort);
+
+ FIB_WALK(&oa->net_fib, nftmp)
+ {
+ anet = (struct area_net *) nftmp;
+ anet->active = 0;
+ }
+ FIB_WALK_END;
ospf_rt_spfa(oa);
}
- if (po->areano > 1)
+ if (po->areano == 1)
{
- //ospf_rt_sum(oa);
+ ospf_rt_sum(HEAD(po->area_list));
}
else
{
- WALK_LIST(oa, po->area_list)
- {
- //if (oa->id == 0) ospf_rt_sum(oa);
- }
+ if (po->backbone) ospf_rt_sum(po->backbone); /* And if backbone is not connected? */
+ }
- WALK_LIST(oa, po->area_list)
+ WALK_LIST(oa, po->area_list)
+ {
+ if (oa->trcap && (oa->areaid != 0))
{
- //if (oa->trcap == 1) ospf_rt_sum(oa);
+ ospf_rt_sum_tr(oa);
+ break;
}
}
+
WALK_LIST(oa, po->area_list)
{
if (!oa->stub)
@@ -333,7 +605,7 @@ static void
ospf_ext_spfa(struct ospf_area *oa)
{
struct proto_ospf *po = oa->po;
- ort *nf1, *nf2;
+ ort *nf1, *nf2, *nfh;
orta nfa;
struct top_hash_entry *en;
struct proto *p = &po->proto;
@@ -345,6 +617,7 @@ ospf_ext_spfa(struct ospf_area *oa)
int met1, met2;
neighbor *nn;
struct ospf_lsa_rt *rt;
+ struct ospf_area *atmp;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation for ext routes");
@@ -364,7 +637,7 @@ ospf_ext_spfa(struct ospf_area *oa)
DBG("%s: Working on LSA. ID: %I, RT: %I, Type: %u, Mask %I\n",
p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask);
- if (lt->metric == LSINFINITY)
+ if ((lt->etm.metric & METRIC_MASK) == LSINFINITY)
continue;
ip = ipa_and(ipa_from_u32(en->lsa.id), le->netmask);
mlen = ipa_mklen(le->netmask);
@@ -382,7 +655,16 @@ ospf_ext_spfa(struct ospf_area *oa)
rtid = ipa_from_u32(en->lsa.rt);
- if (!(nf1 = fib_find(&po->rtf[ORT_ROUTER], &rtid, 32)))
+ nf1 = NULL;
+ WALK_LIST(atmp, po->area_list)
+ {
+ nfh = fib_find(&atmp->rtr, &rtid, 32);
+ if(nfh == NULL) continue;
+ if(nf1 == NULL) nf1 = nfh;
+ else if(ri_better(po, &nfh->n, NULL, &nf1->n, NULL, po->rfc1583)) nf1 = nfh;
+ }
+
+ if (!nf1)
continue; /* No AS boundary router found */
if (nf1->n.metric1 == LSINFINITY)
@@ -393,34 +675,39 @@ ospf_ext_spfa(struct ospf_area *oa)
if (ipa_compare(lt->fwaddr, ipa_from_u32(0)) == 0)
{
- if (lt->etos > 0)
+ if (lt->etm.etos.ebit)
{ /* FW address == 0 */
met1 = nf1->n.metric1;
- met2 = lt->metric;
+ met2 = (lt->etm.metric & METRIC_MASK);
}
else
{
- met1 = nf1->n.metric1 + lt->metric;
+ met1 = nf1->n.metric1 + (lt->etm.metric & METRIC_MASK);
met2 = LSINFINITY;
}
+
nh = nf1->n.nh;
nhi = nf1->n.ifa;
+ nfh = nf1;
}
else
{ /* FW address !=0 */
- if (!(nf2 = fib_route(&po->rtf[ORT_NET], lt->fwaddr, 32)))
+ nf2 = fib_route(&po->rtf, lt->fwaddr, 32);
+
+ if (!nf2)
{
DBG("Cannot find network route (GW=%I)\n", lt->fwaddr);
continue;
}
- if (lt->etos > 0)
+
+ if (lt->etm.etos.ebit)
{
met1 = nf2->n.metric1;
- met2 = lt->metric;
+ met2 = (lt->etm.metric & METRIC_MASK);
}
else
{
- met1 = nf2->n.metric1 + lt->metric;
+ met1 = nf2->n.metric1 + (lt->etm.metric & METRIC_MASK);
met2 = LSINFINITY;
}
@@ -434,9 +721,12 @@ ospf_ext_spfa(struct ospf_area *oa)
nh = nf2->n.nh;
nhi = nf2->n.ifa;
}
+
+ nfh = nf2;
}
- nfa.type = RTS_OSPF_EXT;
+ nfa.type = RTS_OSPF_EXT2;
+ if(met2 == LSINFINITY) nfa.type = RTS_OSPF_EXT1;
nfa.capa = 0;
nfa.metric1 = met1;
nfa.metric2 = met2;
@@ -445,7 +735,7 @@ ospf_ext_spfa(struct ospf_area *oa)
nfa.nh = nh;
nfa.ifa = nhi;
nfa.tag = lt->tag;
- ri_install(po, ip, mlen, ORT_NET, &nfa);
+ ri_install(po, ip, mlen, ORT_NET, &nfa, nfh);
}
}
@@ -463,16 +753,20 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
return;
if (en->lsa.age == LSA_MAXAGE)
return;
- /* FIXME Does it have link back? Test it! */
+
if (en->color == INSPF)
return;
if (dist >= en->dist)
return;
/*
- * FIXME The line above is not a bug, but we don't support multiple
+ * FIXME The line above (=) is not a bug, but we don't support multiple
* next hops. I'll start as soon as nest will
*/
+
+ if (!link_back(oa, en, par))
+ return;
+
DBG(" Adding candidate: rt: %I, id: %I, type: %u\n", en->lsa.rt,
en->lsa.id, en->lsa.type);
@@ -520,7 +814,6 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
add_tail(l, &en->cn);
}
}
- /* FIXME Some VLINK stuff should be here */
}
static void
@@ -607,30 +900,20 @@ rt_sync(struct proto_ospf *po)
{
struct proto *p = &po->proto;
struct fib_iterator fit;
- struct fib *fib = &po->rtf[ORT_NET];
+ struct fib *fib = &po->rtf;
ort *nf;
+ struct ospf_area *oa;
+ struct area_net *anet;
+
+ OSPF_TRACE(D_EVENTS, "Starting routing table synchronisation");
DBG("Now syncing my rt table with nest's\n");
FIB_ITERATE_INIT(&fit, fib);
-again:
+again1:
FIB_ITERATE_START(fib, &fit, nftmp)
{
nf = (ort *) nftmp;
- if (nf->n.metric1 == LSINFINITY)
- {
- net *ne;
-
- ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
- DBG("Deleting rt entry %I\n (IP: %I, GW: %I)\n",
- nf->fn.prefix, ip, nf->nh);
- rte_update(p->table, ne, p, NULL);
-
- /* Now delete my fib */
- FIB_ITERATE_PUT(&fit, nftmp);
- fib_delete(fib, nftmp);
- goto again;
- }
- else if (memcmp(&nf->n, &nf->o, sizeof(orta)))
+ if (memcmp(&nf->n, &nf->o, sizeof(orta)))
{ /* Some difference */
net *ne;
rta a0;
@@ -648,17 +931,59 @@ again:
a0.iface = nf->n.ifa;
a0.gw = nf->n.nh;
ne = net_get(p->table, nf->fn.prefix, nf->fn.pxlen);
- e = rte_get_temp(&a0);
- e->u.ospf.metric1 = nf->n.metric1;
- e->u.ospf.metric2 = nf->n.metric2;
- e->u.ospf.tag = nf->n.tag;
- e->pflags = 0;
- e->net = ne;
- e->pref = p->preference;
- DBG("Modifying rt entry %I\n (IP: %I, GW: %I)\n",
+ check_sum_lsa(po, nf, ORT_NET);
+ if (nf->n.metric1 < LSINFINITY)
+ {
+ e = rte_get_temp(&a0);
+ e->u.ospf.metric1 = nf->n.metric1;
+ e->u.ospf.metric2 = nf->n.metric2;
+ e->u.ospf.tag = nf->n.tag;
+ e->pflags = 0;
+ e->net = ne;
+ e->pref = p->preference;
+ DBG("Modifying rt entry %I\n (IP: %I, GW: %I)\n",
nf->fn.prefix, ip, nf->nh);
- rte_update(p->table, ne, p, e);
+ rte_update(p->table, ne, p, e);
+ }
+ else
+ {
+ rte_update(p->table, ne, p, NULL);
+ FIB_ITERATE_PUT(&fit, nftmp);
+ fib_delete(fib, nftmp);
+ goto again1;
+ }
}
}
FIB_ITERATE_END(nftmp);
+
+ WALK_LIST(oa, po->area_list)
+ {
+ FIB_ITERATE_INIT(&fit, &oa->rtr);
+again2:
+ FIB_ITERATE_START(&oa->rtr, &fit, nftmp)
+ {
+ nf = (ort *) nftmp;
+ if (memcmp(&nf->n, &nf->o, sizeof(orta)))
+ { /* Some difference */
+ check_sum_lsa(po, nf, ORT_ROUTER);
+ if(nf->n.metric1 >= LSINFINITY)
+ {
+ FIB_ITERATE_PUT(&fit, nftmp);
+ fib_delete(&oa->rtr, nftmp);
+ goto again2;
+ }
+ }
+ }
+ FIB_ITERATE_END(nftmp);
+
+ /* Check condensed summary LSAs */
+ FIB_WALK(&oa->net_fib, nftmp)
+ {
+ anet = (struct area_net *) nftmp;
+ if((!anet->hidden) && anet->active && (!oa->trcap))
+ originate_sum_lsa(oa, &anet->fn, ORT_NET, 1);
+ else flush_sum_lsa(oa, &anet->fn, ORT_NET);
+ }
+ FIB_WALK_END;
+ }
}
diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h
index ca3d057..f7b3330 100644
--- a/proto/ospf/rt.h
+++ b/proto/ospf/rt.h
@@ -10,10 +10,16 @@
#ifndef _BIRD_OSPF_RT_H_
#define _BIRD_OSPF_RT_H_
+#define ORT_UNDEF -1
+#define ORT_ROUTER 1
+#define ORT_NET 0
+
typedef struct orta
{
int type;
int capa;
+#define ORTA_ASBR 1
+#define ORTA_ABR 2
struct ospf_area *oa;
int metric1;
int metric2;
@@ -27,12 +33,9 @@ orta;
typedef struct ort
{
struct fib_node fn;
- int dest;
-#define ORT_UNDEF -1
-#define ORT_ROUTER 1
-#define ORT_NET 0
orta n;
orta o;
+ struct ort *efn; /* For RFC1583 */
}
ort;
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index f1e691c..215765e 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -1,8 +1,8 @@
/*
* BIRD -- OSPF Topological Database
*
- * (c) 1999 Martin Mares <mj@ucw.cz>
- * (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
+ * (c) 1999 Martin Mares <mj@ucw.cz>
+ * (c) 1999--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -25,7 +25,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
{
struct proto_ospf *po = oa->po;
struct ospf_iface *ifa;
- int j = 0, k = 0, v = 0;
+ int j = 0, k = 0;
u16 i = 0;
struct ospf_lsa_rt *rt;
struct ospf_lsa_rt_link *ln;
@@ -39,8 +39,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
if ((ifa->an == oa->areaid) && (ifa->state != OSPF_IS_DOWN))
{
i++;
- if (ifa->type == OSPF_IT_VLINK)
- v = 1;
}
}
rt = mb_allocz(po->proto.pool, sizeof(struct ospf_lsa_rt) +
@@ -49,7 +47,6 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
rt->veb.bit.b = 1;
if ((po->ebit) && (!oa->stub))
rt->veb.bit.e = 1;
- rt->veb.bit.v = v;
ln = (struct ospf_lsa_rt_link *) (rt + 1);
WALK_LIST(ifa, po->iface_list)
@@ -83,7 +80,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
}
else
{
- ln->id = ipa_to_u32(ifa->iface->addr->ip);
+ ln->data = ipa_to_u32(ifa->iface->addr->ip);
}
}
else
@@ -97,9 +94,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
ln->data = 0xffffffff;
}
else
- {
i--; /* No link added */
- }
}
break;
case OSPF_IT_BCAST:
@@ -140,14 +135,21 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
}
}
break;
- case OSPF_IT_VLINK: /* FIXME Add virtual links! */
- i--;
- break;
+ case OSPF_IT_VLINK:
+ neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
+ if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
+ {
+ ln->type = LSART_VLNK;
+ ln->id = neigh->rid;
+ ln->metric = ifa->cost;
+ ln->notos = 0;
+ rt->veb.bit.v = 1;
+ }
+ else
+ i--; /* No link added */
+ break;
}
}
- if (ifa->type == OSPF_IT_VLINK)
- v = 1;
- ln = (ln + 1);
}
rt->links = i;
*length = i * sizeof(struct ospf_lsa_rt_link) + sizeof(struct ospf_lsa_rt) +
@@ -305,6 +307,7 @@ originate_net_lsa(struct ospf_iface *ifa)
ifa->orignet = 0;
}
+
static void *
originate_ext_lsa_body(net * n, rte * e, struct proto_ospf *po,
struct ea_list *attrs)
@@ -325,15 +328,16 @@ originate_ext_lsa_body(net * n, rte * e, struct proto_ospf *po,
if (m1 != LSINFINITY)
{
- et->etos = 0;
- et->metric = m1;
+ et->etm.metric = m1;
+ et->etm.etos.tos = 0;
+ et->etm.etos.ebit = 0;
}
else
{
- et->etos = 0x80;
- et->metric = m2;
+ et->etm.metric = m2;
+ et->etm.etos.tos = 0;
+ et->etm.etos.ebit = 1;
}
- et->padding = 0;
et->tag = tag;
if (ipa_compare(e->attrs->gw, ipa_from_u32(0)) != 0)
{
@@ -371,6 +375,175 @@ max_ext_lsa(unsigned pxlen)
return i;
}
+void
+flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type)
+{
+ struct proto_ospf *po = oa->po;
+ struct proto *p = &po->proto;
+ struct top_hash_entry *en;
+ u32 rtid = po->proto.cf->global->router_id;
+ struct ospf_lsa_header lsa;
+ int max, i;
+ struct ospf_lsa_sum *sum = NULL;
+ union ospf_lsa_sum_tm *tm;
+
+ lsa.rt = rtid;
+ lsa.type = LSA_T_SUM_NET;
+ if (type == ORT_ROUTER)
+ lsa.type = LSA_T_SUM_RT;
+
+ max = max_ext_lsa(fn->pxlen);
+
+ for (i = 0; i < max; i++)
+ {
+ lsa.id = ipa_to_u32(fn->prefix) + i;
+ if ((en = ospf_hash_find_header(oa->gr, &lsa)) != NULL)
+ {
+ sum = en->lsa_body;
+ if (fn->pxlen == ipa_mklen(sum->netmask))
+ {
+ en->lsa.age = LSA_MAXAGE;
+ en->lsa.sn = LSA_MAXSEQNO;
+ OSPF_TRACE(D_EVENTS, "Flushing summary lsa.");
+ ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
+ if (can_flush_lsa(oa)) flush_lsa(en, oa);
+ break;
+ }
+ }
+ }
+}
+
+
+
+
+void
+originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric)
+{
+ struct proto_ospf *po = oa->po;
+ struct proto *p = &po->proto;
+ struct top_hash_entry *en;
+ u32 rtid = po->proto.cf->global->router_id;
+ struct ospf_lsa_header lsa;
+ void *body = NULL;
+ int i, max, mlen = fn->pxlen, found = 0, free = -1;
+ struct ospf_lsa_sum *sum = NULL;
+ union ospf_lsa_sum_tm *tm;
+ lsa.type = LSA_T_SUM_NET;
+
+ if (type == ORT_ROUTER)
+ {
+ lsa.type = LSA_T_SUM_RT;
+ mlen = 0;
+ }
+
+ lsa.age = 0;
+ lsa.rt = rtid;
+ lsa.sn = LSA_INITSEQNO;
+ lsa.length = sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm) +
+ sizeof(struct ospf_lsa_header);
+
+ max = max_ext_lsa(fn->pxlen);
+ for (i = 0; i < max; i++)
+ {
+ lsa.id = ipa_to_u32(fn->prefix) + i;
+ if ((en = ospf_hash_find_header(oa->gr, &lsa)) == NULL)
+ {
+ if (free < 0) free = i;
+ }
+ else
+ {
+ sum = en->lsa_body;
+ if (mlen == ipa_mklen(sum->netmask))
+ {
+ tm = (union ospf_lsa_sum_tm *) (sum + 1);
+ if (tm->metric == (unsigned)metric) return; /* No reason for origination */
+ lsa.sn = en->lsa.sn + 1;
+ free = en->lsa.id;
+ break;
+ }
+ }
+ }
+
+ if(free < 0)
+ {
+ log("%s: got more routes for one /%d network then %d, ignoring", p->name,
+ fn->pxlen, max);
+ return;
+ }
+ lsa.id = free;
+
+ sum = en->lsa_body;
+ tm = (union ospf_lsa_sum_tm *) (sum + 1);
+
+ OSPF_TRACE(D_EVENTS, "Originating summary (type %d) lsa for %I/%d.", lsa.type, fn->prefix,
+ fn->pxlen);
+
+ sum = mb_alloc(p->pool, sizeof(struct ospf_lsa_sum) + sizeof(union ospf_lsa_sum_tm));
+ sum->netmask = ipa_mkmask(mlen);
+ tm = (union ospf_lsa_sum_tm *) (sum + 1);
+ tm->metric = metric;
+ tm->tos.tos = 0;
+
+ lsasum_calculate(&lsa, body);
+ en = lsa_install_new(&lsa, body, oa);
+ ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
+}
+
+void
+check_sum_lsa(struct proto_ospf *po, ort *nf, int dest)
+{
+ struct proto *p = &po->proto;
+ struct ospf_area *oa;
+ struct area_net *anet;
+ int flush, mlen;
+ ip_addr ip;
+
+ if (po->areano < 2) return;
+
+ if ((nf->n.type > RTS_OSPF_IA) && (nf->o.type > RTS_OSPF_IA)) return;
+
+ WALK_LIST(oa, po->area_list)
+ {
+ flush = 0;
+ if ((nf->n.metric1 >= LSINFINITY) || (nf->n.type > RTS_OSPF_IA))
+ flush = 1;
+ if ((dest == ORT_ROUTER) && (!(nf->n.capa & ORTA_ABR)))
+ flush = 1;
+ if (nf->n.oa->areaid == oa->areaid)
+ flush = 1;
+ /* FIXME: Test next hop - is it in actual area? */
+ if ((dest == ORT_ROUTER) && oa->stub)
+ flush = 1;
+ /* FIXME stub for networks? */
+
+ mlen = nf->fn.pxlen;
+ ip = ipa_and(nf->fn.prefix, ipa_mkmask(mlen));
+ if((!oa->trcap) && fib_route(&oa->net_fib, ip, mlen)) /* The route fits into some area */
+ flush = 1;
+
+ if(flush) /* FIXME Go on... */
+ {
+ flush_sum_lsa(oa, &nf->fn, dest);
+ continue;
+ }
+ originate_sum_lsa(oa, &nf->fn, dest, nf->n.metric1);
+ }
+}
+
+void
+check_sum_areas(struct proto_ospf *po)
+{
+ struct proto *p = &po->proto;
+ struct ospf_area *oa;
+ struct area_net *anet;
+
+ WALK_LIST(oa, po->area_list)
+ {
+ ; /* FIXME */
+ }
+}
+
+
/**
* originate_ext_lsa - new route received from nest and filters
* @n: network prefix and mask
@@ -397,8 +570,7 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
struct proto *p = &po->proto;
struct ospf_area *oa;
struct ospf_lsa_ext *ext1, *ext2;
- int i;
- int max;
+ int i, max;
OSPF_TRACE(D_EVENTS, "Originating Ext lsa for %I/%d.", n->n.prefix,
n->n.pxlen);
@@ -408,6 +580,7 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
lsa.type = LSA_T_EXT;
lsa.rt = rtid;
lsa.sn = LSA_INITSEQNO;
+
body = originate_ext_lsa_body(n, e, po, attrs);
lsa.length = sizeof(struct ospf_lsa_ext) + sizeof(struct ospf_lsa_ext_tos) +
sizeof(struct ospf_lsa_header);
@@ -440,9 +613,12 @@ originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
lsasum_calculate(&lsa, body);
WALK_LIST(oa, po->area_list)
{
- en = lsa_install_new(&lsa, body, oa);
- ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
- body = originate_ext_lsa_body(n, e, po, attrs);
+ if (!oa->stub)
+ {
+ en = lsa_install_new(&lsa, body, oa);
+ ospf_lsupd_flood(NULL, NULL, &en->lsa, NULL, oa, 1);
+ body = originate_ext_lsa_body(n, e, po, attrs);
+ }
}
mb_free(body);
@@ -617,6 +793,7 @@ ospf_hash_get(struct top_graph *f, u32 lsa, u32 rtr, u32 type)
e->dist = LSINFINITY;
e->nhi = NULL;
e->nh = ipa_from_u32(0);
+ e->lb = ipa_from_u32(0);
e->lsa.id = lsa;
e->lsa.rt = rtr;
e->lsa.type = type;
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 55ecb4f..c6031c5 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -1,7 +1,7 @@
/*
* BIRD -- OSPF
*
- * (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
+ * (c) 1999--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -21,15 +21,15 @@ struct top_hash_entry
void *lsa_body;
bird_clock_t inst_t; /* Time of installation into DB */
ip_addr nh; /* Next hop */
+ ip_addr lb; /* Link back */
struct iface *nhi;
- u16 dist; /* Distance from the root */
+ u32 dist; /* Distance from the root */
u16 ini_age;
u8 color;
#define OUTSPF 0
#define CANDIDATE 1
#define INSPF 2
u8 padding;
- u16 padding2;
};
struct top_graph
@@ -62,5 +62,11 @@ int can_flush_lsa(struct ospf_area *oa);
int max_ext_lsa(unsigned pxlen);
void originate_ext_lsa(net * n, rte * e, struct proto_ospf *po,
struct ea_list *attrs);
+void check_sum_lsa(struct proto_ospf *po, ort *nf, int);
+void originate_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type, int metric);
+void flush_sum_lsa(struct ospf_area *oa, struct fib_node *fn, int type);
+
+
+
#endif /* _BIRD_OSPF_TOPOLOGY_H_ */