mirror of
https://gitlab.labs.nic.cz/labs/bird.git
synced 2024-05-11 16:54:54 +00:00
BGP Extended communities.
This commit is contained in:
238
filter/config.Y
238
filter/config.Y
@@ -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
|
||||
|
||||
280
filter/filter.c
280
filter/filter.c
@@ -51,10 +51,10 @@
|
||||
#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 ((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);
|
||||
#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");
|
||||
|
||||
res.type = T_CLIST;
|
||||
switch (what->aux)
|
||||
if (v1.type == T_CLIST)
|
||||
{
|
||||
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);
|
||||
/* 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;
|
||||
#ifndef IPV6
|
||||
/* 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
|
||||
res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 0);
|
||||
break;
|
||||
runtime("Can't add/delete non-pair");
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
default:
|
||||
bug("unknown Ca operation");
|
||||
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)
|
||||
{
|
||||
/* Extended community list */
|
||||
int arg_set = 0;
|
||||
|
||||
/* 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 ec");
|
||||
res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
bug("unknown Ca operation");
|
||||
}
|
||||
}
|
||||
else
|
||||
runtime("Can't add/delete to non-(e)clist");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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*";
|
||||
|
||||
Reference in New Issue
Block a user