]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BGP Extended communities.
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 12 Aug 2011 19:03:43 +0000 (21:03 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 14 Aug 2011 11:55:02 +0000 (13:55 +0200)
14 files changed:
aclocal.m4
filter/config.Y
filter/filter.c
filter/filter.h
filter/test.conf
nest/a-set.c
nest/attrs.h
nest/route.h
nest/rt-attr.c
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/config.Y
sysdep/autoconf.h.in
sysdep/config.h

index 34a0511d0f193520a558397cb85a75050fbef72a..ee5452526238cf93d926e7b61e89a30e085a6191 100644 (file)
@@ -6,7 +6,8 @@ AC_DEFUN(BIRD_CHECK_INTEGERS,
 AC_CHECK_SIZEOF(short int, 0)
 AC_CHECK_SIZEOF(int, 0)
 AC_CHECK_SIZEOF(long int, 0)
-for size in 1 2 4 ; do
+AC_CHECK_SIZEOF(long long int, 0)
+for size in 1 2 4 8; do
        bits=`expr $size "*" 8`
        AC_MSG_CHECKING([for $bits-bit type])
        if test $ac_cv_sizeof_int = $size ; then
@@ -17,6 +18,8 @@ for size in 1 2 4 ; do
                res="short int"
        elif test $ac_cv_sizeof_long_int = $size ; then
                res="long int"
+       elif test $ac_cv_sizeof_long_long_int = $size ; then
+               res="long long int"
        else
                AC_MSG_RESULT([not found])
                AC_MSG_ERROR([Cannot find $bits-bit integer type.])
index 80e74286923888ee374211e630b5f78a3fd0a6be..3c5f18b71c18517c3f1a54c373c1bae7a88cca0c 100644 (file)
@@ -75,13 +75,185 @@ f_new_pair_set(int fa, int ta, int fb, int tb)
   return lst;
 }
 
+#define EC_ALL 0xFFFFFFFF
+
+static struct f_tree *
+f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
+{
+  u64 fm, to;
+
+  if (ipv4_used || (key >= 0x10000)) {
+    check_u16(vf);
+    if (vt == EC_ALL)
+      vt = 0xFFFF;
+    else
+      check_u16(vt);
+  }
+
+  if (kind == EC_GENERIC) {
+    fm = ec_generic(key, vf);
+    to = ec_generic(key, vt);
+  }
+  else if (ipv4_used) {
+    fm = ec_ip4(kind, key, vf);
+    to = ec_ip4(kind, key, vt);
+  }
+  else if (key < 0x10000) {
+    fm = ec_as2(kind, key, vf);
+    to = ec_as2(kind, key, vt);
+  }
+  else {
+    fm = ec_as4(kind, key, vf);
+    to = ec_as4(kind, key, vt);
+  }
+
+  struct f_tree *t = f_new_tree();
+  t->right = t;
+  t->from.type = t->to.type = T_EC;
+  t->from.val.ec = fm;
+  t->to.val.ec = to;
+  return t;
+}
+
+static inline struct f_inst *
+f_generate_empty(struct f_inst *dyn)
+{ 
+  struct f_inst *e = f_new_inst();
+  e->code = 'E';
+
+  switch (dyn->aux & EAF_TYPE_MASK) {
+    case EAF_TYPE_AS_PATH:
+      e->aux = T_PATH;
+      break;
+    case EAF_TYPE_INT_SET:
+      e->aux = T_CLIST;
+      break;
+    case EAF_TYPE_EC_SET:
+      e->aux = T_ECLIST;
+      break;
+    default:
+      cf_error("Can't empty that attribute");
+  }
+
+  dyn->code = P('e','S');
+  dyn->a1.p = e;
+  return dyn;
+}
+
+
+static inline struct f_inst *
+f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
+{
+  struct f_inst *rv;
+
+  if ((t1->code == 'c') && (t2->code == 'c')) {
+    if ((t1->aux != T_INT) || (t2->aux != T_INT))
+      cf_error( "Can't operate with value of non-integer type in pair constructor");
+
+    check_u16(t1->a2.i);
+    check_u16(t2->a2.i);
+
+    rv = f_new_inst();
+    rv->code = 'c';
+    rv->aux = T_PAIR;
+    rv->a2.i = pair(t1->a2.i, t2->a2.i);
+  }
+  else {
+    rv = f_new_inst();
+    rv->code = P('m', 'p');
+    rv->a1.p = t1;
+    rv->a2.p = t2;
+  }
+
+  return rv;
+}
+
+static inline struct f_inst *
+f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
+{
+  struct f_inst *rv;
+  int c1 = 0, c2 = 0, ipv4_used = 0;
+  u32 key = 0, val2 = 0;
+
+  if (tk->code == 'c') {
+    c1 = 1;
+
+    if (tk->aux == T_INT) {
+      ipv4_used = 0; key = tk->a2.i;
+    }
+    else if (tk->aux == T_QUAD) {
+      ipv4_used = 1; key = tk->a2.i;
+    }
+    else
+      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
+  }
+
+#ifndef IPV6
+  /* IP->Quad implicit conversion */
+  else if (tk->code == 'C') {
+    c1 = 1;
+    struct f_val *val = tk->a1.p;
+    if (val->type == T_IP) {
+      ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
+    }
+    else
+      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
+  }
+#endif
+
+  if (tv->code == 'c') {
+    if (tv->aux != T_INT)
+      cf_error("Can't operate with value of non-integer type in EC constructor");
+    c2 = 1;
+    val2 = tv->a2.i;
+  }
+
+  if (c1 && c2) {
+    u64 ec;
+  
+    if (kind == EC_GENERIC) {
+      ec = ec_generic(key, val2);
+    }
+    else if (ipv4_used) {
+      check_u16(val2);
+      ec = ec_ip4(kind, key, val2);
+    }
+    else if (key < 0x10000) {
+      ec = ec_as2(kind, key, val2);
+    }
+    else {
+      check_u16(val2);
+      ec = ec_as4(kind, key, val2);
+    }
+
+    NEW_F_VAL;
+    rv = f_new_inst();
+    rv->code = 'C';
+    rv->a1.p = val;    
+    val->type = T_EC;
+    val->val.ec = ec;
+  }
+  else {
+    rv = f_new_inst();
+    rv->code = P('m','c');
+    rv->aux = kind;
+    rv->a1.p = tk;
+    rv->a2.p = tv;
+  }
+
+  return rv;
+};
+
+
+
 CF_DECLS
 
 CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        ACCEPT, REJECT, ERROR, QUITBIRD,
-       INT, BOOL, IP, PREFIX, PAIR, QUAD, SET, STRING, BGPMASK, BGPPATH, CLIST,
+       INT, BOOL, IP, PREFIX, PAIR, QUAD, EC,
+       SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
        IF, THEN, ELSE, CASE,
-       TRUE, FALSE,
+       TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
        FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
        LEN,
        DEFINED,
@@ -93,11 +265,11 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 %nonassoc THEN
 %nonassoc ELSE
 
-%type <x> term block cmds cmds_int cmd function_body constant print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol dpair bgp_path_expr
+%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
 %type <f> filter filter_body where_filter
-%type <i> type break_command pair_expr
-%type <i32> pair_atom
-%type <e> pair_item set_item switch_item set_items switch_items switch_body
+%type <i> type break_command pair_expr ec_kind
+%type <i32> pair_atom ec_expr
+%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body
 %type <trie> fprefix_set
 %type <v> set_atom switch_atom fprefix fprefix_s fipa
 %type <s> decls declsn one_decl function_params 
@@ -128,15 +300,18 @@ type:
  | PREFIX { $$ = T_PREFIX; }
  | PAIR { $$ = T_PAIR; }
  | QUAD { $$ = T_QUAD; }
+ | EC { $$ = T_EC; }
  | STRING { $$ = T_STRING; }
  | BGPMASK { $$ = T_PATH_MASK; }
  | BGPPATH { $$ = T_PATH; }
  | CLIST { $$ = T_CLIST; }
+ | ECLIST { $$ = T_ECLIST; }
  | type SET { 
        switch ($1) {
          case T_INT:
          case T_PAIR:
          case T_QUAD:
+         case T_EC:
          case T_IP:
               $$ = T_SET;
               break;
@@ -324,14 +499,32 @@ pair_item:
    }
  ;
 
+ec_expr:
+   term { $$ = f_eval_int($1); }
+
+ec_kind:
+   RT { $$ = EC_RT; }
+ | RO { $$ = EC_RO; }
+ | UNKNOWN NUM { $$ = $2; }
+ | GENERIC { $$ = EC_GENERIC; }
+ ;
+
+ec_item:
+   '(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
+ | '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
+ | '(' ec_kind ',' ec_expr ',' '*' ')' {  $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
+ ;
+
 set_item:
    pair_item
+ | ec_item
  | set_atom { $$ = f_new_item($1, $1); }
  | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
  ;
 
 switch_item:
    pair_item
+ | ec_item
  | switch_atom { $$ = f_new_item($1, $1); }
  | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
  ;
@@ -411,20 +604,6 @@ bgp_path_tail2:
  |                   { $$ = NULL; }
  ;
 
-dpair:
-   '(' term ',' term ')' {
-        if (($2->code == 'c') && ($4->code == 'c'))
-          { 
-            if (($2->aux != T_INT) || ($4->aux != T_INT))
-              cf_error( "Can't operate with value of non-integer type in pair constructor" );
-           check_u16($2->a2.i); check_u16($4->a2.i);
-            $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR;  $$->a2.i = pair($2->a2.i, $4->a2.i);
-          }
-       else
-         { $$ = f_new_inst(); $$->code = P('m', 'p'); $$->a1.p = $2; $$->a2.p = $4; }
-    }
- ;
-
 constant:
    NUM    { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT;  $$->a2.i = $1; }
  | TRUE   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1;  }
@@ -439,6 +618,11 @@ constant:
  | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
  ;
 
+constructor:
+   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); };
+ | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); };
+ ;
+
 
 /*
  *  Maybe there are no dynamic attributes defined by protocols.
@@ -490,6 +674,7 @@ symbol:
        case SYM_VARIABLE | T_INT:
        case SYM_VARIABLE | T_PAIR:
        case SYM_VARIABLE | T_QUAD:
+       case SYM_VARIABLE | T_EC:
        case SYM_VARIABLE | T_STRING:
        case SYM_VARIABLE | T_IP:
        case SYM_VARIABLE | T_PREFIX:
@@ -498,6 +683,7 @@ symbol:
        case SYM_VARIABLE | T_PATH:
        case SYM_VARIABLE | T_PATH_MASK:
        case SYM_VARIABLE | T_CLIST:
+       case SYM_VARIABLE | T_ECLIST:
         $$->code = 'V';
         $$->a1.p = $1->def;
         $$->a2.p = $1->name;
@@ -539,7 +725,7 @@ term:
 
  | symbol   { $$ = $1; }
  | constant { $$ = $1; }
- | dpair    { $$ = $1; }
+ | constructor { $$ = $1; }
 
  | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
 
@@ -563,6 +749,7 @@ term:
 
  | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
  | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
+ | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
  | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } 
  | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } 
  | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
@@ -702,12 +889,11 @@ cmd:
    }
 
 
- | rtadot dynamic_attr '.' EMPTY ';' 
-  { struct f_inst *i = f_new_inst(); i->code = 'E'; i->aux = T_CLIST; $$ = $2; $$->code = P('e','S'); $$->a1.p = i; }
+ | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
  | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
- | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); } 
- | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); } 
- | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); } 
+ | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
+ | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
+ | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
  ;
 
 CF_END
index 0f44a6eea7c03871b8c97e7846fd71e5b890a678..98c657b023511294962e74b52a13da7387afc196 100644 (file)
 #define CMP_ERROR 999
 
 static struct adata *
-adata_empty(struct linpool *pool)
+adata_empty(struct linpool *pool, int l)
 {
-  struct adata *res = lp_alloc(pool, sizeof(struct adata));
-  res->length = 0;
+  struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
+  res->length = l;
   return res;
 }
 
@@ -126,6 +126,13 @@ static inline int uint_cmp(unsigned int i1, unsigned int i2)
   else return 1;
 }
 
+static inline int u64_cmp(u64 i1, u64 i2)
+{
+  if (i1 == i2) return 0;
+  if (i1 < i2) return -1;
+  else return 1;
+}
+
 /**
  * val_compare - compare two values
  * @v1: first value
@@ -167,6 +174,8 @@ val_compare(struct f_val v1, struct f_val v2)
   case T_PAIR:
   case T_QUAD:
     return uint_cmp(v1.val.i, v2.val.i);
+  case T_EC:
+    return u64_cmp(v1.val.ec, v2.val.ec);
   case T_IP:
     return ipa_compare(v1.val.px.ip, v2.val.px.ip);
   case T_PREFIX:
@@ -226,6 +235,9 @@ val_simple_in_range(struct f_val v1, struct f_val v2)
   if ((v1.type == T_IP) && (v2.type == T_CLIST))
     return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
 #endif
+  if ((v1.type == T_EC) && (v2.type == T_ECLIST))
+    return ec_set_contains(v2.val.ad, v1.val.ec);
+
   if ((v1.type == T_STRING) && (v2.type == T_STRING))
     return patmatch(v2.val.s, v1.val.s);
 
@@ -258,6 +270,10 @@ clist_set_type(struct f_tree *set, struct f_val *v)
   }
 }
 
+static inline int
+eclist_set_type(struct f_tree *set)
+{ return set->from.type == T_EC; }
+
 static int
 clist_match_set(struct adata *clist, struct f_tree *set)
 {
@@ -270,6 +286,7 @@ clist_match_set(struct adata *clist, struct f_tree *set)
 
   u32 *l = (u32 *) clist->data;
   u32 *end = l + clist->length/4;
+
   while (l < end) {
     v.val.i = *l++;
     if (find_tree(set, v))
@@ -278,6 +295,30 @@ clist_match_set(struct adata *clist, struct f_tree *set)
   return 0;
 }
 
+static int
+eclist_match_set(struct adata *list, struct f_tree *set)
+{
+  if (!list)
+    return 0;
+
+  if (!eclist_set_type(set))
+    return CMP_ERROR;
+
+  struct f_val v;
+  u32 *l = int_set_get_data(list);
+  int len = int_set_get_size(list);
+  int i;
+
+  v.type = T_EC;
+  for (i = 0; i < len; i += 2) {
+    v.val.ec = ec_get(l, i);
+    if (find_tree(set, v))
+      return 1;
+  }
+
+  return 0;
+}
+
 static struct adata *
 clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int pos)
 {
@@ -302,8 +343,39 @@ clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int
   if (nl == clist->length)
     return clist;
 
-  struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl);
-  res->length = nl;
+  struct adata *res = adata_empty(pool, nl);
+  memcpy(res->data, tmp, nl);
+  return res;
+}
+
+static struct adata *
+eclist_filter(struct linpool *pool, struct adata *list, struct f_tree *set, int pos)
+{
+  if (!list)
+    return NULL;
+
+  struct f_val v;
+
+  int len = int_set_get_size(list);
+  u32 *l = int_set_get_data(list);
+  u32 tmp[len];
+  u32 *k = tmp;
+  int i;
+
+  v.type = T_EC;
+  for (i = 0; i < len; i += 2) {
+    v.val.ec = ec_get(l, i);
+    if (pos == !!find_tree(set, v)) {  /* pos && find_tree || !pos && !find_tree */
+      *k++ = l[i];
+      *k++ = l[i+1];
+    }
+  }
+
+  int nl = (k - tmp) * 4;
+  if (nl == list->length)
+    return list;
+
+  struct adata *res = adata_empty(pool, nl);
   memcpy(res->data, tmp, nl);
   return res;
 }
@@ -332,6 +404,9 @@ val_in_range(struct f_val v1, struct f_val v2)
   if ((v1.type == T_CLIST) && (v2.type == T_SET))
     return clist_match_set(v1.val.ad, v2.val.t);
 
+  if ((v1.type == T_ECLIST) && (v2.type == T_SET))
+    return eclist_match_set(v1.val.ad, v2.val.t);
+
   if (v2.type == T_SET)
     switch (v1.type) {
     case T_ENUM:
@@ -339,6 +414,7 @@ val_in_range(struct f_val v1, struct f_val v2)
     case T_PAIR:
     case T_QUAD:
     case T_IP:
+    case T_EC:
       {
        struct f_tree *n;
        n = find_tree(v2.val.t, v1);
@@ -397,11 +473,13 @@ val_print(struct f_val v)
   case T_PREFIX: logn("%I/%d", v.val.px.ip, v.val.px.len); return;
   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_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;
   case T_PATH: as_path_format(v.val.ad, buf2, 1000); logn("(path %s)", buf2); return;
   case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); logn("(clist %s)", buf2); return;
+  case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); logn("(eclist %s)", buf2); return;
   case T_PATH_MASK: pm_format(v.val.path_mask, buf2, 1000); logn("(pathmask%s)", buf2); return;
   default: logn( "[unknown type %x]", v.type ); return;
   }
@@ -541,7 +619,7 @@ interpret(struct f_inst *what)
     break;
 
   case P('m','p'):
-    TWOARGS_C;
+    TWOARGS;
     if ((v1.type != T_INT) || (v2.type != T_INT))
       runtime( "Can't operate with value of non-integer type in pair constructor" );
     u1 = v1.val.i;
@@ -552,6 +630,53 @@ interpret(struct f_inst *what)
     res.type = T_PAIR;
     break;
 
+  case P('m','c'):
+    {
+      TWOARGS;
+
+      int check, ipv4_used;
+      u32 key, val;
+
+      if (v1.type == T_INT) {
+       ipv4_used = 0; key = v1.val.i;
+      } 
+      else if (v1.type == T_QUAD) {
+       ipv4_used = 1; key = v1.val.i;
+      }
+#ifndef IPV6
+      /* IP->Quad implicit conversion */
+      else if (v1.type == T_IP) {
+       ipv4_used = 1; key = ipa_to_u32(v1.val.px.ip);
+      }
+#endif
+      else
+       runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
+
+      if (v2.type != T_INT)
+       runtime("Can't operate with value of non-integer type in EC constructor");
+      val = v2.val.i;
+
+      res.type = T_EC;
+
+      if (what->aux == EC_GENERIC) {
+       check = 0; res.val.ec = ec_generic(key, val);
+      }
+      else if (ipv4_used) {
+       check = 1; res.val.ec = ec_ip4(what->aux, key, val);
+      }
+      else if (key < 0x10000) {
+       check = 0; res.val.ec = ec_as2(what->aux, key, val);
+      }
+      else {
+       check = 1; res.val.ec = ec_as4(what->aux, key, val);
+      }
+
+      if (check && (val > 0xFFFF))
+       runtime("Can't operate with value out of bounds in EC constructor");
+
+      break;
+    }
+
 /* Relational operators */
 
 #define COMPARE(x) \
@@ -723,9 +848,16 @@ interpret(struct f_inst *what)
        /* A special case: undefined int_set looks like empty int_set */
        if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
          res.type = T_CLIST;
-         res.val.ad = adata_empty(f_pool);
+         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) {
+         res.type = T_ECLIST;
+         res.val.ad = adata_empty(f_pool, 0);
          break;
        }
+
        /* Undefined value */
        res.type = T_VOID;
        break;
@@ -757,6 +889,10 @@ interpret(struct f_inst *what)
        res.type = T_CLIST;
        res.val.ad = e->u.ptr;
        break;
+      case EAF_TYPE_EC_SET:
+       res.type = T_ECLIST;
+       res.val.ad = e->u.ptr;
+       break;
       case EAF_TYPE_UNDEF:
        res.type = T_VOID;
        break;
@@ -802,7 +938,12 @@ interpret(struct f_inst *what)
        break;
       case EAF_TYPE_INT_SET:
        if (v1.type != T_CLIST)
-         runtime( "Setting int set attribute to non-clist value" );
+         runtime( "Setting clist attribute to non-clist value" );
+       l->attrs[0].u.ptr = v1.val.ad;
+       break;
+      case EAF_TYPE_EC_SET:
+       if (v1.type != T_ECLIST)
+         runtime( "Setting eclist attribute to non-eclist value" );
        l->attrs[0].u.ptr = v1.val.ad;
        break;
       case EAF_TYPE_UNDEF:
@@ -926,7 +1067,7 @@ interpret(struct f_inst *what)
 
   case 'E':    /* Create empty attribute */
     res.type = what->aux;
-    res.val.ad = adata_empty(f_pool);
+    res.val.ad = adata_empty(f_pool, 0);
     break;
   case P('A','p'):     /* Path prepend */
     TWOARGS;
@@ -939,52 +1080,93 @@ interpret(struct f_inst *what)
     res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
     break;
 
-  case P('C','a'):     /* Community list add or delete */
+  case P('C','a'):     /* (Extended) Community list add or delete */
     TWOARGS;
-    if (v1.type != T_CLIST)
-      runtime("Can't add/delete to non-clist");
-
-    struct f_val dummy;
-    int arg_set = 0;
-    i = 0;
+    if (v1.type == T_CLIST)
+    {
+      /* Community (or cluster) list */
+      struct f_val dummy;
+      int arg_set = 0;
+      i = 0;
 
-    if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
-      i = v2.val.i;
+      if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
+       i = v2.val.i;
 #ifndef IPV6
-    /* IP->Quad implicit conversion */
-    else if (v2.type == T_IP)
-      i = ipa_to_u32(v2.val.px.ip);
+      /* IP->Quad implicit conversion */
+      else if (v2.type == T_IP)
+       i = ipa_to_u32(v2.val.px.ip);
 #endif
-    else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
-      arg_set = 1;
-    else
-      runtime("Can't add/delete non-pair");
+      else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
+       arg_set = 1;
+      else
+       runtime("Can't add/delete non-pair");
+
+      res.type = T_CLIST;
+      switch (what->aux)
+      {
+      case 'a':
+       if (arg_set)
+         runtime("Can't add set");
+       res.val.ad = int_set_add(f_pool, v1.val.ad, i);
+       break;
+      
+      case 'd':
+       if (!arg_set)
+         res.val.ad = int_set_del(f_pool, v1.val.ad, i);
+       else
+         res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 0);
+       break;
 
-    res.type = T_CLIST;
-    switch (what->aux)
+      case 'f':
+       if (!arg_set)
+         runtime("Can't filter pair");
+       res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 1);
+       break;
+
+      default:
+       bug("unknown Ca operation");
+      }
+    }
+    else if (v1.type == T_ECLIST)
     {
-    case 'a':
-      if (arg_set)
-       runtime("Can't add set");
-      res.val.ad = int_set_add(f_pool, v1.val.ad, i);
-      break;
+      /* Extended community list */
+      int arg_set = 0;
       
-    case 'd':
-      if (!arg_set)
-       res.val.ad = int_set_del(f_pool, v1.val.ad, i);
-      else
-       res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 0);
-      break;
+      /* v2.val is either EC or EC-set */
+      if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
+       arg_set = 1;
+      else if (v2.type != T_EC)
+       runtime("Can't add/delete non-pair");
+
+      res.type = T_ECLIST;
+      switch (what->aux)
+      {
+      case 'a':
+       if (arg_set)
+         runtime("Can't add set");
+       res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
+       break;
+      
+      case 'd':
+       if (!arg_set)
+         res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
+       else
+         res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 0);
+       break;
 
-    case 'f':
-      if (!arg_set)
-       runtime("Can't filter pair");
-      res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 1);
-      break;
+      case 'f':
+       if (!arg_set)
+         runtime("Can't filter ec");
+       res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 1);
+       break;
 
-    default:
-      bug("unknown Ca operation");
+      default:
+       bug("unknown Ca operation");
+      }
     }
+    else
+      runtime("Can't add/delete to non-(e)clist");
+
     break;
 
   default:
