Commit 42a0c054 authored by Ondřej Zajíček's avatar Ondřej Zajíček

BGP Extended communities.

parent bde872bb
...@@ -6,7 +6,8 @@ AC_DEFUN(BIRD_CHECK_INTEGERS, ...@@ -6,7 +6,8 @@ AC_DEFUN(BIRD_CHECK_INTEGERS,
AC_CHECK_SIZEOF(short int, 0) AC_CHECK_SIZEOF(short int, 0)
AC_CHECK_SIZEOF(int, 0) AC_CHECK_SIZEOF(int, 0)
AC_CHECK_SIZEOF(long 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` bits=`expr $size "*" 8`
AC_MSG_CHECKING([for $bits-bit type]) AC_MSG_CHECKING([for $bits-bit type])
if test $ac_cv_sizeof_int = $size ; then if test $ac_cv_sizeof_int = $size ; then
...@@ -17,6 +18,8 @@ for size in 1 2 4 ; do ...@@ -17,6 +18,8 @@ for size in 1 2 4 ; do
res="short int" res="short int"
elif test $ac_cv_sizeof_long_int = $size ; then elif test $ac_cv_sizeof_long_int = $size ; then
res="long int" res="long int"
elif test $ac_cv_sizeof_long_long_int = $size ; then
res="long long int"
else else
AC_MSG_RESULT([not found]) AC_MSG_RESULT([not found])
AC_MSG_ERROR([Cannot find $bits-bit integer type.]) AC_MSG_ERROR([Cannot find $bits-bit integer type.])
......
...@@ -75,13 +75,185 @@ f_new_pair_set(int fa, int ta, int fb, int tb) ...@@ -75,13 +75,185 @@ f_new_pair_set(int fa, int ta, int fb, int tb)
return lst; 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_DECLS
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ACCEPT, REJECT, ERROR, QUITBIRD, 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, IF, THEN, ELSE, CASE,
TRUE, FALSE, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE, FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
LEN, LEN,
DEFINED, DEFINED,
...@@ -93,11 +265,11 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ...@@ -93,11 +265,11 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN %nonassoc THEN
%nonassoc ELSE %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 <f> filter filter_body where_filter
%type <i> type break_command pair_expr %type <i> type break_command pair_expr ec_kind
%type <i32> pair_atom %type <i32> pair_atom ec_expr
%type <e> pair_item set_item switch_item set_items switch_items switch_body %type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body
%type <trie> fprefix_set %type <trie> fprefix_set
%type <v> set_atom switch_atom fprefix fprefix_s fipa %type <v> set_atom switch_atom fprefix fprefix_s fipa
%type <s> decls declsn one_decl function_params %type <s> decls declsn one_decl function_params
...@@ -128,15 +300,18 @@ type: ...@@ -128,15 +300,18 @@ type:
| PREFIX { $$ = T_PREFIX; } | PREFIX { $$ = T_PREFIX; }
| PAIR { $$ = T_PAIR; } | PAIR { $$ = T_PAIR; }
| QUAD { $$ = T_QUAD; } | QUAD { $$ = T_QUAD; }
| EC { $$ = T_EC; }
| STRING { $$ = T_STRING; } | STRING { $$ = T_STRING; }
| BGPMASK { $$ = T_PATH_MASK; } | BGPMASK { $$ = T_PATH_MASK; }
| BGPPATH { $$ = T_PATH; } | BGPPATH { $$ = T_PATH; }
| CLIST { $$ = T_CLIST; } | CLIST { $$ = T_CLIST; }
| ECLIST { $$ = T_ECLIST; }
| type SET { | type SET {
switch ($1) { switch ($1) {
case T_INT: case T_INT:
case T_PAIR: case T_PAIR:
case T_QUAD: case T_QUAD:
case T_EC:
case T_IP: case T_IP:
$$ = T_SET; $$ = T_SET;
break; break;
...@@ -324,14 +499,32 @@ pair_item: ...@@ -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: set_item:
pair_item pair_item
| ec_item
| set_atom { $$ = f_new_item($1, $1); } | set_atom { $$ = f_new_item($1, $1); }
| set_atom DDOT set_atom { $$ = f_new_item($1, $3); } | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
; ;
switch_item: switch_item:
pair_item pair_item
| ec_item
| switch_atom { $$ = f_new_item($1, $1); } | switch_atom { $$ = f_new_item($1, $1); }
| switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
; ;
...@@ -411,20 +604,6 @@ bgp_path_tail2: ...@@ -411,20 +604,6 @@ bgp_path_tail2:
| { $$ = NULL; } | { $$ = 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: constant:
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; } NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; } | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
...@@ -439,6 +618,11 @@ constant: ...@@ -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; } | 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. * Maybe there are no dynamic attributes defined by protocols.
...@@ -490,6 +674,7 @@ symbol: ...@@ -490,6 +674,7 @@ symbol:
case SYM_VARIABLE | T_INT: case SYM_VARIABLE | T_INT:
case SYM_VARIABLE | T_PAIR: case SYM_VARIABLE | T_PAIR:
case SYM_VARIABLE | T_QUAD: case SYM_VARIABLE | T_QUAD:
case SYM_VARIABLE | T_EC:
case SYM_VARIABLE | T_STRING: case SYM_VARIABLE | T_STRING:
case SYM_VARIABLE | T_IP: case SYM_VARIABLE | T_IP:
case SYM_VARIABLE | T_PREFIX: case SYM_VARIABLE | T_PREFIX:
...@@ -498,6 +683,7 @@ symbol: ...@@ -498,6 +683,7 @@ symbol:
case SYM_VARIABLE | T_PATH: case SYM_VARIABLE | T_PATH:
case SYM_VARIABLE | T_PATH_MASK: case SYM_VARIABLE | T_PATH_MASK:
case SYM_VARIABLE | T_CLIST: case SYM_VARIABLE | T_CLIST:
case SYM_VARIABLE | T_ECLIST:
$$->code = 'V'; $$->code = 'V';
$$->a1.p = $1->def; $$->a1.p = $1->def;
$$->a2.p = $1->name; $$->a2.p = $1->name;
...@@ -539,7 +725,7 @@ term: ...@@ -539,7 +725,7 @@ term:
| symbol { $$ = $1; } | symbol { $$ = $1; }
| constant { $$ = $1; } | constant { $$ = $1; }
| dpair { $$ = $1; } | constructor { $$ = $1; }
| PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; } | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
...@@ -563,6 +749,7 @@ term: ...@@ -563,6 +749,7 @@ term:
| '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } | '+' 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_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; } | 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'; } | 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'; } | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
...@@ -702,8 +889,7 @@ cmd: ...@@ -702,8 +889,7 @@ cmd:
} }
| rtadot dynamic_attr '.' EMPTY ';' | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
{ 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 '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); } | 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 '.' 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 '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
......
...@@ -51,10 +51,10 @@ ...@@ -51,10 +51,10 @@
#define CMP_ERROR 999 #define CMP_ERROR 999
static struct adata * static struct adata *
adata_empty(struct linpool *pool) adata_empty(struct linpool *pool, int l)
{ {
struct adata *res = lp_alloc(pool, sizeof(struct adata)); struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
res->length = 0; res->length = l;
return res; return res;
} }
...@@ -126,6 +126,13 @@ static inline int uint_cmp(unsigned int i1, unsigned int i2) ...@@ -126,6 +126,13 @@ static inline int uint_cmp(unsigned int i1, unsigned int i2)
else return 1; 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 * val_compare - compare two values
* @v1: first value * @v1: first value
...@@ -167,6 +174,8 @@ val_compare(struct f_val v1, struct f_val v2) ...@@ -167,6 +174,8 @@ val_compare(struct f_val v1, struct f_val v2)
case T_PAIR: case T_PAIR:
case T_QUAD: case T_QUAD:
return uint_cmp(v1.val.i, v2.val.i); return uint_cmp(v1.val.i, v2.val.i);
case T_EC:
return u64_cmp(v1.val.ec, v2.val.ec);
case T_IP: case T_IP:
return ipa_compare(v1.val.px.ip, v2.val.px.ip); return ipa_compare(v1.val.px.ip, v2.val.px.ip);
case T_PREFIX: case T_PREFIX:
...@@ -226,6 +235,9 @@ val_simple_in_range(struct f_val v1, struct f_val v2) ...@@ -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)) if ((v1.type == T_IP) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip)); return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
#endif #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)) if ((v1.type == T_STRING) && (v2.type == T_STRING))
return patmatch(v2.val.s, v1.val.s); return patmatch(v2.val.s, v1.val.s);
...@@ -258,6 +270,10 @@ clist_set_type(struct f_tree *set, struct f_val *v) ...@@ -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 static int
clist_match_set(struct adata *clist, struct f_tree *set) clist_match_set(struct adata *clist, struct f_tree *set)
{ {
...@@ -270,6 +286,7 @@ 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 *l = (u32 *) clist->data;
u32 *end = l + clist->length/4; u32 *end = l + clist->length/4;
while (l < end) { while (l < end) {
v.val.i = *l++; v.val.i = *l++;
if (find_tree(set, v)) if (find_tree(set, v))
...@@ -278,6 +295,30 @@ clist_match_set(struct adata *clist, struct f_tree *set) ...@@ -278,6 +295,30 @@ clist_match_set(struct adata *clist, struct f_tree *set)
return 0; 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 * static struct adata *
clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int pos) 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 ...@@ -302,8 +343,39 @@ clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int
if (nl == clist->length) if (nl == clist->length)
return clist; return clist;
struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl); struct adata *res = adata_empty(pool, nl);
res->length = 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); memcpy(res->data, tmp, nl);
return res; return res;
} }
...@@ -332,6 +404,9 @@ val_in_range(struct f_val v1, struct f_val v2) ...@@ -332,6 +404,9 @@ val_in_range(struct f_val v1, struct f_val v2)
if ((v1.type == T_CLIST) && (v2.type == T_SET)) if ((v1.type == T_CLIST) && (v2.type == T_SET))
return clist_match_set(v1.val.ad, v2.val.t); 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) if (v2.type == T_SET)
switch (v1.type) { switch (v1.type) {
case T_ENUM: case T_ENUM:
...@@ -339,6 +414,7 @@ val_in_range(struct f_val v1, struct f_val v2) ...@@ -339,6 +414,7 @@ val_in_range(struct f_val v1, struct f_val v2)
case T_PAIR: case T_PAIR:
case T_QUAD: case T_QUAD:
case T_IP: case T_IP:
case T_EC:
{ {
struct f_tree *n; struct f_tree *n;
n = find_tree(v2.val.t, v1); n = find_tree(v2.val.t, v1);
...@@ -397,11 +473,13 @@ val_print(struct f_val v) ...@@ -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_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_PAIR: logn("(%d,%d)", v.val.i >> 16, v.val.i & 0xffff); return;
case T_QUAD: logn("%R", v.val.i); 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_PREFIX_SET: trie_print(v.val.ti); return;
case T_SET: tree_print(v.val.t); 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_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_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_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; 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; default: logn( "[unknown type %x]", v.type ); return;
} }
...@@ -541,7 +619,7 @@ interpret(struct f_inst *what) ...@@ -541,7 +619,7 @@ interpret(struct f_inst *what)
break; break;
case P('m','p'): case P('m','p'):
TWOARGS_C; TWOARGS;
if ((v1.type != T_INT) || (v2.type != T_INT)) if ((v1.type != T_INT) || (v2.type != T_INT))
runtime( "Can't operate with value of non-integer type in pair constructor" ); runtime( "Can't operate with value of non-integer type in pair constructor" );
u1 = v1.val.i; u1 = v1.val.i;
...@@ -552,6 +630,53 @@ interpret(struct f_inst *what) ...@@ -552,6 +630,53 @@ interpret(struct f_inst *what)
res.type = T_PAIR; res.type = T_PAIR;
break; 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 */ /* Relational operators */
#define COMPARE(x) \ #define COMPARE(x) \
...@@ -723,9 +848,16 @@ interpret(struct f_inst *what) ...@@ -723,9 +848,16 @@ interpret(struct f_inst *what)
/* A special case: undefined int_set looks like empty int_set */ /* A special case: undefined int_set looks like empty int_set */
if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) { if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
res.type = T_CLIST; 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; break;
} }
/* Undefined value */ /* Undefined value */
res.type = T_VOID; res.type = T_VOID;
break; break;
...@@ -757,6 +889,10 @@ interpret(struct f_inst *what) ...@@ -757,6 +889,10 @@ interpret(struct f_inst *what)
res.type = T_CLIST; res.type = T_CLIST;
res.val.ad = e->u.ptr; res.val.ad = e->u.ptr;
break; break;
case EAF_TYPE_EC_SET:
res.type = T_ECLIST;
res.val.ad = e->u.ptr;
break;
case EAF_TYPE_UNDEF: case EAF_TYPE_UNDEF:
res.type = T_VOID; res.type = T_VOID;
break; break;
...@@ -802,7 +938,12 @@ interpret(struct f_inst *what) ...@@ -802,7 +938,12 @@ interpret(struct f_inst *what)
break; break;
case EAF_TYPE_INT_SET: case EAF_TYPE_INT_SET:
if (v1.type != T_CLIST) 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; l->attrs[0].u.ptr = v1.val.ad;
break; break;
case EAF_TYPE_UNDEF: