Commit 00572d96 authored by Pavel Tvrdík's avatar Pavel Tvrdík
Browse files

Merge branch 'master' into birdtest

parents b335daec 9fdf9d29
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2248,7 +2248,7 @@ these attributes:

	<tag>ip <cf/krt_prefsrc/</tag> (Linux)
	The preferred source address. Used in source address selection for
 	outgoing packets. Have to be one of IP addresses of the router.
 	outgoing packets. Has to be one of the IP addresses of the router.

	<tag>int <cf/krt_realm/</tag> (Linux)
	The realm of the route. Can be used for traffic classification.
+57 −25
Original line number Diff line number Diff line
@@ -516,6 +516,9 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
#define ACCESS_RTE \
  do { if (!f_rte) runtime("No route to access"); } while (0)

#define BITFIELD_MASK(what) \
  (1u << (what->a2.i >> 24))

/**
 * interpret
 * @what: filter to interpret
@@ -864,12 +867,14 @@ interpret(struct f_inst *what)
    ACCESS_RTE;
    {
      eattr *e = NULL;
      u16 code = what->a2.i;

      if (!(f_flags & FF_FORCE_TMPATTR))
	e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
	e = ea_find((*f_rte)->attrs->eattrs, code);
      if (!e)
	e = ea_find( (*f_tmp_attrs), what->a2.i );
	e = ea_find((*f_tmp_attrs), code);
      if ((!e) && (f_flags & FF_FORCE_TMPATTR))
	e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
	e = ea_find((*f_rte)->attrs->eattrs, code);

      if (!e) {
	/* A special case: undefined int_set looks like empty int_set */
@@ -878,8 +883,9 @@ interpret(struct f_inst *what)
	  res.val.ad = adata_empty(f_pool, 0);
	  break;
	}

	/* The same special case for ec_set */
	else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
	if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
	  res.type = T_ECLIST;
	  res.val.ad = adata_empty(f_pool, 0);
	  break;
@@ -912,6 +918,10 @@ interpret(struct f_inst *what)
        res.type = T_PATH;
	res.val.ad = e->u.ptr;
	break;
      case EAF_TYPE_BITFIELD:
	res.type = T_BOOL;
	res.val.i = !!(e->u.data & BITFIELD_MASK(what));
	break;
      case EAF_TYPE_INT_SET:
	res.type = T_CLIST;
	res.val.ad = e->u.ptr;
@@ -933,13 +943,15 @@ interpret(struct f_inst *what)
    ONEARG;
    {
      struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
      u16 code = what->a2.i;

      l->next = NULL;
      l->flags = EALF_SORTED;
      l->count = 1;
      l->attrs[0].id = what->a2.i;
      l->attrs[0].id = code;
      l->attrs[0].flags = 0;
      l->attrs[0].type = what->aux | EAF_ORIGINATED;

      switch (what->aux & EAF_TYPE_MASK) {
      case EAF_TYPE_INT:
	if (v1.type != T_INT)
@@ -978,6 +990,26 @@ interpret(struct f_inst *what)
	  runtime( "Setting path attribute to non-path value" );
	l->attrs[0].u.ptr = v1.val.ad;
	break;
      case EAF_TYPE_BITFIELD:
	if (v1.type != T_BOOL)
	  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);
	  u32 data = e ? e->u.data : 0;

	  if (v1.val.i)
	    l->attrs[0].u.data = data | BITFIELD_MASK(what);
	  else
	    l->attrs[0].u.data = data & ~BITFIELD_MASK(what);;
	}
	break;
      case EAF_TYPE_INT_SET:
	if (v1.type != T_CLIST)
	  runtime( "Setting clist attribute to non-clist value" );

lib/fletcher16.h

0 → 100644
+196 −0
Original line number Diff line number Diff line
/*
 *	BIRD Library -- Fletcher-16 checksum
 *
 *	(c) 2015 Ondrej Zajicek <santiago@crfreenet.org>
 *	(c) 2015 CZ.NIC z.s.p.o.
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

/**
 * DOC: Fletcher-16 checksum
 *
 * Fletcher-16 checksum is a position-dependent checksum algorithm used for
 * error-detection e.g. in OSPF LSAs.
 *
 * To generate Fletcher-16 checksum, zero the checksum field in data, initialize
 * the context by fletcher16_init(), process the data by fletcher16_update(),
 * compute the checksum value by fletcher16_final() and store it to the checksum
 * field in data by put_u16() (or other means involving htons() conversion).
 *
 * To verify Fletcher-16 checksum, initialize the context by fletcher16_init(),
 * process the data by fletcher16_update(), compute a passing checksum by
 * fletcher16_compute() and check if it is zero.
 */

#ifndef _BIRD_FLETCHER16_H_
#define _BIRD_FLETCHER16_H_

#include "nest/bird.h"


struct fletcher16_context
{
  int c0, c1;
};


/**
 * fletcher16_init - initialize Fletcher-16 context
 * @ctx: the context
 */
static inline void
fletcher16_init(struct fletcher16_context *ctx)
{
  ctx->c0 = ctx->c1 = 0;
}

/**
 * fletcher16_update - process data to Fletcher-16 context
 * @ctx: the context
 * @buf: data buffer
 * @len: data length
 *
 * fletcher16_update() reads data from the buffer @buf and updates passing sums
 * in the context @ctx. It may be used multiple times for multiple blocks of
 * checksummed data.
 */
static inline void
fletcher16_update(struct fletcher16_context *ctx, const u8* buf, int len)
{
  /*
   * The Fletcher-16 sum is essentially a sequence of
   * ctx->c1 += ctx->c0 += *buf++, modulo 255.
   *
   * In the inner loop, we eliminate modulo operation and we do some loop
   * unrolling. MODX is the maximal number of steps that can be done without
   * modulo before overflow, see RFC 1008 for details. We use a bit smaller
   * value to cover for initial steps due to loop unrolling.
   */

#define MODX 4096

  int blen, i;

  blen = len % 4;
  len -= blen;

  for (i = 0; i < blen; i++)
    ctx->c1 += ctx->c0 += *buf++;

  do {
    blen = MIN(len, MODX);
    len -= blen;

    for (i = 0; i < blen; i += 4)
    {
      ctx->c1 += ctx->c0 += *buf++;
      ctx->c1 += ctx->c0 += *buf++;
      ctx->c1 += ctx->c0 += *buf++;
      ctx->c1 += ctx->c0 += *buf++;
    }

    ctx->c0 %= 255;
    ctx->c1 %= 255;

  } while (len);
}


/**
 * fletcher16_update_n32 - process data to Fletcher-16 context, with endianity adjustment
 * @ctx: the context
 * @buf: data buffer
 * @len: data length
 *
 * fletcher16_update_n32() works like fletcher16_update(), except it applies
 * 32-bit host/network endianity swap to the data before they are processed.
 * I.e., it assumes that the data is a sequence of u32 that must be converted by
 * ntohl() or htonl() before processing. The @buf need not to be aligned, but
 * its length (@len) must be multiple of 4. Note that on big endian systems the
 * host endianity is the same as the network endianity, therefore there is no
 * endianity swap.
 */
static inline void
fletcher16_update_n32(struct fletcher16_context *ctx, const u8* buf, int len)
{
  /* See fletcher16_update() for details */

  int blen, i;

  do {
    blen = MIN(len, MODX);
    len -= blen;

    for (i = 0; i < blen; i += 4)
    {
#ifdef CPU_BIG_ENDIAN
      ctx->c1 += ctx->c0 += *buf++;
      ctx->c1 += ctx->c0 += *buf++;
      ctx->c1 += ctx->c0 += *buf++;
      ctx->c1 += ctx->c0 += *buf++;
#else
      ctx->c1 += ctx->c0 += buf[3];
      ctx->c1 += ctx->c0 += buf[2];
      ctx->c1 += ctx->c0 += buf[1];
      ctx->c1 += ctx->c0 += buf[0];
      buf += 4;
#endif
    }

    ctx->c0 %= 255;
    ctx->c1 %= 255;

  } while (len);
}

/**
 * fletcher16_final - compute final Fletcher-16 checksum value
 * @ctx: the context
 * @len: total data length
 * @pos: offset in data where the checksum will be stored
 *
 * fletcher16_final() computes the final checksum value and returns it.
 * The caller is responsible for storing it in the appropriate position.
 * The checksum value depends on @len and @pos, but only their difference
 * (i.e. the offset from the end) is significant.
 *
 * The checksum value is represented as u16, although it is defined as two
 * consecutive bytes. We treat them as one u16 in big endian / network order.
 * I.e., the returned value is in the form that would be returned by get_u16()
 * from the checksum field in the data buffer, therefore the caller should use
 * put_u16() or an explicit host-to-network conversion when storing it to the
 * checksum field in the data buffer.
 *
 * Note that the returned checksum value is always nonzero.
 */
static inline u16
fletcher16_final(struct fletcher16_context *ctx, int len, int pos)
{
  int x = ((len - pos - 1) * ctx->c0 - ctx->c1) % 255;
  if (x <= 0)
    x += 255;

  int y = 510 - ctx->c0 - x;
  if (y > 255)
    y -= 255;

  return (x << 8) | y;
}


/**
 * fletcher16_compute - compute Fletcher-16 sum for verification
 * @ctx: the context
 *
 * fletcher16_compute() returns a passing Fletcher-16 sum for processed data.
 * If the data contains the proper Fletcher-16 checksum value, the returned
 * value is zero.
 */
static inline u16
fletcher16_compute(struct fletcher16_context *ctx)
{
  return (ctx->c0 << 8) | ctx->c1;
}

