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

Kernel protocol now uses out_table resync mechanism for periodic scanning

parent 73ee8e18
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -542,8 +542,12 @@ channel_reset_import(struct channel *c)
static void
static void
channel_reset_export(struct channel *c)
channel_reset_export(struct channel *c)
{
{
  if (c->out_flush_refeed)
    rt_out_flush(c);

  /* Just free the routes */
  /* Just free the routes */
  rt_prune_sync(c->out_table, 1);
  rt_prune_sync(c->out_table, 1);
  bmap_reset(&c->out_seen_map, 1024);
}
}


/* Called by protocol to activate in_table */
/* Called by protocol to activate in_table */
@@ -584,6 +588,10 @@ channel_do_start(struct channel *c)


  bmap_init(&c->export_map, c->proto->pool, 1024);
  bmap_init(&c->export_map, c->proto->pool, 1024);
  bmap_init(&c->export_reject_map, c->proto->pool, 1024);
  bmap_init(&c->export_reject_map, c->proto->pool, 1024);

  if (c->out_table)
    bmap_init(&c->out_seen_map, c->proto->pool, 1024);

  memset(&c->stats, 0, sizeof(struct proto_stats));
  memset(&c->stats, 0, sizeof(struct proto_stats));


  channel_reset_limit(&c->rx_limit);
  channel_reset_limit(&c->rx_limit);
@@ -618,6 +626,8 @@ channel_do_flush(struct channel *c)
  /* This have to be done in here, as channel pool is freed before channel_do_down() */
  /* This have to be done in here, as channel pool is freed before channel_do_down() */
  bmap_free(&c->export_map);
  bmap_free(&c->export_map);
  bmap_free(&c->export_reject_map);
  bmap_free(&c->export_reject_map);
  if (c->out_table)
    bmap_free(&c->out_seen_map);
  c->in_table = NULL;
  c->in_table = NULL;
  c->reload_event = NULL;
  c->reload_event = NULL;
  c->out_table = NULL;
  c->out_table = NULL;
+2 −0
Original line number Original line Diff line number Diff line
@@ -509,6 +509,7 @@ struct channel {
  const struct filter *out_filter;	/* Output filter */
  const struct filter *out_filter;	/* Output filter */
  struct bmap export_map;		/* Keeps track which routes were really exported */
  struct bmap export_map;		/* Keeps track which routes were really exported */
  struct bmap export_reject_map;	/* Keeps track which routes were rejected by export filter */
  struct bmap export_reject_map;	/* Keeps track which routes were rejected by export filter */
  struct bmap out_seen_map;		/* Keeps track which routes have been seen by out_sync */
  struct channel_limit rx_limit;	/* Receive limit (for in_keep_filtered) */
  struct channel_limit rx_limit;	/* Receive limit (for in_keep_filtered) */
  struct channel_limit in_limit;	/* Input limit */
  struct channel_limit in_limit;	/* Input limit */
  struct channel_limit out_limit;	/* Output limit */
  struct channel_limit out_limit;	/* Output limit */
@@ -546,6 +547,7 @@ struct channel {
  u8 reload_pending;			/* Reloading and another reload is scheduled */
  u8 reload_pending;			/* Reloading and another reload is scheduled */
  u8 refeed_pending;			/* Refeeding and another refeed is scheduled */
  u8 refeed_pending;			/* Refeeding and another refeed is scheduled */
  u8 rpki_reload;			/* RPKI changes trigger channel reload */
  u8 rpki_reload;			/* RPKI changes trigger channel reload */
  u8 out_flush_refeed;			/* Feed by withdrawals on export reset */


  list net_feed;			/* Active net feeders (struct channel_net_feed) */
  list net_feed;			/* Active net feeders (struct channel_net_feed) */


+5 −1
Original line number Original line Diff line number Diff line
@@ -367,8 +367,12 @@ void rt_feed_channel_abort(struct channel *c);
int rt_reload_channel(struct channel *c);
int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all);
void rt_prune_sync(rtable *t, int all);
int rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, int refeed);
int rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
void rt_out_sync_start(struct channel *c);
_Bool rt_out_sync_mark(struct channel *c, struct rte_export *e);
void rt_out_sync_finish(struct channel *c);
void rt_out_flush(struct channel *c);




