Commit ff397df7 authored by Maria Matejka's avatar Maria Matejka
Browse files

Routing table is now a resource allocated from its own pool

This also fixes memory leaks from import/export tables being never
cleaned up and freed.
parent a9938b17
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -518,11 +518,12 @@ void
channel_setup_in_table(struct channel *c)
channel_setup_in_table(struct channel *c)
{
{
  struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
  struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));

  cf->name = "import";
  cf->name = "import";
  cf->addr_type = c->net_type;
  cf->addr_type = c->net_type;
  cf->internal = 1;


  c->in_table = mb_allocz(c->proto->pool, sizeof(struct rtable));
  c->in_table = rt_setup(c->proto->pool, cf);
  rt_setup(c->proto->pool, c->in_table, cf);


  c->reload_event = ev_new_init(c->proto->pool, channel_reload_loop, c);
  c->reload_event = ev_new_init(c->proto->pool, channel_reload_loop, c);
}
}
@@ -534,9 +535,9 @@ channel_setup_out_table(struct channel *c)
  struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
  struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
  cf->name = "export";
  cf->name = "export";
  cf->addr_type = c->net_type;
  cf->addr_type = c->net_type;
  cf->internal = 1;


  c->out_table = mb_allocz(c->proto->pool, sizeof(struct rtable));
  c->out_table = rt_setup(c->proto->pool, cf);
  rt_setup(c->proto->pool, c->out_table, cf);
}
}




@@ -609,6 +610,8 @@ channel_do_down(struct channel *c)
  c->reload_event = NULL;
  c->reload_event = NULL;
  c->out_table = NULL;
  c->out_table = NULL;


  /* The in_table and out_table are going to be freed by freeing their resource pools. */

  CALL(c->channel->cleanup, c);
  CALL(c->channel->cleanup, c);


  /* Schedule protocol shutddown */
  /* Schedule protocol shutddown */
+6 −1
Original line number Original line Diff line number Diff line
@@ -148,12 +148,15 @@ struct rtable_config {
  int gc_max_ops;			/* Maximum number of operations before GC is run */
  int gc_max_ops;			/* Maximum number of operations before GC is run */
  int gc_min_time;			/* Minimum time between two consecutive GC runs */
  int gc_min_time;			/* Minimum time between two consecutive GC runs */
  byte sorted;				/* Routes of network are sorted according to rte_better() */
  byte sorted;				/* Routes of network are sorted according to rte_better() */
  byte internal;			/* Internal table of a protocol */
  btime min_settle_time;		/* Minimum settle time for notifications */
  btime min_settle_time;		/* Minimum settle time for notifications */
  btime max_settle_time;		/* Maximum settle time for notifications */
  btime max_settle_time;		/* Maximum settle time for notifications */
};
};


