[PATCH 12/12] Introduce structures in filter. Implement BGP_AGGREGATOR.

Sergey Popovich popovich_sergei at mail.ru
Mon Sep 30 20:34:58 CEST 2013


BIRD has variety of types, used to represent most common
attributes in protocols. But sometimes wery complex attributes
might be found. An good example of such attribute is BGP_AGGREGATOR
which consists from an INT, and QUAD types (ASN,ROUTER_ID).

Rather than making *special* type for aggregator, introduce general
infrastructure for structured types and implement aggregator
as STRUCT ASID with its literal format written as { ASN, ROUTER_ID }.
Variables of STRUCT ASID also supported.

Introduce additional operator for dereference structure members: ->,
So for example bgp_aggregator->'ai.as' gies an ASN number from
structure. Assignment to structure members also supported on both
extended attributes and variables.
---
 conf/cf-lex.l      |   30 +++++++++++
 conf/conf.h        |    2 +
 conf/confbase.Y    |    4 +-
 doc/bird.sgml      |   61 ++++++++++++++++++++--
 filter/config.Y    |   96 ++++++++++++++++++++++++++++++++++
 filter/f-util.c    |   91 ++++++++++++++++++++++++++++++--
 filter/filter.c    |  146
++++++++++++++++++++++++++++++++++++++++++++++++++++
 filter/filter.h    |   31 +++++++++--
 nest/route.h       |    1 +
 proto/bgp/attrs.c  |   14 +++--
 proto/bgp/config.Y |    2 +-
 11 files changed, 457 insertions(+), 21 deletions(-)

diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index b1bbeae..5996f30 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -252,6 +252,7 @@ else: {
 \[\= return PO;
 \=\] return PC;
 +\-\> return REF;
 %%
  static int
@@ -512,6 +513,33 @@ cf_define_symbol(struct symbol *sym, int type, void
*def)
   return sym;
 }
 +/**
+ * cf_define_symbol_if_undef - redefine symbol with new meaning
+ * @sym: symbol to be defined
+ * @type: symbol class to assign
+ * @def: class dependent data
+ *
+ * Takes symbol and re-defines it to the new type if it's type was
+ * undefined previously (%SYM_VOID) or returns symbol unmodified
+ * if it's type same as specified with @type parameter, overwise
+ * an error is reported via cf_error().
+ */
+struct symbol *
+cf_define_symbol_if_undef(struct symbol *sym, int type, void *def)
+{
+  if (sym->class)
+    {
+      if (sym->class != type)
+        cf_error("Symbol already defined");
+    }
+  else
+    {
+      sym->class = type;
+      sym->def = def;
+    }
+  return sym;
+}
+
 static void
 cf_lex_init_kh(void)
 {
@@ -642,6 +670,8 @@ cf_symbol_class_name(struct symbol *sym)
       return "routing table";
     case SYM_ROA:
       return "ROA table";
+    case SYM_REF:
+      return "reference to struct member";
     default:
       return "unknown type";
     }
diff --git a/conf/conf.h b/conf/conf.h
index 2862429..5aaa1f3 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -115,6 +115,7 @@ struct symbol {
 #define SYM_FILTER 4
 #define SYM_TABLE 5
 #define SYM_ROA 6
+#define SYM_REF 255
  #define SYM_VARIABLE 0x100	/* 0x100-0x1ff are variable types */
 #define SYM_CONSTANT 0x200	/* 0x200-0x2ff are variable types */
@@ -141,6 +142,7 @@ void cf_lex_init(int is_cli, struct config *c);
 struct symbol *cf_find_symbol(byte *c);
 struct symbol *cf_default_name(char *template, int *counter);
 struct symbol *cf_define_symbol(struct symbol *symbol, int type, void
*def);
+struct symbol *cf_define_symbol_if_undef(struct symbol *sym, int type,
void *def);
 void cf_push_scope(struct symbol *);
 void cf_pop_scope(void);
 struct symbol *cf_walk_symbols(struct config *cf, struct symbol *sym,
int *pos);
diff --git a/conf/confbase.Y b/conf/confbase.Y
index c6678e7..f5f701f 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -62,7 +62,7 @@ CF_DECLS
   struct timeformat *tf;
 }
 -%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
