From 3d15dcdb1cc91c694aa9319b86bb37510d7ed12b Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 10 Jun 2009 23:45:08 +0200 Subject: [PATCH] Changes OSPF to generate stub networks for non-primary addresses. Also does some reorganization in RT LSA announcement. --- lib/resource.c | 37 ++++++++ lib/resource.h | 8 +- lib/xmalloc.c | 20 +++++ proto/ospf/ospf.c | 28 +++++- proto/ospf/ospf.h | 4 +- proto/ospf/topology.c | 196 ++++++++++++++++++++---------------------- 6 files changed, 184 insertions(+), 109 deletions(-) diff --git a/lib/resource.c b/lib/resource.c index 9e626815..289af933 100644 --- a/lib/resource.c +++ b/lib/resource.c @@ -327,6 +327,42 @@ mb_allocz(pool *p, unsigned size) 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 * @m: memory block @@ -339,3 +375,4 @@ mb_free(void *m) struct mblock *b = SKIP_BACK(struct mblock, data, m); rfree(b); } + diff --git a/lib/resource.h b/lib/resource.h index 42ed26ed..8dd441f0 100644 --- a/lib/resource.h +++ b/lib/resource.h @@ -47,6 +47,7 @@ extern pool root_pool; void *mb_alloc(pool *, unsigned size); void *mb_allocz(pool *, unsigned size); +void *mb_realloc(pool *p, void *m, unsigned size); void mb_free(void *); /* Memory pools with linear allocation */ @@ -75,12 +76,13 @@ void sl_free(slab *, void *); #ifdef HAVE_LIBDMALLOC /* * The standard dmalloc macros tend to produce lots of namespace - * conflicts and we use only xmalloc and xfree, so we can define - * the stubs ourselves. + * conflicts and we use only xmalloc, xrealloc and xfree, so we + * can define the stubs ourselves. */ #define DMALLOC_DISABLE #include #define xmalloc(size) _xmalloc_leap(__FILE__, __LINE__, size) +#define xrealloc(size) _xrealloc_leap(__FILE__, __LINE__, size) #define xfree(ptr) _xfree_leap(__FILE__, __LINE__, ptr) #else /* @@ -89,7 +91,9 @@ void sl_free(slab *, void *); * the renaming. */ #define xmalloc bird_xmalloc +#define xrealloc bird_xrealloc void *xmalloc(unsigned); +void *xrealloc(void *, unsigned); #define xfree(x) free(x) #endif diff --git a/lib/xmalloc.c b/lib/xmalloc.c index bc386c83..da2f0941 100644 --- a/lib/xmalloc.c +++ b/lib/xmalloc.c @@ -32,4 +32,24 @@ xmalloc(unsigned 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 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 #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) { @@ -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 ospf_get_status(struct proto *p, byte * buf) { 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 @@ -22,177 +22,165 @@ 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); } /**