#endif
+10 −1
Original line number Diff line number Diff line
@@ -417,13 +417,15 @@ typedef struct eattr {

#define EA_CODE_MASK 0xffff
#define EA_ALLOW_UNDEF 0x10000		/* ea_find: allow EAF_TYPE_UNDEF */
#define EA_BIT(n) ((n) << 24)		/* Used in bitfield accessors */

#define EAF_TYPE_MASK 0x0f		/* Mask with this to get type */
#define EAF_TYPE_INT 0x01		/* 32-bit signed integer number */
#define EAF_TYPE_INT 0x01		/* 32-bit unsigned integer number */
#define EAF_TYPE_OPAQUE 0x02		/* Opaque byte string (not filterable) */
#define EAF_TYPE_IP_ADDRESS 0x04	/* IP address */
#define EAF_TYPE_ROUTER_ID 0x05		/* Router ID (IPv4 address) */
#define EAF_TYPE_AS_PATH 0x06		/* BGP AS path (encoding per RFC 1771:4.3) */
#define EAF_TYPE_BITFIELD 0x09		/* 32-bit embedded bitfield */
#define EAF_TYPE_INT_SET 0x0a		/* Set of u32's (e.g., a community list) */
#define EAF_TYPE_EC_SET 0x0e		/* Set of pairs of u32's - ext. community list */
#define EAF_TYPE_UNDEF 0x0f		/* `force undefined' entry */
@@ -459,8 +461,14 @@ static inline void rt_lock_source(struct rte_src *src) { src->uc++; }
static inline void rt_unlock_source(struct rte_src *src) { src->uc--; }
void rt_prune_sources(void);

struct ea_walk_state {
  ea_list *eattrs;			/* Ccurrent ea_list, initially set by caller */
  eattr *ea;				/* Current eattr, initially NULL */
  u32 visited[4];			/* Bitfield, limiting max to 128 */
};

eattr *ea_find(ea_list *, unsigned ea);
eattr *ea_walk(struct ea_walk_state *s, uint id, uint max);
int ea_get_int(ea_list *, unsigned ea, int def);
void ea_dump(ea_list *);
void ea_sort(ea_list *);		/* Sort entries in all sub-lists */
@@ -469,6 +477,7 @@ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffe
int ea_same(ea_list *x, ea_list *y);	/* Test whether two ea_lists are identical */
unsigned int 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);

int mpnh__same(struct mpnh *x, struct mpnh *y); /* Compare multipath nexthops */
static inline int mpnh_same(struct mpnh *x, struct mpnh *y)
+105 −0
Original line number Diff line number Diff line
@@ -307,6 +307,82 @@ ea_find(ea_list *e, unsigned id)
  return a;
}

/**
 * ea_walk - walk through extended attributes
 * @s: walk state structure
 * @id: start of attribute ID interval
 * @max: length of attribute ID interval
 *
 * Given an extended attribute list, ea_walk() walks through the list looking
 * for first occurrences of attributes with ID in specified interval from @id to
 * (@id + @max - 1), returning pointers to found &eattr structures, storing its
 * walk state in @s for subsequent calls.

 * The function ea_walk() is supposed to be called in a loop, with initially
 * zeroed walk state structure @s with filled the initial extended attribute
 * list, returning one found attribute in each call or %NULL when no other
 * attribute exists. The extended attribute list or the arguments should not be
 * modified between calls. The maximum value of @max is 128.
 */
eattr *
ea_walk(struct ea_walk_state *s, uint id, uint max)
{
  ea_list *e = s->eattrs;
  eattr *a = s->ea;
  eattr *a_max;

  max = id + max;

  if (a)
    goto step;

  for (; e; e = e->next)
  {
    if (e->flags & EALF_BISECT)
    {
      int l, r, m;

      l = 0;
      r = e->count - 1;
      while (l < r)
      {
	m = (l+r) / 2;
	if (e->attrs[m].id < id)
	  l = m + 1;
	else
	  r = m;
      }
      a = e->attrs + l;
    }
    else
      a = e->attrs;

  step:
    a_max = e->attrs + e->count;
    for (; a < a_max; a++)
      if ((a->id >= id) && (a->id < max))
      {
	int n = a->id - id;

	if (BIT32_TEST(s->visited, n))
	  continue;

	BIT32_SET(s->visited, n);

	if ((a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF)
	  continue;

	s->eattrs = e;
	s->ea = a;
	return a;
      }
      else if (e->flags & EALF_BISECT)
	break;
  }

  return NULL;
}

/**
 * ea_get_int - fetch an integer attribute
 * @e: attribute list
@@ -563,6 +639,32 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
  return GA_UNKNOWN;
}

void
ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
{
  byte *bound = buf + bufsize - 32;
  u32 data = a->u.data;
  int i;

  for (i = min; i < max; i++)
    if ((data & (1u << i)) && names[i])
    {
      if (buf > bound)
      {
	strcpy(buf, " ...");
	return;
      }

      buf += bsprintf(buf, " %s", names[i]);
      data &= ~(1u << i);
    }

  if (data)
    bsprintf(buf, " %08x", data);

  return;
}

static inline void
opaque_format(struct adata *ad, byte *buf, unsigned int size)
{
@@ -665,6 +767,9 @@ ea_show(struct cli *c, eattr *e)
	case EAF_TYPE_AS_PATH:
	  as_path_format(ad, pos, end - pos);
	  break;
	case EAF_TYPE_BITFIELD:
	  bsprintf(pos, "%08x", e->u.data);
	  break;
	case EAF_TYPE_INT_SET:
	  ea_show_int_set(c, ad, 1, pos, buf, end);
	  return;
Loading