Commit 13c0be19 authored by Jan Maria Matejka's avatar Jan Maria Matejka
Browse files

Nest: Removing separate tmpa from route propagation

This is a fundamental change of an original (1999) concept of route
processing inside BIRD. During import/export, there was a temporary
ea_list created which was to be used instead of the another one inside
the route itself.

This led to some confusion, quirks, and strange filter code that handled
extended route attributes. Dropping it now.

The protocol interface has changed in an uniform way -- the
`struct ea_list *attrs` argument has been removed from store_tmp_attrs(),
import_control(), rt_notify() and get_route_info().
parent ee7e2ffd
Loading
Loading
Loading
Loading
+28 −36
Original line number Diff line number Diff line
@@ -538,14 +538,23 @@ val_format(struct f_val v, buffer *buf)

static struct rte **f_rte;
static struct rta *f_old_rta;
static struct ea_list **f_tmp_attrs;
static struct ea_list **f_eattrs;
static struct linpool *f_pool;
static struct buffer f_buf;
static int f_flags;

static inline void f_cache_eattrs(void)
{
  f_eattrs = &((*f_rte)->attrs->eattrs);
}

static inline void f_rte_cow(void)
{
  *f_rte = rte_cow(*f_rte);
  if (!((*f_rte)->flags & REF_COW))
    return;

  *f_rte = rte_do_cow(*f_rte);
  f_eattrs = NULL;
}

/*
@@ -570,6 +579,9 @@ f_rta_cow(void)
   * suppose hostentry is not changed by filters).
   */
  (*f_rte)->attrs = rta_do_cow((*f_rte)->attrs, f_pool);

  /* Re-cache the ea_list */
  f_cache_eattrs();
}

static char *
@@ -603,7 +615,10 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
      return val;

#define ACCESS_RTE \
  do { if (!f_rte) runtime("No route to access"); } while (0)
  do { if (!f_rte) runtime("No route to access"); else f_cache_eattrs(); } while (0)

#define ACCESS_EATTRS \
  do { if (!f_eattrs) f_cache_eattrs(); } while (0)

#define BITFIELD_MASK(what) \
  (1u << (what->a2.i >> 24))
@@ -995,17 +1010,11 @@ interpret(struct f_inst *what)
    break;
  case FI_EA_GET:	/* Access to extended attributes */
    ACCESS_RTE;
    ACCESS_EATTRS;
    {
      eattr *e = NULL;
      u16 code = what->a2.i;
      int f_type = what->aux >> 8;

      if (!(f_flags & FF_FORCE_TMPATTR))
	e = ea_find((*f_rte)->attrs->eattrs, code);
      if (!e)
	e = ea_find((*f_tmp_attrs), code);
      if ((!e) && (f_flags & FF_FORCE_TMPATTR))
	e = ea_find((*f_rte)->attrs->eattrs, code);
      eattr *e = ea_find(*f_eattrs, code);

      if (!e) {
	/* A special case: undefined as_path looks like empty as_path */
@@ -1089,6 +1098,7 @@ interpret(struct f_inst *what)
    break;
  case FI_EA_SET:
    ACCESS_RTE;
    ACCESS_EATTRS;
    ARG_ANY(1);
    {
      struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
@@ -1143,13 +1153,7 @@ interpret(struct f_inst *what)
	  runtime( "Setting bit in bitfield attribute to non-bool value" );
	{
	  /* First, we have to find the old value */
	  eattr *e = NULL;
	  if (!(f_flags & FF_FORCE_TMPATTR))
	    e = ea_find((*f_rte)->attrs->eattrs, code);
	  if (!e)
	    e = ea_find((*f_tmp_attrs), code);
	  if ((!e) && (f_flags & FF_FORCE_TMPATTR))
	    e = ea_find((*f_rte)->attrs->eattrs, code);
	  eattr *e = ea_find(*f_eattrs, code);
	  u32 data = e ? e->u.data : 0;

	  if (v1.val.i)
@@ -1181,14 +1185,9 @@ interpret(struct f_inst *what)
      default: bug("Unknown type in e,S");
      }

      if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
      f_rta_cow();
	l->next = (*f_rte)->attrs->eattrs;
	(*f_rte)->attrs->eattrs = l;
      } else {
	l->next = (*f_tmp_attrs);
	(*f_tmp_attrs) = l;
      }
      l->next = *f_eattrs;
      *f_eattrs = l;
    }
    break;
  case FI_PREF_GET:
@@ -1518,11 +1517,12 @@ interpret(struct f_inst *what)
    else
    {
      ACCESS_RTE;
      ACCESS_EATTRS;
      v1.val.net = (*f_rte)->net->n.addr;

      /* 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 */
      eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
      eattr *e = ea_find(*f_eattrs, EA_CODE(PROTOCOL_BGP, 0x02));

      if (!e || e->type != EAF_TYPE_AS_PATH)
	runtime("Missing AS_PATH attribute");
@@ -1720,7 +1720,6 @@ i_same(struct f_inst *f1, struct f_inst *f2)
 * f_run - run a filter for a route
 * @filter: filter to run
 * @rte: route being filtered, may be modified
 * @tmp_attrs: temporary attributes, prepared by caller or generated by f_run()
 * @tmp_pool: all filter allocations go from this pool
 * @flags: flags
 *
@@ -1742,7 +1741,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
 * modified in place, old cached rta is possibly freed.
 */
int
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags)
{
  if (filter == FILTER_ACCEPT)
    return F_ACCEPT;
@@ -1755,7 +1754,6 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc

  f_rte = rte;
  f_old_rta = NULL;
  f_tmp_attrs = tmp_attrs;
  f_pool = tmp_pool;
  f_flags = flags;

@@ -1797,11 +1795,9 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
struct f_val
f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
{
  struct ea_list *tmp_attrs = NULL;

  f_rte = rte;
  f_old_rta = NULL;
  f_tmp_attrs = &tmp_attrs;
  f_pool = tmp_pool;
  f_flags = 0;

@@ -1810,9 +1806,6 @@ f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool)
  /* Note that in this function we assume that rte->attrs is private / uncached */
  struct f_val res = interpret(expr);

  /* Hack to include EAF_TEMP attributes to the main list */
  (*rte)->attrs->eattrs = ea_append(tmp_attrs, (*rte)->attrs->eattrs);

  return res;
}

@@ -1820,7 +1813,6 @@ struct f_val
f_eval(struct f_inst *expr, struct linpool *tmp_pool)
{
  f_flags = 0;
  f_tmp_attrs = NULL;
  f_rte = NULL;
  f_pool = tmp_pool;

+1 −2
Original line number Diff line number Diff line
@@ -175,7 +175,7 @@ void trie_format(struct f_trie *t, buffer *buf);
struct ea_list;
struct rte;

int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags);
int f_run(struct filter *filter, struct rte **rte, struct linpool *tmp_pool, int flags);
struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool);
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
uint f_eval_int(struct f_inst *expr);
@@ -285,7 +285,6 @@ struct f_trie

#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val));

#define FF_FORCE_TMPATTR 1		/* Force all attributes to be temporary */
#define FF_SILENT 2			/* Silent filter execution */

/* Bird Tests */
+14 −10
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ struct protocol {
  int (*shutdown)(struct proto *);		/* Stop the instance */
  void (*cleanup)(struct proto *);		/* Called after shutdown when protocol became hungry/down */
  void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
  void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */
  void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
  int (*get_attr)(struct eattr *, byte *buf, int buflen);	/* ASCIIfy dynamic attribute (returns GA_*) */
  void (*show_proto_info)(struct proto *);	/* Show protocol info (for `show protocols all' command) */
  void (*copy_config)(struct proto_config *, struct proto_config *);	/* Copy config from given protocol instance */
@@ -191,7 +191,7 @@ struct proto {
   *	   rt_notify	Notify protocol about routing table updates.
   *	   neigh_notify	Notify protocol about neighbor cache events.
   *	   make_tmp_attrs  Construct ea_list from private attrs stored in rte.
   *	   store_tmp_attrs Store private attrs back to the rte.
   *	   store_tmp_attrs Store private attrs back to rta. The route MUST NOT be cached.
   *	   import_control  Called as the first step of the route importing process.
   *			It can construct a new rte, add private attributes and
   *			decide whether the route shall be imported: 1=yes, -1=no,
@@ -205,11 +205,11 @@ 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, struct ea_list *attrs);
  void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old);
  void (*neigh_notify)(struct neighbor *neigh);
  struct ea_list *(*make_tmp_attrs)(struct rte *rt, struct linpool *pool);
  void (*store_tmp_attrs)(struct rte *rt, struct ea_list *attrs);
  int (*import_control)(struct proto *, struct rte **rt, struct ea_list **attrs, struct linpool *pool);
  void (*store_tmp_attrs)(struct rte *rt);
  int (*import_control)(struct proto *, struct rte **rt, struct linpool *pool);
  void (*reload_routes)(struct channel *);
  void (*feed_begin)(struct channel *, int initial);
  void (*feed_end)(struct channel *);
@@ -292,12 +292,16 @@ proto_get_router_id(struct proto_config *pc)
  return pc->router_id ? pc->router_id : pc->global->router_id;
}

static inline struct ea_list *
rte_make_tmp_attrs(struct rte *rt, struct linpool *pool)
static inline void
rte_make_tmp_attrs(struct rte **rt, struct linpool *pool)
{
  struct ea_list *(*mta)(struct rte *rt, struct linpool *pool);
  mta = rt->attrs->src->proto->make_tmp_attrs;
  return mta ? mta(rt, pool) : NULL;
  mta = (*rt)->attrs->src->proto->make_tmp_attrs;
  if (!mta) return;
  *rt = rte_cow_rta(*rt, pool);
  struct ea_list *ea = mta(*rt, pool);
  ea->next = (*rt)->attrs->eattrs;
  (*rt)->attrs->eattrs = ea;
}

