Changes OSPF to generate stub networks for non-primary addresses.

Also does some reorganization in RT LSA announcement.
This commit is contained in:
Ondrej Zajicek 2009-06-10 23:45:08 +02:00
parent b99d378698
commit 3d15dcdb1c
6 changed files with 184 additions and 109 deletions

View file

@ -327,6 +327,42 @@ mb_allocz(pool *p, unsigned size)
return x; return x;
} }
/**
* mb_realloc - reallocate a memory block
* @p: pool
* @m: memory block
* @size: new size of the block
*
* mb_realloc() changes the size of the memory block @m to a given size.
* The contents will be unchanged to the minimum of the old and new sizes;
* newly allocated memory will be uninitialized. If @m is NULL, the call
* is equivalent to mb_alloc(@p, @size).
*
* Like mb_alloc(), mb_realloc() also returns a pointer to the memory
* chunk , not to the resource, hence you have to free it using
* mb_free(), not rfree().
*/
void *
mb_realloc(pool *p, void *m, unsigned size)
{
struct mblock *ob = NULL;
if (m)
{
ob = SKIP_BACK(struct mblock, data, m);
if (ob->r.n.next)
rem_node(&ob->r.n);
}
struct mblock *b = xrealloc(ob, sizeof(struct mblock) + size);
b->r.class = &mb_class;
add_tail(&p->inside, &b->r.n);
b->size = size;
return b->data;
}
/** /**
* mb_free - free a memory block * mb_free - free a memory block
* @m: memory block * @m: memory block
@ -339,3 +375,4 @@ mb_free(void *m)
struct mblock *b = SKIP_BACK(struct mblock, data, m); struct mblock *b = SKIP_BACK(struct mblock, data, m);
rfree(b); rfree(b);
} }

View file

@ -47,6 +47,7 @@ extern pool root_pool;
void *mb_alloc(pool *, unsigned size); void *mb_alloc(pool *, unsigned size);
void *mb_allocz(pool *, unsigned size); void *mb_allocz(pool *, unsigned size);
void *mb_realloc(pool *p, void *m, unsigned size);
void mb_free(void *); void mb_free(void *);
/* Memory pools with linear allocation */ /* Memory pools with linear allocation */
@ -75,12 +76,13 @@ void sl_free(slab *, void *);
#ifdef HAVE_LIBDMALLOC #ifdef HAVE_LIBDMALLOC
/* /*
* The standard dmalloc macros tend to produce lots of namespace * The standard dmalloc macros tend to produce lots of namespace
* conflicts and we use only xmalloc and xfree, so we can define * conflicts and we use only xmalloc, xrealloc and xfree, so we
* the stubs ourselves. * can define the stubs ourselves.
*/ */
#define DMALLOC_DISABLE #define DMALLOC_DISABLE
#include <dmalloc.h> #include <dmalloc.h>
#define xmalloc(size) _xmalloc_leap(__FILE__, __LINE__, size) #define xmalloc(size) _xmalloc_leap(__FILE__, __LINE__, size)
#define xrealloc(size) _xrealloc_leap(__FILE__, __LINE__, size)
#define xfree(ptr) _xfree_leap(__FILE__, __LINE__, ptr) #define xfree(ptr) _xfree_leap(__FILE__, __LINE__, ptr)
#else #else
/* /*
@ -89,7 +91,9 @@ void sl_free(slab *, void *);
* the renaming. * the renaming.
*/ */
#define xmalloc bird_xmalloc #define xmalloc bird_xmalloc
#define xrealloc bird_xrealloc
void *xmalloc(unsigned); void *xmalloc(unsigned);
void *xrealloc(void *, unsigned);
#define xfree(x) free(x) #define xfree(x) free(x)
#endif #endif

View file

@ -32,4 +32,24 @@ xmalloc(unsigned size)
die("Unable to allocate %d bytes of memory", size); die("Unable to allocate %d bytes of memory", size);
} }
/**
* xrealloc - realloc with checking
* @ptr: original memory block
* @size: block size
*
* This function is equivalent to realloc() except that in case of
* failure it calls die() to quit the program instead of returning
* a %NULL pointer.
*
* Wherever possible, please use the memory resources instead.
*/
void *
xrealloc(void *ptr, unsigned size)
{
void *p = realloc(ptr, size);
if (p)
return p;
die("Unable to allocate %d bytes of memory", size);
}
#endif #endif

