Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
labs
BIRD Internet Routing Daemon
Commits
42a0c054
Commit
42a0c054
authored
Aug 12, 2011
by
Ondřej Zajíček
Browse files
BGP Extended communities.
parent
bde872bb
Changes
14
Hide whitespace changes
Inline
Side-by-side
aclocal.m4
View file @
42a0c054
...
...
@@ -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.])
...
...
filter/config.Y
View file @
42a0c054
...
...
@@ -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
filter/filter.c
View file @
42a0c054
...
...
@@ -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
(
v1
.
type
=
=
T_CLIST
)
{
/* Community (or cluster) list */
struct
f_val
dummy
;
int
arg_set
=
0
;