index c3eb8b4d7227829f9e57b3a9479dda3a1f722ae9..2cf4652d68cb065ff753afeed02e1102ad3b8dbb 100644 (file)
@@ -46,6 +46,7 @@ struct f_val {
   int type;
   union {
     int i;
+    u64 ec;
     /*    ip_addr ip; Folded into prefix */    
     struct f_prefix px;
     char *s;
@@ -152,6 +153,8 @@ int tree_compare(const void *p1, const void *p2);
 #define T_PATH_MASK 0x23       /* mask for BGP path */
 #define T_PATH 0x24            /* BGP path */
 #define T_CLIST 0x25           /* Community list */
+#define T_ECLIST 0x26          /* Extended community list */
+#define T_EC 0x27              /* Extended community value, u64 */
 
 #define T_RETURN 0x40
 #define T_SET 0x80
index ca8e26f5ed7707da6a58ccddd88ca9408a606e0b..19372f24bc26dd018d086b45c7fe94185ca18d81 100644 (file)
@@ -11,6 +11,7 @@ router id 62.168.0.1;
 define xyzzy = (120+10);
 define '1a-a1' = (20+10);
 define one = 1;
+define ten = 10;
 
 function onef(int a)
 {
@@ -56,6 +57,7 @@ bgpmask pm1;
 bgpmask pm2;
 bgppath p2;
 clist l;
+eclist el;
 {
        pm1 =  / 4 3 2 1 /;
        pm2 = [= 4 3 2 1 =];
@@ -118,6 +120,29 @@ clist l;
        print "Community list (3,1) ", l;
        l = delete( l, [(*,(onef(5)))] );
        print "Community list empty ", l;
+
+       el = -- empty --;
+       el = add(el, (rt, 10, 20));
+       el = add(el, (ro, 10.20.30.40, 100));
+       el = add(el, (ro, 11.21.31.41.mask(16), 200));
+       print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):";
+       print el;
+       el = delete(el, (rt, 10, 20));
+       el = delete(el, (rt, 10, 30));
+       el = add(el, (unknown 2, ten, 1));
+       el = add(el, (unknown 5, ten, 1));
+       el = add(el, (rt, ten, one+one));
+       el = add(el, (rt, 10, 3));
+       el = add(el, (rt, 10, 4));
+       el = add(el, (rt, 10, 5));
+       el = add(el, (generic, 0x2000a, 3*ten));
+       el = delete(el, [(rt, 10, 2..ten)]);
+       print "EC list (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200) (rt, 10, 1) (unknown 0x5, 10, 1) (rt, 10, 30):";
+       print el;
+       el = filter(el, [(rt, 10, *)]);
+       print "EC list (rt, 10, 1) (rt, 10, 30): ", el;
+       print "Testing EC list, true: ", (rt, 10, 1) ~ el, " ", el ~ [(rt, 10, ten..40)];
+       print "Testing EC list, false: ", (rt, 10, 20) ~ el, " ", (ro, 10.20.30.40, 100) ~ el, " ", el ~ [(rt, 10, 35..40)], " ", el ~ [(ro, 10, *)];
 }
 
 function bla()
@@ -175,11 +200,13 @@ prefix px;
 ip p;
 pair pp;
 quad qq;
+ec cc;
 int set is;
 int set is1;
 int set is2;
 int set is3;
 pair set ps;
+ec set ecs;
 prefix set pxs;
 string s;
 {
@@ -250,6 +277,19 @@ string s;
                ", true: ", qq = 1.2.3.4, " ", qq ~ [1.2.3.4, 5.6.7.8],
                ", false: ", qq = 4.3.2.1, " ", qq ~ [1.2.1.1, 1.2.3.5];
 
+       cc = (rt, 12345, 200000);
+       print "Testing EC: (rt, 12345, 200000) = ", cc;
+       print "Testing EC: (ro, 100000, 20000) = ", (ro, 100000, 20000);
+       print "Testing EC: (rt, 10.20.30.40, 20000) = ", (rt, 10.20.30.40, 20000);
+       print "  true: ", cc = (rt, 12345, 200000), " ", cc < (rt, 12345, 200010),
+               ", false: ", cc = (rt, 12346, 200000), " ", cc = (ro, 12345, 200000), " ",  cc > (rt, 12345, 200010);
+
+       ecs = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)];
+       print "EC set: ", ecs;
+       print "Testing EC set, true:  ",  (rt, 10, 20) ~ ecs, "  ", (ro, 100000, 100) ~ ecs, "  ", (ro, 100000, 200) ~ ecs,
+               "  ", (rt, 12345, 0) ~ ecs, "  ", cc ~ ecs,  "  ", (rt, 12345, 4000000) ~ ecs;
+       print "Testing EC set, false: ", (ro, 10, 20) ~ ecs, " ", (rt, 10, 21) ~ ecs, " ", (ro, 100000, 99) ~ ecs,
+               " ", (ro, 12345, 10) ~ ecs, " ", (rt, 12346, 0) ~ ecs, " ", (ro, 0.1.134.160, 150) ~ ecs;
 
        s = "Hello";
        print "Testing string: ", s, " true: ", s ~ "Hell*", " false: ", s ~ "ell*";
index 3cbd63553f513e3a87f926b05b29ffd82f4a798c..020d09785c4685c55b7278e0766b8635a2d2a367 100644 (file)
@@ -36,10 +36,11 @@ int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int siz
 {
   u32 *z = (u32 *) set->data;
   byte *end = buf + size - 24;
+  int from2 = MAX(from, 0);
   int to = set->length / 4;
   int i;
 
-  for (i = MAX(from, 0); i < to; i++)
+  for (i = from2; i < to; i++)
     {
       if (buf > end)
        {
@@ -50,7 +51,7 @@ int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int siz
          return i;
        }
 
-      if (i > from)
+      if (i > from2)
        *buf++ = ' ';
 
       if (way)
@@ -62,6 +63,84 @@ int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int siz
   return 0;
 }
 
+int
+ec_format(byte *buf, u64 ec)
+{
+  u32 type, key, val;
+  char tbuf[16], *kind;
+
+  type = ec >> 48;
+  switch (type & 0xf0ff)
+    {
+    case EC_RT: kind = "rt"; break;
+    case EC_RO: kind = "ro"; break;
+
+    default:
+      kind = tbuf;
+      bsprintf(kind, "unknown 0x%x", type);
+    }
+
+  switch (ec >> 56)
+    {
+      /* RFC 4360 3.1.  Two-Octet AS Specific Extended Community */
+    case 0x00:
+    case 0x40:
+      key = (ec >> 32) & 0xFFFF;
+      val = ec;
+      return bsprintf(buf, "(%s, %u, %u)", kind, key, val);
+
+      /* RFC 4360 3.2.  IPv4 Address Specific Extended Community */
+    case 0x01:
+    case 0x41:
+      key = ec >> 16;
+      val = ec & 0xFFFF;
+      return bsprintf(buf, "(%s, %R, %u)", kind, key, val);
+
+      /* RFC 5668  4-Octet AS Specific BGP Extended Community */
+    case 0x02:
+    case 0x42:
+      key = ec >> 16;
+      val = ec & 0xFFFF;
+      return bsprintf(buf, "(%s, %u, %u)", kind, key, val);
+
+      /* Generic format for unknown kinds of extended communities */
+    default:
+      key = ec >> 32;
+      val = ec;
+      return bsprintf(buf, "(generic, 0x%x, 0x%x)", key, val);
+    }
+
+}
+
+int
+ec_set_format(struct adata *set, int from, byte *buf, unsigned int size)
+{
+  u32 *z = int_set_get_data(set);
+  byte *end = buf + size - 24;
+  int from2 = MAX(from, 0);
+  int to = int_set_get_size(set);
+  int i;
+
+  for (i = from2; i < to; i += 2)
+    {
+      if (buf > end)
+       {
+         if (from < 0)
+           strcpy(buf, " ...");
+         else
+           *buf = 0;
+         return i;
+       }
+
+      if (i > from2)
+       *buf++ = ' ';
+
+      buf += ec_format(buf, ec_get(z, i));
+    }
+  *buf = 0;
+  return 0;
+}
+
 int
 int_set_contains(struct adata *list, u32 val)
 {
@@ -69,10 +148,32 @@ int_set_contains(struct adata *list, u32 val)
     return 0;
 
   u32 *l = (u32 *) list->data;
-  unsigned int i;
-  for (i=0; i<list->length/4; i++)
+  int len = int_set_get_size(list);
+  int i;
+
+  for (i = 0; i < len; i++)
     if (*l++ == val)
       return 1;
+
+  return 0;
+}
+
+int
+ec_set_contains(struct adata *list, u64 val)
+{
+  if (!list)
+    return 0;
+
+  u32 *l = int_set_get_data(list);
+  int len = int_set_get_size(list);
+  u32 eh = ec_hi(val);
+  u32 el = ec_lo(val);
+  int i;
+
+  for (i=0; i < len; i += 2)
+    if (l[i] == eh && l[i+1] == el)
+      return 1;
+
   return 0;
 }
 
@@ -86,7 +187,7 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val)
     return list;
 
   len = list ? list->length : 0;
-  res = lp_alloc(pool, len + sizeof(struct adata) + 4);
+  res = lp_alloc(pool, sizeof(struct adata) + len + 4);
   res->length = len + 4;
   * (u32 *) res->data = val;
   if (list)
@@ -95,23 +196,71 @@ int_set_add(struct linpool *pool, struct adata *list, u32 val)
 }
 
 struct adata *