View file

@ -76,6 +76,9 @@
#include <stdlib.h> #include <stdlib.h>
#include "ospf.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_better(struct rte *new, struct rte *old);
static int ospf_rte_same(struct rte *new, struct rte *old); static int ospf_rte_same(struct rte *new, struct rte *old);
static void ospf_disp(timer *timer); static void ospf_disp(timer *timer);
@ -124,6 +127,9 @@ ospf_start(struct proto *p)
po->disp_timer->hook = ospf_disp; po->disp_timer->hook = ospf_disp;
po->disp_timer->recurrent = po->tick; po->disp_timer->recurrent = po->tick;
tm_start(po->disp_timer, 1); 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->iface_list));
init_list(&(po->area_list)); init_list(&(po->area_list));
fib_init(&po->rtf, p->pool, sizeof(ort), 16, ospf_rt_initort); 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->accept_ra_types = RA_OPTIMAL;
p->rt_notify = ospf_rt_notify; p->rt_notify = ospf_rt_notify;
p->if_notify = ospf_iface_notify; p->if_notify = ospf_iface_notify;
p->ifa_notify = ospf_ifa_notify;
p->rte_better = ospf_rte_better; p->rte_better = ospf_rte_better;
p->rte_same = ospf_rte_same; p->rte_same = ospf_rte_same;
@ -429,7 +436,7 @@ ospf_shutdown(struct proto *p)
return PS_DOWN; return PS_DOWN;
} }
void static void
ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED, ospf_rt_notify(struct proto *p, net * n, rte * new, rte * old UNUSED,
ea_list * attrs) ea_list * attrs)
{ {
@ -473,6 +480,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 static void
ospf_get_status(struct proto *p, byte * buf) ospf_get_status(struct proto *p, byte * buf)
{ {

View file

@ -550,6 +550,8 @@ struct proto_ospf
int rfc1583; /* RFC1583 compatibility */ int rfc1583; /* RFC1583 compatibility */
int ebit; /* Did I originate any ext lsa? */ int ebit; /* Did I originate any ext lsa? */
struct ospf_area *backbone; /* If exists */ struct ospf_area *backbone; /* If exists */
void *lsab; /* LSA buffer used when originating router LSAs */
int lsab_size, lsab_used;
}; };
struct ospf_iface_patt struct ospf_iface_patt
@ -585,8 +587,6 @@ int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
struct linpool *pool); struct linpool *pool);
struct ea_list *ospf_make_tmp_attrs(struct rte *rt, 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_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_rt_lsa(struct ospf_area *oa);
void schedule_rtcalc(struct proto_ospf *po); void schedule_rtcalc(struct proto_ospf *po);
void schedule_net_lsa(struct ospf_iface *ifa); void schedule_net_lsa(struct ospf_iface *ifa);

View file

@ -22,177 +22,165 @@
int ptp_unnumbered_stub_lsa = 0; 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 * static void *
originate_rt_lsa_body(struct ospf_area *oa, u16 * length) originate_rt_lsa_body(struct ospf_area *oa, u16 * length)
{ {
struct proto_ospf *po = oa->po; struct proto_ospf *po = oa->po;
struct ospf_iface *ifa; struct ospf_iface *ifa;
int j = 0, k = 0; int i = 0, j = 0, k = 0, bitv = 0;
u16 i = 0;
struct ospf_lsa_rt *rt; struct ospf_lsa_rt *rt;
struct ospf_lsa_rt_link *ln, *ln_after; struct ospf_lsa_rt_link *ln;
struct ospf_neighbor *neigh; struct ospf_neighbor *neigh;
DBG("%s: Originating RT_lsa body for area \"%I\".\n", po->proto.name, DBG("%s: Originating RT_lsa body for area \"%I\".\n", po->proto.name,
oa->areaid); oa->areaid);
WALK_LIST(ifa, po->iface_list) ASSERT(po->lsab_used == 0);
{ rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt));
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));
if (po->areano > 1) if (po->areano > 1)
rt->veb.bit.b = 1; rt->veb.bit.b = 1;
if ((po->ebit) && (!oa->stub)) if ((po->ebit) && (!oa->stub))
rt->veb.bit.e = 1; rt->veb.bit.e = 1;
ln = (struct ospf_lsa_rt_link *) (rt + 1); rt = NULL; /* buffer might be reallocated later */
ln_after = ln + i;
WALK_LIST(ifa, po->iface_list) 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); neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) if ((neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff))
rt->veb.bit.v = 1; bitv = 1;
} }
if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN)) if ((ifa->oa != oa) || (ifa->state == OSPF_IS_DOWN))
continue; continue;
if (ln == ln_after) /* BIRD does not support interface loops */
die("LSA space overflow"); ASSERT(ifa->state != OSPF_IS_LOOP);
if (ifa->state == OSPF_IS_LOOP) switch (ifa->type)
{
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)
{ {
case OSPF_IT_PTP: /* rfc2328 - pg126 */ case OSPF_IT_PTP: /* RFC2328 - 12.4.1.1 */
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL)) 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->type = LSART_PTP;
ln->id = neigh->rid; 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->metric = ifa->cost;
ln->notos = 0; ln->notos = 0;
if (ifa->iface->addr->flags & IA_UNNUMBERED) i++;
{ master = 1;
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;
}
} }
break; break;
case OSPF_IT_BCAST:
case OSPF_IT_BCAST: /* RFC2328 - 12.4.1.2 */
case OSPF_IT_NBMA: case OSPF_IT_NBMA:
if (ifa->state == OSPF_IS_WAITING) if (ifa->state == OSPF_IS_WAITING)
{ break;
ln->type = LSART_STUB;
ln->data = ipa_to_u32(ipa_mkmask(ifa->iface->addr->pxlen)); j = 0, k = 0;
ln->id = ipa_to_u32(ifa->iface->addr->prefix) & ln->data; WALK_LIST(neigh, ifa->neigh_list)
ln->metric = ifa->cost;
ln->notos = 0;
}
else
{
j = 0, k = 0;
WALK_LIST(neigh, ifa->neigh_list)
{ {
if ((neigh->rid == ifa->drid) && (neigh->state == NEIGHBOR_FULL)) if ((neigh->rid == ifa->drid) && (neigh->state == NEIGHBOR_FULL))
k = 1; k = 1;
if (neigh->state == NEIGHBOR_FULL) if (neigh->state == NEIGHBOR_FULL)
j = 1; 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->type = LSART_NET;
ln->id = ipa_to_u32(ifa->drip); ln->id = ipa_to_u32(ifa->drip);
ln->data = ipa_to_u32(ifa->iface->addr->ip); ln->data = ipa_to_u32(ifa->iface->addr->ip);
ln->metric = ifa->cost; ln->metric = ifa->cost;
ln->notos = 0; 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; break;
case OSPF_IT_VLINK:
case OSPF_IT_VLINK: /* RFC2328 - 12.4.1.3 */
neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list); neigh = (struct ospf_neighbor *) HEAD(ifa->neigh_list);
if ((!EMPTY_LIST(ifa->neigh_list)) && (neigh->state == NEIGHBOR_FULL) && (ifa->cost <= 0xffff)) 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->type = LSART_VLNK;
ln->id = neigh->rid; ln->id = neigh->rid;
ln->data = ipa_to_u32(ifa->iface->addr->ip);
ln->metric = ifa->cost; ln->metric = ifa->cost;
ln->notos = 0; ln->notos = 0;
} i++;
else master = 1;
{
ln--;
i--; /* No link added */
} }
break; break;
default: default:
ln--;
i--; /* No link added */
log("Unknown interface type %s", ifa->iface->name); log("Unknown interface type %s", ifa->iface->name);
break; 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; rt->links = i;
*length = i * sizeof(struct ospf_lsa_rt_link) + sizeof(struct ospf_lsa_rt) + rt->veb.bit.v = bitv;
sizeof(struct ospf_lsa_header); *length = po->lsab_used + sizeof(struct ospf_lsa_header);
return rt; return lsab_flush(po);
} }
/** /**