/* Moved from route.h to avoid dependency conflicts */
@@ -466,7 +470,7 @@ struct channel_class {
  void (*dump_attrs)(struct rte *);		/* Dump protocol-dependent attributes */

  void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
  void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */
  void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
  int (*get_attr)(struct eattr *, byte *buf, int buflen);	/* ASCIIfy dynamic attribute (returns GA_*) */
  void (*show_proto_info)(struct proto *);	/* Show protocol info (for `show protocols all' command) */

+11 −2
Original line number Diff line number Diff line
@@ -294,7 +294,7 @@ rte *rte_get_temp(struct rta *);
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, struct filter *filter);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, struct ea_list **tmpa, linpool *pool, int silent);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c);
void rt_schedule_prune(rtable *t);
@@ -546,6 +546,15 @@ uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */
ea_list *ea_append(ea_list *to, ea_list *what);
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);

#define ea_normalize(ea) do { \
  if (ea->next) { \
    ea_list *t = alloca(ea_scan(ea)); \
    ea_merge(ea, t); \
    ea = t; \
  } \
  ea_sort(ea); \
} while(0) \

static inline eattr *
ea_set_attr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, uintptr_t val)
{
@@ -611,7 +620,7 @@ rta *rta_do_cow(rta *o, linpool *lp);
static inline rta * rta_cow(rta *r, linpool *lp) { return rta_is_cached(r) ? rta_do_cow(r, lp) : r; }
void rta_dump(rta *);
void rta_dump_all(void);
void rta_show(struct cli *, rta *, ea_list *);
void rta_show(struct cli *, rta *);

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);
+34 −26
Original line number Diff line number Diff line
@@ -550,29 +550,47 @@ ea_do_sort(ea_list *e)
  while (ss);
}

/**
 * In place discard duplicates, undefs and temporary attributes in sorted
 * ea_list. We use stable sort for this reason.
 **/
static inline void
ea_do_prune(ea_list *e)
{
  eattr *s, *d, *l, *s0;
  int i = 0;

  /* Discard duplicates and undefs. Do you remember sorting was stable? */
  s = d = e->attrs;
  l = e->attrs + e->count;
  s = d = e->attrs;	    /* Beginning of the list. @s is source, @d is destination. */
  l = e->attrs + e->count;  /* End of the list */

  /* Walk from begin to end. */
  while (s < l)
    {
      s0 = s++;
      /* Find a consecutive block of the same attribute */
      while (s < l && s->id == s[-1].id)
	s++;
      /* s0 is the most recent version, s[-1] the oldest one */
      if ((s0->type & EAF_TYPE_MASK) != EAF_TYPE_UNDEF)
	{

      /* Now s0 is the most recent version, s[-1] the oldest one */
      /* Drop undefs */
      if ((s0->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF)
	continue;

      /* Drop temporary attributes */
      if (s0->type & EAF_TEMP)
	continue;

      /* Copy the newest version to destination */
      *d = *s0;

      /* Preserve info whether it originated locally */
      d->type = (d->type & ~(EAF_ORIGINATED|EAF_FRESH)) | (s[-1].type & EAF_ORIGINATED);

      /* Next destination */
      d++;
      i++;
    }
    }

  e->count = i;
}

@@ -1128,15 +1146,7 @@ rta_lookup(rta *o)

  ASSERT(!(o->aflags & RTAF_CACHED));
  if (o->eattrs)
    {
      if (o->eattrs->next)	/* Multiple ea_list's, need to merge them */
	{
	  ea_list *ml = alloca(ea_scan(o->eattrs));
	  ea_merge(o->eattrs, ml);
	  o->eattrs = ml;
	}
      ea_sort(o->eattrs);
    }
    ea_normalize(o->eattrs);

  h = rta_hash(o);
  for(r=rta_hash_table[h & rta_cache_mask]; r; r=r->next)
@@ -1250,17 +1260,15 @@ rta_dump_all(void)
}

void
rta_show(struct cli *c, rta *a, ea_list *eal)
rta_show(struct cli *c, rta *a)
{
  static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect",
			       "RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" };
  int i;

  cli_printf(c, -1008, "\tType: %s %s", src_names[a->source], ip_scope_text(a->scope));
  if (!eal)
    eal = a->eattrs;
  for(; eal; eal=eal->next)
    for(i=0; i<eal->count; i++)

  for(ea_list *eal = a->eattrs; eal; eal=eal->next)
    for(int i=0; i<eal->count; i++)
      ea_show(c, &eal->attrs[i]);
}

Loading