/* Default limit for ECMP next hops, defined in sysdep code */
/* Default limit for ECMP next hops, defined in sysdep code */
+77 −3
Original line number Original line Diff line number Diff line
@@ -691,7 +691,7 @@ rt_notify_merged(struct channel *c, struct rte_export_internal *e)
  /* Prepare new merged route */
  /* Prepare new merged route */
  if (e->new_best)
  if (e->new_best)
  {
  {
    ep->new_id = e->new->id;
    ep->new_id = e->new_best->id;
    if (!rt_export_merged(c, e->net, &ep->new, rte_update_pool, 0))
    if (!rt_export_merged(c, e->net, &ep->new, rte_update_pool, 0))
      ep->new.attrs = NULL;
      ep->new.attrs = NULL;
  }
  }
@@ -774,7 +774,7 @@ rte_export_store(struct channel *c, struct rte_export_internal *e)
  /* Apply export table */
  /* Apply export table */
  if (c->out_table)
  if (c->out_table)
  {
  {
    if (!rte_update_out(c, &(e->pub.new), &(e->pub.old), &(e->old_stored), e->refeed))
    if (!rte_update_out(c, &(e->pub.new), &(e->pub.old), &(e->old_stored), e->pub.new_id, e->refeed))
      return 0;
      return 0;
  }
  }
  else if (c->out_filter != FILTER_ACCEPT)
  else if (c->out_filter != FILTER_ACCEPT)
@@ -2471,7 +2471,7 @@ rt_prune_sync(rtable *t, int all)
 */
 */


int
int
rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, int refeed)
rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_stored, u32 id, int refeed)
{
{
  struct rtable *tab = c->out_table;
  struct rtable *tab = c->out_table;
  struct rte_storage **pos;
  struct rte_storage **pos;
@@ -2533,6 +2533,7 @@ rte_update_out(struct channel *c, rte *new, rte *old, struct rte_storage **old_s
  struct rte_storage *e = rte_store(new, net);
  struct rte_storage *e = rte_store(new, net);
  e->sender = c;
  e->sender = c;
  e->lastmod = current_time();
  e->lastmod = current_time();
  e->id = id;
  e->next = *pos;
  e->next = *pos;
  *pos = e;
  *pos = e;
  tab->rt_count++;
  tab->rt_count++;
@@ -2545,6 +2546,79 @@ drop_withdraw:
  return 0;
  return 0;
}
}


void
rt_out_sync_start(struct channel *c)
{
  ASSERT_DIE(c->out_table);
  ASSERT_DIE(c->ra_mode != RA_ANY);
  bmap_reset(&c->out_seen_map, 1024);
}

_Bool
rt_out_sync_mark(struct channel *c, struct rte_export *e)
{
  ASSERT_DIE(c->out_table);
  ASSERT_DIE(c->ra_mode != RA_ANY);

  net *n = net_find(c->out_table, e->old.net);
  if (!n || !n->routes)
    return 1;

  e->new = rte_copy(n->routes);
  e->new_id = n->routes->id;

  if (bmap_test(&c->out_seen_map, n->routes->id))
    return 0;

  bmap_set(&c->out_seen_map, n->routes->id);
  return 1;
}

void
rt_out_sync_finish(struct channel *c)
{
  ASSERT_DIE(c->out_table);
  ASSERT_DIE(c->ra_mode != RA_ANY);

  FIB_WALK(&c->out_table->fib, net, n)
  {
    if (!n->routes)
      continue;

    if (!bmap_test(&c->out_seen_map, n->routes->id))
    {
      struct rte_export ex = {
	.new_id = n->routes->id,
	.new = rte_copy(n->routes),
      };

      c->proto->rt_notify(c, &ex);
    }
  }
  FIB_WALK_END;
  bmap_reset(&c->out_seen_map, 1024);
}

void
rt_out_flush(struct channel *c)
{
  ASSERT_DIE(c->out_table);
  ASSERT_DIE(c->ra_mode != RA_ANY);

  FIB_WALK(&c->out_table->fib, net, n)
  {
    if (!n->routes)
      continue;

    struct rte_export ex = {
      .old_id = n->routes->id,
      .old = rte_copy(n->routes),
    };

    c->proto->rt_notify(c, &ex);
  }
  FIB_WALK_END;
}


/*
/*
 *	Hostcache
 *	Hostcache
+17 −104
Original line number Original line Diff line number Diff line
@@ -68,14 +68,12 @@
 */
 */


pool *krt_pool;
pool *krt_pool;
static linpool *krt_filter_lp;
static list krt_proto_list;
static list krt_proto_list;


void
void
krt_io_init(void)
krt_io_init(void)
{
{
  krt_pool = rp_new(&root_pool, "Kernel Syncer");
  krt_pool = rp_new(&root_pool, "Kernel Syncer");
  krt_filter_lp = lp_new_default(krt_pool);
  init_list(&krt_proto_list);
  init_list(&krt_proto_list);
  krt_sys_io_init();
  krt_sys_io_init();
}
}
@@ -538,61 +536,6 @@ krt_dump(struct proto *P)
 *	Routes
 *	Routes
 */
 */


static inline int
krt_is_installed(struct krt_proto *p, net *n)
{
  return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->id);
}