typedef struct rtable {
typedef struct rtable {
  resource r;
  node n;				/* Node in list of all tables */
  node n;				/* Node in list of all tables */
  pool *rp;				/* Resource pool to allocate everything from, including itself */
  struct fib fib;
  struct fib fib;
  char *name;				/* Name of this table */
  char *name;				/* Name of this table */
  list channels;			/* List of attached channels (struct channel) */
  list channels;			/* List of attached channels (struct channel) */
@@ -311,7 +314,9 @@ void rt_lock_table(rtable *);
void rt_unlock_table(rtable *);
void rt_unlock_table(rtable *);
void rt_subscribe(rtable *tab, struct rt_subscription *s);
void rt_subscribe(rtable *tab, struct rt_subscription *s);
void rt_unsubscribe(struct rt_subscription *s);
void rt_unsubscribe(struct rt_subscription *s);
void rt_setup(pool *, rtable *, struct rtable_config *);
rtable *rt_setup(pool *, struct rtable_config *);
static inline void rt_shutdown(rtable *r) { rfree(r->rp); }

static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
static inline net *net_find_valid(rtable *tab, const net_addr *addr)
static inline net *net_find_valid(rtable *tab, const net_addr *addr)
{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
+111 −40
Original line number Original line Diff line number Diff line
@@ -1839,7 +1839,7 @@ rt_kick_settle_timer(rtable *tab)
  tab->base_settle_time = current_time();
  tab->base_settle_time = current_time();


  if (!tab->settle_timer)
  if (!tab->settle_timer)
    tab->settle_timer = tm_new_init(rt_table_pool, rt_settle_timer, tab, 0, 0);
    tab->settle_timer = tm_new_init(tab->rp, rt_settle_timer, tab, 0, 0);


  if (!tm_active(tab->settle_timer))
  if (!tm_active(tab->settle_timer))
    tm_set(tab->settle_timer, rt_settled_time(tab));
    tm_set(tab->settle_timer, rt_settled_time(tab));
@@ -1872,23 +1872,78 @@ rt_unsubscribe(struct rt_subscription *s)
  rt_unlock_table(s->tab);
  rt_unlock_table(s->tab);
}
}


void
static void
rt_setup(pool *p, rtable *t, struct rtable_config *cf)
rt_free(resource *_r)
{
  rtable *r = (rtable *) _r;

  DBG("Deleting routing table %s\n", r->name);
  ASSERT_DIE(r->use_count == 0);

  r->config->table = NULL;
  rem_node(&r->n);

  if (r->hostcache)
    rt_free_hostcache(r);

  /* Freed automagically by the resource pool
  fib_free(&r->fib);
  hmap_free(&r->id_map);
  rfree(r->rt_event);
  rfree(r->settle_timer);
  mb_free(r);
  */
}

static void
rt_res_dump(resource *_r)
{
  rtable *r = (rtable *) _r;
  debug("name \"%s\", addr_type=%s, rt_count=%u, use_count=%d\n",
      r->name, net_label[r->addr_type], r->rt_count, r->use_count);
}

static struct resclass rt_class = {
  .name = "Routing table",
  .size = sizeof(struct rtable),
  .free = rt_free,
  .dump = rt_res_dump,
  .lookup = NULL,
  .memsize = NULL,
};

rtable *
rt_setup(pool *pp, struct rtable_config *cf)
{
{
  bzero(t, sizeof(*t));
  int ns = strlen("Routing table ") + strlen(cf->name) + 1;
  void *nb = mb_alloc(pp, ns);
  ASSERT_DIE(ns - 1 == bsnprintf(nb, ns, "Routing table %s", cf->name));

  pool *p = rp_new(pp, nb);
  mb_move(nb, p);

  rtable *t = ralloc(p, &rt_class);
  t->rp = p;

  t->name = cf->name;
  t->name = cf->name;
  t->config = cf;
  t->config = cf;
  t->addr_type = cf->addr_type;
  t->addr_type = cf->addr_type;

  fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
  fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
  init_list(&t->channels);


  if (!cf->internal)
  {
    init_list(&t->channels);
    hmap_init(&t->id_map, p, 1024);
    hmap_init(&t->id_map, p, 1024);
    hmap_set(&t->id_map, 0);
    hmap_set(&t->id_map, 0);


    init_list(&t->subscribers);

    t->rt_event = ev_new_init(p, rt_event, t);
    t->rt_event = ev_new_init(p, rt_event, t);
    t->last_rt_change = t->gc_time = current_time();
    t->last_rt_change = t->gc_time = current_time();
  }


  init_list(&t->subscribers);
  return t;
}
}


/**
/**
@@ -2326,16 +2381,9 @@ rt_unlock_table(rtable *r)
  if (!--r->use_count && r->deleted)
  if (!--r->use_count && r->deleted)
    {
    {
      struct config *conf = r->deleted;
      struct config *conf = r->deleted;
      DBG("Deleting routing table %s\n", r->name);

      r->config->table = NULL;
      /* Delete the routing table by freeing its pool */
      if (r->hostcache)
      rt_shutdown(r);
	rt_free_hostcache(r);
      rem_node(&r->n);
      fib_free(&r->fib);
      hmap_free(&r->id_map);
      rfree(r->rt_event);
      rfree(r->settle_timer);
      mb_free(r);
      config_del_obstacle(conf);
      config_del_obstacle(conf);
    }
    }
}
}
@@ -2397,11 +2445,9 @@ rt_commit(struct config *new, struct config *old)
  WALK_LIST(r, new->tables)
  WALK_LIST(r, new->tables)
    if (!r->table)
    if (!r->table)
      {
      {
	rtable *t = mb_allocz(rt_table_pool, sizeof(struct rtable));
	r->table = rt_setup(rt_table_pool, r);
	DBG("\t%s: created\n", r->name);
	DBG("\t%s: created\n", r->name);
	rt_setup(rt_table_pool, t, r);
	add_tail(&routing_tables, &r->table->n);
	add_tail(&routing_tables, &t->n);
	r->table = t;
      }
      }
  DBG("\tdone\n");
  DBG("\tdone\n");
}
}
@@ -2566,6 +2612,9 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
    if (!old)
    if (!old)
      goto drop_withdraw;
      goto drop_withdraw;


    if (!net->routes)
      fib_delete(&tab->fib, net);

    return 1;
    return 1;
  }
  }