-int_set_del(struct linpool *pool, struct adata *list, u32 val)
+ec_set_add(struct linpool *pool, struct adata *list, u64 val)
 {
-  struct adata *res;
-  u32 *l, *k;
-  unsigned int i;
+  if (ec_set_contains(list, val))
+    return list;
+
+  int olen = list ? list->length : 0;
+  struct adata *res = lp_alloc(pool, sizeof(struct adata) + olen + 8);
+  res->length = olen + 8;
+
+  if (list)
+    memcpy(res->data, list->data, list->length);
+
+  u32 *l = (u32 *) (res->data + res->length - 8);
+  l[0] = ec_hi(val);
+  l[1] = ec_lo(val);
+
+  return res;
+}
+
 
+struct adata *
+int_set_del(struct linpool *pool, struct adata *list, u32 val)
+{
   if (!int_set_contains(list, val))
     return list;
 
-  res = lp_alloc(pool, list->length + sizeof(struct adata) - 4);
-  res->length = list->length-4;
+  struct adata *res;
+  res = lp_alloc(pool, sizeof(struct adata) + list->length - 4);
+  res->length = list->length - 4;
+
+  u32 *l = int_set_get_data(list);
+  u32 *k = int_set_get_data(res);
+  int len = int_set_get_size(list);
+  int i;
 
-  l = (u32 *) list->data;
-  k = (u32 *) res->data;
-  for (i=0; i<list->length/4; i++)
+  for (i = 0; i < len; i++)
     if (l[i] != val)
       *k++ = l[i];
 
   return res;
 }
+
+struct adata *
+ec_set_del(struct linpool *pool, struct adata *list, u64 val)
+{
+  if (!ec_set_contains(list, val))
+    return list;
+
+  struct adata *res;
+  res = lp_alloc(pool, sizeof(struct adata) + list->length - 8);
+  res->length = list->length - 8;
+
+  u32 *l = int_set_get_data(list);
+  u32 *k = int_set_get_data(res);
+  int len = int_set_get_size(list);
+  u32 eh = ec_hi(val);
+  u32 el = ec_lo(val);
+  int i;
+
+  for (i=0; i < len; i += 2)
+    if (! (l[i] == eh && l[i+1] == el))
+      {
+       *k++ = l[i];
+       *k++ = l[i+1];
+      }
+
+  return res;
+}
index 6ce5755fe04bd815dd1909c45d92dd0898360c9f..85e4e59a6d9169712b71003a810e7155660fca3f 100644 (file)
@@ -50,12 +50,52 @@ int as_path_match(struct adata *path, struct f_path_mask *mask);
 
 /* a-set.c */
 