static void
krt_flush_routes(struct krt_proto *p)
{
  struct rtable *t = p->p.main_channel->table;

  KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
  FIB_WALK(&t->fib, net, n)
    {
      if (krt_is_installed(p, n))
	{
	  struct rte_export e = {
	    .old = rte_copy(n->routes),
	    .old_id = n->routes->id,
	  };

	  /* FIXME: this does not work if gw is changed in export filter */
	  krt_replace_rte(p, &e);
	}
    }
  FIB_WALK_END;
}

static _Bool
krt_export_net(struct krt_proto *p, net *net, rte *rt)
{
  struct channel *c = p->p.main_channel;
  const struct filter *filter = c->out_filter;

  if (c->ra_mode == RA_MERGED)
    return rt_export_merged(c, net, rt, krt_filter_lp, 1);

  if (!rte_is_valid(net->routes))
    return 0;

  if (filter == FILTER_REJECT)
    return 0;

  /* We could run krt_preexport() here, but it is already handled by krt_is_installed() */
  *rt = rte_copy(net->routes);

  if (filter == FILTER_ACCEPT)
    return 1;

  if (f_run(filter, rt, krt_filter_lp, FF_SILENT) > F_ACCEPT)
    return 0;

  return 1;
}

static int
static int
krt_same_dest(rte *k, rte *e)
krt_same_dest(rte *k, rte *e)
{
{
@@ -644,24 +587,14 @@ krt_got_route(struct krt_proto *p, rte *e, s8 src)
  if (!p->ready)
  if (!p->ready)
    goto ignore;
    goto ignore;


  net *n = net_find(p->p.main_channel->table, e->net);
  if (!rt_out_sync_mark(p->p.main_channel, &ex))

  if (!n || !krt_is_installed(p, n))
    goto delete;

  /* Rejected by filters */
  if (!krt_export_net(p, n, &ex.new))
    goto delete;

  /* Route to this destination was already seen. Strange, but it happens... */
  if (bmap_test(&p->seen_map, n->routes->id))
    goto aseen;
    goto aseen;


  /* Mark route as seen */
  if (!ex.new.attrs)
  bmap_set(&p->seen_map, n->routes->id);
    goto delete;


  /* TODO: There also may be changes in route eattrs, we ignore that for now. */
  /* TODO: There also may be changes in route eattrs, we ignore that for now. */
  if (!bmap_test(&p->sync_map, n->routes->id) || !krt_same_dest(e, &ex.new))
  if (!bmap_test(&p->sync_map, ex.new_id) || !krt_same_dest(e, &ex.new))
    goto update;
    goto update;


  goto seen;
  goto seen;
@@ -680,7 +613,6 @@ ignore:


update:
update:
  krt_trace_in(p, &ex.new, "updating");
  krt_trace_in(p, &ex.new, "updating");
  ex.new_id = n->routes->id;
  krt_replace_rte(p, &ex);
  krt_replace_rte(p, &ex);
  goto done;
  goto done;


@@ -690,39 +622,23 @@ delete:
  goto done;
  goto done;


done:
done:
  lp_flush(krt_filter_lp);
  return;
}
}