+%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT REF
 %token GEQ LEQ NEQ AND OR
 %token PO PC
 %token <i> NUM ENUM
@@ -84,7 +84,7 @@ CF_DECLS
 %left '+' '-'
 %left '*' '/' '%'
 %left '!'
-%nonassoc '.'
+%nonassoc '.' REF
  CF_KEYWORDS(DEFINE, ON, OFF, YES, NO)
 diff --git a/doc/bird.sgml b/doc/bird.sgml
index e4839a6..5791c0b 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1049,6 +1049,60 @@ function is_bird_ipv6()
 	  variables of such type, but some route attributes are of enumeration
 	  type. Enumeration types are incompatible with each other.
 +	<tag/asid struct/
+	  Structured types are supported in filters. Structure aggregates
fixed set of
+	  objects with possibly different types in given order. Each object
within structure
+	  has it's own label by which object can be referenced. Literals of
structured type look
+	  like <cf/{ 1, 192.168.1.1, ... }/ and order of objects in literals
is important.
+	  You can not define your own structures, but any literal of
predefined structure
+	  could be used in configuration. Standard operations like assignment
to variable
+	  of structured type, printing, comparison also supported.
+
+	  There is special operator on structured type <cf/->/ which could be
used for
+	  referencing labeled object in structured type. This allows
retrieving/assignment
+	  of particular object in structured type.
+
+	  BIRD defines following structured types:
+
+	  <cf/asid/ represents AS number of integer type, followed by a router
ID of quad
+	  type. There are two corresponding labels to reference each object
within structure:
+	  <cf/ai.as/ refering to AS number object and <cf/ai.as/ refering to
router ID object.
+	  This type is used to represent <cf/bgp_aggregator/ attribute.
+
+	  There examples on how to work with structured types in filters:
+<code>
+define C_IP = 10.20.20.20;
+define C_BGP_AGGREGATOR = { 10, C_IP };
+
+function make_aggregator(int asn; quad router_id)
+asid struct ai;
+{
+	ai = { asn, router_id };
+	return ai;
+}
+
+function print_aggregator(asid struct ai)
+{
+	print "aggregator: ", ai;
+	print "ai.as: ", ai->'ai.as', ", ai.id: ", ai->'ai.id';
+	print "--";
+}
+
+function test_aggregator()
+{
+	print { 10, 10.10.10.10 }->'ai.as', ", ", { 10, 10.10.10.10 }->'ai.id';
+	print_aggregator({ 10, 10.10.10.10 });
+	print_aggregator(C_BGP_AGGREGATOR);
+
+	bgp_aggregator = { 10, 10.30.30.30 };
+	print_aggregator(bgp_aggregator);
+
+	bgp_aggregator->'ai.as' = 1;
+	bgp_aggregator->'ai.id' = 1.1.1.1;
+	print_aggregator(bgp_aggregator);
+}
+</code>
+
 	<tag/bgppath/
 	  BGP path is a list of autonomous system numbers. You can't write
literals of this type.
 	  There are several special operators on bgppaths:
@@ -1705,9 +1759,10 @@ with `<tt/O/') are optional.
 	has been aggregated from multiple routes by some router on the path from
 	the originator.
 -<!-- we don't handle aggregators right since they are of a very
obscure type
-	<tag>bgp_aggregator</tag>
--->
+	<tag>asid struct bgp_aggregator</tag> This is an optional attribute
which carries
+	ASN and router ID that formed aggregated route. See <cf/asid struct/ type
+	description for more information on type of this attribute.
+
 	<tag>clist <cf/bgp_community/ [O]</tag> List of community values
associated
 	with the route. Each such value is a pair (represented as a <cf/pair/ data
 	type inside the filters) of 16-bit integers, the first of them
containing the number of the AS which defines
diff --git a/filter/config.Y b/filter/config.Y
index a7a69a4..77b2446 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -250,6 +250,48 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct
f_inst *tv)
   return rv;
 }
 +static inline struct f_inst *
+f_generate_ref(struct f_inst *t, struct symbol *s)
+{
+  struct f_inst *rv;
+
+  s = cf_define_symbol_if_undef(s, SYM_REF, NULL);
+
+  if (t->code == 'C') {
+    struct f_val res, *v = t->a1.p;
+
+    res.type = T_VOID;
+    switch (v->type) {
+    case T_STRUCT_ASID:
+      if (!strcmp(s->name, "ai.as")) {
+        res.type = T_INT;
+        res.val.i = v->val.ai.as;
+      } else if (!strcmp(s->name, "ai.id")) {
+        res.type = T_QUAD;
+        res.val.i = v->val.ai.id;
+      }
+      break;
+    default:
+      cf_error("Expected structured type: %x", v->type);
+    }
+
+    if (res.type == T_VOID)
+      cf_error("Unknown member in structure: %s", s->name);
+
+    NEW_F_VAL;
+    rv = f_new_inst();
+    rv->code = 'C';
+    rv->a1.p = val;
+    memcpy(val, &res, sizeof(*val));
+  } else {
+    rv = f_new_inst();
+    rv->code = P('s','s');
+    rv->a1.p = s;
+    rv->a2.p = t;
+  }
+
+  return rv;
+}
   CF_DECLS
@@ -259,6 +301,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 	INT, BOOL, IP, PREFIX, PAIR, QUAD, EC,
 	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
 	IF, THEN, ELSE, CASE, TRY, CATCH,
+	STRUCT, ASID,
 	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
 	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
 	PREFERENCE,
@@ -313,6 +356,7 @@ type:
  | BGPPATH { $$ = T_PATH; }
  | CLIST { $$ = T_CLIST; }
  | ECLIST { $$ = T_ECLIST; }
+ | ASID STRUCT { $$ = T_STRUCT_ASID; }
  | type SET {  	switch ($1) {
 	  case T_INT:
@@ -628,6 +672,7 @@ constant:
 constructor:
    '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
  | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
+ | '{' term ',' term '}' { $$ = f_generate_struct(T_STRUCT_ASID, $2, $4); }
  ;
  @@ -719,6 +764,8 @@ term:
   | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
 + | term REF SYM { $$ = f_generate_ref($1, $3); }
+
  | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p =
$1; $$->aux = T_IP; }
  | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
  | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code =
P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
@@ -877,6 +924,55 @@ cmd:
       $$->a1.p = $2;
       $$->a2.p = build_tree( $4 );
    }
+ | rtadot dynamic_attr REF SYM '=' term ';' {
+      struct f_inst_data *get_dyn;
+      struct f_inst *set_ref;
+      char **c;
+
+      $4 = cf_define_symbol_if_undef($4, SYM_REF, NULL);
+
+      get_dyn = f_new_inst2(sizeof(char *));
+      get_dyn->i = *($2);
+      get_dyn->i.code = P('e','a');
+      c = (char **) get_dyn->data;
+      *c = $4->name;
+
+      set_ref = f_new_inst();
+      set_ref->code = P('s','S');
+      set_ref->a1.p = get_dyn;
+      set_ref->a2.p = $6;
+
+      $$ = $2;
+      $$->code = P('e','S');
+      $$->a1.p = set_ref;
+   }
+ | SYM REF SYM '=' term ';' {
+      struct f_inst_data *get_sym;
+      struct f_inst *set_ref;
+      char **c;
+
+      if (($1->class & ~T_MASK) != SYM_VARIABLE)
+        cf_error( "You may set only variables." );
+
+      $3 = cf_define_symbol_if_undef($3, SYM_REF, NULL);
+
+      get_sym = f_new_inst2(sizeof(char *));
+      get_sym->i.code = 'V';
+      get_sym->i.a1.p = $1->def;
+      get_sym->i.a2.p = $1->name;
+      c = (char **) get_sym->data;
+      *c = $3->name;
+
+      set_ref = f_new_inst();
+      set_ref->code = P('s','S');
+      set_ref->a1.p = get_sym;
+      set_ref->a2.p = $5;
+
+      $$ = f_new_inst();
+      $$->code = 's';
+      $$->a1.p = $1;
+      $$->a2.p = set_ref;
+   }
    | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
diff --git a/filter/f-util.c b/filter/f-util.c
index ad91002..a02d058 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -15,14 +15,21 @@
 struct f_inst *
 f_new_inst(void)
 {
-  struct f_inst * ret;
-  ret = cfg_alloc(sizeof(struct f_inst));
-  ret->code = ret->aux = 0;
-  ret->arg1 = ret->arg2 = ret->next = NULL;
+  struct f_inst *ret;
+  ret = cfg_allocz(sizeof(struct f_inst));
   ret->lineno = ifs->lino;
   return ret;
 }
 +struct f_inst_data *
+f_new_inst2(unsigned int size)
+{
+  struct f_inst_data *ret;
+  ret = cfg_allocz(sizeof(struct f_inst_data) + size);
+  ret->i.lineno = ifs->lino;
+  return ret;
+}
+
 struct f_inst *
 f_new_dynamic_attr(int type, int f_type, int code)
 {
@@ -71,6 +78,82 @@ f_generate_roa_check(struct symbol *sym, struct
f_inst *prefix, struct f_inst *a
   return &ret->i;
 }
 +struct f_inst *
+f_generate_struct(int type, ...)
+{
+  struct f_inst *rv;
+  va_list args;
+
+  va_start(args, type);
+
+  switch (type) {
+    case T_STRUCT_ASID:
+      {
+        struct f_inst *t1 = va_arg(args, struct f_inst *);
+        struct f_inst *t2 = va_arg(args, struct f_inst *);
+        int c1 = 0, c2 = 0;
+        struct f_asid ai = { 0, 0 };
+
+        if (t1->code == 'c') {
+          if (t1->aux != T_INT)
+            cf_error("Can't operate with non-integer value of AS part
in AS,ID constructor");
+
+          ai.as = t1->a2.i;
+          c1 = 1;
+        }
+
+        if (t2->code == 'c') {
+          if (t2->aux != T_QUAD)
+            cf_error("Can't operate with non-quad value of ID part in
AS,ID constructor");
+
+          ai.id = t2->a2.i;
+          c2 = 1;
+        }
+
+#ifndef IPV6
+        /* IP->Quad implicit conversion */
+        else if (t2->code == 'C') {
+          struct f_val *val = t2->a1.p;
+
+          if (val->type == T_QUAD)
+            ai.id = val->val.i;
+          else if (val->type == T_IP)
+            ai.id = ipa_to_u32(val->val.px.ip);
+          else
+            cf_error("Can't operate with non-quad value of ID part in
AS,ID constructor");
+
+          c2 = 1;
+        }
+#endif
+
+        if (c1 && c2) {
+          NEW_F_VAL;
+          rv = f_new_inst();
+          rv->code = 'C';
+          rv->a1.p = val;
+          val->type = T_STRUCT_ASID;
+          val->val.ai = ai;
+        } else {
+          rv = f_new_inst();
+          rv->code = P('m','a');
+          rv->a1.p = t1;
+          rv->a2.p = t2;
+        }
+      }
+      break;
+
+    default:
+      rv = NULL;
+  }
+
+  va_end(args);
+
+  if (!rv)
+    cf_error("Unknown structure type: %x", type);
+
+  return rv;
+}
+
 char *
 filter_name(struct filter *filter)
 {
diff --git a/filter/filter.c b/filter/filter.c
index 9b99f28..4b41d4f 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -50,6 +50,19 @@
  #define CMP_ERROR 999
 +/* [S]tructured types [E]rror codes and their text representation */
+#define SE_OK		 0
+#define SE_NOT_STRUCT	 1
+#define SE_IN_TYPE	 2
+#define SE_NO_MEMBER	 3
+
+static char *se_desc[] = {
+  [SE_OK]         = "",
+  [SE_NOT_STRUCT] = "Requested type is not structure",
+  [SE_IN_TYPE]    = "Attempt to set member to incompatible type",
+  [SE_NO_MEMBER]  = "Unknown member in structure",
+};
+
 static struct adata *
 adata_empty(struct linpool *pool, int l)
 {
@@ -188,6 +201,9 @@ val_compare(struct f_val v1, struct f_val v2)
     return uint_cmp(v1.val.i, v2.val.i);
   case T_EC:
     return u64_cmp(v1.val.ec, v2.val.ec);
+  case T_STRUCT_ASID:
+    return u64_cmp((((u64) v1.val.ai.as) << 32) | v1.val.ai.id,
+                   (((u64) v2.val.ai.as) << 32) | v2.val.ai.id);
   case T_IP:
     return ipa_compare(v1.val.px.ip, v2.val.px.ip);
   case T_PREFIX:
@@ -490,6 +506,7 @@ val_print(struct f_val v)
   case T_PAIR: logn("(%d,%d)", v.val.i >> 16, v.val.i & 0xffff); return;
   case T_QUAD: logn("%R", v.val.i); return;
   case T_EC: ec_format(buf2, v.val.ec); logn("%s", buf2); return;
+  case T_STRUCT_ASID: logn("{ %u, %R }", v.val.ai.as, v.val.ai.id); return;
   case T_PREFIX_SET: trie_print(v.val.ti); return;
   case T_SET: tree_print(v.val.t); return;
   case T_ENUM: logn("(enum %x)%d", v.type, v.val.i); return;
@@ -710,6 +727,102 @@ interpret(struct f_inst *what)
       break;
     }
 +  case P('m','a'):
+    {
+      TWOARGS;
+
+      struct f_asid ai;
+
+      if (v1.type != T_INT)
+        runtime("Can't operate with non-integer value of AS part in
AS,ID constructor");
+      ai.as = v1.val.i;
+
+      if (v2.type == T_QUAD)
+        ai.id = v2.val.i;
+#ifndef IPV6
+      /* IP->Quad implicit conversion */
+      else if (v2.type == T_IP)
+        ai.id = ipa_to_u32(v2.val.px.ip);
+#endif
+      else
+        runtime("Can't operate with non-quad value of ID part in AS,ID
constructor");
+
+      res.val.ai = ai;
+      res.type = T_STRUCT_ASID;
+      break;
+    }
+
+  case P('s','s'):
+    {
+      char *name;
+
+      ARG(v2, a2.p);
+
+      sym = what->a1.p;
+      name = sym->name;
+
+      i = SE_OK;
+      switch (v2.type) {
+      case T_STRUCT_ASID:
+	if (!strcmp(name, "ai.as")) {
+	  res.type = T_INT;
+	  res.val.i = v2.val.ai.as;
+	} else if (!strcmp(name, "ai.id")) {
+	  res.type = T_QUAD;
+	  res.val.i = v2.val.ai.id;
+	} else
+	  i = SE_NO_MEMBER;
+	break;
+      default:
+	i = SE_NOT_STRUCT;
+      }
+
+      if (i != SE_OK)
+	runtime(se_desc[i]);
+    }
+    break;
+
+  case P('s','S'):
+    {
+      char **pname;
+      char *name;
+
+      TWOARGS;
+
+      pname = (char **) ((struct f_inst_data *) what->a1.p)->data;
+      name = *pname;
+
+      res = v1;
+      i = SE_OK;
+      switch (res.type) {
+      case T_STRUCT_ASID:
+	if (!strcmp(name, "ai.as")) {
+	  if (v2.type == T_INT)
+	    res.val.ai.as = v2.val.i;
+	  else
+	    i = SE_IN_TYPE;
+	} else if (!strcmp(name, "ai.id")) {
+	  if (v2.type == T_QUAD)
+	    res.val.ai.id = v2.val.i;
+#ifndef IPV6
+	  /* IP->Quad implicit conversion */
+	  else if (v2.type == T_IP)
+	    res.val.ai.id = ipa_to_u32(v2.val.px.ip);
+#endif
+	  else
+	    i = SE_IN_TYPE;
+	} else
+	  i = SE_NO_MEMBER;
+	break;
+      default:
+	i = SE_NOT_STRUCT;
+      }
+
+      if (i != SE_OK)
+        runtime(se_desc[i]);
+    }
+    break;
+
 /* Relational operators */
  #define COMPARE(f,x) \
@@ -937,6 +1050,12 @@ interpret(struct f_inst *what)
 	  res.val.px.ip = * (ip_addr *) ad->data;
 	}
 	break;
+      case T_STRUCT_ASID:
+        {
+	  struct adata * ad = e->u.ptr;
+	  res.val.ai = * (struct f_asid *) ad->data;
+        }
+        break;
       case T_PATH:
       case T_CLIST:
       case T_ECLIST:
@@ -998,6 +1117,14 @@ interpret(struct f_inst *what)
 	  l->attrs[0].u.ptr = ad;
 	}
 	break;
+      case T_STRUCT_ASID:
+	{
+	  struct adata *ad = lp_alloc(f_pool, sizeof(struct adata) +
sizeof(struct f_asid));
+	  ad->length = sizeof(struct f_asid);
+	  (* (struct f_asid *) ad->data) = v1.val.ai;
+	  l->attrs[0].u.ptr = ad;
+	}
+	break;
       case T_PATH:
       case T_CLIST:
       case T_ECLIST:
@@ -1352,6 +1479,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
   case '&':
   case P('m','p'):
   case P('m','c'):
+  case P('m','a'):
   case P('!','='):
   case P('=','='):
   case '<':
@@ -1361,6 +1489,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
   case '~': TWOARGS; break;
   case P('d','e'): ONEARG; break;
 +  case P('s','s'):
   case 's':
     ARG(v2, a2.p);
     {
@@ -1374,6 +1503,23 @@ i_same(struct f_inst *f1, struct f_inst *f2)
     }
     break;
 +  case P('s','S'):
+    TWOARGS;
+    {
+      char **pname1, **pname2;
+      char *name1, *name2;
+
+      pname1 = (char **) ((struct f_inst_data *) f1->a1.p)->data;
+      name1 = *pname1;
+
+      pname2 = (char **) ((struct f_inst_data *) f2->a1.p)->data;
+      name2 = *pname2;
+
+      if (strcmp(name1, name2))
+	return 0;
+    }
+    break;
+
   case 'c':      switch (f1->aux) {
 diff --git a/filter/filter.h b/filter/filter.h
index aed4418..970d093 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -29,6 +29,11 @@ struct f_inst {		/* Instruction */
   int lineno;
 };
 +struct f_inst_data {
+  struct f_inst i;
+  byte data[0];
+};
+
 #define arg1 a1.p
 #define arg2 a2.p
 @@ -48,11 +53,17 @@ struct f_prefix {
   /* If range then prefix must be in range (len >> 16 & 0xff, len >> 8
& 0xff) */
 };
 +struct f_asid {
+  u32 as;
+  u32 id;
+};
+
 struct f_val {
   int type;
   union {
     int i;
     u64 ec;
+    struct f_asid ai;
     /*    ip_addr ip; Folded into prefix */	
     struct f_prefix px;
     char *s;
@@ -69,10 +80,12 @@ struct filter {
 };
  struct f_inst *f_new_inst(void);
+struct f_inst_data *f_new_inst2(unsigned int size);
 struct f_inst *f_new_dynamic_attr(int type, int f_type, int code);	/*
Type as core knows it, type as filters know it, and code of dynamic
attribute */
 struct f_tree *f_new_tree(void);
 struct f_inst *f_generate_complex(int operation, int operation_aux,
struct f_inst *dyn, struct f_inst *argument);
 struct f_inst *f_generate_roa_check(struct symbol *sym, struct f_inst
*prefix, struct f_inst *asn);
+struct f_inst *f_generate_struct(int type, ...);
   struct f_tree *build_tree(struct f_tree *);
@@ -177,9 +190,21 @@ void val_print(struct f_val v);
 #define T_ECLIST 0x26		/* Extended community list */
 #define T_EC 0x27		/* Extended community value, u64 */
 -#define T_RETURN 0x40
-#define T_SET 0x80
-#define T_PREFIX_SET 0x81
+/* Put set types in 0x40..0x4f range */
+#define T_SET 0x40		/* General set type */
+#define T_PREFIX_SET 0x41	/* Special set for prefixes */
+/* new sets go here */
+
+/* Put structured types in 0x50..0x5f range */
+#define T_STRUCT_LO 0x50
+#define T_STRUCT_HI 0x5f
+
+#define T_STRUCT_ASID 0x50	/* AS,ID structure (BGP_AGGREGATOR) */
+/* new structs go here */
+
+#define T_STRUCT T_STRUCT_LO ... T_STRUCT_HI
+
+#define T_RETURN 0x80
   #define SA_FROM		 1    diff --git a/nest/route.h b/nest/route.h
index 35b5fa1..7aadfc9 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -392,6 +392,7 @@ typedef struct eattr {
 #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_BGP_AGGREGATOR 0x08	/* BGP AGGREGATOR attribute */
 #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 */
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index c27a498..706ed7d 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -231,14 +231,10 @@ bgp_check_aggregator(struct bgp_proto *p, byte *a
UNUSED, int len)
 static void
 bgp_format_aggregator(eattr *a, byte *buf, int buflen UNUSED)
 {
-  struct adata *ad =  a->u.ptr;
-  byte *data = ad->data;
-  u32 as;
-
-  as = get_u32(data);
-  data += 4;
+  struct adata *ad = a->u.ptr;
+  struct f_asid *ai = (struct f_asid *) ad->data;
 -  bsprintf(buf, "%d.%d.%d.%d AS%u", data[0], data[1], data[2],
data[3], as);
+  bsprintf(buf, "%R AS%u", ai->id, ai->as);
 }
  static int
@@ -302,7 +298,7 @@ static struct attr_desc bgp_attr_table[] = {
     NULL, NULL },
   { "atomic_aggr", 0, BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,			/*
BA_ATOMIC_AGGR */
     NULL, NULL },
-  { "aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE,
1,	/* BA_AGGREGATOR */
+  { "aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE,
EAF_TYPE_BGP_AGGREGATOR, 1,/* BA_AGGREGATOR */
     bgp_check_aggregator, bgp_format_aggregator },
   { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET,
1,	/* BA_COMMUNITY */
     bgp_check_community, NULL },
@@ -597,6 +593,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w,
ea_list *attrs, int remains)
 	    memcpy(w, &ip, len);
 	    break;
 	  }
+	case EAF_TYPE_BGP_AGGREGATOR:
 	case EAF_TYPE_INT_SET:
 	case EAF_TYPE_EC_SET:
 	  {
@@ -1660,6 +1657,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte
*attr, unsigned int len, struct lin
 	case EAF_TYPE_IP_ADDRESS:
 	  ipa_ntoh(*(ip_addr *)ad->data);
 	  break;
+	case EAF_TYPE_BGP_AGGREGATOR:
 	case EAF_TYPE_INT_SET:
 	case EAF_TYPE_EC_SET:
 	  {
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 19f7a21..0c949ff 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -125,7 +125,7 @@ CF_ADDTO(dynamic_attr, BGP_LOCAL_PREF
 CF_ADDTO(dynamic_attr, BGP_ATOMIC_AGGR
 	{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_EMPTY, EA_CODE(EAP_BGP,
BA_ATOMIC_AGGR)); })
 CF_ADDTO(dynamic_attr, BGP_AGGREGATOR
-	{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_EMPTY, EA_CODE(EAP_BGP,
BA_AGGREGATOR)); })
+	{ $$ = f_new_dynamic_attr(EAF_TYPE_BGP_AGGREGATOR, T_STRUCT_ASID,
EA_CODE(EAP_BGP, BA_AGGREGATOR)); })
 CF_ADDTO(dynamic_attr, BGP_COMMUNITY
 	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP,
BA_COMMUNITY)); })
 CF_ADDTO(dynamic_attr, BGP_ORIGINATOR_ID
-- 
1.7.10.4



More information about the Bird-users mailing list