+
+/* Extended Community subtypes (kinds) */
+#define EC_RT 0x0002
+#define EC_RO 0x0003
+
+#define EC_GENERIC 0xFFFF
+
+/* Transitive bit (for first u32 half of EC) */
+#define EC_TBIT 0x40000000
+
+
+static inline int int_set_get_size(struct adata *list)
+{ return list->length / 4; }
+
+static inline u32 *int_set_get_data(struct adata *list)
+{ return (u32 *) list->data; }
+
+static inline u32 ec_hi(u64 ec) { return ec >> 32; }
+static inline u32 ec_lo(u64 ec) { return ec; }
+static inline u64 ec_get(const u32 *l, int i)
+{ return (((u64) l[i]) << 32) | l[i+1]; }
+
+/* RFC 4360 3.1.  Two-Octet AS Specific Extended Community */
+static inline u64 ec_as2(u64 kind, u64 key, u64 val)
+{ return ((kind | 0x0000) << 48) | (key << 32) | val; }
+
+/* RFC 5668  4-Octet AS Specific BGP Extended Community */
+static inline u64 ec_as4(u64 kind, u64 key, u64 val)
+{ return ((kind | 0x0200) << 48) | (key << 16) | val; }
+
+/* RFC 4360 3.2.  IPv4 Address Specific Extended Community */
+static inline u64 ec_ip4(u64 kind, u64 key, u64 val)
+{ return ((kind | 0x0100) << 48) | (key << 16) | val; }
+
+static inline u64 ec_generic(u64 key, u64 val)
+{ return (key << 32) | val; }
+
 int int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int size);
-struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
+int ec_format(byte *buf, u64 ec);
+int ec_set_format(struct adata *set, int from, byte *buf, unsigned int size);
 int int_set_contains(struct adata *list, u32 val);
+int ec_set_contains(struct adata *list, u64 val);
+struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
+struct adata *ec_set_add(struct linpool *pool, struct adata *list, u64 val);
 struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val);
+struct adata *ec_set_del(struct linpool *pool, struct adata *list, u64 val);
 
-static inline int int_set_get_size(struct adata *list)
-{ return list->length / 4; }
 
 #endif
index c77fe41735d49e9ebfe32bdc1853db8a7e431a6e..641b9248007d2d1b9b610ed71d64c186d635c49b 100644 (file)
@@ -363,6 +363,7 @@ typedef struct eattr {
 #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_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 */
 #define EAF_EMBEDDED 0x01              /* Data stored in eattr.u.data (part of type spec) */
 #define EAF_VAR_LENGTH 0x02            /* Attribute length is variable (part of type spec) */
index 486a543d3d555d11d012af32de3b91c91264329e..5a78f167e18a03ceb414207186b4f2a34660968f 100644 (file)
@@ -465,6 +465,18 @@ ea_show_int_set(struct cli *c, struct adata *ad, int way, byte *pos, byte *buf,
     }
 }
 
+static inline void
+ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
+{
+  int i = ec_set_format(ad, 0, pos, end - pos);
+  cli_printf(c, -1012, "%s", buf);
+  while (i)
+    {
+      i = ec_set_format(ad, i, buf, end - buf - 1);
+      cli_printf(c, -1012, "\t%s", buf);
+    }
+}
+
 /**
  * ea_show - print an &eattr to CLI
  * @c: destination CLI
@@ -523,6 +535,9 @@ ea_show(struct cli *c, eattr *e)
        case EAF_TYPE_INT_SET:
          ea_show_int_set(c, ad, 1, pos, buf, end);
          return;
+       case EAF_TYPE_EC_SET:
+         ea_show_ec_set(c, ad, pos, buf, end);
+         return;
        case EAF_TYPE_UNDEF:
        default:
          bsprintf(pos, "<type %02x>", e->type);
index 83ca24983f698cd21076400ca82561fa2aa87afe..59d8a8c08cb8f33b462af1ef9b740fa2411219f1 100644 (file)
@@ -247,7 +247,6 @@ bgp_check_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
   return ((len % 4) == 0) ? 0 : WITHDRAW;
 }
 
-
 static int
 bgp_check_cluster_list(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
 {
@@ -281,6 +280,13 @@ bgp_check_unreach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSE
   return IGNORE;
 }
 
+static int
+bgp_check_ext_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
+{
+  return ((len % 8) == 0) ? 0 : WITHDRAW;
+}
+
+
 static struct attr_desc bgp_attr_table[] = {
   { NULL, -1, 0, 0, 0,                                                         /* Undefined */
     NULL, NULL },
@@ -311,7 +317,8 @@ static struct attr_desc bgp_attr_table[] = {
     bgp_check_reach_nlri, NULL },
   { "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1,                   /* BA_MP_UNREACH_NLRI */
     bgp_check_unreach_nlri, NULL },