@@ -2600,6 +2649,10 @@ drop_update:
  c->stats.imp_updates_received++;
  c->stats.imp_updates_received++;
  c->stats.imp_updates_ignored++;
  c->stats.imp_updates_ignored++;
  rte_free(new);
  rte_free(new);

  if (!net->routes)
    fib_delete(&tab->fib, net);

  return 0;
  return 0;


drop_withdraw:
drop_withdraw:
@@ -2669,9 +2722,15 @@ rt_reload_channel_abort(struct channel *c)
void
void
rt_prune_sync(rtable *t, int all)
rt_prune_sync(rtable *t, int all)
{
{
  FIB_WALK(&t->fib, net, n)
  struct fib_iterator fit;

  FIB_ITERATE_INIT(&fit, &t->fib);

again:
  FIB_ITERATE_START(&t->fib, &fit, net, n)
  {
  {
    rte *e, **ee = &n->routes;
    rte *e, **ee = &n->routes;

    while (e = *ee)
    while (e = *ee)
    {
    {
      if (all || (e->flags & (REF_STALE | REF_DISCARD)))
      if (all || (e->flags & (REF_STALE | REF_DISCARD)))
@@ -2683,8 +2742,15 @@ rt_prune_sync(rtable *t, int all)
      else
      else
	ee = &e->next;
	ee = &e->next;
    }
    }

    if (all || !n->routes)
    {
      FIB_ITERATE_PUT(&fit);
      fib_delete(&t->fib, n);
      goto again;
    }
    }
  FIB_WALK_END;
  }
  FIB_ITERATE_END;
}
}




@@ -2750,6 +2816,9 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
    if (!old)
    if (!old)
      goto drop_withdraw;
      goto drop_withdraw;


    if (!net->routes)
      fib_delete(&tab->fib, net);

    return 1;
    return 1;
  }
  }


@@ -2809,7 +2878,7 @@ hc_remove(struct hostcache *hc, struct hostentry *he)
#define HC_LO_ORDER 10
#define HC_LO_ORDER 10


static void
static void
hc_alloc_table(struct hostcache *hc, unsigned order)
hc_alloc_table(struct hostcache *hc, pool *p, unsigned order)
{
{
  uint hsize = 1 << order;
  uint hsize = 1 << order;
  hc->hash_order = order;
  hc->hash_order = order;
@@ -2817,18 +2886,18 @@ hc_alloc_table(struct hostcache *hc, unsigned order)
  hc->hash_max = (order >= HC_HI_ORDER) ? ~0U : (hsize HC_HI_MARK);
  hc->hash_max = (order >= HC_HI_ORDER) ? ~0U : (hsize HC_HI_MARK);
  hc->hash_min = (order <= HC_LO_ORDER) ?  0U : (hsize HC_LO_MARK);
  hc->hash_min = (order <= HC_LO_ORDER) ?  0U : (hsize HC_LO_MARK);


  hc->hash_table = mb_allocz(rt_table_pool, hsize * sizeof(struct hostentry *));
  hc->hash_table = mb_allocz(p, hsize * sizeof(struct hostentry *));
}
}


