summaryrefslogtreecommitdiff
path: root/proto/ospf
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf')
-rw-r--r--proto/ospf/ospf.c28
-rw-r--r--proto/ospf/ospf.h4
-rw-r--r--proto/ospf/topology.c196
3 files changed, 121 insertions, 107 deletions
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 69d37241..4ad6ef46 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -76,6 +76,9 @@
#include <stdlib.h>
#include "ospf.h"
+
+static void ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, ea_list * attrs);
+static void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
static int ospf_rte_better(struct rte *new, struct rte *old);
static int ospf_rte_same(struct rte *new, struct rte *old);
static void ospf_disp(timer *timer);
@@ -124,6 +127,9 @@ ospf_start(struct proto *p)
po->disp_timer->hook = ospf_disp;
po->disp_timer->recurrent = po->tick;
tm_start(po->disp_timer, 1);
+ po->lsab_size = 256;
+ po->lsab_used = 0;
+ po->lsab = mb_alloc(p->pool, po->lsab_size);
init_list(&(po->iface_list));
init_list(&(po->area_list));
fib_init(&po->rtf, p->pool, sizeof(ort), 16, ospf_rt_initort);
@@ -227,6 +233,7 @@ ospf_init(struct proto_config *c)
p->accept_ra_types = RA_OPTIMAL;
p->rt_notify = ospf_rt_notify;
p->if_notify = ospf_iface_notify;
+ p->ifa_notify = ospf_ifa_notify;
p->rte_better = ospf_rte_better;
p->rte_same = ospf_rte_same;
@@ -429,7 +436,7 @@ ospf_shutdown(struct proto *p)
return PS_DOWN;
}
-void
+static void
ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
ea_list * attrs)
{
@@ -474,6 +481,25 @@ ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
}
static void
+ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
+{
+ struct proto_ospf *po = (struct proto_ospf *) p;
+ struct ospf_iface *ifa;
+
+ if ((a->flags & IA_SECONDARY) || (a->flags & IA_UNNUMBERED))
+ return;
+
+ WALK_LIST(ifa, po->iface_list)
+ {
+ if (ifa->iface == a->iface)
+ {
+ schedule_rt_lsa(ifa->oa);
+ return;
+ }
+ }
+}
+
+static void
ospf_get_status(struct proto *p, byte * buf)
{
struct proto_ospf *po = (struct proto_ospf *) p;
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index fb78af4e..71f99d34 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -550,6 +550,8 @@ struct proto_ospf
int rfc1583; /* RFC1583 compatibility */
int ebit; /* Did I originate any ext lsa? */
struct ospf_area *backbone; /* If exists */
+ void *lsab; /* LSA buffer used when originating router LSAs */
+ int lsab_size, lsab_used;
};
struct ospf_iface_patt
@@ -585,8 +587,6 @@ int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
struct linpool *pool);
struct ea_list *ospf_make_tmp_attrs(struct rte *rt, struct linpool *pool);
void ospf_store_tmp_attrs(struct rte *rt, struct ea_list *attrs);
-void ospf_rt_notify(struct proto *p, net *n, rte *new, rte *old,
- ea_list * attrs);
void schedule_rt_lsa(struct ospf_area *oa);
void schedule_rtcalc(struct proto_ospf *po);
void schedule_net_lsa(struct ospf_iface *ifa);
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index a15d2e35..18100f7e 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -23,176 +23,164 @@
int ptp_unnumbered_stub_lsa = 0;
static void *
+lsab_alloc(struct proto_ospf *po, unsigned size)
+{
+ unsigned offset = po->lsab_used;
+ po->lsab_used += size;
+ if (po->lsab_used > po->lsab_size)
+ {
+ po->lsab_size = MAX(po->lsab_used, 2 * po->lsab_size);
+ po->lsab = mb_realloc(po->proto.pool, po->lsab, po->lsab_size);
+ }
+ return ((byte *) po->lsab) + offset;
+}
+
+static inline void *
+lsab_allocz(struct proto_ospf *po, unsigned size)
+{
+ void *r = lsab_alloc(po, size);
+ bzero(r, size);
+ return r;
+}
+
+static inline void *
+lsab_flush(struct proto_ospf *po)
+{
+ void *r = mb_alloc(po->proto.pool, po->lsab_size);
+ memcpy(r, po->lsab, po->lsab_used);
+ po->lsab_used = 0;
+ return r;
+}
+
+
+static void *
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;
- u16 i = 0;
+ int i = 0, j = 0, k = 0, bitv = 0;
struct ospf_lsa_rt *rt;
- struct ospf_lsa_rt_link *ln, *ln_after;
+ struct ospf_lsa_rt_link *ln;
struct ospf_neighbor *neigh;
DBG("%s: Originating RT_lsa body for area \"%I\".\n", po->proto.name,
oa->areaid);
-
- WALK_LIST(ifa, po->iface_list)
- {
- if ((ifa->oa == oa) && (ifa->state != OSPF_IS_DOWN))
- {
- i++;
- if ((ifa->type == OSPF_IT_PTP) && (ifa->state == OSPF_IS_PTP) &&
- (ptp_unnumbered_stub_lsa || !(ifa->iface->addr->flags & IA_UNNUMBERED)))
- i++;
- }
- }
- rt = mb_allocz(po->proto.pool, sizeof(struct ospf_lsa_rt) +
- i * sizeof(struct ospf_lsa_rt_link));
+
+ ASSERT(po->lsab_used == 0);
+ rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
if (po->areano > 1)
rt->veb.bit.b = 1;
if ((po->ebit) && (!oa->stub))
rt->veb.bit.e = 1;
- ln = (struct ospf_lsa_rt_link *) (rt + 1);
- ln_after = ln + i;
+ rt = NULL; /* buffer might be reallocated later */
WALK_LIST(ifa, po->iface_list)
{
- if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) && (!EMPTY_LIST(ifa->neigh_list)))
+ int master = 0;
+
+ if ((ifa->type == OSPF_IT_VLINK) && (ifa->voa == oa) &&
+ (!EMPTY_LIST(ifa->neigh_list)))
{
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
- rt->veb.bit.v = 1;
+ bitv = 1;
}
if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
continue;
- if (ln == ln_after)
- die("LSA space overflow");
+ /* BIRD does not support interface loops */
+ ASSERT(ifa->state != OSPF_IS_LOOP);
- if (ifa->state == OSPF_IS_LOOP)
- {
- ln->type = 3;
- ln->id = ipa_to_u32(ifa->iface->addr->ip);
- ln->data = 0xffffffff;
- ln->metric = 0;
- ln->notos = 0;
- }
- else
- {
- switch (ifa->type)
+ switch (ifa->type)
{
- case OSPF_IT_PTP: /* rfc2328 - pg126 */
+ case OSPF_IT_PTP: /* RFC2328 - 12.4.1.1 */
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL))
{
+ ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
ln->type = LSART_PTP;
ln->id = neigh->rid;
+ ln->data = (ifa->iface->addr->flags & IA_UNNUMBERED) ?
+ ifa->iface->index : ipa_to_u32(ifa->iface->addr->ip);
ln->metric = ifa->cost;
ln->notos = 0;
- if (ifa->iface->addr->flags & IA_UNNUMBERED)
- {
- ln->data = ifa->iface->index;
- }
- else
- {
- ln->data = ipa_to_u32(ifa->iface->addr->ip);
- }
- }
- else
- {
- ln--;
- i--; /* No link added */
- }
-
- if ((ifa->state == OSPF_IS_PTP) &&
- (ptp_unnumbered_stub_lsa || !(ifa->iface->addr->flags & IA_UNNUMBERED)))
- {
- ln++;
- if (ln == ln_after)
- die("LSA space overflow");
-
- ln->type = LSART_STUB;
- ln->metric = ifa->cost;
- ln->notos = 0;
- if (ifa->iface->addr->flags & IA_UNNUMBERED)
- {
- ln->id = ipa_to_u32(ifa->iface->addr->opposite);
- ln->data = 0xffffffff;
- }
- else
- {
- ln->data = ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
- ln->id = ipa_to_u32(ifa->iface->addr->prefix) & ln->data;
- }
+ i++;
+ master = 1;
}
break;
- case OSPF_IT_BCAST:
+
+ case OSPF_IT_BCAST: /* RFC2328 - 12.4.1.2 */
case OSPF_IT_NBMA:
if (ifa->state == OSPF_IS_WAITING)
- {
- ln->type = LSART_STUB;
- ln->data = ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
- ln->id = ipa_to_u32(ifa->iface->addr->prefix) & ln->data;
- ln->metric = ifa->cost;
- ln->notos = 0;
- }
- else
- {
- j = 0, k = 0;
- WALK_LIST(neigh, ifa->neigh_list)
+ break;
+
+ j = 0, k = 0;
+ WALK_LIST(neigh, ifa->neigh_list)
{
if ((neigh->rid == ifa->drid) && (neigh->state == NEIGHBOR_FULL))
k = 1;
if (neigh->state == NEIGHBOR_FULL)
j = 1;
}
- if (((ifa->state == OSPF_IS_DR) && (j == 1)) || (k == 1))
+
+ if (((ifa->state == OSPF_IS_DR) && (j == 1)) || (k == 1))
{
+ ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
ln->type = LSART_NET;
ln->id = ipa_to_u32(ifa->drip);
ln->data = ipa_to_u32(ifa->iface->addr->ip);
ln->metric = ifa->cost;
ln->notos = 0;
+ i++;
+ master = 1;
}
- else
- {
- ln->type = LSART_STUB;
- ln->data = ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen));
- ln->id = ipa_to_u32(ifa->iface->addr->prefix) & ln->data;
- ln->metric = ifa->cost;
- ln->notos = 0;
- }
- }
break;
- case OSPF_IT_VLINK:
+
+ case OSPF_IT_VLINK: /* RFC2328 - 12.4.1.3 */
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
{
+ ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
ln->type = LSART_VLNK;
ln->id = neigh->rid;
+ ln->data = ipa_to_u32(ifa->iface->addr->ip);
ln->metric = ifa->cost;
ln->notos = 0;
- }
- else
- {
- ln--;
- i--; /* No link added */
+ i++;
+ master = 1;
}
break;
+
default:
- ln--;
- i--; /* No link added */
log("Unknown interface type %s", ifa->iface->name);
break;
}
- }
- ln++;
+
+ /* Now we will originate stub areas for interfaces addresses */
+ struct ifa *a;
+ WALK_LIST(a, ifa->iface->addrs)
+ {
+ if (((a == ifa->iface->addr) && master) ||
+ (a->flags & IA_SECONDARY) ||
+ (a->flags & IA_UNNUMBERED))
+ continue;
+
+ ln = lsab_alloc(po, sizeof(struct ospf_lsa_rt_link));
+ ln->type = LSART_STUB;
+ ln->id = ipa_to_u32(a->prefix);
+ ln->data = ipa_to_u32(ipa_mkmask(a->pxlen));
+ ln->metric = ifa->cost;
+ ln->notos = 0;
+ i++;
+ }
}
+
+ rt = po->lsab;
rt->links = i;
- *length = i * sizeof(struct ospf_lsa_rt_link) + sizeof(struct ospf_lsa_rt) +
- sizeof(struct ospf_lsa_header);
- return rt;
+ rt->veb.bit.v = bitv;
+ *length = po->lsab_used + sizeof(struct ospf_lsa_header);
+ return lsab_flush(po);
}
/**