-  {  .name = NULL },                                                           /* BA_EXTENDED_COMM */
+  { "ext_community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_EC_SET, 1,    /* BA_EXT_COMMUNITY */
+    bgp_check_ext_community, NULL },
   { "as4_path", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,         /* BA_AS4_PATH */
     NULL, NULL },
   { "as4_aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,   /* BA_AS4_PATH */
@@ -468,7 +475,7 @@ bgp_get_attr_len(eattr *a)
 unsigned int
 bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
 {
-  unsigned int i, code, flags;
+  unsigned int i, code, type, flags;
   byte *start = w;
   int len, rv;
 
@@ -477,6 +484,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
       eattr *a = &attrs->attrs[i];
       ASSERT(EA_PROTO(a->id) == EAP_BGP);
       code = EA_ID(a->id);
+
 #ifdef IPV6
       /* When talking multiprotocol BGP, the NEXT_HOP attributes are used only temporarily. */
       if (code == BA_NEXT_HOP)
@@ -559,11 +567,12 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
 
       /* Standard path continues here ... */
 
+      type = a->type & EAF_TYPE_MASK;
       flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
       len = bgp_get_attr_len(a);
 
-      /* Skip empty int sets */ 
-      if (((a->type & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) && (len == 0))
+      /* Skip empty sets */ 
+      if (((type == EAF_TYPE_INT_SET) || (type == EAF_TYPE_EC_SET)) && (len == 0))
        continue; 
 
       if (remains < len + 4)
@@ -572,7 +581,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
       rv = bgp_encode_attr_hdr(w, flags, code, len);
       ADVANCE(w, remains, rv);
 
-      switch (a->type & EAF_TYPE_MASK)
+      switch (type)
        {
        case EAF_TYPE_INT:
        case EAF_TYPE_ROUTER_ID:
@@ -589,8 +598,9 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
            break;
          }
        case EAF_TYPE_INT_SET:
+       case EAF_TYPE_EC_SET:
          {
-           u32 *z = (u32 *)a->u.ptr->data;
+           u32 *z = int_set_get_data(a->u.ptr);
            int i;
            for(i=0; i<len; i+=4)
              put_u32(w+i, *z++);
@@ -624,13 +634,50 @@ bgp_compare_u32(const u32 *x, const u32 *y)
   return (*x < *y) ? -1 : (*x > *y) ? 1 : 0;
 }
 
-static void
-bgp_normalize_set(u32 *dest, u32 *src, unsigned cnt)
+static inline void
+bgp_normalize_int_set(u32 *dest, u32 *src, unsigned cnt)
 {
   memcpy(dest, src, sizeof(u32) * cnt);
   qsort(dest, cnt, sizeof(u32), (int(*)(const void *, const void *)) bgp_compare_u32);
 }
 
+static int
+bgp_compare_ec(const u32 *xp, const u32 *yp)
+{
+  u64 x = ec_get(xp, 0);
+  u64 y = ec_get(yp, 0);
+  return (x < y) ? -1 : (x > y) ? 1 : 0;
+}
+
+static inline void
+bgp_normalize_ec_set(struct adata *ad, u32 *src, int internal)
+{
+  u32 *dst = int_set_get_data(ad);
+
+  /* Remove non-transitive communities (EC_TBIT active) on external sessions */
+  if (! internal)
+    {
+      int len = int_set_get_size(ad);
+      u32 *t = dst;
+      int i;
+
+      for (i=0; i < len; i += 2)
+       {
+         if (src[i] & EC_TBIT)
+           continue;
+         
+         *t++ = src[i];
+         *t++ = src[i+1];
+       }
+
+      ad->length = (t - dst) * 4;
+    }
+  else
+    memcpy(dst, src, ad->length);
+
+  qsort(dst, ad->length / 8, 8, (int(*)(const void *, const void *)) bgp_compare_ec);
+}
+
 static void
 bgp_rehash_buckets(struct bgp_proto *p)
 {
@@ -763,7 +810,15 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
          {
            struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
            z->length = d->u.ptr->length;
-           bgp_normalize_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / 4);
+           bgp_normalize_int_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / 4);
+           d->u.ptr = z;
+           break;
+         }
+       case EAF_TYPE_EC_SET:
+         {
+           struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
+           z->length = d->u.ptr->length;
+           bgp_normalize_ec_set(z, (u32 *) d->u.ptr->data, p->is_internal);
            d->u.ptr = z;
            break;
          }
@@ -1447,6 +1502,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
          ipa_ntoh(*(ip_addr *)ad->data);
          break;
        case EAF_TYPE_INT_SET:
+       case EAF_TYPE_EC_SET:
          {
            u32 *z = (u32 *) ad->data;
            for(i=0; i<ad->length/4; i++)
index 097faa6a8e1ca06b34c2f9c51e36b3d60c47d136..12478709dce1c1551937fc0a70280122ba02ce5f 100644 (file)
@@ -236,7 +236,7 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi
 #define BA_RCID_PATH           0x0d
 #define BA_MP_REACH_NLRI       0x0e    /* [RFC2283] */
 #define BA_MP_UNREACH_NLRI     0x0f
-#define BA_EXTENDED_COMM       0x10    /* draft-ramachandra-bgp-ext-communities */
+#define BA_EXT_COMMUNITY       0x10    /* [RFC4360] */
 #define BA_AS4_PATH             0x11    /* [RFC4893] */
 #define BA_AS4_AGGREGATOR       0x12
 
index 93f832aa871bd1e7bf179323d6c468342aef599e..93cc85f659da072be69859554f20ce8d172da35c 100644 (file)
@@ -21,11 +21,11 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
        PATH, METRIC, ERROR, START, DELAY, FORGET, WAIT, ENABLE,
        DISABLE, AFTER, BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN,
        BGP_NEXT_HOP, BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY,
-       SOURCE, ADDRESS, PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4,
-       ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER,
-       MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET,
-       COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE,
-       GATEWAY, DIRECT, RECURSIVE, MED)
+       BGP_EXT_COMMUNITY, SOURCE, ADDRESS, PASSWORD, RR, RS, CLIENT,
+       CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE,
+       PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
+       INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
+       TABLE, GATEWAY, DIRECT, RECURSIVE, MED)
 
 CF_GRAMMAR
 
@@ -120,6 +120,9 @@ CF_ADDTO(dynamic_attr, BGP_ORIGINATOR_ID
        { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID)); })
 CF_ADDTO(dynamic_attr, BGP_CLUSTER_LIST
        { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); })
+CF_ADDTO(dynamic_attr, BGP_EXT_COMMUNITY
+       { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(EAP_BGP, BA_EXT_COMMUNITY)); })
+
 
 
 CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE)
index 4739fbaffcef85fa75e5d80247c25f43c42513c0..d029e2a7d40da06262f2868fa24de43c9271c221 100644 (file)
@@ -18,6 +18,9 @@
 /* 32-bit integer type */
 #define INTEGER_32 ?
 
+/* 64-bit integer type */
+#define INTEGER_64 ?
+
 /* CPU endianity */
 #undef CPU_LITTLE_ENDIAN
 #undef CPU_BIG_ENDIAN
index 0b06a70726021f59790398566583fc15e043cc35..8c7f8be15cc2b7ea576dd434b9681cf4b2bf7aef 100644 (file)
@@ -30,6 +30,8 @@ typedef INTEGER_16 s16;
 typedef unsigned INTEGER_16 u16;
 typedef INTEGER_32 s32;
 typedef unsigned INTEGER_32 u32;
+typedef INTEGER_64 s64;
+typedef unsigned INTEGER_64 u64;
 typedef u8 byte;
 typedef u16 word;