static void
static void
hc_resize(struct hostcache *hc, unsigned new_order)
hc_resize(struct hostcache *hc, pool *p, unsigned new_order)
{
{
  struct hostentry **old_table = hc->hash_table;
  struct hostentry **old_table = hc->hash_table;
  struct hostentry *he, *hen;
  struct hostentry *he, *hen;
  uint old_size = 1 << hc->hash_order;
  uint old_size = 1 << hc->hash_order;
  uint i;
  uint i;


  hc_alloc_table(hc, new_order);
  hc_alloc_table(hc, p, new_order);
  for (i = 0; i < old_size; i++)
  for (i = 0; i < old_size; i++)
    for (he = old_table[i]; he != NULL; he=hen)
    for (he = old_table[i]; he != NULL; he=hen)
      {
      {
@@ -2839,7 +2908,7 @@ hc_resize(struct hostcache *hc, unsigned new_order)
}
}


static struct hostentry *
static struct hostentry *
hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsigned k)
hc_new_hostentry(struct hostcache *hc, pool *p, ip_addr a, ip_addr ll, rtable *dep, unsigned k)
{
{
  struct hostentry *he = sl_alloc(hc->slab);
  struct hostentry *he = sl_alloc(hc->slab);


@@ -2855,13 +2924,13 @@ hc_new_hostentry(struct hostcache *hc, ip_addr a, ip_addr ll, rtable *dep, unsig


  hc->hash_items++;
  hc->hash_items++;
  if (hc->hash_items > hc->hash_max)
  if (hc->hash_items > hc->hash_max)
    hc_resize(hc, hc->hash_order + HC_HI_STEP);
    hc_resize(hc, p, hc->hash_order + HC_HI_STEP);


  return he;
  return he;
}
}


static void
static void
hc_delete_hostentry(struct hostcache *hc, struct hostentry *he)
hc_delete_hostentry(struct hostcache *hc, pool *p, struct hostentry *he)
{
{
  rta_free(he->src);
  rta_free(he->src);


@@ -2871,20 +2940,20 @@ hc_delete_hostentry(struct hostcache *hc, struct hostentry *he)


  hc->hash_items--;
  hc->hash_items--;
  if (hc->hash_items < hc->hash_min)
  if (hc->hash_items < hc->hash_min)
    hc_resize(hc, hc->hash_order - HC_LO_STEP);
    hc_resize(hc, p, hc->hash_order - HC_LO_STEP);
}
}


static void
static void
rt_init_hostcache(rtable *tab)
rt_init_hostcache(rtable *tab)
{
{
  struct hostcache *hc = mb_allocz(rt_table_pool, sizeof(struct hostcache));
  struct hostcache *hc = mb_allocz(tab->rp, sizeof(struct hostcache));
  init_list(&hc->hostentries);
  init_list(&hc->hostentries);


  hc->hash_items = 0;
  hc->hash_items = 0;
  hc_alloc_table(hc, HC_DEF_ORDER);
  hc_alloc_table(hc, tab->rp, HC_DEF_ORDER);
  hc->slab = sl_new(rt_table_pool, sizeof(struct hostentry));
  hc->slab = sl_new(tab->rp, sizeof(struct hostentry));


  hc->lp = lp_new(rt_table_pool, LP_GOOD_SIZE(1024));
  hc->lp = lp_new(tab->rp, LP_GOOD_SIZE(1024));
  hc->trie = f_new_trie(hc->lp, 0);
  hc->trie = f_new_trie(hc->lp, 0);


  tab->hostcache = hc;
  tab->hostcache = hc;
@@ -2905,10 +2974,12 @@ rt_free_hostcache(rtable *tab)
	log(L_ERR "Hostcache is not empty in table %s", tab->name);
	log(L_ERR "Hostcache is not empty in table %s", tab->name);
    }
    }


  /* Freed automagically by the resource pool
  rfree(hc->slab);
  rfree(hc->slab);
  rfree(hc->lp);
  rfree(hc->lp);
  mb_free(hc->hash_table);
  mb_free(hc->hash_table);
  mb_free(hc);
  mb_free(hc);
  */
}
}


