Commit 92b83238 authored by Maria Matejka's avatar Maria Matejka
Browse files

Merge commit '1b9189d5' into haugesund

parents 9b6db9f9 1b9189d5
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -519,14 +519,14 @@
    {
      STATIC_ATTR;
      ACCESS_RTE;
      struct rta *rta = (*fs->rte)->attrs;
      struct rta *rta = fs->rte->attrs;

      switch (sa.sa_code)
      {
      case SA_FROM:	RESULT(sa.f_type, ip, rta->from); break;
      case SA_GW:	RESULT(sa.f_type, ip, rta->nh.gw); break;
      case SA_NET:	RESULT(sa.f_type, net, (*fs->rte)->net->n.addr); break;
      case SA_PROTO:	RESULT(sa.f_type, s, (*fs->rte)->src->proto->name); break;
      case SA_NET:	RESULT(sa.f_type, net, fs->rte->net); break;
      case SA_PROTO:	RESULT(sa.f_type, s, fs->rte->src->proto->name); break;
      case SA_SOURCE:	RESULT(sa.f_type, i, rta->source); break;
      case SA_SCOPE:	RESULT(sa.f_type, i, rta->scope); break;
      case SA_DEST:	RESULT(sa.f_type, i, rta->dest); break;
@@ -550,7 +550,7 @@

    f_rta_cow(fs);
    {
      struct rta *rta = (*fs->rte)->attrs;
      struct rta *rta = fs->rte->attrs;

      switch (sa.sa_code)
      {
@@ -562,7 +562,7 @@
	{
	  ip_addr ip = v1.val.ip;
	  struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL;
	  neighbor *n = neigh_find((*fs->rte)->src->proto, ip, ifa, 0);
	  neighbor *n = neigh_find(fs->rte->src->proto, ip, ifa, 0);
	  if (!n || (n->scope == SCOPE_HOST))
	    runtime( "Invalid gw address" );

@@ -1314,7 +1314,7 @@
    struct rtable *table = rtc->table;
    ACCESS_RTE;
    ACCESS_EATTRS;
    const net_addr *net = (*fs->rte)->net->n.addr;
    const net_addr *net = fs->rte->net;

    /* We ignore temporary attributes, probably not a problem here */
    /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
+10 −69
Original line number Diff line number Diff line
@@ -74,10 +74,7 @@ struct filter_state {
  } stack;

  /* The route we are processing. This may be NULL to indicate no route available. */
  struct rte **rte;

  /* The old rta to be freed after filters are done. */
  struct rta *old_rta;
  struct rte *rte;

  /* Cached pointer to ea_list */
  struct ea_list **eattrs;
@@ -102,15 +99,7 @@ void (*bt_assert_hook)(int result, const struct f_line_item *assert);

static inline void f_cache_eattrs(struct filter_state *fs)
{
  fs->eattrs = &((*fs->rte)->attrs->eattrs);
}

static inline void f_rte_cow(struct filter_state *fs)
{
  if (!((*fs->rte)->flags & REF_COW))
    return;

  *fs->rte = rte_cow(*fs->rte);
  fs->eattrs = &(fs->rte->attrs->eattrs);
}

/*
@@ -119,22 +108,16 @@ static inline void f_rte_cow(struct filter_state *fs)
static void
f_rta_cow(struct filter_state *fs)
{
  if (!rta_is_cached((*fs->rte)->attrs))
  if (!rta_is_cached(fs->rte->attrs))
    return;

  /* Prepare to modify rte */
  f_rte_cow(fs);

  /* Store old rta to free it later, it stores reference from rte_cow() */
  fs->old_rta = (*fs->rte)->attrs;

  /*
   * Get shallow copy of rta. Fields eattrs and nexthops of rta are shared
   * with fs->old_rta (they will be copied when the cached rta will be obtained
   * at the end of f_run()), also the lock of hostentry is inherited (we
   * suppose hostentry is not changed by filters).
   */
  (*fs->rte)->attrs = rta_do_cow((*fs->rte)->attrs, fs->pool);
  fs->rte->attrs = rta_do_cow(fs->rte->attrs, fs->pool);

  /* Re-cache the ea_list */
  f_cache_eattrs(fs);
@@ -246,29 +229,15 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
/**
 * f_run - run a filter for a route
 * @filter: filter to run
 * @rte: route being filtered, may be modified
 * @rte: route being filtered, must be write-able
 * @tmp_pool: all filter allocations go from this pool
 * @flags: flags
 *
 * If filter needs to modify the route, there are several
 * posibilities. @rte might be read-only (with REF_COW flag), in that
 * case rw copy is obtained by rte_cow() and @rte is replaced. If
 * @rte is originally rw, it may be directly modified (and it is never
 * copied).
 *
 * The returned rte may reuse the (possibly cached, cloned) rta, or
 * (if rta was modified) contains a modified uncached rta, which
 * uses parts allocated from @tmp_pool and parts shared from original
 * rta. There is one exception - if @rte is rw but contains a cached
 * rta and that is modified, rta in returned rte is also cached.
 *
 * Ownership of cached rtas is consistent with rte, i.e.
 * if a new rte is returned, it has its own clone of cached rta
 * (and cached rta of read-only source rte is intact), if rte is
 * modified in place, old cached rta is possibly freed.
 * If @rte->attrs is cached, the returned rte allocates a new rta on
 * tmp_pool, otherwise the filters may modify it.
 */
enum filter_return
f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
f_run(const struct filter *filter, struct rte *rte, struct linpool *tmp_pool, int flags)
{
  if (filter == FILTER_ACCEPT)
    return F_ACCEPT;
@@ -276,7 +245,6 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
  if (filter == FILTER_REJECT)
    return F_REJECT;

  int rte_cow = ((*rte)->flags & REF_COW);
  DBG( "Running filter `%s'...", filter->name );

  /* Initialize the filter state */
@@ -293,32 +261,6 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
  /* Run the interpreter itself */
  enum filter_return fret = interpret(&filter_state, filter->root, NULL);

  if (filter_state.old_rta) {
    /*
     * Cached rta was modified and filter_state->rte contains now an uncached one,
     * sharing some part with the cached one. The cached rta should
     * be freed (if rte was originally COW, filter_state->old_rta is a clone
     * obtained during rte_cow()).
     *
     * This also implements the exception mentioned in f_run()
     * description. The reason for this is that rta reuses parts of
     * filter_state->old_rta, and these may be freed during rta_free(filter_state->old_rta).
     * This is not the problem if rte was COW, because original rte
     * also holds the same rta.
     */
    if (!rte_cow) {
      /* Cache the new attrs */
      (*filter_state.rte)->attrs = rta_lookup((*filter_state.rte)->attrs);

      /* Drop cached ea_list pointer */
      filter_state.eattrs = NULL;
    }

    /* Uncache the old attrs and drop the pointer as it is invalid now. */
    rta_free(filter_state.old_rta);
    filter_state.old_rta = NULL;
  }

  /* Process the filter output, log it and return */
  if (fret < F_ACCEPT) {
    if (!(filter_state.flags & FF_SILENT))
@@ -343,7 +285,7 @@ f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, i
 */

enum filter_return
f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool)
f_eval_rte(const struct f_line *expr, struct rte *rte, struct linpool *tmp_pool)
{
  filter_state = (struct filter_state) {
    .rte = rte,
@@ -354,8 +296,7 @@ f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool

  LOG_BUFFER_INIT(filter_state.buf);

  ASSERT(!((*rte)->flags & REF_COW));
  ASSERT(!rta_is_cached((*rte)->attrs));
  ASSERT(!rta_is_cached(rte->attrs));

  return interpret(&filter_state, expr, NULL);
}
+2 −2
Original line number Diff line number Diff line
@@ -51,8 +51,8 @@ struct filter {

struct rte;

enum filter_return f_run(const struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
enum filter_return f_eval_rte(const struct f_line *expr, struct rte **rte, struct linpool *tmp_pool);
enum filter_return f_run(const struct filter *filter, struct rte *rte, struct linpool *tmp_pool, int flags);
enum filter_return f_eval_rte(const struct f_line *expr, struct rte *rte, struct linpool *tmp_pool);
uint f_eval_int(const struct f_line *expr);
enum filter_return f_eval_buf(const struct f_line *expr, struct linpool *tmp_pool, buffer *buf);

+4 −18
Original line number Diff line number Diff line
@@ -211,9 +211,9 @@ struct proto {

  void (*if_notify)(struct proto *, unsigned flags, struct iface *i);
  void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a);
  void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
  void (*rt_notify)(struct proto *, struct channel *, const net_addr *net, struct rte *new, const struct rte *old);
  void (*neigh_notify)(struct neighbor *neigh);
  int (*preexport)(struct proto *, struct rte *rt);
  int (*preexport)(struct channel *, struct rte *rt);
  void (*reload_routes)(struct channel *);
  void (*feed_begin)(struct channel *, int initial);
  void (*feed_end)(struct channel *);
@@ -542,7 +542,7 @@ struct channel {
  struct rtable *in_table;		/* Internal table for received routes */
  struct event *reload_event;		/* Event responsible for reloading from in_table */
  struct fib_iterator reload_fit;	/* FIB iterator in in_table used during reloading */
  struct rte *reload_next_rte;		/* Route iterator in in_table used during reloading */
  struct rte_storage *reload_next_rte;	/* Route iterator in in_table used during reloading */
  u8 reload_active;			/* Iterator reload_fit is linked */

  u8 reload_pending;			/* Reloading and another reload is scheduled */
@@ -632,18 +632,4 @@ void *channel_config_new(const struct channel_class *cc, const char *name, uint
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
int channel_reconfigure(struct channel *c, struct channel_config *cf);


/* Moved from route.h to avoid dependency conflicts */
static inline void rte_update(struct proto *p, const net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); }

static inline void
rte_update3(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
{
  if (c->in_table && !rte_update_in(c, n, new, src))
    return;

  rte_update2(c, n, new, src);
}


#endif
+60 −23
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ typedef struct rtable {
  resource r;
  node n;				/* Node in list of all tables */
  pool *rp;				/* Resource pool to allocate everything from, including itself */
  struct slab *rte_slab;		/* Slab to allocate route objects */
  struct fib fib;
  struct f_trie *trie;			/* Trie of prefixes defined in fib */
  char *name;				/* Name of this table */
@@ -221,7 +222,7 @@ struct rt_flowspec_link {
#define NHU_DIRTY	3

typedef struct network {
  struct rte *routes;			/* Available routes for this network */
  struct rte_storage *routes;			/* Available routes for this network */
  struct fib_node n;			/* FIB flags reserved for kernel syncer */
} net;

@@ -253,25 +254,34 @@ struct hostentry {
};

typedef struct rte {
  struct rte *next;
  net *net;				/* Network this RTE belongs to */
  struct rta *attrs;			/* Attributes of this route */
  const net_addr *net;			/* Network this RTE belongs to */
  struct rte_src *src;			/* Route source that created the route */
  struct channel *sender;		/* Channel used to send the route to the routing table */
  struct rta *attrs;			/* Attributes of this route */
  btime lastmod;			/* Last modified (set by table) */
  u32 id;				/* Table specific route id */
  byte flags;				/* Flags (REF_...) */
  byte flags;				/* Table-specific flags */
  byte pflags;				/* Protocol-specific flags */
  btime lastmod;			/* Last modified */
} rte;

#define REF_COW		1		/* Copy this rte on write */
struct rte_storage {
  struct rte_storage *next;		/* Next in chain */
  struct rte rte;			/* Route data */
};

#define RTE_COPY(r, l)	((r) ? (((*(l)) = (r)->rte), (l)) : NULL)
#define RTE_OR_NULL(r)	((r) ? &((r)->rte) : NULL)

#define REF_FILTERED	2		/* Route is rejected by import filter */
#define REF_STALE	4		/* Route is stale in a refresh cycle */
#define REF_DISCARD	8		/* Route is scheduled for discard */
#define REF_MODIFY	16		/* Route is scheduled for modify */

/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_FILTERED); }
static inline int rte_is_valid_rte(rte *r) { return r && !(r->flags & REF_FILTERED); }
static inline int rte_is_valid_storage(struct rte_storage *r) { return r && rte_is_valid_rte(&r->rte); }

#define rte_is_valid(r)		_Generic((*r), rte: rte_is_valid_rte, struct rte_storage: rte_is_valid_storage)(r)

/* Route just has REF_FILTERED flag */
static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED); }
@@ -290,6 +300,40 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
#define RIC_REJECT	-1		/* Rejected by protocol */
#define RIC_DROP	-2		/* Silently dropped by protocol */

/**
 * rte_update - enter a new update to a routing table
 * @c: channel doing the update
 * @net: network address
 * @rte: a &rte representing the new route
 * @src: old route source identifier
 *
 * This function imports a new route to the appropriate table (via the channel).
 * Table keys are @net (obligatory) and @rte->attrs->src.
 * Both the @net and @rte pointers can be local.
 *
 * The route attributes (@rte->attrs) are obligatory. They can be also allocated
 * locally. Anyway, if you use an already-cached attribute object, you shall
 * call rta_clone() on that object yourself. (This semantics may change in future.)
 *
 * If the route attributes are local, you may set @rte->attrs->src to NULL, then
 * the protocol's default route source will be supplied.
 *
 * When rte_update() gets a route, it automatically validates it. This includes
 * checking for validity of the given network and next hop addresses and also
 * checking for host-scope or link-scope routes. Then the import filters are
 * processed and if accepted, the route is passed to route table recalculation.
 *
 * The accepted routes are then inserted into the table, replacing the old route
 * for the same @net identified by @src. Then the route is announced
 * to all the channels connected to the table using the standard export mechanism.
 * Setting @rte to NULL makes this a withdraw, otherwise @rte->src must be the same
 * as @src.
 *
 * All memory used for temporary allocations is taken from a special linpool
 * @rte_update_pool and freed when rte_update() finishes.
 */
void rte_update(struct channel *c, const net_addr *net, struct rte *rte, struct rte_src *src);

extern list routing_tables;
struct config;

@@ -309,35 +353,28 @@ 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_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 && n->routes && rte_is_valid(&n->routes->rte)) ? n : NULL; }
static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) fib_get(&tab->fib, addr); }
net *net_get(rtable *tab, const net_addr *addr);
net *net_route(rtable *tab, const net_addr *n);
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
rte *rte_find(net *net, struct rte_src *src);
rte *rte_get_temp(struct rta *, struct rte_src *src);
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
/* rte_update() moved to protocol.h to avoid dependency conflicts */
int rt_examine(rtable *t, net_addr *a, struct proto *p, const struct filter *filter);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
int rt_examine(rtable *t, net_addr *a, struct channel *c, const struct filter *filter);
rte *rt_export_merged(struct channel *c, net *net, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c);
void rt_modify_stale(rtable *t, struct channel *c);
void rt_schedule_prune(rtable *t);
void rte_dump(rte *);
void rte_free(rte *);
rte *rte_do_cow(rte *);
static inline rte * rte_cow(rte *r) { return (r->flags & REF_COW) ? rte_do_cow(r) : r; }
rte *rte_cow_rta(rte *r, linpool *lp);
void rte_dump(struct rte_storage *);
void rte_free(struct rte_storage *, rtable *);
struct rte_storage *rte_store(const rte *, net *net, rtable *);
void rt_dump(rtable *);
void rt_dump_all(void);
int rt_feed_channel(struct channel *c);
void rt_feed_channel_abort(struct channel *c);
int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all);
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, rte **old_exported, int refeed);
int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old, struct rte_storage **old_exported, int refeed);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);

static inline int rt_is_ip(rtable *tab)
@@ -678,7 +715,7 @@ void rta_dump(rta *);
void rta_dump_all(void);
void rta_show(struct cli *, rta *);

u32 rt_get_igp_metric(rte *rt);
u32 rt_get_igp_metric(rte *);
struct hostentry * rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep);
void rta_apply_hostentry(rta *a, struct hostentry *he, mpls_label_stack *mls);

Loading