static void
static void
krt_init_scan(struct krt_proto *p)
krt_init_scan(struct krt_proto *p)
{
{
  bmap_reset(&p->seen_map, 1024);
  rt_out_sync_start(p->p.main_channel);
}
}


static void
static void
krt_prune(struct krt_proto *p)
krt_prune(struct krt_proto *p)
{
{
  struct rtable *t = p->p.main_channel->table;
  KRT_TRACE(p, D_EVENTS, "Sync finished, pruning table %s", p->p.main_channel->table->name);


  KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
  p->pruning = 1;
  FIB_WALK(&t->fib, net, n)
  rt_out_sync_finish(p->p.main_channel);
  {
  p->pruning = 0;
    if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id))
    {
      struct rte_export ex = {
	.new_id = n->routes->id
      };

      if (krt_export_net(p, n, &ex.new))
      {
	krt_trace_in(p, &ex.new, "installing");
	krt_replace_rte(p, &ex);
      }

      lp_flush(krt_filter_lp);
    }
  }
  FIB_WALK_END;


#ifdef KRT_ALLOW_LEARN
#ifdef KRT_ALLOW_LEARN
  if (KRT_CF->learn)
  if (KRT_CF->learn)
@@ -897,7 +813,7 @@ krt_rt_notify(struct channel *ch, struct rte_export *e)
    return;
    return;
#endif
#endif


  if (p->initialized)		/* Before first scan we don't touch the routes */
  if (p->initialized || p->ready && p->pruning)		/* Before first scan we don't touch the routes */
    krt_replace_rte(p, e);
    krt_replace_rte(p, e);
}
}


@@ -994,6 +910,7 @@ krt_init(struct proto_config *CF)
  // struct krt_config *cf = (void *) CF;
  // struct krt_config *cf = (void *) CF;


  p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
  p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
  p->p.main_channel->out_flush_refeed = 1;


  p->p.preexport = krt_preexport;
  p->p.preexport = krt_preexport;
  p->p.rt_notify = krt_rt_notify;
  p->p.rt_notify = krt_rt_notify;
@@ -1022,12 +939,11 @@ krt_start(struct proto *P)
  }
  }


  /* If it is needed, setup out table automagically */
  /* If it is needed, setup out table automagically */
  if (!TRIVIAL_FILTER(p->p.main_channel->out_filter))
  /* For now, setup out table always. 
  if (!TRIVIAL_FILTER(p->p.main_channel->out_filter)) */
    channel_setup_out_table(p->p.main_channel);
    channel_setup_out_table(p->p.main_channel);



  bmap_init(&p->sync_map, p->p.pool, 1024);
  bmap_init(&p->sync_map, p->p.pool, 1024);
  bmap_init(&p->seen_map, p->p.pool, 1024);
  add_tail(&krt_proto_list, &p->krt_node);
  add_tail(&krt_proto_list, &p->krt_node);


#ifdef KRT_ALLOW_LEARN
#ifdef KRT_ALLOW_LEARN
@@ -1057,7 +973,7 @@ krt_shutdown(struct proto *P)


  /* FIXME we should flush routes even when persist during reconfiguration */
  /* FIXME we should flush routes even when persist during reconfiguration */
  if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
  if (p->initialized && !KRT_CF->persist && (P->down_code != PDC_CMD_GR_DOWN))
    krt_flush_routes(p);
    rt_out_flush(p->p.main_channel);


  p->ready = 0;
  p->ready = 0;
  p->initialized = 0;
  p->initialized = 0;
@@ -1073,12 +989,9 @@ krt_shutdown(struct proto *P)
}
}


static int
static int
krt_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed UNUSED, int *export_changed)
krt_channel_reconfigure(struct channel *C UNUSED, struct channel_config *CC UNUSED, int *import_changed UNUSED, int *export_changed)
{
{
  if (!*export_changed)
  return !*export_changed;
    return 1;

  return (TRIVIAL_FILTER(C->out_filter) == TRIVIAL_FILTER(CC->out_filter));
}
}


static int
static int
Loading