static void
static void
@@ -3051,7 +3122,7 @@ rt_update_hostcache(rtable *tab)
      he = SKIP_BACK(struct hostentry, ln, n);
      he = SKIP_BACK(struct hostentry, ln, n);
      if (!he->uc)
      if (!he->uc)
	{
	{
	  hc_delete_hostentry(hc, he);
	  hc_delete_hostentry(hc, tab->rp, he);
	  continue;
	  continue;
	}
	}


@@ -3076,7 +3147,7 @@ rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
    if (ipa_equal(he->addr, a) && (he->tab == dep))
    if (ipa_equal(he->addr, a) && (he->tab == dep))
      return he;
      return he;


  he = hc_new_hostentry(hc, a, ipa_zero(ll) ? a : ll, dep, k);
  he = hc_new_hostentry(hc, tab->rp, a, ipa_zero(ll) ? a : ll, dep, k);
  rt_update_hostentry(tab, he);
  rt_update_hostentry(tab, he);
  return he;
  return he;
}
}
+6 −5
Original line number Original line Diff line number Diff line
@@ -317,7 +317,7 @@ static void
krt_learn_scan(struct krt_proto *p, rte *e)
krt_learn_scan(struct krt_proto *p, rte *e)
{
{
  net *n0 = e->net;
  net *n0 = e->net;
  net *n = net_get(&p->krt_table, n0->n.addr);
  net *n = net_get(p->krt_table, n0->n.addr);
  rte *m, **mm;
  rte *m, **mm;


  e->attrs = rta_lookup(e->attrs);
  e->attrs = rta_lookup(e->attrs);
@@ -354,7 +354,7 @@ krt_learn_scan(struct krt_proto *p, rte *e)
static void
static void
krt_learn_prune(struct krt_proto *p)
krt_learn_prune(struct krt_proto *p)
{
{
  struct fib *fib = &p->krt_table.fib;
  struct fib *fib = &p->krt_table->fib;
  struct fib_iterator fit;
  struct fib_iterator fit;


  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
  KRT_TRACE(p, D_EVENTS, "Pruning inherited routes");
@@ -430,7 +430,7 @@ static void
krt_learn_async(struct krt_proto *p, rte *e, int new)
krt_learn_async(struct krt_proto *p, rte *e, int new)
{
{
  net *n0 = e->net;
  net *n0 = e->net;
  net *n = net_get(&p->krt_table, n0->n.addr);
  net *n = net_get(p->krt_table, n0->n.addr);
  rte *g, **gg, *best, **bestp, *old_best;
  rte *g, **gg, *best, **bestp, *old_best;


  e->attrs = rta_lookup(e->attrs);
  e->attrs = rta_lookup(e->attrs);
@@ -511,8 +511,9 @@ krt_learn_init(struct krt_proto *p)
    struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config));
    struct rtable_config *cf = mb_allocz(p->p.pool, sizeof(struct rtable_config));
    cf->name = "Inherited";
    cf->name = "Inherited";
    cf->addr_type = p->p.net_type;
    cf->addr_type = p->p.net_type;
    cf->internal = 1;


    rt_setup(p->p.pool, &p->krt_table, cf);
    p->krt_table = rt_setup(p->p.pool, cf);
  }
  }
}
}


@@ -524,7 +525,7 @@ krt_dump(struct proto *P)
  if (!KRT_CF->learn)
  if (!KRT_CF->learn)
    return;
    return;
  debug("KRT: Table of inheritable routes\n");
  debug("KRT: Table of inheritable routes\n");
  rt_dump(&p->krt_table);
  rt_dump(p->krt_table);
}
}


static void
static void
+1 −1
Original line number Original line Diff line number Diff line
@@ -49,7 +49,7 @@ struct krt_proto {
  struct krt_state sys;		/* Sysdep state */
  struct krt_state sys;		/* Sysdep state */


#ifdef KRT_ALLOW_LEARN
#ifdef KRT_ALLOW_LEARN
  struct rtable krt_table;	/* Internal table of inherited routes */
  struct rtable *krt_table;	/* Internal table of inherited routes */
#endif
#endif


#ifndef CONFIG_ALL_TABLES_AT_ONCE
#ifndef CONFIG_ALL_TABLES_AT_ONCE